mirror of
https://github.com/reactos/reactos.git
synced 2024-09-01 00:03:39 +00:00
[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
This commit is contained in:
parent
aeed6a7831
commit
b6825a1328
|
@ -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++)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue