https://git.reactos.org/?p=reactos.git;a=commitdiff;h=138eb58b955e733d1bb53…
commit 138eb58b955e733d1bb53eb72445641ced65ebf6
Author:     Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Thu Dec 1 08:54:39 2022 +0900
Commit:     GitHub <noreply(a)github.com>
CommitDate: Thu Dec 1 08:54:39 2022 +0900
    [NTGDI][FREETYPE] lfWidth for GetTextMetrics and GetCharWidth (#4919)
    - Add lfWidth member into FONTGDI structure.
    - Delete IntWidthMatrix function.
    - Fix IntRequestFontSize behavior for processing lfWidth value.
    - Apply lfWidth in GetTextMetrics and GetCharWidth.
    - Ignore the XFORM values in GetTextMetrics and GetCharWidth.
    CORE-11848
---
 win32ss/gdi/eng/engobjects.h |   1 +
 win32ss/gdi/ntgdi/font.h     |   1 +
 win32ss/gdi/ntgdi/freetype.c | 127 ++++++++++++++++++++-----------------------
 3 files changed, 60 insertions(+), 69 deletions(-)
diff --git a/win32ss/gdi/eng/engobjects.h b/win32ss/gdi/eng/engobjects.h
index 81f2b586432..98af01af982 100644
--- a/win32ss/gdi/eng/engobjects.h
+++ b/win32ss/gdi/eng/engobjects.h
@@ -164,6 +164,7 @@ typedef struct _FONTGDI {
   LONG          tmInternalLeading;
   LONG          Magic;
   LONG          lfHeight;
+  LONG          lfWidth;
 } FONTGDI, *PFONTGDI;
 /* The initialized 'Magic' value in FONTGDI */
diff --git a/win32ss/gdi/ntgdi/font.h b/win32ss/gdi/ntgdi/font.h
index 674406281a0..fe54c3b8d8d 100644
--- a/win32ss/gdi/ntgdi/font.h
+++ b/win32ss/gdi/ntgdi/font.h
@@ -42,6 +42,7 @@ typedef struct _FONT_CACHE_HASHED
     INT GlyphIndex;
     FT_Face Face;
     LONG lfHeight;
+    LONG lfWidth;
     _ANONYMOUS_UNION union {
         DWORD AspectValue;
         FONT_ASPECT Aspect;
diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c
index ea4a854bfad..fa60795b70c 100644
--- a/win32ss/gdi/ntgdi/freetype.c
+++ b/win32ss/gdi/ntgdi/freetype.c
@@ -703,37 +703,12 @@ InitFontSupport(VOID)
     return TRUE;
 }
-static LONG FASTCALL IntWidthMatrix(FT_Face face, FT_Matrix *pmat, LONG lfWidth)
+static LONG IntNormalizeAngle(LONG nTenthsOfDegrees)
 {
-    LONG tmAveCharWidth;
-    TT_OS2 *pOS2;
-    FT_Fixed XScale;
-
-    *pmat = identityMat;
-
-    if (lfWidth == 0)
-        return 0;
-
-    ASSERT_FREETYPE_LOCK_HELD();
-    pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
-    if (!pOS2)
-        return 0;
-
-    XScale = face->size->metrics.x_scale;
-    tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
-    if (tmAveCharWidth == 0)
-    {
-        tmAveCharWidth = 1;
-    }
-
-    if (lfWidth == tmAveCharWidth)
-        return 0;
-
-    pmat->xx = INT_TO_FIXED(lfWidth) / tmAveCharWidth;
-    pmat->xy = 0;
-    pmat->yx = 0;
-    pmat->yy = INT_TO_FIXED(1);
-    return lfWidth;
+    nTenthsOfDegrees %= 360 * 10;
+    if (nTenthsOfDegrees >= 0)
+        return nTenthsOfDegrees;
+    return nTenthsOfDegrees + 360 * 10;
 }
 VOID FASTCALL IntEscapeMatrix(FT_Matrix *pmat, LONG lfEscapement)
@@ -2188,12 +2163,13 @@ FillTM(TEXTMETRICW *TM, PFONTGDI FontGDI,
                                     - ((Ascent + Descent)
                                        - (pHori->Ascender - pHori->Descender)),
                                     YScale) + 32) >> 6);
