#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H
+#include FT_TYPE1_TABLES_H
#include <freetype/tttables.h>
#include <freetype/fttrigon.h>
#include <freetype/ftglyph.h>
};
/*
- * For NtGdiTranslateCharsetInfo
+ * For TranslateCharsetInfo
*/
#define FS(x) {{0,0,0,0},{0x1<<(x),0}}
#define MAXTCIINDEX 32
Otm->otmSize = Needed;
- FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+// FillTM(&Otm->otmTextMetrics, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
+ {
+ FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
+ }
+
+ RtlCopyMemory(&Otm->otmTextMetrics, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
Otm->otmFiller = 0;
memcpy(&Otm->otmPanoseNumber, pOS2->panose, PANOSE_COUNT);
return FALSE;
}
-int STDCALL
-NtGdiGetFontFamilyInfo(HDC Dc,
- LPLOGFONTW UnsafeLogFont,
- PFONTFAMILYINFO UnsafeInfo,
- DWORD Size)
-{
- NTSTATUS Status;
- LOGFONTW LogFont;
- PFONTFAMILYINFO Info;
- DWORD Count;
- PW32PROCESS Win32Process;
-
- /* Make a safe copy */
- Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
- if (! NT_SUCCESS(Status))
- {
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return -1;
- }
-
- /* Allocate space for a safe copy */
- Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
- if (NULL == Info)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return -1;
- }
-
- /* Enumerate font families in the global list */
- IntLockGlobalFonts;
- Count = 0;
- if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
- {
- IntUnLockGlobalFonts;
- ExFreePool(Info);
- return -1;
- }
- IntUnLockGlobalFonts;
-
- /* Enumerate font families in the process local list */
- Win32Process = PsGetCurrentProcessWin32Process();
- IntLockProcessPrivateFonts(Win32Process);
- if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
- &Win32Process->PrivateFontListHead))
- {
- IntUnLockProcessPrivateFonts(Win32Process);
- ExFreePool(Info);
- return -1;
- }
- IntUnLockProcessPrivateFonts(Win32Process);
-
- /* Enumerate font families in the registry */
- if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
- {
- ExFreePool(Info);
- return -1;
- }
-
- /* Return data to caller */
- if (0 != Count)
- {
- Status = MmCopyToCaller(UnsafeInfo, Info,
- (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
- if (! NT_SUCCESS(Status))
- {
- ExFreePool(Info);
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return -1;
- }
- }
-
- ExFreePool(Info);
-
- return Count;
-}
FT_Glyph STDCALL
ftGdiGlyphCacheGet(
return GlyphCopy;
}
-BOOL
-APIENTRY
-NtGdiExtTextOutW(
- IN HDC hDC,
- IN INT XStart,
- IN INT YStart,
- IN UINT fuOptions,
- IN OPTIONAL LPRECT lprc,
- IN LPWSTR UnsafeString,
- IN INT Count,
- IN OPTIONAL LPINT UnsafeDx,
- IN DWORD dwCodePage)
+
+static
+void
+FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
{
- /*
- * FIXME:
- * Call EngTextOut, which does the real work (calling DrvTextOut where
- * appropriate)
- */
+ pt->x.value = vec->x >> 6;
+ pt->x.fract = (vec->x & 0x3f) << 10;
+ pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
+ pt->y.value = vec->y >> 6;
+ pt->y.fract = (vec->y & 0x3f) << 10;
+ pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
+ return;
+}
- DC *dc;
- PDC_ATTR Dc_Attr;
- SURFOBJ *SurfObj;
- BITMAPOBJ *BitmapObj = NULL;
- int error, glyph_index, n, i;
- FT_Face face;
- FT_GlyphSlot glyph;
- FT_Glyph realglyph;
- FT_BitmapGlyph realglyph2;
- LONGLONG TextLeft, RealXStart;
- ULONG TextTop, previous, BackgroundLeft;
- FT_Bool use_kerning;
- RECTL DestRect, MaskRect, SpecifiedDestRect;
- POINTL SourcePoint, BrushOrigin;
- HBRUSH hBrushFg = NULL;
- PGDIBRUSHOBJ BrushFg = NULL;
- GDIBRUSHINST BrushFgInst;
- HBRUSH hBrushBg = NULL;
- PGDIBRUSHOBJ BrushBg = NULL;
- GDIBRUSHINST BrushBgInst;
- HBITMAP HSourceGlyph;
- SURFOBJ *SourceGlyphSurf;
- SIZEL bitSize;
- FT_CharMap found = 0, charmap;
- INT yoff;
- FONTOBJ *FontObj;
- PFONTGDI FontGDI;
- PTEXTOBJ TextObj = NULL;
- PPALGDI PalDestGDI;
- XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
- ULONG Mode;
- FT_Render_Mode RenderMode;
- BOOLEAN Render;
- NTSTATUS Status;
- INT *Dx = NULL;
- POINT Start;
- BOOL DoBreak = FALSE;
- LPCWSTR String, SafeString = NULL;
- HPALETTE hDestPalette;
+/*
+ This function builds an FT_Fixed from a float. It puts the integer part
+ in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
+ It fails if the integer part of the float number is greater than SHORT_MAX.
+*/
+static __inline FT_Fixed FT_FixedFromFloat(float f)
+{
+ short value = f;
+ unsigned short fract = (f - value) * 0xFFFF;
+ return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
+}
- // TODO: Write test-cases to exactly match real Windows in different
- // bad parameters (e.g. does Windows check the DC or the RECT first?).
- dc = DC_LockDc(hDC);
- if (!dc)
+/*
+ This function builds an FT_Fixed from a FIXED. It simply put f.value
+ in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
+*/
+static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
+{
+ return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
+}
+
+/*
+ * Based on WineEngGetGlyphOutline
+ *
+ */
+ULONG
+FASTCALL
+ftGdiGetGlyphOutline(
+ PDC dc,
+ WCHAR wch,
+ UINT iFormat,
+ LPGLYPHMETRICS pgm,
+ ULONG cjBuf,
+ PVOID pvBuf,
+ LPMAT2 pmat2,
+ BOOL bIgnoreRotation)
+{
+ static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
+ PDC_ATTR Dc_Attr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ HFONT hFont = 0;
+ GLYPHMETRICS gm;
+ ULONG Size;
+ FT_Face ft_face;
+ FT_UInt glyph_index;
+ DWORD width, height, pitch, needed = 0;
+ FT_Bitmap ft_bitmap;
+ FT_Error error;
+ INT left, right, top = 0, bottom = 0;
+ FT_Angle angle = 0;
+ FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
+ FLOAT eM11, widthRatio = 1.0;
+ FT_Matrix transMat = identityMat;
+ BOOL needsTransform = FALSE;
+ INT orientation;
+ LONG aveWidth;
+ INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
+ OUTLINETEXTMETRICW *potm;
+ int n = 0;
+ FT_CharMap found = 0, charmap;
+ XFORM xForm;
+
+ DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
+ cjBuf, pvBuf, pmat2);
+
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+ MatrixS2XForm(&xForm, &dc->DcLevel.mxWorldToDevice);
+ eM11 = xForm.eM11;
+
+ hFont = Dc_Attr->hlfntNew;
+ TextObj = TEXTOBJ_LockText(hFont);
+
+ if (!TextObj)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
- if (dc->DC_Type == DC_TYPE_INFO)
- {
- DC_UnlockDc(dc);
- /* Yes, Windows really returns TRUE in this case */
- return TRUE;
+ return GDI_ERROR;
}
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+ ft_face = FontGDI->face;
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
+ orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
- /* Check if String is valid */
- if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
- {
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- goto fail;
- }
- if (Count > 0)
- {
- SafeString = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
- if (!SafeString)
- {
- goto fail;
- }
- Status = MmCopyFromCaller(SafeString, UnsafeString, Count * sizeof(WCHAR));
- if (! NT_SUCCESS(Status))
- {
- goto fail;
- }
- }
- String = SafeString;
-
- if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
- {
- // At least one of the two flags were specified. Copy lprc. Once.
- Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
- if (!NT_SUCCESS(Status))
- {
- DC_UnlockDc(dc);
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
- }
-
- if (NULL != UnsafeDx && Count > 0)
- {
- Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
- if (NULL == Dx)
- {
- goto fail;
- }
- Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
- if (! NT_SUCCESS(Status))
- {
- goto fail;
- }
- }
-
- BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
- if ( !BitmapObj )
- {
- goto fail;
- }
- SurfObj = &BitmapObj->SurfObj;
- ASSERT(SurfObj);
-
- Start.x = XStart; Start.y = YStart;
- IntLPtoDP(dc, &Start, 1);
-
- RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
- YStart = Start.y + dc->ptlDCOrig.y;
-
- /* Create the brushes */
- hDestPalette = BitmapObj->hDIBPalette;
- if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
- PalDestGDI = PALETTE_LockPalette(hDestPalette);
- if ( !PalDestGDI )
- Mode = PAL_RGB;
- else
- {
- Mode = PalDestGDI->Mode;
- PALETTE_UnlockPalette(PalDestGDI);
- }
- XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
- if ( !XlateObj )
- {
- goto fail;
- }
- hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crForegroundClr), 0);
- if ( !hBrushFg )
- {
- goto fail;
- }
- BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
- if ( !BrushFg )
- {
- goto fail;
- }
- IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
- if ((fuOptions & ETO_OPAQUE) || Dc_Attr->jBkMode == OPAQUE)
- {
- hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crBackgroundClr), 0);
- if ( !hBrushBg )
- {
- goto fail;
- }
- BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
- if ( !BrushBg )
- {
- goto fail;
- }
- IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
- }
- XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, hDestPalette);
- if ( !XlateObj2 )
- {
- goto fail;
- }
-
- SourcePoint.x = 0;
- SourcePoint.y = 0;
- MaskRect.left = 0;
- MaskRect.top = 0;
- BrushOrigin.x = 0;
- BrushOrigin.y = 0;
-
- if ((fuOptions & ETO_OPAQUE) && lprc)
- {
- DestRect.left = SpecifiedDestRect.left + dc->ptlDCOrig.x;
- DestRect.top = SpecifiedDestRect.top + dc->ptlDCOrig.y;
- DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
- DestRect.bottom = SpecifiedDestRect.bottom + dc->ptlDCOrig.y;
- IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
- IntEngBitBlt(
- &BitmapObj->SurfObj,
- NULL,
- NULL,
- dc->CombinedClip,
- NULL,
- &DestRect,
- &SourcePoint,
- &SourcePoint,
- &BrushBgInst.BrushObject,
- &BrushOrigin,
- ROP3_TO_ROP4(PATCOPY));
- fuOptions &= ~ETO_OPAQUE;
- }
- else
- {
- if (Dc_Attr->jBkMode == OPAQUE)
- {
- fuOptions |= ETO_OPAQUE;
- }
- }
-
- TextObj = TEXTOBJ_LockText(Dc_Attr->hlfntNew);
- if(TextObj == NULL)
- {
- goto fail;
- }
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!potm)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ TEXTOBJ_UnlockText(TextObj);
+ return GDI_ERROR;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, potm);
- FontObj = TextObj->Font;
- ASSERT(FontObj);
- FontGDI = ObjToGDI(FontObj, FONT);
- ASSERT(FontGDI);
+ IntLockFreeType;
- IntLockFreeType;
- face = FontGDI->face;
- if (face->charmap == NULL)
- {
+ /* During testing, I never saw this used. In here just incase.*/
+ if (ft_face->charmap == NULL)
+ {
DPRINT("WARNING: No charmap selected!\n");
- DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+ DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
- for (n = 0; n < face->num_charmaps; n++)
+ for (n = 0; n < ft_face->num_charmaps; n++)
{
- charmap = face->charmaps[n];
+ charmap = ft_face->charmaps[n];
DPRINT("found charmap encoding: %u\n", charmap->encoding);
if (charmap->encoding != 0)
{
{
DPRINT1("WARNING: Could not find desired charmap!\n");
}
- error = FT_Set_Charmap(face, found);
- if (error)
- {
- DPRINT1("WARNING: Could not set the charmap!\n");
- }
- }
+ error = FT_Set_Charmap(ft_face, found);
+ if (error)
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
+ }
- Render = IntIsFontRenderingEnabled();
- if (Render)
- RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
- else
- RenderMode = FT_RENDER_MODE_MONO;
+// FT_Set_Pixel_Sizes(ft_face,
+// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+// (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- error = FT_Set_Pixel_Sizes(
- face,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
- (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
- - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- if (error)
- {
- DPRINT1("Error in setting pixel sizes: %u\n", error);
- IntUnLockFreeType;
- goto fail;
- }
+ TEXTOBJ_UnlockText(TextObj);
- /*
- * Process the vertical alignment and determine the yoff.
- */
+ if (iFormat & GGO_GLYPH_INDEX)
+ {
+ glyph_index = wch;
+ iFormat &= ~GGO_GLYPH_INDEX;
+ }
+ else glyph_index = FT_Get_Char_Index(ft_face, wch);
- if (Dc_Attr->lTextAlign & TA_BASELINE)
- yoff = 0;
- else if (Dc_Attr->lTextAlign & TA_BOTTOM)
- yoff = -face->size->metrics.descender >> 6;
- else /* TA_TOP */
- yoff = face->size->metrics.ascender >> 6;
+ if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
+ load_flags |= FT_LOAD_NO_BITMAP;
- use_kerning = FT_HAS_KERNING(face);
- previous = 0;
+ if (iFormat & GGO_UNHINTED)
+ {
+ load_flags |= FT_LOAD_NO_HINTING;
+ iFormat &= ~GGO_UNHINTED;
+ }
- /*
- * Process the horizontal alignment and modify XStart accordingly.
- */
+ error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
+ return GDI_ERROR;
+ }
+ IntUnLockFreeType;
- if (Dc_Attr->lTextAlign & (TA_RIGHT | TA_CENTER))
- {
- ULONGLONG TextWidth = 0;
- LPCWSTR TempText = String;
- int Start;
+ if (aveWidth && potm)
+ {
+ widthRatio = (FLOAT)aveWidth * eM11 /
+ (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
+ }
- /*
- * Calculate width of the text.
- */
+ left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
+ right = (INT)((ft_face->glyph->metrics.horiBearingX +
+ ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
- if (NULL != Dx)
- {
- Start = Count < 2 ? 0 : Count - 2;
- TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
- }
- else
- {
- Start = 0;
- }
- TempText = String + Start;
-
- for (i = Start; i < Count; i++)
- {
- if (fuOptions & ETO_GLYPH_INDEX)
- glyph_index = *TempText;
- else
- glyph_index = FT_Get_Char_Index(face, *TempText);
-
- if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
- {
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- if (error)
- {
- DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
- }
-
- glyph = face->glyph;
- realglyph = ftGdiGlyphCacheSet(face, glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
- if (!realglyph)
- {
- DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
- IntUnLockFreeType;
- goto fail;
- }
-
- }
- /* retrieve kerning distance */
- if (use_kerning && previous && glyph_index)
- {
- FT_Vector delta;
- FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- TextWidth += delta.x;
- }
+ adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
+ lsb = left >> 6;
+ bbx = (right - left) >> 6;
- TextWidth += realglyph->advance.x >> 10;
+ DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
- previous = glyph_index;
- TempText++;
- }
+ IntLockFreeType;
- previous = 0;
+ /* Scaling transform */
+ if (aveWidth)
+ {
+ FT_Matrix scaleMat;
+ DPRINT("Scaling Trans!\n");
+ scaleMat.xx = FT_FixedFromFloat(widthRatio);
+ scaleMat.xy = 0;
+ scaleMat.yx = 0;
+ scaleMat.yy = (1 << 16);
+ FT_Matrix_Multiply(&scaleMat, &transMat);
+ needsTransform = TRUE;
+ }
- if (Dc_Attr->lTextAlign & TA_RIGHT)
- {
- RealXStart -= TextWidth;
- }
- else
- {
- RealXStart -= TextWidth / 2;
- }
- }
+ /* Slant transform */
+ if (potm->otmTextMetrics.tmItalic)
+ {
+ FT_Matrix slantMat;
+ DPRINT("Slant Trans!\n");
+ slantMat.xx = (1 << 16);
+ slantMat.xy = ((1 << 16) >> 2);
+ slantMat.yx = 0;
+ slantMat.yy = (1 << 16);
+ FT_Matrix_Multiply(&slantMat, &transMat);
+ needsTransform = TRUE;
+ }
- TextLeft = RealXStart;
- TextTop = YStart;
- BackgroundLeft = (RealXStart + 32) >> 6;
+ /* Rotation transform */
+ if (orientation)
+ {
+ FT_Matrix rotationMat;
+ FT_Vector vecAngle;
+ DPRINT("Rotation Trans!\n");
+ angle = FT_FixedFromFloat((float)orientation / 10.0);
+ FT_Vector_Unit(&vecAngle, angle);
+ rotationMat.xx = vecAngle.x;
+ rotationMat.xy = -vecAngle.y;
+ rotationMat.yx = -rotationMat.xy;
+ rotationMat.yy = rotationMat.xx;
+ FT_Matrix_Multiply(&rotationMat, &transMat);
+ needsTransform = TRUE;
+ }
- /*
- * The main rendering loop.
- */
+ /* Extra transformation specified by caller */
+ if (pmat2)
+ {
+ FT_Matrix extraMat;
+ DPRINT("MAT2 Matrix Trans!\n");
+ extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
+ extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
+ extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
+ extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
+ FT_Matrix_Multiply(&extraMat, &transMat);
+ needsTransform = TRUE;
+ }
- for (i = 0; i < Count; i++)
- {
- if (fuOptions & ETO_GLYPH_INDEX)
- glyph_index = *String;
- else
- glyph_index = FT_Get_Char_Index(face, *String);
+ if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
- if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
- {
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- if (error)
- {
- DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
- IntUnLockFreeType;
- goto fail;
- }
- glyph = face->glyph;
- realglyph = ftGdiGlyphCacheSet(face,
- glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
- glyph,
- RenderMode);
- if (!realglyph)
+ if (!needsTransform)
+ {
+ DPRINT("No Need to be Transformed!\n");
+ top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
+ bottom = (ft_face->glyph->metrics.horiBearingY -
+ ft_face->glyph->metrics.height) & -64;
+ gm.gmCellIncX = adv;
+ gm.gmCellIncY = 0;
+ }
+ else
+ {
+ INT xc, yc;
+ FT_Vector vec;
+ for(xc = 0; xc < 2; xc++)
{
- DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
- IntUnLockFreeType;
- goto fail;
+ for(yc = 0; yc < 2; yc++)
+ {
+ vec.x = (ft_face->glyph->metrics.horiBearingX +
+ xc * ft_face->glyph->metrics.width);
+ vec.y = ft_face->glyph->metrics.horiBearingY -
+ yc * ft_face->glyph->metrics.height;
+ DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
+ FT_Vector_Transform(&vec, &transMat);
+ if(xc == 0 && yc == 0)
+ {
+ left = right = vec.x;
+ top = bottom = vec.y;
+ }
+ else
+ {
+ if(vec.x < left) left = vec.x;
+ else if(vec.x > right) right = vec.x;
+ if(vec.y < bottom) bottom = vec.y;
+ else if(vec.y > top) top = vec.y;
+ }
+ }
}
- }
-// DbgPrint("realglyph: %x\n", realglyph);
-// DbgPrint("TextLeft: %d\n", TextLeft);
-
- /* retrieve kerning distance and move pen position */
- if (use_kerning && previous && glyph_index && NULL == Dx)
- {
- FT_Vector delta;
- FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- TextLeft += delta.x;
- }
-// DPRINT1("TextLeft: %d\n", TextLeft);
-// DPRINT1("TextTop: %d\n", TextTop);
+ left = left & -64;
+ right = (right + 63) & -64;
+ bottom = bottom & -64;
+ top = (top + 63) & -64;
- if (realglyph->format == ft_glyph_format_outline)
- {
- DbgPrint("Should already be done\n");
-// error = FT_Render_Glyph(glyph, RenderMode);
- error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);
- if (error)
- {
- DPRINT1("WARNING: Failed to render glyph!\n");
- goto fail;
- }
- }
- realglyph2 = (FT_BitmapGlyph)realglyph;
+ DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
+ vec.x = ft_face->glyph->metrics.horiAdvance;
+ vec.y = 0;
+ FT_Vector_Transform(&vec, &transMat);
+ gm.gmCellIncX = (vec.x+63) >> 6;
+ gm.gmCellIncY = -((vec.y+63) >> 6);
+ }
+ gm.gmBlackBoxX = (right - left) >> 6;
+ gm.gmBlackBoxY = (top - bottom) >> 6;
+ gm.gmptGlyphOrigin.x = left >> 6;
+ gm.gmptGlyphOrigin.y = top >> 6;
-// DPRINT1("Pitch: %d\n", pitch);
-// DPRINT1("Advance: %d\n", realglyph->advance.x);
+ DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
+ gm.gmCellIncX, gm.gmCellIncY,
+ gm.gmBlackBoxX, gm.gmBlackBoxY,
+ gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
- if (fuOptions & ETO_OPAQUE)
- {
- DestRect.left = BackgroundLeft;
- DestRect.right = (TextLeft + (realglyph->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);
- IntEngBitBlt(
- &BitmapObj->SurfObj,
- NULL,
- NULL,
- dc->CombinedClip,
- NULL,
- &DestRect,
- &SourcePoint,
- &SourcePoint,
- &BrushBgInst.BrushObject,
- &BrushOrigin,
- ROP3_TO_ROP4(PATCOPY));
- BackgroundLeft = DestRect.right;
- }
+ IntUnLockFreeType;
- DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;
- DestRect.right = DestRect.left + realglyph2->bitmap.width;
- DestRect.top = TextTop + yoff - realglyph2->top;
- DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;
+ if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
- bitSize.cx = realglyph2->bitmap.width;
- bitSize.cy = realglyph2->bitmap.rows;
- MaskRect.right = realglyph2->bitmap.width;
- MaskRect.bottom = realglyph2->bitmap.rows;
+ if (iFormat == GGO_METRICS)
+ {
+ DPRINT("GGO_METRICS Exit!\n");
+ return 1; /* FIXME */
+ }
- /*
- * We should create the bitmap out of the loop at the biggest possible
- * glyph size. Then use memset with 0 to clear it and sourcerect to
- * limit the work of the transbitblt.
- *
- * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
- * Here we pass in the pitch from the FreeType bitmap, which is not
- * guaranteed to be a multiple of 4. If it's not, we should expand
- * the FreeType bitmap to a temporary bitmap.
- */
+ if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
+ {
+ DPRINT1("loaded a bitmap\n");
+ return GDI_ERROR;
+ }
- HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,
- (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?
- BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
- realglyph2->bitmap.buffer);
- if ( !HSourceGlyph )
- {
- DPRINT1("WARNING: EngLockSurface() failed!\n");
- // FT_Done_Glyph(realglyph);
- IntUnLockFreeType;
- goto fail;
- }
- SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
- if ( !SourceGlyphSurf )
- {
- EngDeleteSurface((HSURF)HSourceGlyph);
- DPRINT1("WARNING: EngLockSurface() failed!\n");
- IntUnLockFreeType;
- goto fail;
- }
+ switch(iFormat)
+ {
+ case GGO_BITMAP:
+ width = gm.gmBlackBoxX;
+ height = gm.gmBlackBoxY;
+ pitch = ((width + 31) >> 5) << 2;
+ needed = pitch * height;
- /*
- * Use the font data as a mask to paint onto the DCs surface using a
- * brush.
- */
+ if(!pvBuf || !cjBuf) break;
- if (lprc &&
- (fuOptions & ETO_CLIPPED) &&
- DestRect.right >= SpecifiedDestRect.right + dc->ptlDCOrig.x)
- {
- // We do the check '>=' instead of '>' to possibly save an iteration
- // through this loop, since it's breaking after the drawing is done,
- // and x is always incremented.
- DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
- DoBreak = TRUE;
- }
+ switch(ft_face->glyph->format)
+ {
+ case ft_glyph_format_bitmap:
+ {
+ BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
+ INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
+ INT h = ft_face->glyph->bitmap.rows;
+ while(h--)
+ {
+ RtlCopyMemory(dst, src, w);
+ src += ft_face->glyph->bitmap.pitch;
+ dst += pitch;
+ }
+ break;
+ }
- IntEngMaskBlt(
- SurfObj,
- SourceGlyphSurf,
- dc->CombinedClip,
- XlateObj,
- XlateObj2,
- &DestRect,
- &SourcePoint,
- (PPOINTL)&MaskRect,
- &BrushFgInst.BrushObject,
- &BrushOrigin);
+ case ft_glyph_format_outline:
+ ft_bitmap.width = width;
+ ft_bitmap.rows = height;
+ ft_bitmap.pitch = pitch;
+ ft_bitmap.pixel_mode = ft_pixel_mode_mono;
+ ft_bitmap.buffer = pvBuf;
- EngUnlockSurface(SourceGlyphSurf);
- EngDeleteSurface((HSURF)HSourceGlyph);
+ IntLockFreeType;
+ if(needsTransform)
+ {
+ FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
+ }
+ FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
+ /* Note: FreeType will only set 'black' bits for us. */
+ RtlZeroMemory(pvBuf, needed);
+ FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
+ IntUnLockFreeType;
+ break;
- if (DoBreak)
- {
- break;
- }
+ default:
+ DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
+ return GDI_ERROR;
+ }
+ break;
- if (NULL == Dx)
- {
- TextLeft += realglyph->advance.x >> 10;
-// DbgPrint("new TextLeft: %d\n", TextLeft);
- }
- else
+ case GGO_GRAY2_BITMAP:
+ case GGO_GRAY4_BITMAP:
+ case GGO_GRAY8_BITMAP:
{
- TextLeft += Dx[i] << 6;
-// DbgPrint("new TextLeft2: %d\n", TextLeft);
- }
- previous = glyph_index;
+ unsigned int mult, row, col;
+ BYTE *start, *ptr;
- String++;
- }
+ width = gm.gmBlackBoxX;
+ height = gm.gmBlackBoxY;
+ pitch = (width + 3) / 4 * 4;
+ needed = pitch * height;
- IntUnLockFreeType;
+ if(!pvBuf || !cjBuf) break;
- EngDeleteXlate(XlateObj);
- EngDeleteXlate(XlateObj2);
- BITMAPOBJ_UnlockBitmap(BitmapObj);
- if(TextObj != NULL)
- TEXTOBJ_UnlockText(TextObj);
- if (hBrushBg != NULL)
- {
- BRUSHOBJ_UnlockBrush(BrushBg);
- NtGdiDeleteObject(hBrushBg);
- }
- BRUSHOBJ_UnlockBrush(BrushFg);
- NtGdiDeleteObject(hBrushFg);
- if (NULL != SafeString)
- {
- ExFreePool((void*)SafeString);
- }
- if (NULL != Dx)
- {
- ExFreePool(Dx);
- }
- DC_UnlockDc( dc );
+ switch(ft_face->glyph->format)
+ {
+ case ft_glyph_format_bitmap:
+ {
+ BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
+ INT h = ft_face->glyph->bitmap.rows;
+ INT x;
+ while(h--)
+ {
+ for(x = 0; x < pitch; x++)
+ {
+ if(x < ft_face->glyph->bitmap.width)
+ dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
+ else
+ dst[x] = 0;
+ }
+ src += ft_face->glyph->bitmap.pitch;
+ dst += pitch;
+ }
+ return needed;
+ }
+ case ft_glyph_format_outline:
+ {
+ ft_bitmap.width = width;
+ ft_bitmap.rows = height;
+ ft_bitmap.pitch = pitch;
+ ft_bitmap.pixel_mode = ft_pixel_mode_grays;
+ ft_bitmap.buffer = pvBuf;
- return TRUE;
+ IntLockFreeType;
+ if (needsTransform)
+ {
+ FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
+ }
+ FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
+ RtlZeroMemory(ft_bitmap.buffer, cjBuf);
+ FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
+ IntUnLockFreeType;
-fail:
- if ( XlateObj2 != NULL )
- EngDeleteXlate(XlateObj2);
- if ( XlateObj != NULL )
- EngDeleteXlate(XlateObj);
- if(TextObj != NULL)
- TEXTOBJ_UnlockText(TextObj);
- if (BitmapObj != NULL)
- BITMAPOBJ_UnlockBitmap(BitmapObj);
- if (hBrushBg != NULL)
- {
- BRUSHOBJ_UnlockBrush(BrushBg);
- NtGdiDeleteObject(hBrushBg);
- }
- if (hBrushFg != NULL)
- {
- BRUSHOBJ_UnlockBrush(BrushFg);
- NtGdiDeleteObject(hBrushFg);
- }
- if (NULL != SafeString)
- {
- ExFreePool((void*)SafeString);
- }
- if (NULL != Dx)
- {
- ExFreePool(Dx);
- }
- DC_UnlockDc(dc);
+ if (iFormat == GGO_GRAY2_BITMAP)
+ mult = 4;
+ else if (iFormat == GGO_GRAY4_BITMAP)
+ mult = 16;
+ else if (iFormat == GGO_GRAY8_BITMAP)
+ mult = 64;
+ else
+ {
+ return GDI_ERROR;
+ }
+ }
+ default:
+ DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
+ return GDI_ERROR;
+ }
+ start = pvBuf;
+ for(row = 0; row < height; row++)
+ {
+ ptr = start;
+ for(col = 0; col < width; col++, ptr++)
+ {
+ *ptr = (((int)*ptr) * mult + 128) / 256;
+ }
+ start += pitch;
+ }
+ break;
+ }
- return FALSE;
-}
+ case GGO_NATIVE:
+ {
+ int contour, point = 0, first_pt;
+ FT_Outline *outline = &ft_face->glyph->outline;
+ TTPOLYGONHEADER *pph;
+ TTPOLYCURVE *ppc;
+ DWORD pph_start, cpfx, type;
- /*
- * @implemented
- */
-BOOL
-STDCALL
-NtGdiGetCharABCWidthsW(
- IN HDC hDC,
- IN UINT FirstChar,
- IN ULONG Count,
- IN OPTIONAL PWCHAR pwch,
- IN FLONG fl,
- OUT PVOID Buffer)
-{
- LPABC SafeBuff;
- LPABCFLOAT SafeBuffF = NULL;
- PDC dc;
- PDC_ATTR Dc_Attr;
- PTEXTOBJ TextObj;
- PFONTGDI FontGDI;
- FT_Face face;
- FT_CharMap charmap, found = NULL;
- UINT i, glyph_index, BufferSize;
- HFONT hFont = 0;
- NTSTATUS Status = STATUS_SUCCESS;
-
- if(pwch)
- {
- _SEH_TRY
- {
- ProbeForRead(pwch,
- sizeof(PWSTR),
- 1);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- if (!NT_SUCCESS(Status))
- {
- SetLastWin32Error(Status);
- return FALSE;
- }
-
- BufferSize = Count * sizeof(ABC); // Same size!
- SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
- if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
- if (SafeBuff == NULL)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- dc = DC_LockDc(hDC);
- if (dc == NULL)
- {
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(dc);
+ if(cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
- if (TextObj == NULL)
- {
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
+ IntLockFreeType;
+ if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
- FontGDI = ObjToGDI(TextObj->Font, FONT);
+ for(contour = 0; contour < outline->n_contours; contour++)
+ {
+ pph_start = needed;
+ pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
+ first_pt = point;
+ if(pvBuf)
+ {
+ pph->dwType = TT_POLYGON_TYPE;
+ FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+ }
+ needed += sizeof(*pph);
+ point++;
+ while(point <= outline->contours[contour])
+ {
+ ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
+ type = (outline->tags[point] & FT_Curve_Tag_On) ?
+ TT_PRIM_LINE : TT_PRIM_QSPLINE;
+ cpfx = 0;
+ do
+ {
+ if(pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ } while(point <= outline->contours[contour] &&
+ (outline->tags[point] & FT_Curve_Tag_On) ==
+ (outline->tags[point-1] & FT_Curve_Tag_On));
- face = FontGDI->face;
- if (face->charmap == NULL)
- {
- for (i = 0; i < face->num_charmaps; i++)
- {
- charmap = face->charmaps[i];
- if (charmap->encoding != 0)
- {
- found = charmap;
- break;
- }
+ /* At the end of a contour Windows adds the start point, but
+ only for Beziers */
+ if(point > outline->contours[contour] &&
+ !(outline->tags[point-1] & FT_Curve_Tag_On))
+ {
+ if(pvBuf)
+ FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
+ cpfx++;
+ }
+ else if(point <= outline->contours[contour] &&
+ outline->tags[point] & FT_Curve_Tag_On)
+ {
+ /* add closing pt for bezier */
+ if(pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ }
+ if(pvBuf)
+ {
+ ppc->wType = type;
+ ppc->cpfx = cpfx;
+ }
+ needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+ }
+ if(pvBuf) pph->cb = needed - pph_start;
+ }
+ IntUnLockFreeType;
+ break;
}
-
- if (!found)
+ case GGO_BEZIER:
{
- DPRINT1("WARNING: Could not find desired charmap!\n");
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- IntLockFreeType;
- FT_Set_Charmap(face, found);
- IntUnLockFreeType;
- }
+ /* Convert the quadratic Beziers to cubic Beziers.
+ The parametric eqn for a cubic Bezier is, from PLRM:
+ r(t) = at^3 + bt^2 + ct + r0
+ with the control points:
+ r1 = r0 + c/3
+ r2 = r1 + (c + b)/3
+ r3 = r0 + c + b + a
- IntLockFreeType;
- FT_Set_Pixel_Sizes(face,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
- (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ A quadratic Beizer has the form:
+ p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
- for (i = FirstChar; i < FirstChar+Count; i++)
- {
- int adv, lsb, bbx, left, right;
+ So equating powers of t leads to:
+ r1 = 2/3 p1 + 1/3 p0
+ r2 = 2/3 p1 + 1/3 p2
+ and of course r0 = p0, r3 = p2
+ */
- if (pwch)
- {
- if (fl & GCABCW_INDICES)
- glyph_index = pwch[i - FirstChar];
- else
- glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
- }
- else
- {
- if (fl & GCABCW_INDICES)
- glyph_index = i;
- else
- glyph_index = FT_Get_Char_Index(face, i);
- }
- FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ int contour, point = 0, first_pt;
+ FT_Outline *outline = &ft_face->glyph->outline;
+ TTPOLYGONHEADER *pph;
+ TTPOLYCURVE *ppc;
+ DWORD pph_start, cpfx, type;
+ FT_Vector cubic_control[4];
+ if(cjBuf == 0) pvBuf = NULL;
- left = (INT)face->glyph->metrics.horiBearingX & -64;
- right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
- adv = (face->glyph->advance.x + 32) >> 6;
+ if (needsTransform && pvBuf)
+ {
+ IntLockFreeType;
+ FT_Outline_Transform(outline, &transMat);
+ IntUnLockFreeType;
+ }
-// int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
-// DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
+ for(contour = 0; contour < outline->n_contours; contour++)
+ {
+ pph_start = needed;
+ pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
+ first_pt = point;
+ if(pvBuf)
+ {
+ pph->dwType = TT_POLYGON_TYPE;
+ FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
+ }
+ needed += sizeof(*pph);
+ point++;
+ while(point <= outline->contours[contour])
+ {
+ ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
+ type = (outline->tags[point] & FT_Curve_Tag_On) ?
+ TT_PRIM_LINE : TT_PRIM_CSPLINE;
+ cpfx = 0;
+ do
+ {
+ if(type == TT_PRIM_LINE)
+ {
+ if(pvBuf)
+ FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
+ cpfx++;
+ point++;
+ }
+ else
+ {
+ /* Unlike QSPLINEs, CSPLINEs always have their endpoint
+ so cpfx = 3n */
- lsb = left >> 6;
- bbx = (right - left) >> 6;
-/*
- DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
- */
- if (!fl)
- {
- SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
- SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
- SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
- }
- else
- {
- SafeBuff[i - FirstChar].abcA = lsb;
- SafeBuff[i - FirstChar].abcB = bbx;
- SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
- }
- }
- IntUnLockFreeType;
- TEXTOBJ_UnlockText(TextObj);
- Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
- if (! NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- ExFreePool(SafeBuff);
- return FALSE;
- }
- ExFreePool(SafeBuff);
- DPRINT("NtGdiGetCharABCWidths Worked!\n");
- return TRUE;
-}
-
- /*
- * @implemented
- */
-BOOL
-STDCALL
-NtGdiGetCharWidthW(
- IN HDC hDC,
- IN UINT FirstChar,
- IN UINT Count,
- IN OPTIONAL PWCHAR pwc,
- IN FLONG fl,
- OUT PVOID Buffer)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- LPINT SafeBuff;
- PFLOAT SafeBuffF = NULL;
- PDC dc;
- PDC_ATTR Dc_Attr;
- PTEXTOBJ TextObj;
- PFONTGDI FontGDI;
- FT_Face face;
- FT_CharMap charmap, found = NULL;
- UINT i, glyph_index, BufferSize;
- HFONT hFont = 0;
-
- if(pwc)
- {
- _SEH_TRY
- {
- ProbeForRead(pwc,
- sizeof(PWSTR),
- 1);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- if (!NT_SUCCESS(Status))
- {
- SetLastWin32Error(Status);
- return FALSE;
- }
-
- BufferSize = Count * sizeof(INT); // Same size!
- SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
- if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
- if (SafeBuff == NULL)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- dc = DC_LockDc(hDC);
- if (dc == NULL)
- {
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(dc);
-
- if (TextObj == NULL)
- {
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- FontGDI = ObjToGDI(TextObj->Font, FONT);
-
- face = FontGDI->face;
- if (face->charmap == NULL)
- {
- for (i = 0; i < face->num_charmaps; i++)
- {
- charmap = face->charmaps[i];
- if (charmap->encoding != 0)
- {
- found = charmap;
- break;
- }
- }
-
- if (!found)
- {
- DPRINT1("WARNING: Could not find desired charmap!\n");
- ExFreePool(SafeBuff);
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- IntLockFreeType;
- FT_Set_Charmap(face, found);
- IntUnLockFreeType;
- }
-
- IntLockFreeType;
- FT_Set_Pixel_Sizes(face,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
- (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
- - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
-
- for (i = FirstChar; i < FirstChar+Count; i++)
- {
- if (pwc)
- {
- if (fl & GCW_INDICES)
- glyph_index = pwc[i - FirstChar];
- else
- glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
- }
- else
- {
- if (fl & GCW_INDICES)
- glyph_index = i;
- else
- glyph_index = FT_Get_Char_Index(face, i);
- }
- FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- if (!fl)
- SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
- else
- SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
- }
- IntUnLockFreeType;
- TEXTOBJ_UnlockText(TextObj);
- MmCopyToCaller(Buffer, SafeBuff, BufferSize);
- ExFreePool(SafeBuff);
- return TRUE;
-}
-
-
- /*
- * @implemented
- */
-DWORD
-STDCALL
-NtGdiGetGlyphIndicesW(
- IN HDC hdc,
- IN OPTIONAL LPWSTR UnSafepwc,
- IN INT cwc,
- OUT OPTIONAL LPWORD UnSafepgi,
- IN DWORD iMode)
-{
- PDC dc;
- PDC_ATTR Dc_Attr;
- PTEXTOBJ TextObj;
- PFONTGDI FontGDI;
- HFONT hFont = 0;
- NTSTATUS Status = STATUS_SUCCESS;
- OUTLINETEXTMETRICW *potm;
- INT i;
- FT_Face face;
- WCHAR DefChar = 0xffff;
- PWSTR Buffer = NULL;
- ULONG Size;
-
- if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
-
- dc = DC_LockDc(hdc);
- if (!dc)
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return GDI_ERROR;
- }
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(dc);
- if (!TextObj)
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return GDI_ERROR;
- }
-
- FontGDI = ObjToGDI(TextObj->Font, FONT);
- TEXTOBJ_UnlockText(TextObj);
-
- Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
- if (!Buffer)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return GDI_ERROR;
- }
-
- if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
- else
- {
- Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
- potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
- if (!potm)
- {
- Status = ERROR_NOT_ENOUGH_MEMORY;
- goto ErrorRet;
- }
- IntGetOutlineTextMetrics(FontGDI, Size, potm);
- DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
- ExFreePool(potm);
- }
-
- _SEH_TRY
- {
- ProbeForRead(UnSafepwc,
- sizeof(PWSTR),
- 1);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status)) goto ErrorRet;
-
- IntLockFreeType;
- face = FontGDI->face;
-
- for (i = 0; i < cwc; i++)
- {
- Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
- if (Buffer[i] == 0)
- {
- if (DefChar == 0xffff && FT_IS_SFNT(face))
- {
- TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
- DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
- }
- Buffer[i] = DefChar;
- }
- }
-
- IntUnLockFreeType;
-
- _SEH_TRY
- {
- ProbeForWrite(UnSafepgi,
- sizeof(WORD),
- 1);
- RtlCopyMemory(UnSafepgi,
- Buffer,
- cwc*sizeof(WORD));
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
-ErrorRet:
- ExFreePoolWithTag(Buffer, TAG_GDITEXT);
- if (NT_SUCCESS(Status)) return cwc;
- SetLastWin32Error(Status);
- return GDI_ERROR;
-}
-
-static
-void
-FTVectorToPOINTFX(FT_Vector *vec, POINTFX *pt)
-{
- pt->x.value = vec->x >> 6;
- pt->x.fract = (vec->x & 0x3f) << 10;
- pt->x.fract |= ((pt->x.fract >> 6) | (pt->x.fract >> 12));
- pt->y.value = vec->y >> 6;
- pt->y.fract = (vec->y & 0x3f) << 10;
- pt->y.fract |= ((pt->y.fract >> 6) | (pt->y.fract >> 12));
- return;
-}
+ /* FIXME: Possible optimization in endpoint calculation
+ if there are two consecutive curves */
+ cubic_control[0] = outline->points[point-1];
+ if(!(outline->tags[point-1] & FT_Curve_Tag_On))
+ {
+ cubic_control[0].x += outline->points[point].x + 1;
+ cubic_control[0].y += outline->points[point].y + 1;
+ cubic_control[0].x >>= 1;
+ cubic_control[0].y >>= 1;
+ }
+ if(point+1 > outline->contours[contour])
+ cubic_control[3] = outline->points[first_pt];
+ else
+ {
+ cubic_control[3] = outline->points[point+1];
+ if(!(outline->tags[point+1] & FT_Curve_Tag_On))
+ {
+ cubic_control[3].x += outline->points[point].x + 1;
+ cubic_control[3].y += outline->points[point].y + 1;
+ cubic_control[3].x >>= 1;
+ cubic_control[3].y >>= 1;
+ }
+ }
+ /* r1 = 1/3 p0 + 2/3 p1
+ r2 = 1/3 p2 + 2/3 p1 */
+ cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
+ cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
+ cubic_control[2] = cubic_control[1];
+ cubic_control[1].x += (cubic_control[0].x + 1) / 3;
+ cubic_control[1].y += (cubic_control[0].y + 1) / 3;
+ cubic_control[2].x += (cubic_control[3].x + 1) / 3;
+ cubic_control[2].y += (cubic_control[3].y + 1) / 3;
+ if(pvBuf)
+ {
+ FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
+ FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
+ FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
+ }
+ cpfx += 3;
+ point++;
+ }
+ }
+ while(point <= outline->contours[contour] &&
+ (outline->tags[point] & FT_Curve_Tag_On) ==
+ (outline->tags[point-1] & FT_Curve_Tag_On));
+ /* At the end of a contour Windows adds the start point,
+ but only for Beziers and we've already done that.
+ */
+ if(point <= outline->contours[contour] &&
+ outline->tags[point] & FT_Curve_Tag_On)
+ {
+ /* This is the closing pt of a bezier, but we've already
+ added it, so just inc point and carry on */
+ point++;
+ }
+ if(pvBuf)
+ {
+ ppc->wType = type;
+ ppc->cpfx = cpfx;
+ }
+ needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
+ }
+ if(pvBuf) pph->cb = needed - pph_start;
+ }
+ break;
+ }
-/*
- This function builds an FT_Fixed from a float. It puts the integer part
- in the highest 16 bits and the decimal part in the lowest 16 bits of the FT_Fixed.
- It fails if the integer part of the float number is greater than SHORT_MAX.
-*/
-static __inline FT_Fixed FT_FixedFromFloat(float f)
-{
- short value = f;
- unsigned short fract = (f - value) * 0xFFFF;
- return (FT_Fixed)((long)value << 16 | (unsigned long)fract);
-}
+ default:
+ DPRINT1("Unsupported format %d\n", iFormat);
+ return GDI_ERROR;
+ }
-/*
- This function builds an FT_Fixed from a FIXED. It simply put f.value
- in the highest 16 bits and f.fract in the lowest 16 bits of the FT_Fixed.
-*/
-static __inline FT_Fixed FT_FixedFromFIXED(FIXED f)
-{
- return (FT_Fixed)((long)f.value << 16 | (unsigned long)f.fract);
+ DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
+ return needed;
}
-/*
- * Based on WineEngGetGlyphOutline
- *
- */
-ULONG
+BOOL
FASTCALL
-ftGdiGetGlyphOutline(
- PDC dc,
- WCHAR wch,
- UINT iFormat,
- LPGLYPHMETRICS pgm,
- ULONG cjBuf,
- PVOID pvBuf,
- LPMAT2 pmat2,
- BOOL bIgnoreRotation)
+TextIntGetTextExtentPoint(PDC dc,
+ PTEXTOBJ TextObj,
+ LPCWSTR String,
+ int Count,
+ int MaxExtent,
+ LPINT Fit,
+ LPINT Dx,
+ LPSIZE Size)
{
- static const FT_Matrix identityMat = {(1 << 16), 0, 0, (1 << 16)};
- PDC_ATTR Dc_Attr;
- PTEXTOBJ TextObj;
PFONTGDI FontGDI;
- HFONT hFont = 0;
- GLYPHMETRICS gm;
- ULONG Size;
- FT_Face ft_face;
- FT_UInt glyph_index;
- DWORD width, height, pitch, needed = 0;
- FT_Bitmap ft_bitmap;
- FT_Error error;
- INT left, right, top = 0, bottom = 0;
- FT_Angle angle = 0;
- FT_Int load_flags = FT_LOAD_DEFAULT | FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH;
- FLOAT eM11, widthRatio = 1.0;
- FT_Matrix transMat = identityMat;
- BOOL needsTransform = FALSE;
- INT orientation;
- LONG aveWidth;
- INT adv, lsb, bbx; /* These three hold to widths of the unrotated chars */
- OUTLINETEXTMETRICW *potm;
- int n = 0;
- FT_CharMap found = 0, charmap;
- XFORM xForm;
-
- DPRINT("%d, %08x, %p, %08lx, %p, %p\n", wch, iFormat, pgm,
- cjBuf, pvBuf, pmat2);
-
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
-
- MatrixS2XForm(&xForm, &dc->DcLevel.mxWorldToDevice);
- eM11 = xForm.eM11;
-
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_Glyph realglyph;
+ INT error, n, glyph_index, i, previous;
+ ULONGLONG TotalWidth = 0;
+ FT_CharMap charmap, found = NULL;
+ BOOL use_kerning;
+ FT_Render_Mode RenderMode;
+ BOOLEAN Render;
- if (!TextObj)
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return GDI_ERROR;
- }
FontGDI = ObjToGDI(TextObj->Font, FONT);
- ft_face = FontGDI->face;
-
- aveWidth = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth: 0;
- orientation = FT_IS_SCALABLE(ft_face) ? TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfOrientation: 0;
- Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
- potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
- if (!potm)
+ face = FontGDI->face;
+ if (NULL != Fit)
{
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- TEXTOBJ_UnlockText(TextObj);
- return GDI_ERROR;
+ *Fit = 0;
}
- IntGetOutlineTextMetrics(FontGDI, Size, potm);
IntLockFreeType;
-
- /* During testing, I never saw this used. In here just incase.*/
- if (ft_face->charmap == NULL)
+ if (face->charmap == NULL)
{
DPRINT("WARNING: No charmap selected!\n");
- DPRINT("This font face has %d charmaps\n", ft_face->num_charmaps);
+ DPRINT("This font face has %d charmaps\n", face->num_charmaps);
- for (n = 0; n < ft_face->num_charmaps; n++)
- {
- charmap = ft_face->charmaps[n];
- DPRINT("found charmap encoding: %u\n", charmap->encoding);
- if (charmap->encoding != 0)
- {
- found = charmap;
- break;
- }
- }
- if (!found)
- {
- DPRINT1("WARNING: Could not find desired charmap!\n");
- }
- error = FT_Set_Charmap(ft_face, found);
+ for (n = 0; n < face->num_charmaps; n++)
+ {
+ charmap = face->charmaps[n];
+ DPRINT("found charmap encoding: %u\n", charmap->encoding);
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+
+ if (! found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ }
+
+ error = FT_Set_Charmap(face, found);
if (error)
- {
- DPRINT1("WARNING: Could not set the charmap!\n");
- }
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
}
-// FT_Set_Pixel_Sizes(ft_face,
-// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
-// (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
-// TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ Render = IntIsFontRenderingEnabled();
+ if (Render)
+ RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+ else
+ RenderMode = FT_RENDER_MODE_MONO;
- TEXTOBJ_UnlockText(TextObj);
+ error = FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ if (error)
+ {
+ DPRINT1("Error in setting pixel sizes: %u\n", error);
+ }
- if (iFormat & GGO_GLYPH_INDEX)
+ use_kerning = FT_HAS_KERNING(face);
+ previous = 0;
+
+ for (i = 0; i < Count; i++)
{
- glyph_index = wch;
- iFormat &= ~GGO_GLYPH_INDEX;
+ glyph_index = FT_Get_Char_Index(face, *String);
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ break;
+ }
+
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ break;
+ }
+ }
+
+ /* retrieve kerning distance */
+ if (use_kerning && previous && glyph_index)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TotalWidth += delta.x;
+ }
+
+ TotalWidth += realglyph->advance.x >> 10;
+
+ if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
+ {
+ *Fit = i + 1;
+ }
+ if (NULL != Dx)
+ {
+ Dx[i] = (TotalWidth + 32) >> 6;
+ }
+
+ previous = glyph_index;
+ String++;
}
- else glyph_index = FT_Get_Char_Index(ft_face, wch);
+ IntUnLockFreeType;
+
+ Size->cx = (TotalWidth + 32) >> 6;
+ Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
+ Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
+
+ return TRUE;
+}
+
+DWORD
+FASTCALL
+IntGdiGetCharSet(HDC hDC)
+{
+ UINT cp = 0;
+ CHARSETINFO csi;
+ DWORD charset = NtGdiGetTextCharsetInfo(hDC,NULL,0);
+ if (IntTranslateCharsetInfo(&charset, &csi, TCI_SRCCHARSET))
+ cp = csi.ciACP;
+ else
+ {
+ switch(charset)
+ {
+ case OEM_CHARSET:
+ cp = 1;
+ break;
+ case DEFAULT_CHARSET:
+ cp = 0;
+ break;
+ default:
+ DPRINT1("Can't find codepage for charset %d\n", charset);
+ break;
+ }
+ }
+ DPRINT("charset %d => cp %d\n", charset, LOWORD(cp));
+ return (MAKELONG(cp, charset));
+}
- if (orientation || (iFormat != GGO_METRICS && iFormat != GGO_BITMAP) || aveWidth || pmat2)
- load_flags |= FT_LOAD_NO_BITMAP;
+INT
+FASTCALL
+ftGdiGetTextCharsetInfo(
+ PDC Dc,
+ LPFONTSIGNATURE lpSig,
+ DWORD dwFlags)
+{
+ PDC_ATTR Dc_Attr;
+ UINT Ret = DEFAULT_CHARSET, i = 0, fs_fsCsb0 = 0;
+ HFONT hFont;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGdi;
+ FONTSIGNATURE fs;
+ TT_OS2 *pOS2;
+ FT_Face Face;
- if (iFormat & GGO_UNHINTED)
- {
- load_flags |= FT_LOAD_NO_HINTING;
- iFormat &= ~GGO_UNHINTED;
- }
+ Dc_Attr = Dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
+ hFont = Dc_Attr->hlfntNew;
+ TextObj = TEXTOBJ_LockText(hFont);
- error = FT_Load_Glyph(ft_face, glyph_index, load_flags);
- if (error)
+ if ( TextObj == NULL)
{
- DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
- IntUnLockFreeType;
- if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT);
- return GDI_ERROR;
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return Ret;
}
+ FontGdi = ObjToGDI(TextObj->Font, FONT);
+ Face = FontGdi->face;
+ TEXTOBJ_UnlockText(TextObj);
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
IntUnLockFreeType;
-
- if (aveWidth && potm)
+ memset(&fs, 0, sizeof(FONTSIGNATURE));
+ if (NULL != pOS2)
{
- widthRatio = (FLOAT)aveWidth * eM11 /
- (FLOAT) potm->otmTextMetrics.tmAveCharWidth;
- }
-
- left = (INT)(ft_face->glyph->metrics.horiBearingX * widthRatio) & -64;
- right = (INT)((ft_face->glyph->metrics.horiBearingX +
- ft_face->glyph->metrics.width) * widthRatio + 63) & -64;
+ fs.fsCsb[0] = pOS2->ulCodePageRange1;
+ fs.fsCsb[1] = pOS2->ulCodePageRange2;
+ fs.fsUsb[0] = pOS2->ulUnicodeRange1;
+ fs.fsUsb[1] = pOS2->ulUnicodeRange2;
+ fs.fsUsb[2] = pOS2->ulUnicodeRange3;
+ fs.fsUsb[3] = pOS2->ulUnicodeRange4;
+ fs_fsCsb0 = pOS2->ulCodePageRange1;
+ if (pOS2->version == 0)
+ {
+ FT_UInt dummy;
- adv = (INT)((ft_face->glyph->metrics.horiAdvance * widthRatio) + 63) >> 6;
- lsb = left >> 6;
- bbx = (right - left) >> 6;
+ if(FT_Get_First_Char( Face, &dummy ) < 0x100)
+ fs_fsCsb0 |= 1;
+ else
+ fs_fsCsb0 |= 1L << 31;
+ }
+ }
+ DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
+ if (lpSig)
+ {
+ RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
+ }
+ if (0 == fs_fsCsb0)
+ { /* let's see if we can find any interesting cmaps */
+ for (i = 0; i < Face->num_charmaps; i++)
+ {
+ switch (Face->charmaps[i]->encoding)
+ {
+ case ft_encoding_unicode:
+ case ft_encoding_apple_roman:
+ fs_fsCsb0 |= 1;
+ break;
+ case ft_encoding_symbol:
+ fs_fsCsb0 |= 1L << 31;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ while (0 == (fs_fsCsb0 >> i & 0x0001) && i < MAXTCIINDEX)
+ {
+ i++;
+ }
+ Ret = FontTci[i].ciCharset;
+ DPRINT("CharSet %d\n",Ret);
+ return Ret;
+}
- DPRINT("Advance = %d, lsb = %d, bbx = %d\n",adv, lsb, bbx);
- IntLockFreeType;
+DWORD
+FASTCALL
+ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
+{
+ DWORD size = 0;
+ DWORD num_ranges = 0;
+ FT_Face face = Font->face;
- /* Scaling transform */
- if (aveWidth)
+ if (face->charmap->encoding == FT_ENCODING_UNICODE)
{
- FT_Matrix scaleMat;
- DPRINT("Scaling Trans!\n");
- scaleMat.xx = FT_FixedFromFloat(widthRatio);
- scaleMat.xy = 0;
- scaleMat.yx = 0;
- scaleMat.yy = (1 << 16);
- FT_Matrix_Multiply(&scaleMat, &transMat);
- needsTransform = TRUE;
- }
+ FT_UInt glyph_code = 0;
+ FT_ULong char_code, char_code_prev;
- /* Slant transform */
- if (potm->otmTextMetrics.tmItalic)
- {
- FT_Matrix slantMat;
- DPRINT("Slant Trans!\n");
- slantMat.xx = (1 << 16);
- slantMat.xy = ((1 << 16) >> 2);
- slantMat.yx = 0;
- slantMat.yy = (1 << 16);
- FT_Matrix_Multiply(&slantMat, &transMat);
- needsTransform = TRUE;
- }
+ char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
- /* Rotation transform */
- if (orientation)
- {
- FT_Matrix rotationMat;
- FT_Vector vecAngle;
- DPRINT("Rotation Trans!\n");
- angle = FT_FixedFromFloat((float)orientation / 10.0);
- FT_Vector_Unit(&vecAngle, angle);
- rotationMat.xx = vecAngle.x;
- rotationMat.xy = -vecAngle.y;
- rotationMat.yx = -rotationMat.xy;
- rotationMat.yy = rotationMat.xx;
- FT_Matrix_Multiply(&rotationMat, &transMat);
- needsTransform = TRUE;
- }
+ DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
+ face->num_glyphs, glyph_code, char_code);
- /* Extra transformation specified by caller */
- if (pmat2)
- {
- FT_Matrix extraMat;
- DPRINT("MAT2 Matrix Trans!\n");
- extraMat.xx = FT_FixedFromFIXED(pmat2->eM11);
- extraMat.xy = FT_FixedFromFIXED(pmat2->eM21);
- extraMat.yx = FT_FixedFromFIXED(pmat2->eM12);
- extraMat.yy = FT_FixedFromFIXED(pmat2->eM22);
- FT_Matrix_Multiply(&extraMat, &transMat);
- needsTransform = TRUE;
- }
+ if (!glyph_code) return 0;
- if (potm) ExFreePoolWithTag(potm, TAG_GDITEXT); /* It looks like we are finished with potm ATM.*/
+ if (glyphset)
+ {
+ glyphset->ranges[0].wcLow = (USHORT)char_code;
+ glyphset->ranges[0].cGlyphs = 0;
+ glyphset->cGlyphsSupported = 0;
+ }
- if (!needsTransform)
- {
- DPRINT("No Need to be Transformed!\n");
- top = (ft_face->glyph->metrics.horiBearingY + 63) & -64;
- bottom = (ft_face->glyph->metrics.horiBearingY -
- ft_face->glyph->metrics.height) & -64;
- gm.gmCellIncX = adv;
- gm.gmCellIncY = 0;
- }
- else
- {
- INT xc, yc;
- FT_Vector vec;
- for(xc = 0; xc < 2; xc++)
+ num_ranges = 1;
+ while (glyph_code)
{
- for(yc = 0; yc < 2; yc++)
+ if (char_code < char_code_prev)
{
- vec.x = (ft_face->glyph->metrics.horiBearingX +
- xc * ft_face->glyph->metrics.width);
- vec.y = ft_face->glyph->metrics.horiBearingY -
- yc * ft_face->glyph->metrics.height;
- DPRINT("Vec %ld,%ld\n", vec.x, vec.y);
- FT_Vector_Transform(&vec, &transMat);
- if(xc == 0 && yc == 0)
- {
- left = right = vec.x;
- top = bottom = vec.y;
- }
- else
- {
- if(vec.x < left) left = vec.x;
- else if(vec.x > right) right = vec.x;
- if(vec.y < bottom) bottom = vec.y;
- else if(vec.y > top) top = vec.y;
- }
+ DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
+ return 0;
}
- }
- left = left & -64;
- right = (right + 63) & -64;
- bottom = bottom & -64;
- top = (top + 63) & -64;
-
- DPRINT("transformed box: (%d,%d - %d,%d)\n", left, top, right, bottom);
- vec.x = ft_face->glyph->metrics.horiAdvance;
- vec.y = 0;
- FT_Vector_Transform(&vec, &transMat);
- gm.gmCellIncX = (vec.x+63) >> 6;
- gm.gmCellIncY = -((vec.y+63) >> 6);
- }
- gm.gmBlackBoxX = (right - left) >> 6;
- gm.gmBlackBoxY = (top - bottom) >> 6;
- gm.gmptGlyphOrigin.x = left >> 6;
- gm.gmptGlyphOrigin.y = top >> 6;
-
- DPRINT("CX %d CY %d BBX %d BBY %d GOX %d GOY %d\n",
- gm.gmCellIncX, gm.gmCellIncY,
- gm.gmBlackBoxX, gm.gmBlackBoxY,
- gm.gmptGlyphOrigin.x, gm.gmptGlyphOrigin.y);
-
- IntUnLockFreeType;
-
- if (pgm) RtlCopyMemory(pgm, &gm, sizeof(GLYPHMETRICS));
-
- if (iFormat == GGO_METRICS)
- {
- DPRINT("GGO_METRICS Exit!\n");
- return 1; /* FIXME */
+ if (char_code - char_code_prev > 1)
+ {
+ num_ranges++;
+ if (glyphset)
+ {
+ glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
+ glyphset->ranges[num_ranges - 1].cGlyphs = 1;
+ glyphset->cGlyphsSupported++;
+ }
+ }
+ else if (glyphset)
+ {
+ glyphset->ranges[num_ranges - 1].cGlyphs++;
+ glyphset->cGlyphsSupported++;
+ }
+ char_code_prev = char_code;
+ char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
+ }
}
+ else
+ DPRINT1("encoding %u not supported\n", face->charmap->encoding);
- if (ft_face->glyph->format != ft_glyph_format_outline && iFormat != GGO_BITMAP)
+ size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
+ if (glyphset)
{
- DPRINT1("loaded a bitmap\n");
- return GDI_ERROR;
+ glyphset->cbThis = size;
+ glyphset->cRanges = num_ranges;
}
+ return size;
+}
- switch(iFormat)
- {
- case GGO_BITMAP:
- width = gm.gmBlackBoxX;
- height = gm.gmBlackBoxY;
- pitch = ((width + 31) >> 5) << 2;
- needed = pitch * height;
- if(!pvBuf || !cjBuf) break;
+DWORD
+FASTCALL
+ftGetFontLanguageInfo(PDC Dc)
+{
+ PDC_ATTR Dc_Attr;
+ FONTSIGNATURE fontsig;
+ static const DWORD GCP_DBCS_MASK=0x003F0000,
+ GCP_DIACRITIC_MASK=0x00000000,
+ FLI_GLYPHS_MASK=0x00000000,
+ GCP_GLYPHSHAPE_MASK=0x00000040,
+ GCP_KASHIDA_MASK=0x00000000,
+ GCP_LIGATE_MASK=0x00000000,
+ GCP_USEKERNING_MASK=0x00000000,
+ GCP_REORDER_MASK=0x00000060;
- switch(ft_face->glyph->format)
- {
- case ft_glyph_format_bitmap:
- {
- BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
- INT w = (ft_face->glyph->bitmap.width + 7) >> 3;
- INT h = ft_face->glyph->bitmap.rows;
- while(h--)
- {
- RtlCopyMemory(dst, src, w);
- src += ft_face->glyph->bitmap.pitch;
- dst += pitch;
- }
- break;
- }
+ DWORD result=0;
- case ft_glyph_format_outline:
- ft_bitmap.width = width;
- ft_bitmap.rows = height;
- ft_bitmap.pitch = pitch;
- ft_bitmap.pixel_mode = ft_pixel_mode_mono;
- ft_bitmap.buffer = pvBuf;
+ ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
- IntLockFreeType;
- if(needsTransform)
- {
- FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
- }
- FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
- /* Note: FreeType will only set 'black' bits for us. */
- RtlZeroMemory(pvBuf, needed);
- FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
- IntUnLockFreeType;
- break;
+ /* We detect each flag we return using a bitmask on the Codepage Bitfields */
+ if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
+ result|=GCP_DBCS;
- default:
- DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
- return GDI_ERROR;
- }
- break;
+ if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
+ result|=GCP_DIACRITIC;
- case GGO_GRAY2_BITMAP:
- case GGO_GRAY4_BITMAP:
- case GGO_GRAY8_BITMAP:
- {
- unsigned int mult, row, col;
- BYTE *start, *ptr;
+ if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
+ result|=FLI_GLYPHS;
- width = gm.gmBlackBoxX;
- height = gm.gmBlackBoxY;
- pitch = (width + 3) / 4 * 4;
- needed = pitch * height;
+ if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
+ result|=GCP_GLYPHSHAPE;
- if(!pvBuf || !cjBuf) break;
+ if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
+ result|=GCP_KASHIDA;
- switch(ft_face->glyph->format)
- {
- case ft_glyph_format_bitmap:
- {
- BYTE *src = ft_face->glyph->bitmap.buffer, *dst = pvBuf;
- INT h = ft_face->glyph->bitmap.rows;
- INT x;
- while(h--)
- {
- for(x = 0; x < pitch; x++)
- {
- if(x < ft_face->glyph->bitmap.width)
- dst[x] = (src[x / 8] & (1 << ( (7 - (x % 8))))) ? 0xff : 0;
- else
- dst[x] = 0;
- }
- src += ft_face->glyph->bitmap.pitch;
- dst += pitch;
- }
- return needed;
- }
- case ft_glyph_format_outline:
- {
- ft_bitmap.width = width;
- ft_bitmap.rows = height;
- ft_bitmap.pitch = pitch;
- ft_bitmap.pixel_mode = ft_pixel_mode_grays;
- ft_bitmap.buffer = pvBuf;
+ if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
+ result|=GCP_LIGATE;
- IntLockFreeType;
- if (needsTransform)
- {
- FT_Outline_Transform(&ft_face->glyph->outline, &transMat);
- }
- FT_Outline_Translate(&ft_face->glyph->outline, -left, -bottom );
- RtlZeroMemory(ft_bitmap.buffer, cjBuf);
- FT_Outline_Get_Bitmap(library, &ft_face->glyph->outline, &ft_bitmap);
- IntUnLockFreeType;
+ if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
+ result|=GCP_USEKERNING;
- if (iFormat == GGO_GRAY2_BITMAP)
- mult = 4;
- else if (iFormat == GGO_GRAY4_BITMAP)
- mult = 16;
- else if (iFormat == GGO_GRAY8_BITMAP)
- mult = 64;
- else
- {
- return GDI_ERROR;
- }
- }
- default:
- DPRINT1("loaded glyph format %x\n", ft_face->glyph->format);
- return GDI_ERROR;
- }
- start = pvBuf;
- for(row = 0; row < height; row++)
- {
- ptr = start;
- for(col = 0; col < width; col++, ptr++)
- {
- *ptr = (((int)*ptr) * mult + 128) / 256;
- }
- start += pitch;
- }
- break;
- }
+ Dc_Attr = Dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
- case GGO_NATIVE:
- {
- int contour, point = 0, first_pt;
- FT_Outline *outline = &ft_face->glyph->outline;
- TTPOLYGONHEADER *pph;
- TTPOLYCURVE *ppc;
- DWORD pph_start, cpfx, type;
+ /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
+ if ( Dc_Attr->lTextAlign & TA_RTLREADING )
+ if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
+ result|=GCP_REORDER;
- if(cjBuf == 0) pvBuf = NULL; /* This is okay, need cjBuf to allocate. */
+ return result;
+}
- IntLockFreeType;
- if (needsTransform && pvBuf) FT_Outline_Transform(outline, &transMat);
- for(contour = 0; contour < outline->n_contours; contour++)
- {
- pph_start = needed;
- pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
- first_pt = point;
- if(pvBuf)
- {
- pph->dwType = TT_POLYGON_TYPE;
- FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
- }
- needed += sizeof(*pph);
- point++;
- while(point <= outline->contours[contour])
- {
- ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
- type = (outline->tags[point] & FT_Curve_Tag_On) ?
- TT_PRIM_LINE : TT_PRIM_QSPLINE;
- cpfx = 0;
- do
- {
- if(pvBuf)
- FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
- cpfx++;
- point++;
- } while(point <= outline->contours[contour] &&
- (outline->tags[point] & FT_Curve_Tag_On) ==
- (outline->tags[point-1] & FT_Curve_Tag_On));
+BOOL
+FASTCALL
+ftGdiGetTextMetricsW(
+ HDC hDC,
+ PTMW_INTERNAL ptmwi)
+{
+ PDC dc;
+ PDC_ATTR Dc_Attr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face Face;
+ TT_OS2 *pOS2;
+ TT_HoriHeader *pHori;
+ FT_WinFNT_HeaderRec Win;
+ ULONG Error;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if (!ptmwi)
+ {
+ SetLastWin32Error(STATUS_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ if(!(dc = DC_LockDc(hDC)))
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ TextObj = TEXTOBJ_LockText(Dc_Attr->hlfntNew);
+ if (NULL != TextObj)
+ {
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+
+ Face = FontGDI->face;
+ IntLockFreeType;
+ Error = FT_Set_Pixel_Sizes(Face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ IntUnLockFreeType;
+ if (0 != Error)
+ {
+ DPRINT1("Error in setting pixel sizes: %u\n", Error);
+ Status = STATUS_UNSUCCESSFUL;
+ }
+ else
+ {
+ Status = STATUS_SUCCESS;
- /* At the end of a contour Windows adds the start point, but
- only for Beziers */
- if(point > outline->contours[contour] &&
- !(outline->tags[point-1] & FT_Curve_Tag_On))
- {
- if(pvBuf)
- FTVectorToPOINTFX(&outline->points[first_pt], &ppc->apfx[cpfx]);
- cpfx++;
- }
- else if(point <= outline->contours[contour] &&
- outline->tags[point] & FT_Curve_Tag_On)
+ IntLockFreeType;
+ pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
+ if (NULL == pOS2)
{
- /* add closing pt for bezier */
- if(pvBuf)
- FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
- cpfx++;
- point++;
+ DPRINT1("Can't find OS/2 table - not TT font?\n");
+ Status = STATUS_INTERNAL_ERROR;
}
- if(pvBuf)
+
+ pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
+ if (NULL == pHori)
{
- ppc->wType = type;
- ppc->cpfx = cpfx;
+ DPRINT1("Can't find HHEA table - not TT font?\n");
+ Status = STATUS_INTERNAL_ERROR;
}
- needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
- }
- if(pvBuf) pph->cb = needed - pph_start;
- }
- IntUnLockFreeType;
- break;
- }
- case GGO_BEZIER:
- {
- /* Convert the quadratic Beziers to cubic Beziers.
- The parametric eqn for a cubic Bezier is, from PLRM:
- r(t) = at^3 + bt^2 + ct + r0
- with the control points:
- r1 = r0 + c/3
- r2 = r1 + (c + b)/3
- r3 = r0 + c + b + a
-
- A quadratic Beizer has the form:
- p(t) = (1-t)^2 p0 + 2(1-t)t p1 + t^2 p2
- So equating powers of t leads to:
- r1 = 2/3 p1 + 1/3 p0
- r2 = 2/3 p1 + 1/3 p2
- and of course r0 = p0, r3 = p2
- */
+ Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
- int contour, point = 0, first_pt;
- FT_Outline *outline = &ft_face->glyph->outline;
- TTPOLYGONHEADER *pph;
- TTPOLYCURVE *ppc;
- DWORD pph_start, cpfx, type;
- FT_Vector cubic_control[4];
- if(cjBuf == 0) pvBuf = NULL;
+ IntUnLockFreeType;
- if (needsTransform && pvBuf)
+ if (NT_SUCCESS(Status))
{
- IntLockFreeType;
- FT_Outline_Transform(outline, &transMat);
- IntUnLockFreeType;
+ if (!(FontGDI->flRealizedType & FDM_TYPE_TEXT_METRIC))
+ {
+ FillTM(&FontGDI->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
+ FontGDI->flRealizedType |= FDM_TYPE_TEXT_METRIC;
+ }
+
+ RtlCopyMemory(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
+ /* FIXME: Fill Diff member */
+ RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
}
+ }
+ TEXTOBJ_UnlockText(TextObj);
+ }
+ else
+ {
+ Status = STATUS_INVALID_HANDLE;
+ }
+ DC_UnlockDc(dc);
- for(contour = 0; contour < outline->n_contours; contour++)
- {
- pph_start = needed;
- pph = (TTPOLYGONHEADER *)((char *)pvBuf + needed);
- first_pt = point;
- if(pvBuf)
- {
- pph->dwType = TT_POLYGON_TYPE;
- FTVectorToPOINTFX(&outline->points[point], &pph->pfxStart);
- }
- needed += sizeof(*pph);
- point++;
- while(point <= outline->contours[contour])
- {
- ppc = (TTPOLYCURVE *)((char *)pvBuf + needed);
- type = (outline->tags[point] & FT_Curve_Tag_On) ?
- TT_PRIM_LINE : TT_PRIM_CSPLINE;
- cpfx = 0;
- do
- {
- if(type == TT_PRIM_LINE)
- {
- if(pvBuf)
- FTVectorToPOINTFX(&outline->points[point], &ppc->apfx[cpfx]);
- cpfx++;
- point++;
- }
- else
- {
- /* Unlike QSPLINEs, CSPLINEs always have their endpoint
- so cpfx = 3n */
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ return FALSE;
+ }
+ return TRUE;
+}
- /* FIXME: Possible optimization in endpoint calculation
- if there are two consecutive curves */
- cubic_control[0] = outline->points[point-1];
- if(!(outline->tags[point-1] & FT_Curve_Tag_On))
- {
- cubic_control[0].x += outline->points[point].x + 1;
- cubic_control[0].y += outline->points[point].y + 1;
- cubic_control[0].x >>= 1;
- cubic_control[0].y >>= 1;
- }
- if(point+1 > outline->contours[contour])
- cubic_control[3] = outline->points[first_pt];
- else
- {
- cubic_control[3] = outline->points[point+1];
- if(!(outline->tags[point+1] & FT_Curve_Tag_On))
- {
- cubic_control[3].x += outline->points[point].x + 1;
- cubic_control[3].y += outline->points[point].y + 1;
- cubic_control[3].x >>= 1;
- cubic_control[3].y >>= 1;
- }
- }
- /* r1 = 1/3 p0 + 2/3 p1
- r2 = 1/3 p2 + 2/3 p1 */
- cubic_control[1].x = (2 * outline->points[point].x + 1) / 3;
- cubic_control[1].y = (2 * outline->points[point].y + 1) / 3;
- cubic_control[2] = cubic_control[1];
- cubic_control[1].x += (cubic_control[0].x + 1) / 3;
- cubic_control[1].y += (cubic_control[0].y + 1) / 3;
- cubic_control[2].x += (cubic_control[3].x + 1) / 3;
- cubic_control[2].y += (cubic_control[3].y + 1) / 3;
- if(pvBuf)
- {
- FTVectorToPOINTFX(&cubic_control[1], &ppc->apfx[cpfx]);
- FTVectorToPOINTFX(&cubic_control[2], &ppc->apfx[cpfx+1]);
- FTVectorToPOINTFX(&cubic_control[3], &ppc->apfx[cpfx+2]);
- }
- cpfx += 3;
- point++;
- }
- }
- while(point <= outline->contours[contour] &&
- (outline->tags[point] & FT_Curve_Tag_On) ==
- (outline->tags[point-1] & FT_Curve_Tag_On));
- /* At the end of a contour Windows adds the start point,
- but only for Beziers and we've already done that.
- */
- if(point <= outline->contours[contour] &&
- outline->tags[point] & FT_Curve_Tag_On)
- {
- /* This is the closing pt of a bezier, but we've already
- added it, so just inc point and carry on */
- point++;
- }
- if(pvBuf)
- {
- ppc->wType = type;
- ppc->cpfx = cpfx;
- }
- needed += sizeof(*ppc) + (cpfx - 1) * sizeof(POINTFX);
- }
- if(pvBuf) pph->cb = needed - pph_start;
+
+DWORD
+FASTCALL
+ftGdiGetFontData(
+ PFONTGDI FontGdi,
+ DWORD Table,
+ DWORD Offset,
+ PVOID Buffer,
+ DWORD Size)
+{
+ DWORD Result = GDI_ERROR;
+
+ IntLockFreeType;
+
+ if (FT_IS_SFNT(FontGdi->face))
+ {
+ if (Table)
+ Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
+ (Table << 8 & 0xFF0000);
+
+ if (!Buffer) Size = 0;
+
+ if (Buffer && Size)
+ {
+ FT_Error Error;
+ FT_ULong Needed = 0;
+
+ Error = FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, NULL, &Needed);
+
+ if( !Error && Needed < Size) Size = Needed;
+ }
+ if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
+ Result = Size;
+ }
+
+ IntUnLockFreeType;
+
+ return Result;
+}
+
+static UINT FASTCALL
+GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
+{
+ ANSI_STRING EntryFaceNameA;
+ UNICODE_STRING EntryFaceNameW;
+ unsigned Size;
+ OUTLINETEXTMETRICW *Otm;
+ LONG WeightDiff;
+ NTSTATUS Status;
+ UINT Score = 1;
+
+ RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
+ Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
+ if (NT_SUCCESS(Status))
+ {
+ if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
+ {
+ EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
+ EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
}
- break;
- }
+ if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
+ {
+ Score += 49;
+ }
+ RtlFreeUnicodeString(&EntryFaceNameW);
+ }
- default:
- DPRINT1("Unsupported format %d\n", iFormat);
- return GDI_ERROR;
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (NULL == Otm)
+ {
+ return Score;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+
+ if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
+ (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
+ {
+ Score += 25;
+ }
+ if (LogFont->lfWeight != FW_DONTCARE)
+ {
+ if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
+ {
+ WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
+ }
+ else
+ {
+ WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
}
+ Score += (1000 - WeightDiff) / (1000 / 25);
+ }
+ else
+ {
+ Score += 25;
+ }
- DPRINT("ftGdiGetGlyphOutline END and needed %d\n", needed);
- return needed;
+ ExFreePool(Otm);
+
+ return Score;
}
-BOOL
-FASTCALL
-TextIntGetTextExtentPoint(PDC dc,
- PTEXTOBJ TextObj,
- LPCWSTR String,
- int Count,
- int MaxExtent,
- LPINT Fit,
- LPINT Dx,
- LPSIZE Size)
+static __inline VOID
+FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
+ PUNICODE_STRING FaceName, PLIST_ENTRY Head)
{
- PFONTGDI FontGDI;
- FT_Face face;
- FT_GlyphSlot glyph;
- FT_Glyph realglyph;
- INT error, n, glyph_index, i, previous;
- ULONGLONG TotalWidth = 0;
- FT_CharMap charmap, found = NULL;
- BOOL use_kerning;
- FT_Render_Mode RenderMode;
- BOOLEAN Render;
-
- FontGDI = ObjToGDI(TextObj->Font, FONT);
+ PLIST_ENTRY Entry;
+ PFONT_ENTRY CurrentEntry;
+ FONTGDI *FontGDI;
+ UINT Score;
- face = FontGDI->face;
- if (NULL != Fit)
+ Entry = Head->Flink;
+ while (Entry != Head)
{
- *Fit = 0;
+ CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+
+ FontGDI = CurrentEntry->Font;
+ ASSERT(FontGDI);
+
+ Score = GetFontScore(LogFont, FaceName, FontGDI);
+ if (*MatchScore == 0 || *MatchScore < Score)
+ {
+ *FontObj = GDIToObj(FontGDI, FONT);
+ *MatchScore = Score;
+ }
+ Entry = Entry->Flink;
}
+}
- IntLockFreeType;
- if (face->charmap == NULL)
- {
- DPRINT("WARNING: No charmap selected!\n");
- DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+static __inline BOOLEAN
+SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
+ LPCWSTR Key)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
+ NTSTATUS Status;
+ UNICODE_STRING Value;
- for (n = 0; n < face->num_charmaps; n++)
- {
- charmap = face->charmaps[n];
- DPRINT("found charmap encoding: %u\n", charmap->encoding);
- if (charmap->encoding != 0)
- {
- found = charmap;
- break;
- }
- }
+ RtlInitUnicodeString(&Value, NULL);
- if (! found)
- {
- DPRINT1("WARNING: Could not find desired charmap!\n");
- }
+ QueryTable[0].QueryRoutine = NULL;
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
+ RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].Name = FaceName->Buffer;
+ QueryTable[0].EntryContext = &Value;
+ QueryTable[0].DefaultType = REG_NONE;
+ QueryTable[0].DefaultData = NULL;
+ QueryTable[0].DefaultLength = 0;
- error = FT_Set_Charmap(face, found);
- if (error)
- {
- DPRINT1("WARNING: Could not set the charmap!\n");
- }
+ QueryTable[1].QueryRoutine = NULL;
+ QueryTable[1].Name = NULL;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
+ Key,
+ QueryTable,
+ NULL,
+ NULL);
+ if (NT_SUCCESS(Status))
+ {
+ RtlFreeUnicodeString(FaceName);
+ *FaceName = Value;
}
- Render = IntIsFontRenderingEnabled();
- if (Render)
- RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
- else
- RenderMode = FT_RENDER_MODE_MONO;
+ return NT_SUCCESS(Status);
+}
- error = FT_Set_Pixel_Sizes(face,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
- (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
- - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- if (error)
+static __inline void
+SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
+{
+ if (10 < Level) /* Enough is enough */
{
- DPRINT1("Error in setting pixel sizes: %u\n", error);
+ return;
}
- use_kerning = FT_HAS_KERNING(face);
- previous = 0;
-
- for (i = 0; i < Count; i++)
+ if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
+ SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
{
- glyph_index = FT_Get_Char_Index(face, *String);
- if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
- {
- error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- if (error)
- {
- DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
- break;
- }
+ SubstituteFontFamily(FaceName, Level + 1);
+ }
+}
- glyph = face->glyph;
- realglyph = ftGdiGlyphCacheSet(face, glyph_index,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
- if (!realglyph)
- {
- DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
- break;
- }
- }
+static
+VOID
+FASTCALL
+IntFontType(PFONTGDI Font)
+{
+ PS_FontInfoRec psfInfo;
+
+ if (FT_HAS_MULTIPLE_MASTERS(Font->face))
+ Font->FontObj.flFontType |= FO_MULTIPLEMASTER;
+ if (FT_HAS_VERTICAL( Font->face ))
+ Font->FontObj.flFontType |= FO_VERT_FACE;
+ if (FT_IS_SCALABLE( Font->face ))
+ Font->FontObj.flFontType |= FO_TYPE_RASTER;
+ if (FT_IS_SFNT(Font->face))
+ {
+ Font->FontObj.flFontType |= FO_TYPE_TRUETYPE;
+ if (FT_Get_Sfnt_Table(Font->face, ft_sfnt_post))
+ Font->FontObj.flFontType |= FO_POSTSCRIPT;
+ }
+ if (!FT_Get_PS_Font_Info(Font->face, &psfInfo ))
+ {
+ Font->FontObj.flFontType |= FO_POSTSCRIPT;
+ }
+}
- /* retrieve kerning distance */
- if (use_kerning && previous && glyph_index)
- {
- FT_Vector delta;
- FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- TotalWidth += delta.x;
- }
+NTSTATUS
+FASTCALL
+TextIntRealizeFont(HFONT FontHandle)
+{
+ NTSTATUS Status = STATUS_SUCCESS;
+ PTEXTOBJ TextObj;
+ UNICODE_STRING FaceName;
+ PW32PROCESS Win32Process;
+ UINT MatchScore;
- TotalWidth += realglyph->advance.x >> 10;
+ TextObj = TEXTOBJ_LockText(FontHandle);
+ if (NULL == TextObj)
+ {
+ return STATUS_INVALID_HANDLE;
+ }
- if (((TotalWidth + 32) >> 6) <= MaxExtent && NULL != Fit)
- {
- *Fit = i + 1;
- }
- if (NULL != Dx)
- {
- Dx[i] = (TotalWidth + 32) >> 6;
- }
+ if (TextObj->Initialized)
+ {
+ TEXTOBJ_UnlockText(TextObj);
+ return STATUS_SUCCESS;
+ }
- previous = glyph_index;
- String++;
+ if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
+ {
+ TEXTOBJ_UnlockText(TextObj);
+ return STATUS_NO_MEMORY;
+ }
+ SubstituteFontFamily(&FaceName, 0);
+ MatchScore = 0;
+ TextObj->Font = NULL;
+
+ /* First search private fonts */
+ Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ FindBestFontFromList(&TextObj->Font, &MatchScore,
+ &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
+ &Win32Process->PrivateFontListHead);
+ IntUnLockProcessPrivateFonts(Win32Process);
+
+ /* Search system fonts */
+ IntLockGlobalFonts;
+ FindBestFontFromList(&TextObj->Font, &MatchScore,
+ &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
+ &FontListHead);
+ IntUnLockGlobalFonts;
+ if (NULL == TextObj->Font)
+ {
+ DPRINT1("Requested font %S not found, no fonts loaded at all\n",
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
+ Status = STATUS_NOT_FOUND;
+ }
+ else
+ {
+ PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
+ // Need hdev, when freetype is loaded need to create DEVOBJ for
+ // Consumer and Producer.
+ TextObj->Font->iUniq = 1; // Now it can be cached.
+ IntFontType(FontGdi);
+ FontGdi->flType = TextObj->Font->flFontType;
+ FontGdi->flRealizedType = 0;
+ FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
+ FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
+ TextObj->Initialized = TRUE;
+ Status = STATUS_SUCCESS;
}
- IntUnLockFreeType;
- Size->cx = (TotalWidth + 32) >> 6;
- Size->cy = (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight);
- Size->cy = EngMulDiv(Size->cy, IntGdiGetDeviceCaps(dc, LOGPIXELSY), 72);
+ RtlFreeUnicodeString(&FaceName);
+ TEXTOBJ_UnlockText(TextObj);
- return TRUE;
-}
+ ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
-DWORD
-FASTCALL
-IntGdiGetCharSet(HDC hDC)
-{
- UINT cp = 0;
- CHARSETINFO csi;
- DWORD charset = NtGdiGetTextCharsetInfo(hDC,NULL,0);
- if (IntTranslateCharsetInfo(&charset, &csi, TCI_SRCCHARSET))
- cp = csi.ciACP;
- else
- {
- switch(charset)
- {
- case OEM_CHARSET:
- cp = 1;
- break;
- case DEFAULT_CHARSET:
- cp = 0;
- break;
- default:
- DPRINT1("Can't find codepage for charset %d\n", charset);
- break;
- }
- }
- DPRINT("charset %d => cp %d\n", charset, LOWORD(cp));
- return (MAKELONG(cp, charset));
+ return Status;
}
-INT
+
+static
+BOOL
FASTCALL
-ftGdiGetTextCharsetInfo(
- PDC Dc,
- LPFONTSIGNATURE lpSig,
- DWORD dwFlags)
+IntGetFullFileName(
+ POBJECT_NAME_INFORMATION NameInfo,
+ ULONG Size,
+ PUNICODE_STRING FileName)
{
- PDC_ATTR Dc_Attr;
- UINT Ret = DEFAULT_CHARSET, i = 0, fs_fsCsb0 = 0;
- HFONT hFont;
- PTEXTOBJ TextObj;
- PFONTGDI FontGdi;
- FONTSIGNATURE fs;
- TT_OS2 *pOS2;
- FT_Face Face;
+ NTSTATUS Status;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ HANDLE hFile;
+ IO_STATUS_BLOCK IoStatusBlock;
+ ULONG Desired;
- Dc_Attr = Dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
+ InitializeObjectAttributes(&ObjectAttributes,
+ FileName,
+ OBJ_CASE_INSENSITIVE,
+ NULL,
+ NULL);
- if ( TextObj == NULL)
+ Status = ZwOpenFile(
+ &hFile,
+ 0, //FILE_READ_ATTRIBUTES,
+ &ObjectAttributes,
+ &IoStatusBlock,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ 0);
+
+ if (!NT_SUCCESS(Status))
{
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return Ret;
+ DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
+ return FALSE;
}
- FontGdi = ObjToGDI(TextObj->Font, FONT);
- Face = FontGdi->face;
- TEXTOBJ_UnlockText(TextObj);
- IntLockFreeType;
- pOS2 = FT_Get_Sfnt_Table(Face, ft_sfnt_os2);
- IntUnLockFreeType;
- memset(&fs, 0, sizeof(FONTSIGNATURE));
- if (NULL != pOS2)
- {
- fs.fsCsb[0] = pOS2->ulCodePageRange1;
- fs.fsCsb[1] = pOS2->ulCodePageRange2;
- fs.fsUsb[0] = pOS2->ulUnicodeRange1;
- fs.fsUsb[1] = pOS2->ulUnicodeRange2;
- fs.fsUsb[2] = pOS2->ulUnicodeRange3;
- fs.fsUsb[3] = pOS2->ulUnicodeRange4;
- fs_fsCsb0 = pOS2->ulCodePageRange1;
- if (pOS2->version == 0)
- {
- FT_UInt dummy;
- if(FT_Get_First_Char( Face, &dummy ) < 0x100)
- fs_fsCsb0 |= 1;
- else
- fs_fsCsb0 |= 1L << 31;
- }
- }
- DPRINT("Csb 1=%x 0=%x\n", fs.fsCsb[1],fs.fsCsb[0]);
- if (lpSig)
- {
- RtlCopyMemory(lpSig, &fs, sizeof(FONTSIGNATURE));
- }
- if (0 == fs_fsCsb0)
- { /* let's see if we can find any interesting cmaps */
- for (i = 0; i < Face->num_charmaps; i++)
- {
- switch (Face->charmaps[i]->encoding)
- {
- case ft_encoding_unicode:
- case ft_encoding_apple_roman:
- fs_fsCsb0 |= 1;
- break;
- case ft_encoding_symbol:
- fs_fsCsb0 |= 1L << 31;
- break;
- default:
- break;
- }
- }
+ Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
+ ZwClose(hFile);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
+ return FALSE;
}
- while (0 == (fs_fsCsb0 >> i & 0x0001) && i < MAXTCIINDEX)
- {
- i++;
- }
- Ret = FontTci[i].ciCharset;
- DPRINT("CharSet %d\n",Ret);
- return Ret;
-}
+ return TRUE;
+}
-DWORD
+BOOL
FASTCALL
-ftGetFontUnicodeRanges(PFONTGDI Font, PGLYPHSET glyphset)
+IntGdiGetFontResourceInfo(
+ PUNICODE_STRING FileName,
+ PVOID pBuffer,
+ DWORD *pdwBytes,
+ DWORD dwType)
{
- DWORD size = 0;
- DWORD num_ranges = 0;
- FT_Face face = Font->face;
+ UNICODE_STRING EntryFileName;
+ POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
+ PLIST_ENTRY ListEntry;
+ PFONT_ENTRY FontEntry;
+ FONTFAMILYINFO Info;
+ ULONG Size;
+ BOOL bFound = FALSE;
- if (face->charmap->encoding == FT_ENCODING_UNICODE)
+ /* Create buffer for full path name */
+ Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
+ NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
+ if (!NameInfo1)
{
- FT_UInt glyph_code = 0;
- FT_ULong char_code, char_code_prev;
-
- char_code_prev = char_code = FT_Get_First_Char(face, &glyph_code);
-
- DPRINT("face encoding FT_ENCODING_UNICODE, number of glyphs %ld, first glyph %u, first char %04lx\n",
- face->num_glyphs, glyph_code, char_code);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- if (!glyph_code) return 0;
+ /* Get the full path name */
+ if (!IntGetFullFileName(NameInfo1, Size, FileName))
+ {
+ ExFreePool(NameInfo1);
+ return FALSE;
+ }
- if (glyphset)
- {
- glyphset->ranges[0].wcLow = (USHORT)char_code;
- glyphset->ranges[0].cGlyphs = 0;
- glyphset->cGlyphsSupported = 0;
- }
+ /* Create a buffer for the entries' names */
+ NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
+ if (!NameInfo2)
+ {
+ ExFreePool(NameInfo1);
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- num_ranges = 1;
- while (glyph_code)
+ /* Try to find the pathname in the global font list */
+ IntLockGlobalFonts;
+ for (ListEntry = FontListHead.Flink;
+ ListEntry != &FontListHead;
+ ListEntry = ListEntry->Flink)
+ {
+ FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
+ if (FontEntry->Font->Filename != NULL)
{
- if (char_code < char_code_prev)
- {
- DPRINT1("expected increasing char code from FT_Get_Next_Char\n");
- return 0;
- }
- if (char_code - char_code_prev > 1)
+ RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
+ if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
{
- num_ranges++;
- if (glyphset)
+ if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
{
- glyphset->ranges[num_ranges - 1].wcLow = (USHORT)char_code;
- glyphset->ranges[num_ranges - 1].cGlyphs = 1;
- glyphset->cGlyphsSupported++;
+ /* found */
+ FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
+ bFound = TRUE;
+ break;
}
}
- else if (glyphset)
- {
- glyphset->ranges[num_ranges - 1].cGlyphs++;
- glyphset->cGlyphsSupported++;
- }
- char_code_prev = char_code;
- char_code = FT_Get_Next_Char(face, char_code, &glyph_code);
}
}
- else
- DPRINT1("encoding %u not supported\n", face->charmap->encoding);
+ IntUnLockGlobalFonts;
+
+ /* Free the buffers */
+ ExFreePool(NameInfo1);
+ ExFreePool(NameInfo2);
+
+ if (!bFound && dwType != 5)
+ {
+ /* Font could not be found in system table
+ dwType == 5 will still handle this */
+ return FALSE;
+ }
+
+ switch(dwType)
+ {
+ case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
+ *(DWORD*)pBuffer = 1;
+ *pdwBytes = sizeof(DWORD);
+ break;
+
+ case 1: /* Copy the full font name */
+ Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
+ Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
+ memcpy(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
+ // FIXME: Do we have to zeroterminate?
+ *pdwBytes = Size;
+ break;
- size = sizeof(GLYPHSET) + sizeof(WCRANGE) * (num_ranges - 1);
- if (glyphset)
- {
- glyphset->cbThis = size;
- glyphset->cRanges = num_ranges;
+ case 2: /* Copy a LOGFONTW structure */
+ Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
+ memcpy(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
+ *pdwBytes = sizeof(LOGFONTW);
+ break;
+
+ case 3: /* FIXME: What exactly is copied here? */
+ *(DWORD*)pBuffer = 1;
+ *pdwBytes = sizeof(DWORD*);
+ break;
+
+ case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
+ *(BOOL*)pBuffer = !bFound;
+ *pdwBytes = sizeof(BOOL);
+ break;
+
+ default:
+ return FALSE;
}
- return size;
+
+ return TRUE;
}
+BOOL
+FASTCALL
+ftGdiRealizationInfo(PFONTGDI Font, PREALIZATION_INFO Info)
+{
+ if (FT_HAS_FIXED_SIZES(Font->face))
+ Info->iTechnology = RI_TECH_BITMAP;
+ else
+ {
+ if (FT_IS_SCALABLE(Font->face))
+ Info->iTechnology = RI_TECH_SCALABLE;
+ else
+ Info->iTechnology = RI_TECH_FIXED;
+ }
+ Info->iUniq = Font->FontObj.iUniq;
+ Info->dwUnknown = -1;
+ return TRUE;
+}
+
DWORD
FASTCALL
-ftGetFontLanguageInfo(PDC Dc)
+ftGdiGetKerningPairs( PFONTGDI Font,
+ DWORD cPairs,
+ LPKERNINGPAIR pKerningPair)
{
- PDC_ATTR Dc_Attr;
- FONTSIGNATURE fontsig;
- static const DWORD GCP_DBCS_MASK=0x003F0000,
- GCP_DIACRITIC_MASK=0x00000000,
- FLI_GLYPHS_MASK=0x00000000,
- GCP_GLYPHSHAPE_MASK=0x00000040,
- GCP_KASHIDA_MASK=0x00000000,
- GCP_LIGATE_MASK=0x00000000,
- GCP_USEKERNING_MASK=0x00000000,
- GCP_REORDER_MASK=0x00000060;
+ DWORD Count = 0;
+ FT_Face face;
- DWORD result=0;
+ face = Font->face;
- ftGdiGetTextCharsetInfo( Dc, &fontsig, 0 );
+ if (FT_HAS_KERNING(face) && face->charmap->encoding == FT_ENCODING_UNICODE)
+ {
+ FT_UInt previous_index = 0, glyph_index = 0;
+ FT_ULong char_code, char_previous;
+ FT_Vector delta;
+ int i;
+
+ char_previous = char_code = FT_Get_First_Char(face, &glyph_index);
- /* We detect each flag we return using a bitmask on the Codepage Bitfields */
- if( (fontsig.fsCsb[0]&GCP_DBCS_MASK)!=0 )
- result|=GCP_DBCS;
+ IntUnLockFreeType;
- if( (fontsig.fsCsb[0]&GCP_DIACRITIC_MASK)!=0 )
- result|=GCP_DIACRITIC;
+ for (i = 0; i < face->num_glyphs; i++)
+ {
+ if (previous_index && glyph_index)
+ {
+ FT_Get_Kerning(face, previous_index, glyph_index, FT_KERNING_DEFAULT, &delta);
+
+ if (pKerningPair && cPairs)
+ {
+ pKerningPair[i].wFirst = char_previous;
+ pKerningPair[i].wSecond = char_code;
+ pKerningPair[i].iKernAmount = delta.x;
+ }
+ Count++;
+ }
+ previous_index = glyph_index;
+ char_previous = char_code;
+ char_code = FT_Get_Next_Char(face, char_code, &glyph_index);
+ }
+ IntUnLockFreeType;
+ }
+ return Count;
+}
- if( (fontsig.fsCsb[0]&FLI_GLYPHS_MASK)!=0 )
- result|=FLI_GLYPHS;
- if( (fontsig.fsCsb[0]&GCP_GLYPHSHAPE_MASK)!=0 )
- result|=GCP_GLYPHSHAPE;
+////////////////
+//
+// Functions needing sorting.
+//
+///////////////
+int STDCALL
+NtGdiGetFontFamilyInfo(HDC Dc,
+ LPLOGFONTW UnsafeLogFont,
+ PFONTFAMILYINFO UnsafeInfo,
+ DWORD Size)
+{
+ NTSTATUS Status;
+ LOGFONTW LogFont;
+ PFONTFAMILYINFO Info;
+ DWORD Count;
+ PW32PROCESS Win32Process;
- if( (fontsig.fsCsb[0]&GCP_KASHIDA_MASK)!=0 )
- result|=GCP_KASHIDA;
+ /* Make a safe copy */
+ Status = MmCopyFromCaller(&LogFont, UnsafeLogFont, sizeof(LOGFONTW));
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
- if( (fontsig.fsCsb[0]&GCP_LIGATE_MASK)!=0 )
- result|=GCP_LIGATE;
+ /* Allocate space for a safe copy */
+ Info = ExAllocatePoolWithTag(PagedPool, Size * sizeof(FONTFAMILYINFO), TAG_GDITEXT);
+ if (NULL == Info)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
- if( (fontsig.fsCsb[0]&GCP_USEKERNING_MASK)!=0 )
- result|=GCP_USEKERNING;
+ /* Enumerate font families in the global list */
+ IntLockGlobalFonts;
+ Count = 0;
+ if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
+ {
+ IntUnLockGlobalFonts;
+ ExFreePool(Info);
+ return -1;
+ }
+ IntUnLockGlobalFonts;
- Dc_Attr = Dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
+ /* Enumerate font families in the process local list */
+ Win32Process = PsGetCurrentProcessWin32Process();
+ IntLockProcessPrivateFonts(Win32Process);
+ if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size,
+ &Win32Process->PrivateFontListHead))
+ {
+ IntUnLockProcessPrivateFonts(Win32Process);
+ ExFreePool(Info);
+ return -1;
+ }
+ IntUnLockProcessPrivateFonts(Win32Process);
- /* this might need a test for a HEBREW- or ARABIC_CHARSET as well */
- if ( Dc_Attr->lTextAlign & TA_RTLREADING )
- if( (fontsig.fsCsb[0]&GCP_REORDER_MASK)!=0 )
- result|=GCP_REORDER;
+ /* Enumerate font families in the registry */
+ if (! GetFontFamilyInfoForSubstitutes(&LogFont, Info, &Count, Size))
+ {
+ ExFreePool(Info);
+ return -1;
+ }
- return result;
-}
+ /* Return data to caller */
+ if (0 != Count)
+ {
+ Status = MmCopyToCaller(UnsafeInfo, Info,
+ (Count < Size ? Count : Size) * sizeof(FONTFAMILYINFO));
+ if (! NT_SUCCESS(Status))
+ {
+ ExFreePool(Info);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return -1;
+ }
+ }
+
+ ExFreePool(Info);
+ return Count;
+}
BOOL
-FASTCALL
-ftGdiGetTextMetricsW(
- HDC hDC,
- PTMW_INTERNAL ptmwi)
+APIENTRY
+NtGdiExtTextOutW(
+ IN HDC hDC,
+ IN INT XStart,
+ IN INT YStart,
+ IN UINT fuOptions,
+ IN OPTIONAL LPRECT lprc,
+ IN LPWSTR UnsafeString,
+ IN INT Count,
+ IN OPTIONAL LPINT UnsafeDx,
+ IN DWORD dwCodePage)
{
- PDC dc;
- PDC_ATTR Dc_Attr;
- PTEXTOBJ TextObj;
- PFONTGDI FontGDI;
- FT_Face Face;
- TT_OS2 *pOS2;
- TT_HoriHeader *pHori;
- FT_WinFNT_HeaderRec Win;
- ULONG Error;
- NTSTATUS Status = STATUS_SUCCESS;
+ /*
+ * FIXME:
+ * Call EngTextOut, which does the real work (calling DrvTextOut where
+ * appropriate)
+ */
- if (!ptmwi)
- {
- SetLastWin32Error(STATUS_INVALID_PARAMETER);
- return FALSE;
- }
+ DC *dc;
+ PDC_ATTR Dc_Attr;
+ SURFOBJ *SurfObj;
+ BITMAPOBJ *BitmapObj = NULL;
+ int error, glyph_index, n, i;
+ FT_Face face;
+ FT_GlyphSlot glyph;
+ FT_Glyph realglyph;
+ FT_BitmapGlyph realglyph2;
+ LONGLONG TextLeft, RealXStart;
+ ULONG TextTop, previous, BackgroundLeft;
+ FT_Bool use_kerning;
+ RECTL DestRect, MaskRect, SpecifiedDestRect;
+ POINTL SourcePoint, BrushOrigin;
+ HBRUSH hBrushFg = NULL;
+ PGDIBRUSHOBJ BrushFg = NULL;
+ GDIBRUSHINST BrushFgInst;
+ HBRUSH hBrushBg = NULL;
+ PGDIBRUSHOBJ BrushBg = NULL;
+ GDIBRUSHINST BrushBgInst;
+ HBITMAP HSourceGlyph;
+ SURFOBJ *SourceGlyphSurf;
+ SIZEL bitSize;
+ FT_CharMap found = 0, charmap;
+ INT yoff;
+ FONTOBJ *FontObj;
+ PFONTGDI FontGDI;
+ PTEXTOBJ TextObj = NULL;
+ PPALGDI PalDestGDI;
+ XLATEOBJ *XlateObj=NULL, *XlateObj2=NULL;
+ ULONG Mode;
+ FT_Render_Mode RenderMode;
+ BOOLEAN Render;
+ NTSTATUS Status;
+ INT *Dx = NULL;
+ POINT Start;
+ BOOL DoBreak = FALSE;
+ LPCWSTR String, SafeString = NULL;
+ HPALETTE hDestPalette;
+
+ // TODO: Write test-cases to exactly match real Windows in different
+ // bad parameters (e.g. does Windows check the DC or the RECT first?).
+ dc = DC_LockDc(hDC);
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ if (dc->DC_Type == DC_TYPE_INFO)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
+
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+
+ /* Check if String is valid */
+ if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ goto fail;
+ }
+ if (Count > 0)
+ {
+ SafeString = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
+ if (!SafeString)
+ {
+ goto fail;
+ }
+ Status = MmCopyFromCaller(SafeString, UnsafeString, Count * sizeof(WCHAR));
+ if (! NT_SUCCESS(Status))
+ {
+ goto fail;
+ }
+ }
+ String = SafeString;
- if(!(dc = DC_LockDc(hDC)))
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
- }
- Dc_Attr = dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
- TextObj = TEXTOBJ_LockText(Dc_Attr->hlfntNew);
- if (NULL != TextObj)
- {
- FontGDI = ObjToGDI(TextObj->Font, FONT);
+ if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
+ {
+ // At least one of the two flags were specified. Copy lprc. Once.
+ Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
+ if (!NT_SUCCESS(Status))
+ {
+ DC_UnlockDc(dc);
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
+ }
- Face = FontGDI->face;
- IntLockFreeType;
- Error = FT_Set_Pixel_Sizes(Face,
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
- /* FIXME should set character height if neg */
- (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
- - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- IntUnLockFreeType;
- if (0 != Error)
- {
- DPRINT1("Error in setting pixel sizes: %u\n", Error);
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- memcpy(&ptmwi->TextMetric, &FontGDI->TextMetric, sizeof(TEXTMETRICW));
- /* FIXME: Fill Diff member */
- RtlZeroMemory(&ptmwi->Diff, sizeof(ptmwi->Diff));
+ if (NULL != UnsafeDx && Count > 0)
+ {
+ Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
+ if (NULL == Dx)
+ {
+ goto fail;
+ }
+ Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
+ if (! NT_SUCCESS(Status))
+ {
+ goto fail;
+ }
+ }
- Status = STATUS_SUCCESS;
- IntLockFreeType;
- pOS2 = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_os2);
- if (NULL == pOS2)
- {
- DPRINT1("Can't find OS/2 table - not TT font?\n");
- Status = STATUS_INTERNAL_ERROR;
- }
+ BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
+ if ( !BitmapObj )
+ {
+ goto fail;
+ }
+ SurfObj = &BitmapObj->SurfObj;
+ ASSERT(SurfObj);
- pHori = FT_Get_Sfnt_Table(FontGDI->face, ft_sfnt_hhea);
- if (NULL == pHori)
- {
- DPRINT1("Can't find HHEA table - not TT font?\n");
- Status = STATUS_INTERNAL_ERROR;
- }
+ Start.x = XStart; Start.y = YStart;
+ IntLPtoDP(dc, &Start, 1);
- Error = FT_Get_WinFNT_Header(FontGDI->face , &Win);
+ RealXStart = (Start.x + dc->ptlDCOrig.x) << 6;
+ YStart = Start.y + dc->ptlDCOrig.y;
- IntUnLockFreeType;
+ /* Create the brushes */
+ hDestPalette = BitmapObj->hDIBPalette;
+ if (!hDestPalette) hDestPalette = pPrimarySurface->DevInfo.hpalDefault;
+ PalDestGDI = PALETTE_LockPalette(hDestPalette);
+ if ( !PalDestGDI )
+ Mode = PAL_RGB;
+ else
+ {
+ Mode = PalDestGDI->Mode;
+ PALETTE_UnlockPalette(PalDestGDI);
+ }
+ XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, hDestPalette, NULL);
+ if ( !XlateObj )
+ {
+ goto fail;
+ }
+ hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crForegroundClr), 0);
+ if ( !hBrushFg )
+ {
+ goto fail;
+ }
+ BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
+ if ( !BrushFg )
+ {
+ goto fail;
+ }
+ IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
+ if ((fuOptions & ETO_OPAQUE) || Dc_Attr->jBkMode == OPAQUE)
+ {
+ hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, Dc_Attr->crBackgroundClr), 0);
+ if ( !hBrushBg )
+ {
+ goto fail;
+ }
+ BrushBg = BRUSHOBJ_LockBrush(hBrushBg);
+ if ( !BrushBg )
+ {
+ goto fail;
+ }
+ IntGdiInitBrushInstance(&BrushBgInst, BrushBg, NULL);
+ }
+ XlateObj2 = (XLATEOBJ*)IntEngCreateXlate(PAL_RGB, Mode, NULL, hDestPalette);
+ if ( !XlateObj2 )
+ {
+ goto fail;
+ }
- if (NT_SUCCESS(Status))
- {
- FillTM(&ptmwi->TextMetric, FontGDI, pOS2, pHori, !Error ? &Win : 0);
- }
- }
- TEXTOBJ_UnlockText(TextObj);
- }
- else
- {
- Status = STATUS_INVALID_HANDLE;
- }
- DC_UnlockDc(dc);
+ SourcePoint.x = 0;
+ SourcePoint.y = 0;
+ MaskRect.left = 0;
+ MaskRect.top = 0;
+ BrushOrigin.x = 0;
+ BrushOrigin.y = 0;
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- return FALSE;
- }
- return TRUE;
-}
+ if ((fuOptions & ETO_OPAQUE) && lprc)
+ {
+ DestRect.left = SpecifiedDestRect.left + dc->ptlDCOrig.x;
+ DestRect.top = SpecifiedDestRect.top + dc->ptlDCOrig.y;
+ DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
+ DestRect.bottom = SpecifiedDestRect.bottom + dc->ptlDCOrig.y;
+ IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
+ IntEngBitBlt(
+ &BitmapObj->SurfObj,
+ NULL,
+ NULL,
+ dc->CombinedClip,
+ NULL,
+ &DestRect,
+ &SourcePoint,
+ &SourcePoint,
+ &BrushBgInst.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(PATCOPY));
+ fuOptions &= ~ETO_OPAQUE;
+ }
+ else
+ {
+ if (Dc_Attr->jBkMode == OPAQUE)
+ {
+ fuOptions |= ETO_OPAQUE;
+ }
+ }
+ TextObj = TEXTOBJ_LockText(Dc_Attr->hlfntNew);
+ if(TextObj == NULL)
+ {
+ goto fail;
+ }
-DWORD STDCALL
-NtGdiGetFontData(
- HDC hDC,
- DWORD Table,
- DWORD Offset,
- LPVOID Buffer,
- DWORD Size)
-{
- PDC Dc;
- PDC_ATTR Dc_Attr;
- HFONT hFont;
- PTEXTOBJ TextObj;
- PFONTGDI FontGdi;
- DWORD Result = GDI_ERROR;
+ FontObj = TextObj->Font;
+ ASSERT(FontObj);
+ FontGDI = ObjToGDI(FontObj, FONT);
+ ASSERT(FontGDI);
- Dc = DC_LockDc(hDC);
- if (Dc == NULL)
+ IntLockFreeType;
+ face = FontGDI->face;
+ if (face->charmap == NULL)
{
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return GDI_ERROR;
+ DPRINT("WARNING: No charmap selected!\n");
+ DPRINT("This font face has %d charmaps\n", face->num_charmaps);
+
+ for (n = 0; n < face->num_charmaps; n++)
+ {
+ charmap = face->charmaps[n];
+ DPRINT("found charmap encoding: %u\n", charmap->encoding);
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ }
+ error = FT_Set_Charmap(face, found);
+ if (error)
+ {
+ DPRINT1("WARNING: Could not set the charmap!\n");
+ }
}
- Dc_Attr = Dc->pDc_Attr;
- if(!Dc_Attr) Dc_Attr = &Dc->Dc_Attr;
- hFont = Dc_Attr->hlfntNew;
- TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(Dc);
- if (TextObj == NULL)
+ Render = IntIsFontRenderingEnabled();
+ if (Render)
+ RenderMode = IntGetFontRenderMode(&TextObj->logfont.elfEnumLogfontEx.elfLogFont);
+ else
+ RenderMode = FT_RENDER_MODE_MONO;
+
+ error = FT_Set_Pixel_Sizes(
+ face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
+ if (error)
{
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return GDI_ERROR;
+ DPRINT1("Error in setting pixel sizes: %u\n", error);
+ IntUnLockFreeType;
+ goto fail;
}
- FontGdi = ObjToGDI(TextObj->Font, FONT);
+ /*
+ * Process the vertical alignment and determine the yoff.
+ */
+
+ if (Dc_Attr->lTextAlign & TA_BASELINE)
+ yoff = 0;
+ else if (Dc_Attr->lTextAlign & TA_BOTTOM)
+ yoff = -face->size->metrics.descender >> 6;
+ else /* TA_TOP */
+ yoff = face->size->metrics.ascender >> 6;
+
+ use_kerning = FT_HAS_KERNING(face);
+ previous = 0;
- IntLockFreeType;
+ /*
+ * Process the horizontal alignment and modify XStart accordingly.
+ */
- if (FT_IS_SFNT(FontGdi->face))
+ if (Dc_Attr->lTextAlign & (TA_RIGHT | TA_CENTER))
{
- if (Table)
- Table = Table >> 24 | Table << 24 | (Table >> 8 & 0xFF00) |
- (Table << 8 & 0xFF0000);
-
- if (Buffer == NULL)
- Size = 0;
+ ULONGLONG TextWidth = 0;
+ LPCWSTR TempText = String;
+ int Start;
- if (!FT_Load_Sfnt_Table(FontGdi->face, Table, Offset, Buffer, &Size))
- Result = Size;
- }
+ /*
+ * Calculate width of the text.
+ */
- IntUnLockFreeType;
+ if (NULL != Dx)
+ {
+ Start = Count < 2 ? 0 : Count - 2;
+ TextWidth = Count < 2 ? 0 : (Dx[Count - 2] << 6);
+ }
+ else
+ {
+ Start = 0;
+ }
+ TempText = String + Start;
- TEXTOBJ_UnlockText(TextObj);
+ for (i = Start; i < Count; i++)
+ {
+ if (fuOptions & ETO_GLYPH_INDEX)
+ glyph_index = *TempText;
+ else
+ glyph_index = FT_Get_Char_Index(face, *TempText);
- return Result;
-}
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ }
-static UINT FASTCALL
-GetFontScore(LOGFONTW *LogFont, PUNICODE_STRING FaceName, PFONTGDI FontGDI)
-{
- ANSI_STRING EntryFaceNameA;
- UNICODE_STRING EntryFaceNameW;
- unsigned Size;
- OUTLINETEXTMETRICW *Otm;
- LONG WeightDiff;
- NTSTATUS Status;
- UINT Score = 1;
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight, glyph, RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail;
+ }
- RtlInitAnsiString(&EntryFaceNameA, FontGDI->face->family_name);
- Status = RtlAnsiStringToUnicodeString(&EntryFaceNameW, &EntryFaceNameA, TRUE);
- if (NT_SUCCESS(Status))
- {
- if ((LF_FACESIZE - 1) * sizeof(WCHAR) < EntryFaceNameW.Length)
- {
- EntryFaceNameW.Length = (LF_FACESIZE - 1) * sizeof(WCHAR);
- EntryFaceNameW.Buffer[LF_FACESIZE - 1] = L'\0';
- }
- if (0 == RtlCompareUnicodeString(FaceName, &EntryFaceNameW, TRUE))
- {
- Score += 49;
- }
- RtlFreeUnicodeString(&EntryFaceNameW);
- }
+ }
+ /* retrieve kerning distance */
+ if (use_kerning && previous && glyph_index)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TextWidth += delta.x;
+ }
- Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
- Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
- if (NULL == Otm)
- {
- return Score;
- }
- IntGetOutlineTextMetrics(FontGDI, Size, Otm);
+ TextWidth += realglyph->advance.x >> 10;
- if ((0 != LogFont->lfItalic && 0 != Otm->otmTextMetrics.tmItalic) ||
- (0 == LogFont->lfItalic && 0 == Otm->otmTextMetrics.tmItalic))
- {
- Score += 25;
- }
- if (LogFont->lfWeight != FW_DONTCARE)
- {
- if (LogFont->lfWeight < Otm->otmTextMetrics.tmWeight)
- {
- WeightDiff = Otm->otmTextMetrics.tmWeight - LogFont->lfWeight;
- }
- else
- {
- WeightDiff = LogFont->lfWeight - Otm->otmTextMetrics.tmWeight;
- }
- Score += (1000 - WeightDiff) / (1000 / 25);
- }
- else
- {
- Score += 25;
- }
+ previous = glyph_index;
+ TempText++;
+ }
- ExFreePool(Otm);
+ previous = 0;
- return Score;
-}
+ if (Dc_Attr->lTextAlign & TA_RIGHT)
+ {
+ RealXStart -= TextWidth;
+ }
+ else
+ {
+ RealXStart -= TextWidth / 2;
+ }
+ }
-static __inline VOID
-FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
- PUNICODE_STRING FaceName, PLIST_ENTRY Head)
-{
- PLIST_ENTRY Entry;
- PFONT_ENTRY CurrentEntry;
- FONTGDI *FontGDI;
- UINT Score;
+ TextLeft = RealXStart;
+ TextTop = YStart;
+ BackgroundLeft = (RealXStart + 32) >> 6;
- Entry = Head->Flink;
- while (Entry != Head)
- {
- CurrentEntry = (PFONT_ENTRY) CONTAINING_RECORD(Entry, FONT_ENTRY, ListEntry);
+ /*
+ * The main rendering loop.
+ */
- FontGDI = CurrentEntry->Font;
- ASSERT(FontGDI);
+ for (i = 0; i < Count; i++)
+ {
+ if (fuOptions & ETO_GLYPH_INDEX)
+ glyph_index = *String;
+ else
+ glyph_index = FT_Get_Char_Index(face, *String);
- Score = GetFontScore(LogFont, FaceName, FontGDI);
- if (*MatchScore == 0 || *MatchScore < Score)
+ if (!(realglyph = ftGdiGlyphCacheGet(face, glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight)))
+ {
+ error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (error)
{
- *FontObj = GDIToObj(FontGDI, FONT);
- *MatchScore = Score;
+ DPRINT1("Failed to load and render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail;
}
- Entry = Entry->Flink;
- }
-}
+ glyph = face->glyph;
+ realglyph = ftGdiGlyphCacheSet(face,
+ glyph_index,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight,
+ glyph,
+ RenderMode);
+ if (!realglyph)
+ {
+ DPRINT1("Failed to render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
+ goto fail;
+ }
+ }
+// DbgPrint("realglyph: %x\n", realglyph);
+// DbgPrint("TextLeft: %d\n", TextLeft);
-static __inline BOOLEAN
-SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
- LPCWSTR Key)
-{
- RTL_QUERY_REGISTRY_TABLE QueryTable[2] = {{0}};
- NTSTATUS Status;
- UNICODE_STRING Value;
+ /* retrieve kerning distance and move pen position */
+ if (use_kerning && previous && glyph_index && NULL == Dx)
+ {
+ FT_Vector delta;
+ FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
+ TextLeft += delta.x;
+ }
+// DPRINT1("TextLeft: %d\n", TextLeft);
+// DPRINT1("TextTop: %d\n", TextTop);
- RtlInitUnicodeString(&Value, NULL);
+ if (realglyph->format == ft_glyph_format_outline)
+ {
+ DbgPrint("Should already be done\n");
+// error = FT_Render_Glyph(glyph, RenderMode);
+ error = FT_Glyph_To_Bitmap(&realglyph, RenderMode, 0, 0);
+ if (error)
+ {
+ DPRINT1("WARNING: Failed to render glyph!\n");
+ goto fail;
+ }
+ }
+ realglyph2 = (FT_BitmapGlyph)realglyph;
- QueryTable[0].QueryRoutine = NULL;
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOEXPAND |
- RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].Name = FaceName->Buffer;
- QueryTable[0].EntryContext = &Value;
- QueryTable[0].DefaultType = REG_NONE;
- QueryTable[0].DefaultData = NULL;
- QueryTable[0].DefaultLength = 0;
+// DPRINT1("Pitch: %d\n", pitch);
+// DPRINT1("Advance: %d\n", realglyph->advance.x);
+
+ if (fuOptions & ETO_OPAQUE)
+ {
+ DestRect.left = BackgroundLeft;
+ DestRect.right = (TextLeft + (realglyph->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);
+ IntEngBitBlt(
+ &BitmapObj->SurfObj,
+ NULL,
+ NULL,
+ dc->CombinedClip,
+ NULL,
+ &DestRect,
+ &SourcePoint,
+ &SourcePoint,
+ &BrushBgInst.BrushObject,
+ &BrushOrigin,
+ ROP3_TO_ROP4(PATCOPY));
+ BackgroundLeft = DestRect.right;
+ }
+
+ DestRect.left = ((TextLeft + 32) >> 6) + realglyph2->left;
+ DestRect.right = DestRect.left + realglyph2->bitmap.width;
+ DestRect.top = TextTop + yoff - realglyph2->top;
+ DestRect.bottom = DestRect.top + realglyph2->bitmap.rows;
- QueryTable[1].QueryRoutine = NULL;
- QueryTable[1].Name = NULL;
+ bitSize.cx = realglyph2->bitmap.width;
+ bitSize.cy = realglyph2->bitmap.rows;
+ MaskRect.right = realglyph2->bitmap.width;
+ MaskRect.bottom = realglyph2->bitmap.rows;
- Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
- Key,
- QueryTable,
- NULL,
- NULL);
- if (NT_SUCCESS(Status))
- {
- RtlFreeUnicodeString(FaceName);
- *FaceName = Value;
- }
+ /*
+ * We should create the bitmap out of the loop at the biggest possible
+ * glyph size. Then use memset with 0 to clear it and sourcerect to
+ * limit the work of the transbitblt.
+ *
+ * FIXME: DIB bitmaps should have an lDelta which is a multiple of 4.
+ * Here we pass in the pitch from the FreeType bitmap, which is not
+ * guaranteed to be a multiple of 4. If it's not, we should expand
+ * the FreeType bitmap to a temporary bitmap.
+ */
- return NT_SUCCESS(Status);
-}
+ HSourceGlyph = EngCreateBitmap(bitSize, realglyph2->bitmap.pitch,
+ (realglyph2->bitmap.pixel_mode == ft_pixel_mode_grays) ?
+ BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
+ realglyph2->bitmap.buffer);
+ if ( !HSourceGlyph )
+ {
+ DPRINT1("WARNING: EngLockSurface() failed!\n");
+ // FT_Done_Glyph(realglyph);
+ IntUnLockFreeType;
+ goto fail;
+ }
+ SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
+ if ( !SourceGlyphSurf )
+ {
+ EngDeleteSurface((HSURF)HSourceGlyph);
+ DPRINT1("WARNING: EngLockSurface() failed!\n");
+ IntUnLockFreeType;
+ goto fail;
+ }
-static __inline void
-SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
-{
- if (10 < Level) /* Enough is enough */
- {
- return;
- }
+ /*
+ * Use the font data as a mask to paint onto the DCs surface using a
+ * brush.
+ */
- if (SubstituteFontFamilyKey(FaceName, L"SysFontSubstitutes") ||
- SubstituteFontFamilyKey(FaceName, L"FontSubstitutes"))
- {
- SubstituteFontFamily(FaceName, Level + 1);
- }
-}
+ if (lprc &&
+ (fuOptions & ETO_CLIPPED) &&
+ DestRect.right >= SpecifiedDestRect.right + dc->ptlDCOrig.x)
+ {
+ // We do the check '>=' instead of '>' to possibly save an iteration
+ // through this loop, since it's breaking after the drawing is done,
+ // and x is always incremented.
+ DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
+ DoBreak = TRUE;
+ }
-NTSTATUS FASTCALL
-TextIntRealizeFont(HFONT FontHandle)
-{
- NTSTATUS Status = STATUS_SUCCESS;
- PTEXTOBJ TextObj;
- UNICODE_STRING FaceName;
- PW32PROCESS Win32Process;
- UINT MatchScore;
+ IntEngMaskBlt(
+ SurfObj,
+ SourceGlyphSurf,
+ dc->CombinedClip,
+ XlateObj,
+ XlateObj2,
+ &DestRect,
+ &SourcePoint,
+ (PPOINTL)&MaskRect,
+ &BrushFgInst.BrushObject,
+ &BrushOrigin);
- TextObj = TEXTOBJ_LockText(FontHandle);
- if (NULL == TextObj)
- {
- return STATUS_INVALID_HANDLE;
- }
+ EngUnlockSurface(SourceGlyphSurf);
+ EngDeleteSurface((HSURF)HSourceGlyph);
- if (TextObj->Initialized)
- {
- TEXTOBJ_UnlockText(TextObj);
- return STATUS_SUCCESS;
- }
+ if (DoBreak)
+ {
+ break;
+ }
- if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName))
- {
- TEXTOBJ_UnlockText(TextObj);
- return STATUS_NO_MEMORY;
- }
- SubstituteFontFamily(&FaceName, 0);
- MatchScore = 0;
- TextObj->Font = NULL;
+ if (NULL == Dx)
+ {
+ TextLeft += realglyph->advance.x >> 10;
+// DbgPrint("new TextLeft: %d\n", TextLeft);
+ }
+ else
+ {
+ TextLeft += Dx[i] << 6;
+// DbgPrint("new TextLeft2: %d\n", TextLeft);
+ }
+ previous = glyph_index;
- /* First search private fonts */
- Win32Process = PsGetCurrentProcessWin32Process();
- IntLockProcessPrivateFonts(Win32Process);
- FindBestFontFromList(&TextObj->Font, &MatchScore,
- &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
- &Win32Process->PrivateFontListHead);
- IntUnLockProcessPrivateFonts(Win32Process);
+ String++;
+ }
- /* Search system fonts */
- IntLockGlobalFonts;
- FindBestFontFromList(&TextObj->Font, &MatchScore,
- &TextObj->logfont.elfEnumLogfontEx.elfLogFont, &FaceName,
- &FontListHead);
- IntUnLockGlobalFonts;
- if (NULL == TextObj->Font)
- {
- DPRINT1("Requested font %S not found, no fonts loaded at all\n",
- TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfFaceName);
- Status = STATUS_NOT_FOUND;
- }
- else
- {
- PFONTGDI FontGdi = ObjToGDI(TextObj->Font, FONT);
- TextObj->Font->iUniq = 1; // Now it can be cached.
- FontGdi->Underline = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfUnderline ? 0xff : 0;
- FontGdi->StrikeOut = TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfStrikeOut ? 0xff : 0;
- TextObj->Initialized = TRUE;
- Status = STATUS_SUCCESS;
- }
+ IntUnLockFreeType;
- RtlFreeUnicodeString(&FaceName);
- TEXTOBJ_UnlockText(TextObj);
+ EngDeleteXlate(XlateObj);
+ EngDeleteXlate(XlateObj2);
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
+ if(TextObj != NULL)
+ TEXTOBJ_UnlockText(TextObj);
+ if (hBrushBg != NULL)
+ {
+ BRUSHOBJ_UnlockBrush(BrushBg);
+ NtGdiDeleteObject(hBrushBg);
+ }
+ BRUSHOBJ_UnlockBrush(BrushFg);
+ NtGdiDeleteObject(hBrushFg);
+ if (NULL != SafeString)
+ {
+ ExFreePool((void*)SafeString);
+ }
+ if (NULL != Dx)
+ {
+ ExFreePool(Dx);
+ }
+ DC_UnlockDc( dc );
- ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);
+ return TRUE;
- return Status;
+fail:
+ if ( XlateObj2 != NULL )
+ EngDeleteXlate(XlateObj2);
+ if ( XlateObj != NULL )
+ EngDeleteXlate(XlateObj);
+ if(TextObj != NULL)
+ TEXTOBJ_UnlockText(TextObj);
+ if (BitmapObj != NULL)
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
+ if (hBrushBg != NULL)
+ {
+ BRUSHOBJ_UnlockBrush(BrushBg);
+ NtGdiDeleteObject(hBrushBg);
+ }
+ if (hBrushFg != NULL)
+ {
+ BRUSHOBJ_UnlockBrush(BrushFg);
+ NtGdiDeleteObject(hBrushFg);
+ }
+ if (NULL != SafeString)
+ {
+ ExFreePool((void*)SafeString);
+ }
+ if (NULL != Dx)
+ {
+ ExFreePool(Dx);
+ }
+ DC_UnlockDc(dc);
+
+ return FALSE;
}
-INT FASTCALL
-FontGetObject(PTEXTOBJ TFont, INT Count, PVOID Buffer)
-{
- if( Buffer == NULL ) return sizeof(LOGFONTW);
+ /*
+ * @implemented
+ */
+BOOL
+STDCALL
+NtGdiGetCharABCWidthsW(
+ IN HDC hDC,
+ IN UINT FirstChar,
+ IN ULONG Count,
+ IN OPTIONAL PWCHAR pwch,
+ IN FLONG fl,
+ OUT PVOID Buffer)
+{
+ LPABC SafeBuff;
+ LPABCFLOAT SafeBuffF = NULL;
+ PDC dc;
+ PDC_ATTR Dc_Attr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face face;
+ FT_CharMap charmap, found = NULL;
+ UINT i, glyph_index, BufferSize;
+ HFONT hFont = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ if(pwch)
+ {
+ _SEH_TRY
+ {
+ ProbeForRead(pwch,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(Status);
+ return FALSE;
+ }
+
+ BufferSize = Count * sizeof(ABC); // Same size!
+ SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
+ if (!fl) SafeBuffF = (LPABCFLOAT) SafeBuff;
+ if (SafeBuff == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- switch (Count)
- {
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ hFont = Dc_Attr->hlfntNew;
+ TextObj = TEXTOBJ_LockText(hFont);
+ DC_UnlockDc(dc);
- case sizeof(ENUMLOGFONTEXDVW):
- RtlCopyMemory( (LPENUMLOGFONTEXDVW) Buffer,
- &TFont->logfont,
- sizeof(ENUMLOGFONTEXDVW));
- break;
- case sizeof(ENUMLOGFONTEXW):
- RtlCopyMemory( (LPENUMLOGFONTEXW) Buffer,
- &TFont->logfont.elfEnumLogfontEx,
- sizeof(ENUMLOGFONTEXW));
- break;
+ if (TextObj == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- case sizeof(EXTLOGFONTW):
- case sizeof(ENUMLOGFONTW):
- RtlCopyMemory((LPENUMLOGFONTW) Buffer,
- &TFont->logfont.elfEnumLogfontEx.elfLogFont,
- sizeof(ENUMLOGFONTW));
- break;
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
- case sizeof(LOGFONTW):
- RtlCopyMemory((LPLOGFONTW) Buffer,
- &TFont->logfont.elfEnumLogfontEx.elfLogFont,
- sizeof(LOGFONTW));
- break;
+ face = FontGDI->face;
+ if (face->charmap == NULL)
+ {
+ for (i = 0; i < face->num_charmaps; i++)
+ {
+ charmap = face->charmaps[i];
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
+ break;
+ }
+ }
- default:
- SetLastWin32Error(ERROR_BUFFER_OVERFLOW);
- return 0;
- }
- return Count;
-}
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ IntLockFreeType;
+ FT_Set_Charmap(face, found);
+ IntUnLockFreeType;
+ }
-static BOOL FASTCALL
-IntGetFullFileName(
- POBJECT_NAME_INFORMATION NameInfo,
- ULONG Size,
- PUNICODE_STRING FileName)
-{
- NTSTATUS Status;
- OBJECT_ATTRIBUTES ObjectAttributes;
- HANDLE hFile;
- IO_STATUS_BLOCK IoStatusBlock;
- ULONG Desired;
+ IntLockFreeType;
+ FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ? - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- InitializeObjectAttributes(&ObjectAttributes,
- FileName,
- OBJ_CASE_INSENSITIVE,
- NULL,
- NULL);
+ for (i = FirstChar; i < FirstChar+Count; i++)
+ {
+ int adv, lsb, bbx, left, right;
- Status = ZwOpenFile(
- &hFile,
- 0, //FILE_READ_ATTRIBUTES,
- &ObjectAttributes,
- &IoStatusBlock,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- 0);
+ if (pwch)
+ {
+ if (fl & GCABCW_INDICES)
+ glyph_index = pwch[i - FirstChar];
+ else
+ glyph_index = FT_Get_Char_Index(face, pwch[i - FirstChar]);
+ }
+ else
+ {
+ if (fl & GCABCW_INDICES)
+ glyph_index = i;
+ else
+ glyph_index = FT_Get_Char_Index(face, i);
+ }
+ FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("ZwOpenFile() failed (Status = 0x%lx)\n", Status);
- return FALSE;
- }
+ left = (INT)face->glyph->metrics.horiBearingX & -64;
+ right = (INT)((face->glyph->metrics.horiBearingX + face->glyph->metrics.width) + 63) & -64;
+ adv = (face->glyph->advance.x + 32) >> 6;
- Status = ZwQueryObject(hFile, ObjectNameInformation, NameInfo, Size, &Desired);
- ZwClose(hFile);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("ZwQueryObject() failed (Status = %lx)\n", Status);
- return FALSE;
- }
+// int test = (INT)(face->glyph->metrics.horiAdvance + 63) >> 6;
+// DPRINT1("Advance Wine %d and Advance Ros %d\n",test, adv ); /* It's the same!*/
- return TRUE;
+ lsb = left >> 6;
+ bbx = (right - left) >> 6;
+/*
+ DPRINT1("lsb %d and bbx %d\n", lsb, bbx );
+ */
+ if (!fl)
+ {
+ SafeBuffF[i - FirstChar].abcfA = (FLOAT) lsb;
+ SafeBuffF[i - FirstChar].abcfB = (FLOAT) bbx;
+ SafeBuffF[i - FirstChar].abcfC = (FLOAT) (adv - lsb - bbx);
+ }
+ else
+ {
+ SafeBuff[i - FirstChar].abcA = lsb;
+ SafeBuff[i - FirstChar].abcB = bbx;
+ SafeBuff[i - FirstChar].abcC = adv - lsb - bbx;
+ }
+ }
+ IntUnLockFreeType;
+ TEXTOBJ_UnlockText(TextObj);
+ Status = MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+ if (! NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ ExFreePool(SafeBuff);
+ return FALSE;
+ }
+ ExFreePool(SafeBuff);
+ DPRINT("NtGdiGetCharABCWidths Worked!\n");
+ return TRUE;
}
-static BOOL FASTCALL
-IntGdiGetFontResourceInfo(
- IN PUNICODE_STRING FileName,
- OUT void *pBuffer,
- OUT DWORD *pdwBytes,
- IN DWORD dwType)
+ /*
+ * @implemented
+ */
+BOOL
+STDCALL
+NtGdiGetCharWidthW(
+ IN HDC hDC,
+ IN UINT FirstChar,
+ IN UINT Count,
+ IN OPTIONAL PWCHAR pwc,
+ IN FLONG fl,
+ OUT PVOID Buffer)
{
- UNICODE_STRING EntryFileName;
- POBJECT_NAME_INFORMATION NameInfo1, NameInfo2;
- PLIST_ENTRY ListEntry;
- PFONT_ENTRY FontEntry;
- FONTFAMILYINFO Info;
- ULONG Size;
- BOOL bFound = FALSE;
-
- /* Create buffer for full path name */
- Size = sizeof(OBJECT_NAME_INFORMATION) + MAX_PATH * sizeof(WCHAR);
- NameInfo1 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
- if (!NameInfo1)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
-
- /* Get the full path name */
- if (!IntGetFullFileName(NameInfo1, Size, FileName))
- {
- ExFreePool(NameInfo1);
- return FALSE;
- }
-
- /* Create a buffer for the entries' names */
- NameInfo2 = ExAllocatePoolWithTag(PagedPool, Size, TAG_FINF);
- if (!NameInfo2)
- {
- ExFreePool(NameInfo1);
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+ NTSTATUS Status = STATUS_SUCCESS;
+ LPINT SafeBuff;
+ PFLOAT SafeBuffF = NULL;
+ PDC dc;
+ PDC_ATTR Dc_Attr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ FT_Face face;
+ FT_CharMap charmap, found = NULL;
+ UINT i, glyph_index, BufferSize;
+ HFONT hFont = 0;
- /* Try to find the pathname in the global font list */
- IntLockGlobalFonts;
- for (ListEntry = FontListHead.Flink;
- ListEntry != &FontListHead;
- ListEntry = ListEntry->Flink)
- {
- FontEntry = CONTAINING_RECORD(ListEntry, FONT_ENTRY, ListEntry);
- if (FontEntry->Font->Filename != NULL)
- {
- RtlInitUnicodeString(&EntryFileName , FontEntry->Font->Filename);
- if (IntGetFullFileName(NameInfo2, Size, &EntryFileName))
- {
- if (RtlEqualUnicodeString(&NameInfo1->Name, &NameInfo2->Name, FALSE))
- {
- /* found */
- FontFamilyFillInfo(&Info, FontEntry->FaceName.Buffer, FontEntry->Font);
- bFound = TRUE;
- break;
- }
- }
- }
- }
- IntUnLockGlobalFonts;
+ if(pwc)
+ {
+ _SEH_TRY
+ {
+ ProbeForRead(pwc,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
+ }
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastWin32Error(Status);
+ return FALSE;
+ }
- /* Free the buffers */
- ExFreePool(NameInfo1);
- ExFreePool(NameInfo2);
+ BufferSize = Count * sizeof(INT); // Same size!
+ SafeBuff = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_GDITEXT);
+ if (!fl) SafeBuffF = (PFLOAT) SafeBuff;
+ if (SafeBuff == NULL)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
- if (!bFound && dwType != 5)
- {
- /* Font could not be found in system table
- dwType == 5 will still handle this */
- return FALSE;
- }
+ dc = DC_LockDc(hDC);
+ if (dc == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ hFont = Dc_Attr->hlfntNew;
+ TextObj = TEXTOBJ_LockText(hFont);
+ DC_UnlockDc(dc);
- switch(dwType)
- {
- case 0: /* FIXME: returns 1 or 2, don't know what this is atm */
- *(DWORD*)pBuffer = 1;
- *pdwBytes = sizeof(DWORD);
- break;
+ if (TextObj == NULL)
+ {
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- case 1: /* Copy the full font name */
- Size = wcslen(Info.EnumLogFontEx.elfFullName) + 1;
- Size = min(Size , LF_FULLFACESIZE) * sizeof(WCHAR);
- memcpy(pBuffer, Info.EnumLogFontEx.elfFullName, Size);
- // FIXME: Do we have to zeroterminate?
- *pdwBytes = Size;
- break;
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
- case 2: /* Copy a LOGFONTW structure */
- Info.EnumLogFontEx.elfLogFont.lfWidth = 0;
- memcpy(pBuffer, &Info.EnumLogFontEx.elfLogFont, sizeof(LOGFONTW));
- *pdwBytes = sizeof(LOGFONTW);
+ face = FontGDI->face;
+ if (face->charmap == NULL)
+ {
+ for (i = 0; i < face->num_charmaps; i++)
+ {
+ charmap = face->charmaps[i];
+ if (charmap->encoding != 0)
+ {
+ found = charmap;
break;
+ }
+ }
- case 3: /* FIXME: What exactly is copied here? */
- *(DWORD*)pBuffer = 1;
- *pdwBytes = sizeof(DWORD*);
- break;
+ if (!found)
+ {
+ DPRINT1("WARNING: Could not find desired charmap!\n");
+ ExFreePool(SafeBuff);
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
- case 5: /* Looks like a BOOL that is copied, TRUE, if the font was not found */
- *(BOOL*)pBuffer = !bFound;
- *pdwBytes = sizeof(BOOL);
- break;
+ IntLockFreeType;
+ FT_Set_Charmap(face, found);
+ IntUnLockFreeType;
+ }
- default:
- return FALSE;
- }
+ IntLockFreeType;
+ FT_Set_Pixel_Sizes(face,
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfWidth,
+ /* FIXME should set character height if neg */
+ (TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight < 0 ?
+ - TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight :
+ TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight == 0 ? 11 : TextObj->logfont.elfEnumLogfontEx.elfLogFont.lfHeight));
- return TRUE;
+ for (i = FirstChar; i < FirstChar+Count; i++)
+ {
+ if (pwc)
+ {
+ if (fl & GCW_INDICES)
+ glyph_index = pwc[i - FirstChar];
+ else
+ glyph_index = FT_Get_Char_Index(face, pwc[i - FirstChar]);
+ }
+ else
+ {
+ if (fl & GCW_INDICES)
+ glyph_index = i;
+ else
+ glyph_index = FT_Get_Char_Index(face, i);
+ }
+ FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
+ if (!fl)
+ SafeBuffF[i - FirstChar] = (FLOAT) ((face->glyph->advance.x + 32) >> 6);
+ else
+ SafeBuff[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
+ }
+ IntUnLockFreeType;
+ TEXTOBJ_UnlockText(TextObj);
+ MmCopyToCaller(Buffer, SafeBuff, BufferSize);
+ ExFreePool(SafeBuff);
+ return TRUE;
}
-W32KAPI BOOL APIENTRY
-NtGdiGetFontResourceInfoInternalW(
- IN LPWSTR pwszFiles,
- IN ULONG cwc,
- IN ULONG cFiles,
- IN UINT cjIn,
- OUT LPDWORD pdwBytes,
- OUT LPVOID pvBuf,
- IN DWORD dwType)
+
+ /*
+ * @implemented
+ */
+DWORD
+STDCALL
+NtGdiGetGlyphIndicesW(
+ IN HDC hdc,
+ IN OPTIONAL LPWSTR UnSafepwc,
+ IN INT cwc,
+ OUT OPTIONAL LPWORD UnSafepgi,
+ IN DWORD iMode)
{
- NTSTATUS Status = STATUS_SUCCESS;
- DWORD dwBytes;
- UNICODE_STRING SafeFileNames;
- BOOL bRet = FALSE;
- ULONG cbStringSize;
+ PDC dc;
+ PDC_ATTR Dc_Attr;
+ PTEXTOBJ TextObj;
+ PFONTGDI FontGDI;
+ HFONT hFont = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ OUTLINETEXTMETRICW *potm;
+ INT i;
+ FT_Face face;
+ WCHAR DefChar = 0xffff;
+ PWSTR Buffer = NULL;
+ ULONG Size;
- union
- {
- LOGFONTW logfontw;
- WCHAR FullName[LF_FULLFACESIZE];
- } Buffer;
+ if ((!UnSafepwc) && (!UnSafepgi)) return cwc;
- /* FIXME: handle cFiles > 0 */
+ dc = DC_LockDc(hdc);
+ if (!dc)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
+ Dc_Attr = dc->pDc_Attr;
+ if(!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
+ hFont = Dc_Attr->hlfntNew;
+ TextObj = TEXTOBJ_LockText(hFont);
+ DC_UnlockDc(dc);
+ if (!TextObj)
+ {
+ SetLastWin32Error(ERROR_INVALID_HANDLE);
+ return GDI_ERROR;
+ }
- /* Check for valid dwType values
- dwType == 4 seems to be handled by gdi32 only */
- if (dwType == 4 || dwType > 5)
- {
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
+ FontGDI = ObjToGDI(TextObj->Font, FONT);
+ TEXTOBJ_UnlockText(TextObj);
- /* Allocate a safe unicode string buffer */
- cbStringSize = cwc * sizeof(WCHAR);
- SafeFileNames.MaximumLength = SafeFileNames.Length = cbStringSize - sizeof(WCHAR);
- SafeFileNames.Buffer = ExAllocatePoolWithTag(PagedPool,
- cbStringSize,
- TAG('R','T','S','U'));
- if (!SafeFileNames.Buffer)
- {
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
- }
+ Buffer = ExAllocatePoolWithTag(PagedPool, cwc*sizeof(WORD), TAG_GDITEXT);
+ if (!Buffer)
+ {
+ SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+ return GDI_ERROR;
+ }
- /* Check buffers and copy pwszFiles to safe unicode string */
- _SEH_TRY
- {
- ProbeForRead(pwszFiles, cbStringSize, 1);
- ProbeForWrite(pdwBytes, sizeof(DWORD), 1);
- ProbeForWrite(pvBuf, cjIn, 1);
+ if (iMode & GGI_MARK_NONEXISTING_GLYPHS) DefChar = 0x001f; /* Indicate non existence */
+ else
+ {
+ Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
+ potm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
+ if (!potm)
+ {
+ Status = ERROR_NOT_ENOUGH_MEMORY;
+ goto ErrorRet;
+ }
+ IntGetOutlineTextMetrics(FontGDI, Size, potm);
+ DefChar = potm->otmTextMetrics.tmDefaultChar; // May need this.
+ ExFreePool(potm);
+ }
- RtlCopyMemory(SafeFileNames.Buffer, pwszFiles, cbStringSize);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END
+ _SEH_TRY
+ {
+ ProbeForRead(UnSafepwc,
+ sizeof(PWSTR),
+ 1);
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
- if(!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- /* Free the string buffer for the safe filename */
- ExFreePool(SafeFileNames.Buffer);
- return FALSE;
- }
+ if (!NT_SUCCESS(Status)) goto ErrorRet;
- /* Do the actual call */
- bRet = IntGdiGetFontResourceInfo(&SafeFileNames, &Buffer, &dwBytes, dwType);
+ IntLockFreeType;
+ face = FontGDI->face;
- /* Check if succeeded and the buffer is big enough */
- if (bRet && cjIn >= dwBytes)
- {
- /* Copy the data back to caller */
- _SEH_TRY
- {
- /* Buffers are already probed */
- RtlCopyMemory(pvBuf, &Buffer, dwBytes);
- *pdwBytes = dwBytes;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END
+ for (i = 0; i < cwc; i++)
+ {
+ Buffer[i] = FT_Get_Char_Index(face, UnSafepwc[i]);
+ if (Buffer[i] == 0)
+ {
+ if (DefChar == 0xffff && FT_IS_SFNT(face))
+ {
+ TT_OS2 *pOS2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
+ DefChar = (pOS2->usDefaultChar ? FT_Get_Char_Index(face, pOS2->usDefaultChar) : 0);
+ }
+ Buffer[i] = DefChar;
+ }
+ }
- if(!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- bRet = FALSE;
- }
- }
+ IntUnLockFreeType;
- /* Free the string for the safe filenames */
- ExFreePool(SafeFileNames.Buffer);
+ _SEH_TRY
+ {
+ ProbeForWrite(UnSafepgi,
+ sizeof(WORD),
+ 1);
+ RtlCopyMemory(UnSafepgi,
+ Buffer,
+ cwc*sizeof(WORD));
+ }
+ _SEH_HANDLE
+ {
+ Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
- return bRet;
+ErrorRet:
+ ExFreePoolWithTag(Buffer, TAG_GDITEXT);
+ if (NT_SUCCESS(Status)) return cwc;
+ SetLastWin32Error(Status);
+ return GDI_ERROR;
}
+
/* EOF */