From b6825a132875732f6ca8d1ec07db766759b24477 Mon Sep 17 00:00:00 2001 From: Timo Kreuzer Date: Sun, 3 Mar 2013 17:20:44 +0000 Subject: [PATCH] [WIN32K] Properly handle glyph positions and take target coordinate transformation into account when caching glyphs. (This is suboptimal, since we might cache duplicates of the same glyphs, but it works). Fixes CORE-4657. svn path=/trunk/; revision=58418 --- reactos/win32ss/gdi/ntgdi/freetype.c | 110 ++++++++++++++++++++------- 1 file changed, 84 insertions(+), 26 deletions(-) diff --git a/reactos/win32ss/gdi/ntgdi/freetype.c b/reactos/win32ss/gdi/ntgdi/freetype.c index 49a9913913f..652f22f6f7f 100644 --- a/reactos/win32ss/gdi/ntgdi/freetype.c +++ b/reactos/win32ss/gdi/ntgdi/freetype.c @@ -59,6 +59,7 @@ typedef struct _FONT_CACHE_ENTRY FT_Face Face; FT_BitmapGlyph BitmapGlyph; int Height; + MATRIX mxWorldToDevice; } FONT_CACHE_ENTRY, *PFONT_CACHE_ENTRY; static LIST_ENTRY FontCacheListHead; static UINT FontCacheNumEntries; @@ -161,15 +162,11 @@ InitFontSupport(VOID) VOID FtSetCoordinateTransform( FT_Face face, - PDC pdc) + PMATRIX pmx) { FT_Matrix ftmatrix; - PMATRIX pmx; FLOATOBJ efTemp; - /* Get the DC's world-to-device transformation matrix */ - pmx = DC_pmxWorldToDevice(pdc); - /* Create a freetype matrix, by converting to 16.16 fixpoint format */ efTemp = pmx->efM11; FLOATOBJ_MulLong(&efTemp, 0x00010000); @@ -1343,12 +1340,24 @@ ftGdiGetRasterizerCaps(LPRASTERIZER_STATUS lprs) return FALSE; } +static +BOOL +SameScaleMatrix( + PMATRIX pmx1, + PMATRIX pmx2) +{ + return (FLOATOBJ_Equal(&pmx1->efM11, &pmx2->efM11) && + FLOATOBJ_Equal(&pmx1->efM12, &pmx2->efM12) && + FLOATOBJ_Equal(&pmx1->efM21, &pmx2->efM21) && + FLOATOBJ_Equal(&pmx1->efM22, &pmx2->efM22)); +} FT_BitmapGlyph APIENTRY ftGdiGlyphCacheGet( FT_Face Face, INT GlyphIndex, - INT Height) + INT Height, + PMATRIX pmx) { PLIST_ENTRY CurrentEntry; PFONT_CACHE_ENTRY FontEntry; @@ -1357,9 +1366,10 @@ ftGdiGlyphCacheGet( while (CurrentEntry != &FontCacheListHead) { FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry; - if (FontEntry->Face == Face && - FontEntry->GlyphIndex == GlyphIndex && - FontEntry->Height == Height) + if ((FontEntry->Face == Face) && + (FontEntry->GlyphIndex == GlyphIndex) && + (FontEntry->Height == Height) && + (SameScaleMatrix(&FontEntry->mxWorldToDevice, pmx))) break; CurrentEntry = CurrentEntry->Flink; } @@ -1379,6 +1389,7 @@ ftGdiGlyphCacheSet( FT_Face Face, INT GlyphIndex, INT Height, + PMATRIX pmx, FT_GlyphSlot GlyphSlot, FT_Render_Mode RenderMode) { @@ -1428,6 +1439,7 @@ ftGdiGlyphCacheSet( NewEntry->Face = Face; NewEntry->BitmapGlyph = BitmapGlyph; NewEntry->Height = Height; + NewEntry->mxWorldToDevice = *pmx; InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry); if (FontCacheNumEntries++ > MAX_FONT_CACHE) @@ -1585,7 +1597,7 @@ ftGdiGetGlyphOutline( /* FIXME: Should set character height if neg */ // (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? // dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); -// FtSetCoordinateTransform(face, dc); +// FtSetCoordinateTransform(face, DC_pmxWorldToDevice(dc)); TEXTOBJ_UnlockText(TextObj); @@ -2132,6 +2144,7 @@ TextIntGetTextExtentPoint(PDC dc, BOOL use_kerning; FT_Render_Mode RenderMode; BOOLEAN Render; + PMATRIX pmxWorldToDevice; FontGDI = ObjToGDI(TextObj->Font, FONT); @@ -2186,7 +2199,9 @@ TextIntGetTextExtentPoint(PDC dc, DPRINT1("Error in setting pixel sizes: %u\n", error); } - FtSetCoordinateTransform(face, dc); + /* Get the DC's world-to-device transformation matrix */ + pmxWorldToDevice = DC_pmxWorldToDevice(dc); + FtSetCoordinateTransform(face, pmxWorldToDevice); use_kerning = FT_HAS_KERNING(face); previous = 0; @@ -2199,7 +2214,8 @@ TextIntGetTextExtentPoint(PDC dc, glyph_index = FT_Get_Char_Index(face, *String); if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) + TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice))) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -2209,8 +2225,12 @@ TextIntGetTextExtentPoint(PDC dc, } glyph = face->glyph; - realglyph = ftGdiGlyphCacheSet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode); + realglyph = ftGdiGlyphCacheSet(face, + glyph_index, + TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice, + glyph, + RenderMode); if (!realglyph) { DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index); @@ -2470,7 +2490,7 @@ ftGdiGetTextMetricsW( /* FIXME: Should set character height if neg */ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); - FtSetCoordinateTransform(Face, dc); + FtSetCoordinateTransform(Face, DC_pmxWorldToDevice(dc)); IntUnLockFreeType; if (0 != Error) { @@ -3119,6 +3139,24 @@ NtGdiGetFontFamilyInfo(HDC Dc, return Count; } +LONG +FORCEINLINE +ScaleLong(LONG lValue, PFLOATOBJ pef) +{ + FLOATOBJ efTemp; + + /* Check if we have scaling different from 1 */ + if (!FLOATOBJ_Equal(pef, (PFLOATOBJ)&gef1)) + { + /* Need to multiply */ + FLOATOBJ_SetLong(&efTemp, lValue); + FLOATOBJ_Mul(&efTemp, pef); + lValue = FLOATOBJ_GetLong(&efTemp); + } + + return lValue; +} + BOOL APIENTRY GreExtTextOutW( @@ -3165,6 +3203,8 @@ GreExtTextOutW( POINT Start; BOOL DoBreak = FALSE; USHORT DxShift; + PMATRIX pmxWorldToDevice; + LONG fixAscender, fixDescender; // TODO: Write test-cases to exactly match real Windows in different // bad parameters (e.g. does Windows check the DC or the RECT first?). @@ -3328,18 +3368,22 @@ GreExtTextOutW( goto fail; } - FtSetCoordinateTransform(face, dc); + pmxWorldToDevice = DC_pmxWorldToDevice(dc); + FtSetCoordinateTransform(face, pmxWorldToDevice); /* * Process the vertical alignment and determine the yoff. */ + fixAscender = ScaleLong(face->size->metrics.ascender, &pmxWorldToDevice->efM22); + fixDescender = ScaleLong(face->size->metrics.descender, &pmxWorldToDevice->efM22); + if (pdcattr->lTextAlign & TA_BASELINE) yoff = 0; else if (pdcattr->lTextAlign & TA_BOTTOM) - yoff = -face->size->metrics.descender >> 6; + yoff = -fixDescender >> 6; else /* TA_TOP */ - yoff = face->size->metrics.ascender >> 6; + yoff = fixAscender >> 6; use_kerning = FT_HAS_KERNING(face); previous = 0; @@ -3377,7 +3421,8 @@ GreExtTextOutW( glyph_index = FT_Get_Char_Index(face, *TempText); if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) + TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice))) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -3386,8 +3431,12 @@ GreExtTextOutW( } glyph = face->glyph; - realglyph = ftGdiGlyphCacheSet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode); + realglyph = ftGdiGlyphCacheSet(face, + glyph_index, + TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice, + glyph, + RenderMode); if (!realglyph) { DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index); @@ -3453,7 +3502,8 @@ GreExtTextOutW( glyph_index = FT_Get_Char_Index(face, *String); if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index, - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))) + TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice))) { error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); if (error) @@ -3466,6 +3516,7 @@ GreExtTextOutW( realglyph = ftGdiGlyphCacheSet(face, glyph_index, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, + pmxWorldToDevice, glyph, RenderMode); if (!realglyph) @@ -3491,8 +3542,8 @@ GreExtTextOutW( { DestRect.left = BackgroundLeft; DestRect.right = (TextLeft + (realglyph->root.advance.x >> 10) + 32) >> 6; - DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6); - DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6); + DestRect.top = TextTop + yoff - ((fixAscender + 32) >> 6); + DestRect.bottom = TextTop + yoff + ((32 - fixDescender) >> 6); MouseSafetyOnDrawStart(dc->ppdev, DestRect.left, DestRect.top, DestRect.right, DestRect.bottom); IntEngBitBlt( &psurf->SurfObj, @@ -3777,6 +3828,7 @@ NtGdiGetCharABCWidthsW( UINT i, glyph_index, BufferSize; HFONT hFont = 0; NTSTATUS Status = STATUS_SUCCESS; + PMATRIX pmxWorldToDevice; if (pwch) { @@ -3823,6 +3875,9 @@ NtGdiGetCharABCWidthsW( 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) @@ -3866,7 +3921,7 @@ NtGdiGetCharABCWidthsW( /* FIXME: Should set character height if neg */ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); - FtSetCoordinateTransform(face, dc); + FtSetCoordinateTransform(face, pmxWorldToDevice); for (i = FirstChar; i < FirstChar+Count; i++) { @@ -3951,6 +4006,7 @@ NtGdiGetCharWidthW( FT_CharMap charmap, found = NULL; UINT i, glyph_index, BufferSize; HFONT hFont = 0; + PMATRIX pmxWorldToDevice; if (pwc) { @@ -3991,6 +4047,8 @@ 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) @@ -4034,7 +4092,7 @@ NtGdiGetCharWidthW( /* FIXME: Should set character height if neg */ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? dc->ppdev->devinfo.lfDefaultFont.lfHeight : abs(TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight))); - FtSetCoordinateTransform(face, dc); + FtSetCoordinateTransform(face, pmxWorldToDevice); for (i = FirstChar; i < FirstChar+Count; i++) {