GetTextMetrics returns wrong First/Last char index for Symbol fonts

Jie Zhu jonathan at corvu.com.au
Thu Sep 7 19:22:48 CDT 2006


ChangeLog:
	Set proper tmFirstChar, tmLastChar, tmBreakChar, and
	tmDefaultChar value in GetTextMetricsA and GetTextMetricsW
	according to Symbol font flag.



What's wrong:
For TrueType Symbol font, Wine GetTextMetricsA & GetTextMetricsW return
different First/Last char index comparing to Windows. Take 'Wingdings 2'
font for example, following table shows differences between Wine
implementation and windows.
                            FirstChar      LastChar
GetTextMetricsA Wine         255            255
                 Windows       30            249

GetTextMetricsW Wine        0x0F020        0x0F0F9
                 Windows       0x0          0x0F0FF

Further investigation found that in Wine implementation, GetTextMetricsW
takes First/Last char index from OS2 table from TrueTypeFont file.
FONT_TextMetricWToA make sure these 2 values in TEXTMETRICSA are no
greater than 255. According to TrueTypeFont specification, Symbol font
runs characters in Unicode range 0x0F000 ~ 0x0F0FF (inclusive). In
'Wingdings 2' font case, OS2 table returns 0x0F020 & 0x0F0F9 as
first/last char index. So after calling FONT_TextMetricWToA, both
First/Last chars in TEXTMETRICSA become 255.



What's better:
GetTextMetricsA and GetTextMetricsW behave more like windows.



What's changed:
For TrueType Symbol font, First/Last char index in GetTextMetricsW are
always 0 & 0x0F0FF; GetTextMetricsA uses 0x0FF to mask the value from
OS2 table from TrueTypeFont (if last char index from OS2 table is
greater than 0x0F0FF, GetTextMetrcisA uses 0x0FF instead).

For non Symbol font, GetTextMetricsW uses First/Last char value from OS2
table in TrueTypeFont; GetTextMetricsA uses these values as well but put
255 as maximum limit.

Details please see patch section and Test Package section.



Test package:
A test package is attached. It can be built under Windows and Linux
(define linux when compiling with wine). tm_window.txt and tm_linux.txt
will be generated for comparing tmFirstChar, tmLastChar, tmBreakChar,
tmDefaultChar, and tmCharSet.

The test package discovered following Window behaviors:
For Symbol fonts:
    1. GetTextMetricsW always return 0x0 and 0x0F0FF as first/last 
characters, which is different from OS2 values
    2. GetTextMetricsA mask 0x0F000 off the first/last char from OS2 table.
    3. If last char from OS2 table is greater than 0x0F0FF,
GetTextMetricsA set last char to 0x0FF
    4. GetTextMetricsW tmBreakChar equals OS2 table First Char & 0x0FF
For non Symbol fonts:
    1. GetTextMetricsW uses First/Last char from OS2 table in
TrueTypeFont file.
    2. GetTextMetricsA First/Last char has 255 as upper limit
    3. GetTextMetricsW use First char from OS2 table as tmBreakChar
General rules:
    1. tmA.tmBreakChar equals to tmW.tmBreakChar
    2. tmA.tmFirstChar is always the tmBreakChar - 2.
    3. If tmBreakChar is less than 2, tmBreakChar in both tmA & tmW are
automatically increased by 2.
    4. Generally tmDefaultChar is 1 less than tmBreakChar in both tmA & tmW.
    5. If tmW.tmDefaultChar is greater than 255 then tmA.tmDefaultChar
equals to tmBreakChar

We also found that although Symbol font should be determined by a symbol
bit flag in OS2 table ulCodePageRange1 plus a symbol cmap subtable,
Window doesn't respect this rule. Practically, Windows treat any fonts
with symbol cmap subtable as symbol font (sample TrueType Symbol fonts
are MT Extra, CityBlueprint, CommercialPi BT, CountryBlueprint,
EuroRoman, PanRoman, Romantic, SansSerif, SuperFrench, Technic,
UniversalMath1 BT, etc). In the test package, statement 'P20' shows this
point. In the patch, we specifically check whether symbol subtable is
available.

Best Regards
Jonathan



-- 
________________________________________
Jonathan Jie Zhu

CorVu Corporation (www.corvu.com)
Sydney Office: +61 2 9495 5400

