@@ -66,6 +66,37 @@ static RefPtr<cairo_scaled_font_t> scaledFontWithoutMetricsHinting(cairo_scaled_
6666 return adoptRef (cairo_scaled_font_create (cairo_scaled_font_get_font_face (scaledFont), &fontMatrix, &fontCTM, fontOptions.get ()));
6767}
6868
69+ static float scaledFontScaleFactor (cairo_scaled_font_t * scaledFont)
70+ {
71+ cairo_matrix_t fontMatrix;
72+ cairo_scaled_font_get_font_matrix (scaledFont, &fontMatrix);
73+
74+ float determinant = fontMatrix.xx * fontMatrix.yy - fontMatrix.yx * fontMatrix.xy ;
75+ if (!std::isfinite (determinant))
76+ return 1 ;
77+
78+ determinant = std::abs (determinant);
79+ if (!determinant)
80+ return 0 ;
81+
82+ double x = 1 ;
83+ double y = 0 ;
84+ cairo_matrix_transform_distance (&fontMatrix, &x, &y);
85+ double xScale = std::hypot (x, y);
86+ return xScale ? narrowPrecisionToFloat (determinant / xScale) : 0 .;
87+ }
88+
89+ static Optional<unsigned > fontUnitsPerEm (FT_Face freeTypeFace)
90+ {
91+ if (freeTypeFace->units_per_EM )
92+ return freeTypeFace->units_per_EM ;
93+
94+ if (auto * ttHeader = static_cast <TT_Header*>(FT_Get_Sfnt_Table (freeTypeFace, ft_sfnt_head)))
95+ return ttHeader->Units_Per_EM ;
96+
97+ return WTF ::nullopt ;
98+ }
99+
69100void Font::platformInit ()
70101{
71102 if (!m_platformData.size ())
@@ -84,24 +115,35 @@ void Font::platformInit()
84115 float capHeight = narrowPrecisionToFloat (fontExtents.height );
85116 float lineGap = narrowPrecisionToFloat (fontExtents.height - fontExtents.ascent - fontExtents.descent );
86117 Optional<float > xHeight;
118+ Optional<unsigned > unitsPerEm;
119+ Optional<float > underlinePosition;
120+ Optional<float > underlineThickness;
87121
88122 {
89123 CairoFtFaceLocker cairoFtFaceLocker (m_platformData.scaledFont ());
124+ if (FT_Face freeTypeFace = cairoFtFaceLocker.ftFace ()) {
125+ unitsPerEm = fontUnitsPerEm (freeTypeFace);
126+
127+ if (freeTypeFace->face_flags & FT_FACE_FLAG_SCALABLE ) {
128+ // If the USE_TYPO_METRICS flag is set in the OS/2 table then we use typo metrics instead.
129+ if (auto * OS2Table = static_cast <TT_OS2 *>(FT_Get_Sfnt_Table (freeTypeFace, ft_sfnt_os2))) {
130+ const FT_Short kUseTypoMetricsMask = 1 << 7 ;
131+ // FT_Size_Metrics::y_scale is in 16.16 fixed point format.
132+ // Its (fractional) value is a factor that converts vertical metrics from design units to units of 1/64 pixels.
133+ double yscale = (freeTypeFace->size ->metrics .y_scale / 65536.0 ) / 64.0 ;
134+ if (OS2Table->fsSelection & kUseTypoMetricsMask ) {
135+ ascent = narrowPrecisionToFloat (yscale * OS2Table->sTypoAscender );
136+ descent = -narrowPrecisionToFloat (yscale * OS2Table->sTypoDescender );
137+ lineGap = narrowPrecisionToFloat (yscale * OS2Table->sTypoLineGap );
138+ }
139+ xHeight = narrowPrecisionToFloat (yscale * OS2Table->sxHeight );
140+ }
90141
91- // If the USE_TYPO_METRICS flag is set in the OS/2 table then we use typo metrics instead.
92- FT_Face freeTypeFace = cairoFtFaceLocker.ftFace ();
93- if (freeTypeFace && freeTypeFace->face_flags & FT_FACE_FLAG_SCALABLE ) {
94- if (auto * OS2Table = static_cast <TT_OS2 *>(FT_Get_Sfnt_Table (freeTypeFace, ft_sfnt_os2))) {
95- const FT_Short kUseTypoMetricsMask = 1 << 7 ;
96- // FT_Size_Metrics::y_scale is in 16.16 fixed point format.
97- // Its (fractional) value is a factor that converts vertical metrics from design units to units of 1/64 pixels.
98- double yscale = (freeTypeFace->size ->metrics .y_scale / 65536.0 ) / 64.0 ;
99- if (OS2Table->fsSelection & kUseTypoMetricsMask ) {
100- ascent = narrowPrecisionToFloat (yscale * OS2Table->sTypoAscender );
101- descent = -narrowPrecisionToFloat (yscale * OS2Table->sTypoDescender );
102- lineGap = narrowPrecisionToFloat (yscale * OS2Table->sTypoLineGap );
142+ if (unitsPerEm) {
143+ float scaleFactor = scaledFontScaleFactor (fontWithoutMetricsHinting.get ());
144+ underlinePosition = -((freeTypeFace->underline_position + freeTypeFace->underline_thickness / 2 .) / static_cast <float >(unitsPerEm.value ())) * scaleFactor;
145+ underlineThickness = (freeTypeFace->underline_thickness / static_cast <float >(unitsPerEm.value ())) * scaleFactor;
103146 }
104- xHeight = narrowPrecisionToFloat (yscale * OS2Table->sxHeight );
105147 }
106148 }
107149 }
@@ -118,17 +160,16 @@ void Font::platformInit()
118160 m_fontMetrics.setLineSpacing (lroundf (ascent) + lroundf (descent) + lroundf (lineGap));
119161 m_fontMetrics.setLineGap (lineGap);
120162 m_fontMetrics.setXHeight (xHeight.value ());
163+ if (unitsPerEm)
164+ m_fontMetrics.setUnitsPerEm (unitsPerEm.value ());
165+ if (underlinePosition)
166+ m_fontMetrics.setUnderlinePosition (underlinePosition.value ());
167+ if (underlineThickness)
168+ m_fontMetrics.setUnderlineThickness (underlineThickness.value ());
121169
122170 cairo_text_extents_t textExtents;
123171 cairo_scaled_font_text_extents (m_platformData.scaledFont (), " " , &textExtents);
124172 m_spaceWidth = narrowPrecisionToFloat ((platformData ().orientation () == FontOrientation::Horizontal) ? textExtents.x_advance : -textExtents.y_advance );
125-
126- if ((platformData ().orientation () == FontOrientation::Vertical) && !isTextOrientationFallback ()) {
127- CairoFtFaceLocker cairoFtFaceLocker (m_platformData.scaledFont ());
128- FT_Face freeTypeFace = cairoFtFaceLocker.ftFace ();
129- m_fontMetrics.setUnitsPerEm (freeTypeFace->units_per_EM );
130- }
131-
132173 m_syntheticBoldOffset = m_platformData.syntheticBold () ? 1 .0f : 0 .f ;
133174
134175 FcChar8* fontConfigFamilyName;
0 commit comments