+    if (FontGDI->lfWidth != 0)
+        TM->tmAveCharWidth = FontGDI->lfWidth;
+    else
+        TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >>
6;
-    TM->tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
     if (TM->tmAveCharWidth == 0)
-    {
         TM->tmAveCharWidth = 1;
-    }
     /* Correct forumla to get the maxcharwidth from unicode and ansi font */
     TM->tmMaxCharWidth = (FT_MulFix(Face->max_advance_width, XScale) + 32) >>
6;
@@ -3145,6 +3121,7 @@ ftGdiGlyphCacheGet(IN const FONT_CACHE_ENTRY *pCache)
             FontEntry->Hashed.GlyphIndex == pCache->Hashed.GlyphIndex &&
             FontEntry->Hashed.Face == pCache->Hashed.Face &&
             FontEntry->Hashed.lfHeight == pCache->Hashed.lfHeight &&
+            FontEntry->Hashed.lfWidth == pCache->Hashed.lfWidth &&
             FontEntry->Hashed.AspectValue == pCache->Hashed.AspectValue &&
             memcmp(&FontEntry->Hashed.matTransform,
&pCache->Hashed.matTransform,
                    sizeof(FT_Matrix)) == 0)
@@ -3478,7 +3455,7 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG
lfHeight)
     TT_OS2 *pOS2;
     TT_HoriHeader *pHori;
     FT_WinFNT_HeaderRec WinFNT;
-    LONG Ascent, Descent, Sum, EmHeight;
+    LONG Ascent, Descent, Sum, EmHeight, Width64;
     lfWidth = abs(lfWidth);
     if (lfHeight == 0)
@@ -3497,8 +3474,12 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG
lfHeight)
     if (lfHeight == -1)
         lfHeight = -2;
-    if (FontGDI->Magic == FONTGDI_MAGIC && FontGDI->lfHeight == lfHeight)
+    if (FontGDI->Magic == FONTGDI_MAGIC &&
+        FontGDI->lfHeight == lfHeight &&
+        FontGDI->lfWidth == lfWidth)
+    {
         return 0; /* Cached */
+    }
     ASSERT_FREETYPE_LOCK_HELD();
     pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
@@ -3520,6 +3501,7 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG
lfHeight)
         FontGDI->tmInternalLeading  = WinFNT.internal_leading;
         FontGDI->Magic              = FONTGDI_MAGIC;
         FontGDI->lfHeight           = lfHeight;
+        FontGDI->lfWidth            = lfWidth;
         return 0;
     }
@@ -3574,13 +3556,19 @@ IntRequestFontSize(PDC dc, PFONTGDI FontGDI, LONG lfWidth, LONG
lfHeight)
     FontGDI->Magic = FONTGDI_MAGIC;
     FontGDI->lfHeight = lfHeight;
+    FontGDI->lfWidth = lfWidth;
     EmHeight = FontGDI->tmHeight - FontGDI->tmInternalLeading;
     EmHeight = max(EmHeight, 1);
     EmHeight = min(EmHeight, USHORT_MAX);
+    if (pOS2 && lfWidth > 0)
+        Width64 = FT_MulDiv(lfWidth, face->units_per_EM, pOS2->xAvgCharWidth)
<< 6;
+    else
+        Width64 = 0;
+
     req.type           = FT_SIZE_REQUEST_TYPE_NOMINAL;
-    req.width          = 0;
+    req.width          = Width64;
     req.height         = (EmHeight << 6);
     req.horiResolution = 0;
     req.vertResolution = 0;