If you wish to receive no further email from CorVu: <http://emb.corvu.com/>


-------------- next part --------------
A non-text attachment was scrubbed...
Name: ttfontfile.zip
Type: application/x-zip-compressed
Size: 14055 bytes
Desc: not available
Url : http://www.winehq.org/pipermail/wine-patches/attachments/20060908/3782c95d/ttfontfile-0001.bin
-------------- next part --------------
diff --git a/dlls/gdi/font.c b/dlls/gdi/font.c
index 33a03f6..ecd0c27 100644
--- a/dlls/gdi/font.c
+++ b/dlls/gdi/font.c
@@ -289,10 +289,18 @@ static void FONT_TextMetricWToA(const TE
     ptmA->tmOverhang = ptmW->tmOverhang;
     ptmA->tmDigitizedAspectX = ptmW->tmDigitizedAspectX;
     ptmA->tmDigitizedAspectY = ptmW->tmDigitizedAspectY;
-    ptmA->tmFirstChar = ptmW->tmFirstChar > 255 ? 255 : ptmW->tmFirstChar;
-    ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
-    ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? 255 : ptmW->tmDefaultChar;
-    ptmA->tmBreakChar = ptmW->tmBreakChar > 255 ? 255 : ptmW->tmBreakChar;
+    ptmA->tmBreakChar = ptmW->tmBreakChar;
+    ptmA->tmFirstChar = ptmA->tmBreakChar - 2;
+    if (ptmW->tmCharSet == SYMBOL_CHARSET)
+    {
+        ptmA->tmLastChar = ptmW->tmLastChar > 0x0F0FF ? 0x0FF : ptmW->tmLastChar & 0x0FF;
+    }
+    else
+    {
+        ptmA->tmLastChar = ptmW->tmLastChar > 255 ? 255 : ptmW->tmLastChar;
+    }
+    ptmA->tmDefaultChar = ptmW->tmDefaultChar > 255 ? ptmA->tmBreakChar : ptmW->tmDefaultChar;
+
     ptmA->tmItalic = ptmW->tmItalic;
     ptmA->tmUnderlined = ptmW->tmUnderlined;
     ptmA->tmStruckOut = ptmW->tmStruckOut;
@@ -314,10 +322,18 @@ static void FONT_NewTextMetricExWTo16(co
     ptm16->ntmTm.tmOverhang = ptmW->ntmTm.tmOverhang;
     ptm16->ntmTm.tmDigitizedAspectX = ptmW->ntmTm.tmDigitizedAspectX;
     ptm16->ntmTm.tmDigitizedAspectY = ptmW->ntmTm.tmDigitizedAspectY;
-    ptm16->ntmTm.tmFirstChar = ptmW->ntmTm.tmFirstChar > 255 ? 255 : ptmW->ntmTm.tmFirstChar;
-    ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 255 ? 255 : ptmW->ntmTm.tmLastChar;
-    ptm16->ntmTm.tmDefaultChar = ptmW->ntmTm.tmDefaultChar > 255 ? 255 : ptmW->ntmTm.tmDefaultChar;
-    ptm16->ntmTm.tmBreakChar = ptmW->ntmTm.tmBreakChar > 255 ? 255 : ptmW->ntmTm.tmBreakChar;
+    ptm16->ntmTm.tmBreakChar = ptmW->ntmTm.tmBreakChar;
+    ptm16->ntmTm.tmFirstChar = ptm16->ntmTm.tmBreakChar - 2;
+    if (ptmW->ntmTm.tmCharSet == SYMBOL_CHARSET)
+    {
+        ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 0x0F0FF ? 0x0FF : ptmW->ntmTm.tmLastChar & 0x0FF;
+    }
+    else
+    {
+        ptm16->ntmTm.tmLastChar = ptmW->ntmTm.tmLastChar > 255 ? 255 : ptmW->ntmTm.tmLastChar;
+    }
+    ptm16->ntmTm.tmDefaultChar = ptmW->ntmTm.tmDefaultChar > 255 ? ptm16->ntmTm.tmBreakChar : ptmW->ntmTm.tmDefaultChar;
+
     ptm16->ntmTm.tmItalic = ptmW->ntmTm.tmItalic;
     ptm16->ntmTm.tmUnderlined = ptmW->ntmTm.tmUnderlined;
     ptm16->ntmTm.tmStruckOut = ptmW->ntmTm.tmStruckOut;
@@ -1239,21 +1255,9 @@ done:
 }
 
 /***********************************************************************
- *           GetTextMetricsA    (GDI32.@)
+ *           get_text_metrics_w    (GDI32.@)
  */
-BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
-{
-    TEXTMETRICW tm32;
-
-    if (!GetTextMetricsW( hdc, &tm32 )) return FALSE;
-    FONT_TextMetricWToA( &tm32, metrics );
-    return TRUE;
-}
-
-/***********************************************************************
- *           GetTextMetricsW    (GDI32.@)
- */
-BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
+static BOOL get_text_metrics_w( HDC hdc, TEXTMETRICW *metrics )
 {
     BOOL ret = FALSE;
     DC * dc = DC_GetDCPtr( hdc );
@@ -1284,6 +1288,18 @@ BOOL WINAPI GetTextMetricsW( HDC hdc, TE
     metrics->tmAveCharWidth     = WDPTOLP(metrics->tmAveCharWidth);
     metrics->tmMaxCharWidth     = WDPTOLP(metrics->tmMaxCharWidth);
     metrics->tmOverhang         = WDPTOLP(metrics->tmOverhang);
+    if (metrics->tmCharSet == SYMBOL_CHARSET)
+    {
+	    metrics->tmBreakChar = metrics->tmFirstChar & 0x0FF;
+    }
+    else
+    {
+	    metrics->tmBreakChar = metrics->tmFirstChar;
+    }
+    if (metrics->tmBreakChar < 2)
+	    metrics->tmBreakChar = metrics->tmBreakChar + 2;
+    if (!metrics->tmDefaultChar)
+	    metrics->tmDefaultChar = metrics->tmBreakChar - 1;
         ret = TRUE;
 #undef WDPTOLP
 #undef HDPTOLP
@@ -1312,6 +1328,36 @@ BOOL WINAPI GetTextMetricsW( HDC hdc, TE
     return ret;
 }
 
+/***********************************************************************
+ *           GetTextMetricsA    (GDI32.@)
+ */
+BOOL WINAPI GetTextMetricsA( HDC hdc, TEXTMETRICA *metrics )
+{
+    TEXTMETRICW tm32;
+
+    if (!get_text_metrics_w( hdc, &tm32 )) return FALSE;
+    FONT_TextMetricWToA( &tm32, metrics );
+    return TRUE;
+}
+
+/***********************************************************************
+ *           GetTextMetricsW    (GDI32.@)
+ */
+BOOL WINAPI GetTextMetricsW( HDC hdc, TEXTMETRICW *metrics )
+{
+    if (get_text_metrics_w(hdc, metrics))
+    {
+        if (metrics->tmCharSet == SYMBOL_CHARSET)
+        {
+            metrics->tmFirstChar = 0;
+            metrics->tmLastChar = 0x0F0FF;
+        }
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
 
 /***********************************************************************
  * GetOutlineTextMetrics [GDI.308]  Gets metrics for TrueType fonts.
@@ -1561,7 +1607,7 @@ UINT WINAPI GetOutlineTextMetricsW(
 	    else {
 	        memset(lpOTM, 0, ret);
 		lpOTM->otmSize = sizeof(*lpOTM);
-		GetTextMetricsW(hdc, &lpOTM->otmTextMetrics);
+		get_text_metrics_w(hdc, &lpOTM->otmTextMetrics);
 		/*
 		  Further fill of the structure not implemented,
 		  Needs real values for the structure members
diff --git a/dlls/gdi/freetype.c b/dlls/gdi/freetype.c
index 9f52e60..23b8312 100644
--- a/dlls/gdi/freetype.c
+++ b/dlls/gdi/freetype.c
@@ -2508,6 +2508,14 @@ found:
         return 0;
     }
 
+    /**
+     * In windows version, some true type fonts don't have SYMBOL flag in OS2
+     * ulCodeRange1, but it has MS_SYMBOL cmap section and still be treated
+     * as Symbol font.
+     **/
+    if (!pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL))
+        ret->charset = SYMBOL_CHARSET;
+
     if (ret->charset == SYMBOL_CHARSET && 
         !pFT_Select_Charmap(ret->ft_face, FT_ENCODING_MS_SYMBOL)) {
         /* No ops */


More information about the wine-patches mailing list