https://git.reactos.org/?p=reactos.git;a=commitdiff;h=a0be8d2c2d974128b48a1…
commit a0be8d2c2d974128b48a118da8d987d30a951a51
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Sun May 26 16:12:35 2019 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Sun May 26 16:12:35 2019 +0900
[WIN32SS][NTGDI] Improve Text Transformation (#1573)
Reduce gdi32_apitest!TextTransform failures. Optimize for speed. Add Width and
Escapement parameters to FONT_CACHE_ENTRY structure.
CORE-15554
---
win32ss/gdi/ntgdi/font.h | 2 +
win32ss/gdi/ntgdi/freetype.c | 180 ++++++++++++++++++++++---------------------
2 files changed, 95 insertions(+), 87 deletions(-)
diff --git a/win32ss/gdi/ntgdi/font.h b/win32ss/gdi/ntgdi/font.h
index a5e43330cc..b5629c794f 100644
--- a/win32ss/gdi/ntgdi/font.h
+++ b/win32ss/gdi/ntgdi/font.h
@@ -30,6 +30,8 @@ typedef struct _FONT_CACHE_ENTRY
FT_Face Face;
FT_BitmapGlyph BitmapGlyph;
int Height;
+ int Width;
+ int Escapement;
FT_Render_Mode RenderMode;
MATRIX mxWorldToDevice;
} FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY;
diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c
index eef7cb3e5c..60f8c5669c 100644
--- a/win32ss/gdi/ntgdi/freetype.c
+++ b/win32ss/gdi/ntgdi/freetype.c
@@ -684,7 +684,7 @@ InitFontSupport(VOID)
return TRUE;
}
-VOID FASTCALL IntWidthMatrix(FT_Face face, FT_Matrix *pmat, LONG lfWidth)
+LONG FASTCALL IntWidthMatrix(FT_Face face, FT_Matrix *pmat, LONG lfWidth)
{
LONG tmAveCharWidth;
TT_OS2 *pOS2;
@@ -693,12 +693,12 @@ VOID FASTCALL IntWidthMatrix(FT_Face face, FT_Matrix *pmat, LONG
lfWidth)
*pmat = identityMat;
if (lfWidth == 0)
- return;
+ return 0;
ASSERT_FREETYPE_LOCK_HELD();
pOS2 = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
if (!pOS2)
- return;
+ return 0;
XScale = face->size->metrics.x_scale;
tmAveCharWidth = (FT_MulFix(pOS2->xAvgCharWidth, XScale) + 32) >> 6;
@@ -708,12 +708,13 @@ VOID FASTCALL IntWidthMatrix(FT_Face face, FT_Matrix *pmat, LONG
lfWidth)
}
if (lfWidth == tmAveCharWidth)
- return;
+ return 0;
- pmat->xx = (FT_Fixed)((1 << 16) * lfWidth / tmAveCharWidth);
+ pmat->xx = INT_TO_FIXED(lfWidth) / tmAveCharWidth;
pmat->xy = 0;
pmat->yx = 0;
- pmat->yy = (FT_Fixed)(1 << 16);
+ pmat->yy = INT_TO_FIXED(1);
+ return lfWidth;
}
VOID FASTCALL IntEscapeMatrix(FT_Matrix *pmat, LONG lfEscapement)
@@ -2866,6 +2867,8 @@ ftGdiGlyphCacheGet(
FT_Face Face,
INT GlyphIndex,
INT Height,
+ INT Width,
+ INT Escapement,
FT_Render_Mode RenderMode,
PMATRIX pmx)
{
@@ -2882,6 +2885,8 @@ ftGdiGlyphCacheGet(
if ((FontEntry->Face == Face) &&
(FontEntry->GlyphIndex == GlyphIndex) &&
(FontEntry->Height == Height) &&
+ (FontEntry->Width == Width) &&
+ (FontEntry->Escapement == Escapement) &&
(FontEntry->RenderMode == RenderMode) &&
(SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx)))
break;
@@ -2944,6 +2949,8 @@ ftGdiGlyphCacheSet(
FT_Face Face,
INT GlyphIndex,
INT Height,
+ INT Width,
+ INT Escapement,
PMATRIX pmx,
FT_GlyphSlot GlyphSlot,
FT_Render_Mode RenderMode)
@@ -2997,6 +3004,8 @@ ftGdiGlyphCacheSet(
NewEntry->Face = Face;
NewEntry->BitmapGlyph = BitmapGlyph;
NewEntry->Height = Height;
+ NewEntry->Width = Width;
+ NewEntry->Escapement = Escapement;
NewEntry->RenderMode = RenderMode;
NewEntry->mxWorldToDevice = *pmx;
@@ -3962,6 +3971,7 @@ TextIntGetTextExtentPoint(PDC dc,
realglyph = NULL;
else
realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
+ plf->lfWidth, plf->lfEscapement,
RenderMode, pmxWorldToDevice);
if (EmuBold || EmuItalic || !realglyph)
@@ -3987,6 +3997,8 @@ TextIntGetTextExtentPoint(PDC dc,
realglyph = ftGdiGlyphCacheSet(face,
glyph_index,
plf->lfHeight,
+ plf->lfWidth,
+ plf->lfEscapement,
pmxWorldToDevice,
glyph,
RenderMode);
@@ -5594,7 +5606,7 @@ IntExtTextOutW(
FT_Face face;
FT_GlyphSlot glyph;
FT_BitmapGlyph realglyph;
- LONGLONG TextLeft64, TextTop64, DeltaX64, DeltaY64, XStart64, YStart64;
+ LONGLONG TextLeft64, TextTop64, TextWidth64, DeltaX64, DeltaY64, XStart64, YStart64;
ULONG previous;
FT_Bool use_kerning;
RECTL DestRect, MaskRect;
@@ -5620,6 +5632,7 @@ IntExtTextOutW(
BOOL bResult;
FT_Matrix mat = identityMat, matWidth, matEscape, matWorld;
FT_Vector vecs[9];
+ BOOL bNeedCache;
/* Check if String is valid */
if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
@@ -5765,32 +5778,10 @@ IntExtTextOutW(
goto Cleanup;
}
- /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
- DC_vUpdateWorldToDevice(dc);
- if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
- {
- pmxWorldToDevice = DC_pmxWorldToDevice(dc);
- }
- else
- {
- pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
- }
+ FT_Set_Transform(face, NULL, NULL);
- IntWidthMatrix(face, &matWidth, lfWidth);
- FT_Matrix_Multiply(&matWidth, &mat);
-
- IntEscapeMatrix(&matEscape, lfEscapement);
- FT_Matrix_Multiply(&matEscape, &mat);
-
- FtMatrixFromMx(&matWorld, pmxWorldToDevice);
- matWorld.yx = -matWorld.yx;
- matWorld.xy = -matWorld.xy;
- FT_Matrix_Multiply(&matWorld, &mat);
-
- FT_Set_Transform(face, &mat, NULL);
-
- // Calculate displacement of the text.
- DeltaX64 = DeltaY64 = 0;
+ // Calculate the text width.
+ TextWidth64 = 0;
DxShift = fuOptions & ETO_PDY ? 1 : 0;
use_kerning = FT_HAS_KERNING(face);
previous = 0;
@@ -5803,7 +5794,6 @@ IntExtTextOutW(
{
glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX,
fuOptions);
- // FIXME: Use FT_LOAD_BITMAP_METRICS_ONLY or cache.
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
if (error)
{
@@ -5832,14 +5822,12 @@ IntExtTextOutW(
{
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- DeltaX64 += delta.x;
- DeltaY64 -= delta.y;
+ TextWidth64 += delta.x;
}
if (Dx == NULL)
{
- DeltaX64 += realglyph->root.advance.x >> 10;
- DeltaY64 -= realglyph->root.advance.y >> 10;
+ TextWidth64 += realglyph->root.advance.x >> 10;
}
else
{
@@ -5850,12 +5838,7 @@ IntExtTextOutW(
/* do the shift before multiplying to preserve precision */
FLOATOBJ_MulLong(&Scale, Dx[i << DxShift] << 6);
- DeltaX64 += FLOATOBJ_GetLong(&Scale);
- }
-
- if (DxShift)
- {
- DeltaY64 -= Dx[2 * i + 1] << 6;
+ TextWidth64 += FLOATOBJ_GetLong(&Scale);
}
previous = glyph_index;
@@ -5864,21 +5847,43 @@ IntExtTextOutW(
}
}
- // Process the X and Y alignments.
- if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
+ /* NOTE: Don't trust face->size->metrics.ascender and descender values. */
+ if (lfWidth)
{
- XStart64 = -DeltaX64 / 2;
- YStart64 = -DeltaY64 / 2;
+ lfWidth = IntWidthMatrix(face, &matWidth, lfWidth);
+ FT_Matrix_Multiply(&matWidth, &mat);
}
- else if ((pdcattr->flTextAlign & TA_RIGHT) == TA_RIGHT)
+
+ if (lfEscapement)
{
- XStart64 = -DeltaX64;
- YStart64 = -DeltaY64;
+ IntEscapeMatrix(&matEscape, lfEscapement);
+ FT_Matrix_Multiply(&matEscape, &mat);
+ }
+
+ DC_vUpdateWorldToDevice(dc);
+ if (dc->pdcattr->iGraphicsMode == GM_ADVANCED)
+ {
+ pmxWorldToDevice = DC_pmxWorldToDevice(dc);
}
else
{
- XStart64 = YStart64 = 0;
+ pmxWorldToDevice = (PMATRIX)&gmxWorldToDeviceDefault;
}
+ FtMatrixFromMx(&matWorld, pmxWorldToDevice);
+ matWorld.xy = -matWorld.xy;
+ matWorld.yx = -matWorld.yx;
+ FT_Matrix_Multiply(&matWorld, &mat);
+
+ vecs[0].x = TextWidth64 << 10;
+ vecs[0].y = 0;
+ FT_Vector_Transform(&vecs[0], &mat);
+ DeltaX64 = vecs[0].x >> 10;
+ DeltaY64 = -vecs[0].y >> 10;
+
+ XStart64 = (Start.x << 6);
+ YStart64 = (Start.y << 6);
+
+ FT_Set_Transform(face, &mat, NULL);
psurf = dc->dclevel.pSurface;
SurfObj = &psurf->SurfObj ;
@@ -5919,8 +5924,10 @@ IntExtTextOutW(
vecs[4].y = FontGDI->tmAscent << 16; // baseline
vecs[0].y = FontGDI->tmHeight << 16; // lower left
}
- vecs[2] = vecs[1]; // upper right
- vecs[3] = vecs[0]; // lower right
+ vecs[2] = vecs[1];
+ vecs[2].x += (TextWidth64 << 10); // upper right
+ vecs[3] = vecs[0];
+ vecs[3].x += (TextWidth64 << 10); // lower right
#undef VALIGN_MASK
// underline
@@ -5933,51 +5940,50 @@ IntExtTextOutW(
face->size->metrics.y_ppem / face->units_per_EM;
}
vecs[5].y = vecs[6].y = vecs[4].y - (position << 16);
+ vecs[6].x += (TextWidth64 << 10);
}
// strike through
if (plf->lfStrikeOut)
{
vecs[7].y = vecs[8].y = vecs[4].y - ((FontGDI->tmAscent / 3) << 16);
+ vecs[8].x += (TextWidth64 << 10);
}
- // invert y axis
- IntEscapeMatrix(&matEscape, -lfEscapement);
-
- matWorld.yx = -matWorld.yx;
- matWorld.xy = -matWorld.xy;
-
- // convert vecs
- for (i = 0; i < 9; ++i)
+ if (lfEscapement)
{
- FT_Vector_Transform(&vecs[i], &matWidth);
- FT_Vector_Transform(&vecs[i], &matEscape);
- FT_Vector_Transform(&vecs[i], &matWorld);
+ // invert y axis
+ IntEscapeMatrix(&matEscape, -lfEscapement);
}
- vecs[2].x += DeltaX64 << 10;
- vecs[2].y += DeltaY64 << 10; // upper right
- vecs[3].x += DeltaX64 << 10;
- vecs[3].y += DeltaY64 << 10; // lower right
- vecs[6].x += DeltaX64 << 10;
- vecs[6].y += DeltaY64 << 10; // underline right
- vecs[8].x += DeltaX64 << 10;
- vecs[8].y += DeltaY64 << 10; // strike through right
+ // convert vecs
+ for (i = 0; i < 9; ++i)
{
- POINT pt;
- pt.x = Start.x + (XStart64 >> 6);
- pt.y = Start.y + (YStart64 >> 6);
- IntLPtoDP(dc, &pt, 1);
-
- for (i = 0; i < 9; ++i)
+ if (lfWidth)
{
- vecs[i].x += pt.x << 16;
- vecs[i].y += pt.y << 16;
- vecs[i].x >>= 16;
- vecs[i].y >>= 16;
- vecs[i].x += dc->ptlDCOrig.x;
- vecs[i].y += dc->ptlDCOrig.y;
+ FT_Vector_Transform(&vecs[i], &matWidth);
}
+ if (lfEscapement)
+ {
+ FT_Vector_Transform(&vecs[i], &matEscape);
+ }
+ vecs[i].x += (XStart64 << 10);
+ vecs[i].y += (YStart64 << 10);
+ vecs[i].x >>= 16;
+ vecs[i].y >>= 16;
+ IntLPtoDP(dc, &vecs[i], 1);
+ if ((pdcattr->flTextAlign & TA_CENTER) == TA_CENTER)
+ {
+ vecs[i].x -= (DeltaX64 >> 6) / 2;
+ vecs[i].y -= (DeltaY64 >> 6) / 2;
+ }
+ else if ((pdcattr->flTextAlign & TA_RIGHT) == TA_RIGHT)
+ {
+ vecs[i].x -= (DeltaX64 >> 6);
+ vecs[i].y -= (DeltaY64 >> 6);
+ }
+ vecs[i].x += dc->ptlDCOrig.x;
+ vecs[i].y += dc->ptlDCOrig.y;
}
if (fuOptions & ETO_OPAQUE)
@@ -6042,15 +6048,15 @@ IntExtTextOutW(
TextLeft64 = vecs[4].x << 6;
TextTop64 = vecs[4].y << 6;
previous = 0;
+ bNeedCache = (!EmuBold && !EmuItalic);
for (i = 0; i < Count; ++i)
{
- BOOL bNeedCache = (!EmuBold && !EmuItalic &&
- memcmp(&mat, &identityMat, sizeof(mat)) == 0);
glyph_index = get_glyph_index_flagged(face, String[i], ETO_GLYPH_INDEX,
fuOptions);
realglyph = NULL;
if (bNeedCache)
{
realglyph = ftGdiGlyphCacheGet(face, glyph_index, plf->lfHeight,
+ lfWidth, lfEscapement,
RenderMode, pmxWorldToDevice);
}
if (!realglyph)
@@ -6067,7 +6073,7 @@ IntExtTextOutW(
{
realglyph = ftGdiGlyphCacheSet(face,
glyph_index,
- plf->lfHeight,
+ plf->lfHeight, lfWidth, lfEscapement,
pmxWorldToDevice,
glyph,
RenderMode);