@@ -3805,7 +3793,7 @@ ftGdiGetGlyphOutline(
     IntLockFreeType();
     TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
     FtMatrixFromMx(&mat, DC_pmxWorldToDevice(dc));
-    FT_Set_Transform(ft_face, &mat, 0);
+    FT_Set_Transform(ft_face, &mat, NULL);
     TEXTOBJ_UnlockText(TextObj);
@@ -4274,10 +4262,10 @@ TextIntGetTextExtentPoint(PDC dc,
 {
     PFONTGDI FontGDI;
     FT_BitmapGlyph realglyph;
-    INT glyph_index, i, previous;
+    INT glyph_index, i, previous, nTenthsOfDegrees;
     ULONGLONG TotalWidth64 = 0;
     LOGFONTW *plf;
-    BOOL use_kerning;
+    BOOL use_kerning, bVerticalWriting;
     LONG ascender, descender;
     FONT_CACHE_ENTRY Cache;
@@ -4289,27 +4277,26 @@ TextIntGetTextExtentPoint(PDC dc,
         *Fit = 0;
     }
-    IntLockFreeType();
-
-    TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
-
     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
     Cache.Hashed.lfHeight = plf->lfHeight;
+    Cache.Hashed.lfWidth = plf->lfWidth;
     Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight,
plf->lfWeight);
     Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic &&
!FontGDI->OriginalItalic);
+    // Check vertical writing (tategaki)
+    nTenthsOfDegrees = IntNormalizeAngle(plf->lfEscapement - plf->lfOrientation);
+    bVerticalWriting = ((nTenthsOfDegrees == 90 * 10) || (nTenthsOfDegrees == 270 * 10));
+
     if (IntIsFontRenderingEnabled())
         Cache.Hashed.Aspect.RenderMode = (BYTE)IntGetFontRenderMode(plf);
     else
         Cache.Hashed.Aspect.RenderMode = (BYTE)FT_RENDER_MODE_MONO;
     // NOTE: GetTextExtentPoint32 simply ignores lfEscapement and XFORM.
-    if (FT_IS_SCALABLE(Cache.Hashed.Face) && plf->lfWidth != 0)
-        IntWidthMatrix(Cache.Hashed.Face, &Cache.Hashed.matTransform,
plf->lfWidth);
-    else
-        Cache.Hashed.matTransform = identityMat;
-
-    FT_Set_Transform(Cache.Hashed.Face, &Cache.Hashed.matTransform, 0);
+    IntLockFreeType();
+    TextIntUpdateSize(dc, TextObj, FontGDI, FALSE);
+    Cache.Hashed.matTransform = identityMat;
+    FT_Set_Transform(Cache.Hashed.Face, NULL, NULL);
     use_kerning = FT_HAS_KERNING(Cache.Hashed.Face);
     previous = 0;
@@ -4356,8 +4343,16 @@ TextIntGetTextExtentPoint(PDC dc,
     descender = FontGDI->tmDescent; /* Units below baseline */
     IntUnLockFreeType();
-    Size->cx = (TotalWidth64 + 32) >> 6;
-    Size->cy = ascender + descender;
+    if (bVerticalWriting)
+    {
+        Size->cx = ascender + descender;
+        Size->cy = (TotalWidth64 + 32) >> 6;
+    }
+    else
+    {
+        Size->cx = (TotalWidth64 + 32) >> 6;
+        Size->cy = ascender + descender;
+    }
     return TRUE;
 }
@@ -4561,7 +4556,6 @@ ftGdiGetTextMetricsW(
     ULONG Error;
     NTSTATUS Status = STATUS_SUCCESS;
     LOGFONTW *plf;
-    FT_Matrix mat;
     if (!ptmwi)
     {
@@ -4584,10 +4578,11 @@ ftGdiGetTextMetricsW(
         Face = FontGDI->SharedFace->Face;
+        // NOTE: GetTextMetrics simply ignores lfEscapement and XFORM.
         IntLockFreeType();
         Error = IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
-        FtMatrixFromMx(&mat, DC_pmxWorldToDevice(dc));
-        FT_Set_Transform(Face, &mat, 0);
+        FT_Set_Transform(Face, NULL, NULL);
+
         IntUnLockFreeType();
         if (0 != Error)
@@ -4597,7 +4592,6 @@ ftGdiGetTextMetricsW(
         }
         else
         {
-            FT_Face Face = FontGDI->SharedFace->Face;
             Status = STATUS_SUCCESS;
             IntLockFreeType();
@@ -6073,6 +6067,7 @@ IntExtTextOutW(
     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
     Cache.Hashed.lfHeight = plf->lfHeight;
+    Cache.Hashed.lfWidth = plf->lfWidth;
     Cache.Hashed.Aspect.Emu.Bold = EMUBOLD_NEEDED(FontGDI->OriginalWeight,
plf->lfWeight);
     Cache.Hashed.Aspect.Emu.Italic = (plf->lfItalic &&
!FontGDI->OriginalItalic);
@@ -6093,7 +6088,7 @@ IntExtTextOutW(
     {
         pmxWorldToDevice = DC_pmxWorldToDevice(dc);
         FtMatrixFromMx(&Cache.Hashed.matTransform, pmxWorldToDevice);
-        FT_Set_Transform(face, &Cache.Hashed.matTransform, 0);
+        FT_Set_Transform(face, &Cache.Hashed.matTransform, NULL);
         fixAscender = ScaleLong(FontGDI->tmAscent, &pmxWorldToDevice->efM22)
<< 6;
         fixDescender = ScaleLong(FontGDI->tmDescent, &pmxWorldToDevice->efM22)
<< 6;
@@ -6102,7 +6097,7 @@ IntExtTextOutW(
     {
         pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
         FtMatrixFromMx(&Cache.Hashed.matTransform, pmxWorldToDevice);
-        FT_Set_Transform(face, &Cache.Hashed.matTransform, 0);
+        FT_Set_Transform(face, &Cache.Hashed.matTransform, NULL);
         fixAscender = FontGDI->tmAscent << 6;
         fixDescender = FontGDI->tmDescent << 6;
@@ -6594,11 +6589,9 @@ NtGdiGetCharABCWidthsW(
     PFONTGDI FontGDI;
     FT_Face face;
     FT_CharMap charmap, found = NULL;
-    FT_Matrix mat;
     UINT i, glyph_index, BufferSize;
     HFONT hFont = 0;
     NTSTATUS Status = STATUS_SUCCESS;
-    PMATRIX pmxWorldToDevice;
     PWCHAR Safepwch = NULL;
     LOGFONTW *plf;
@@ -6668,8 +6661,6 @@ NtGdiGetCharABCWidthsW(
     hFont = pdcattr->hlfntNew;
     TextObj = RealizeFontInit(hFont);
-    /* Get the DC's world-to-device transformation matrix */
-    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
     DC_UnlockDc(dc);
     if (TextObj == NULL)
@@ -6716,10 +6707,11 @@ NtGdiGetCharABCWidthsW(
     }
     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+
+    // NOTE: GetCharABCWidths simply ignores lfEscapement and XFORM.
     IntLockFreeType();
     IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
-    FtMatrixFromMx(&mat, pmxWorldToDevice);
-    FT_Set_Transform(face, &mat, 0);
+    FT_Set_Transform(face, NULL, NULL);
     for (i = FirstChar; i < FirstChar+Count; i++)
     {
@@ -6801,10 +6793,8 @@ NtGdiGetCharWidthW(
     PFONTGDI FontGDI;
     FT_Face face;
     FT_CharMap charmap, found = NULL;
-    FT_Matrix mat;
     UINT i, glyph_index, BufferSize;
     HFONT hFont = 0;
-    PMATRIX pmxWorldToDevice;
     PWCHAR Safepwc = NULL;
     LOGFONTW *plf;
@@ -6861,8 +6851,6 @@ NtGdiGetCharWidthW(
     pdcattr = dc->pdcattr;
     hFont = pdcattr->hlfntNew;
     TextObj = RealizeFontInit(hFont);
-    /* Get the DC's world-to-device transformation matrix */
-    pmxWorldToDevice = DC_pmxWorldToDevice(dc);
     DC_UnlockDc(dc);
     if (TextObj == NULL)
@@ -6908,10 +6896,11 @@ NtGdiGetCharWidthW(
     }
     plf = &TextObj->logfont.elfEnumLogfontEx.elfLogFont;
+
+    // NOTE: GetCharWidth simply ignores lfEscapement and XFORM.
     IntLockFreeType();
     IntRequestFontSize(dc, FontGDI, plf->lfWidth, plf->lfHeight);
-    FtMatrixFromMx(&mat, pmxWorldToDevice);
-    FT_Set_Transform(face, &mat, 0);
+    FT_Set_Transform(face, NULL, NULL);
     for (i = FirstChar; i < FirstChar+Count; i++)
     {