From a0be8d2c2d974128b48a118da8d987d30a951a51 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Sun, 26 May 2019 16:12:35 +0900 Subject: [PATCH] [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 a5e43330cc4..b5629c794fe 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 eef7cb3e5c0..60f8c5669c6 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; + if (lfEscapement) + { + // invert y axis + IntEscapeMatrix(&matEscape, -lfEscapement); + } // convert vecs for (i = 0; i < 9; ++i) { - FT_Vector_Transform(&vecs[i], &matWidth); - FT_Vector_Transform(&vecs[i], &matEscape); - FT_Vector_Transform(&vecs[i], &matWorld); - } - 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 - - { - 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);