* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id$ */
+
#include <w32k.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <freetype/tttables.h>
+#define NDEBUG
+#include <debug.h>
+
FT_Library library;
typedef struct _FONT_ENTRY {
{ DEFAULT_CHARSET, 0, FS(0)},
/* reserved for system */
{ DEFAULT_CHARSET, 0, FS(0)},
- { SYMBOL_CHARSET, CP_SYMBOL, FS(31)},
+ { SYMBOL_CHARSET, 42 /* CP_SYMBOL */, FS(31)},
};
VOID FASTCALL
return;
}
- FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH);
+ FileName.Buffer = ExAllocatePool(PagedPool, MAX_PATH * sizeof(WCHAR));
if (FileName.Buffer == NULL)
{
ExFreePool(DirInfoBuffer);
return;
}
FileName.Length = 0;
- FileName.MaximumLength = MAX_PATH;
+ FileName.MaximumLength = MAX_PATH * sizeof(WCHAR);
while (1)
{
NTSTATUS Status;
HANDLE FileHandle;
OBJECT_ATTRIBUTES ObjectAttributes;
- FILE_STANDARD_INFORMATION FileStdInfo;
- PVOID Buffer;
+ PVOID Buffer = NULL;
IO_STATUS_BLOCK Iosb;
INT Error;
FT_Face Face;
ANSI_STRING AnsiFaceName;
PFONT_ENTRY Entry;
+ PSECTION_OBJECT SectionObject;
+ ULONG ViewSize = 0;
/* Open the font file */
InitializeObjectAttributes(&ObjectAttributes, FileName, 0, NULL, NULL);
Status = ZwOpenFile(
&FileHandle,
- GENERIC_READ | SYNCHRONIZE,
+ FILE_GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes,
&Iosb,
- 0,
+ FILE_SHARE_READ,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
return 0;
}
- /* Get the size of the file */
-
- Status = NtQueryInformationFile(
- FileHandle,
- &Iosb,
- &FileStdInfo,
- sizeof(FileStdInfo),
- FileStandardInformation);
-
+ Status = MmCreateSection(&SectionObject, SECTION_ALL_ACCESS,
+ NULL, NULL, PAGE_READONLY,
+ 0, FileHandle, NULL);
if (!NT_SUCCESS(Status))
{
- DPRINT("Could not get file size\n");
+ DPRINT("Could not map file: %wZ\n", FileName);
ZwClose(FileHandle);
return 0;
}
- /* Allocate pageable memory for the font */
-
- Buffer = ExAllocatePoolWithTag(
- PagedPool,
- FileStdInfo.EndOfFile.u.LowPart,
- TAG_FNTFILE);
-
- if (Buffer == NULL)
- {
- DPRINT("Could not allocate memory for font");
- ZwClose(FileHandle);
- return 0;
- }
-
- /* Load the font into memory chunk */
-
- Status = ZwReadFile(
- FileHandle,
- NULL,
- NULL,
- NULL,
- &Iosb,
- Buffer,
- FileStdInfo.EndOfFile.u.LowPart,
- NULL,
- NULL);
+ ZwClose(FileHandle);
+ Status = MmMapViewInSystemSpace(SectionObject, &Buffer, &ViewSize);
if (!NT_SUCCESS(Status))
{
- DPRINT("Could not read the font file into memory");
- ExFreePool(Buffer);
- ZwClose(FileHandle);
- return 0;
+ DPRINT("Could not map file: %wZ\n", FileName);
+ return Status;
}
- ZwClose(FileHandle);
-
IntLockFreeType;
Error = FT_New_Memory_Face(
library,
Buffer,
- FileStdInfo.EndOfFile.u.LowPart,
+ ViewSize,
0,
&Face);
IntUnLockFreeType;
DPRINT("Unknown font file format\n");
else
DPRINT("Error reading font file (error code: %u)\n", Error);
- ExFreePool(Buffer);
+ ObDereferenceObject(SectionObject);
return 0;
}
if (!Entry)
{
FT_Done_Face(Face);
- ExFreePool(Buffer);
+ ObDereferenceObject(SectionObject);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
}
if(FontGDI == NULL)
{
FT_Done_Face(Face);
- ExFreePool(Buffer);
+ ObDereferenceObject(SectionObject);
ExFreePool(Entry);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return 0;
{
switch(logfont->lfQuality)
{
- //case ANTIALIASED_QUALITY:
- case DEFAULT_QUALITY:
- return FT_RENDER_MODE_NORMAL;
+ case NONANTIALIASED_QUALITY:
+ return FT_RENDER_MODE_MONO;
case DRAFT_QUALITY:
return FT_RENDER_MODE_LIGHT;
- //case NONANTIALIASED_QUALITY:
- case PROOF_QUALITY:
- return FT_RENDER_MODE_MONO;
- //case CLEARTYPE_QUALITY:
- // return FT_RENDER_MODE_LCD;
+/* case CLEARTYPE_QUALITY:
+ return FT_RENDER_MODE_LCD; */
}
- return FT_RENDER_MODE_MONO;
+ return FT_RENDER_MODE_NORMAL;
}
int
/* this should really depend on whether GM_ADVANCED is set */
TextObj->logfont.lfOrientation = TextObj->logfont.lfEscapement;
}
- TEXTOBJ_UnlockText(*NewFont);
+ TEXTOBJ_UnlockText(TextObj);
}
else
{
TEXTMETRICW *TM;
NEWTEXTMETRICW *Ntm;
- ZeroMemory(Info, sizeof(FONTFAMILYINFO));
+ RtlZeroMemory(Info, sizeof(FONTFAMILYINFO));
Size = IntGetOutlineTextMetrics(FontGDI, 0, NULL);
Otm = ExAllocatePoolWithTag(PagedPool, Size, TAG_GDITEXT);
if (NULL == Otm)
DC *dc;
SURFOBJ *SurfObj;
- BITMAPOBJ *BitmapObj;
+ BITMAPOBJ *BitmapObj = NULL;
int error, glyph_index, n, i;
FT_Face face;
FT_GlyphSlot glyph;
LONGLONG TextLeft, RealXStart;
- ULONG TextTop, pitch, previous, BackgroundLeft;
+ ULONG TextTop, previous, BackgroundLeft;
FT_Bool use_kerning;
- RECTL DestRect, MaskRect;
+ RECTL DestRect, MaskRect, SpecifiedDestRect;
POINTL SourcePoint, BrushOrigin;
HBRUSH hBrushFg = NULL;
PGDIBRUSHOBJ BrushFg = NULL;
NTSTATUS Status;
INT *Dx = NULL;
POINT Start;
+ BOOL DoBreak = FALSE;
+
+ // TODO: Write test-cases to exactly match real Windows in different
+ // bad parameters (e.g. does Windows check the DC or the RECT first?).
+ 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))
+ {
+ SetLastWin32Error(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+ }
dc = DC_LockDc(hDC);
if (!dc)
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
+ if (dc->IsIC)
+ {
+ DC_UnlockDc(dc);
+ /* Yes, Windows really returns TRUE in this case */
+ return TRUE;
+ }
if (NULL != UnsafeDx && Count > 0)
{
else
{
Mode = PalDestGDI->Mode;
- PALETTE_UnlockPalette(dc->w.hPalette);
+ PALETTE_UnlockPalette(PalDestGDI);
}
XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
if ( !XlateObj )
{
goto fail;
}
- hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor));
+ hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.textColor), 0);
if ( !hBrushFg )
{
goto fail;
IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
{
- hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor));
+ hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor), 0);
if ( !hBrushBg )
{
goto fail;
if ((fuOptions & ETO_OPAQUE) && lprc)
{
- MmCopyFromCaller(&DestRect, lprc, sizeof(RECT));
- DestRect.left += dc->w.DCOrgX;
- DestRect.top += dc->w.DCOrgY;
- DestRect.right += dc->w.DCOrgX;
- DestRect.bottom += dc->w.DCOrgY;
+ DestRect.left = SpecifiedDestRect.left + dc->w.DCOrgX;
+ DestRect.top = SpecifiedDestRect.top + dc->w.DCOrgY;
+ DestRect.right = SpecifiedDestRect.right + dc->w.DCOrgX;
+ DestRect.bottom = SpecifiedDestRect.bottom + dc->w.DCOrgY;
+ IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
IntEngBitBlt(
- BitmapObj,
+ &BitmapObj->SurfObj,
NULL,
NULL,
dc->CombinedClip,
&SourcePoint,
&BrushBgInst.BrushObject,
&BrushOrigin,
- PATCOPY);
+ ROP3_TO_ROP4(PATCOPY));
fuOptions &= ~ETO_OPAQUE;
}
else
FontGDI = ObjToGDI(FontObj, FONT);
ASSERT(FontGDI);
+ IntLockFreeType;
face = FontGDI->face;
if (face->charmap == NULL)
{
{
DPRINT1("WARNING: Could not find desired charmap!\n");
}
- IntLockFreeType;
error = FT_Set_Charmap(face, found);
- IntUnLockFreeType;
- if (error)
+ if (error)
{
DPRINT1("WARNING: Could not set the charmap!\n");
}
else
RenderMode = FT_RENDER_MODE_MONO;
- IntLockFreeType;
error = FT_Set_Pixel_Sizes(
face,
TextObj->logfont.lfWidth,
(TextObj->logfont.lfHeight < 0 ?
- TextObj->logfont.lfHeight :
TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
- IntUnLockFreeType;
if (error)
{
DPRINT1("Error in setting pixel sizes: %u\n", error);
+ IntUnLockFreeType;
goto fail;
}
for (i = Start; i < Count; i++)
{
- IntLockFreeType;
glyph_index = FT_Get_Char_Index(face, *TempText);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- IntUnLockFreeType;
if (error)
{
if (use_kerning && previous && glyph_index)
{
FT_Vector delta;
- IntLockFreeType;
FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- IntUnLockFreeType;
TextWidth += delta.x;
}
for (i = 0; i < Count; i++)
{
- IntLockFreeType;
glyph_index = FT_Get_Char_Index(face, *String);
error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
- IntUnLockFreeType;
if (error)
{
DPRINT1("WARNING: Failed to load and render glyph! [index: %u]\n", glyph_index);
+ IntUnLockFreeType;
goto fail;
}
if (use_kerning && previous && glyph_index && NULL == Dx)
{
FT_Vector delta;
- IntLockFreeType;
FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
- IntUnLockFreeType;
TextLeft += delta.x;
}
if (glyph->format == ft_glyph_format_outline)
{
- IntLockFreeType;
error = FT_Render_Glyph(glyph, RenderMode);
- IntUnLockFreeType;
if (error)
{
DPRINT1("WARNING: Failed to render glyph!\n");
goto fail;
}
- pitch = glyph->bitmap.pitch;
- } else {
- pitch = glyph->bitmap.width;
}
if (fuOptions & ETO_OPAQUE)
DestRect.top = TextTop + yoff - ((face->size->metrics.ascender + 32) >> 6);
DestRect.bottom = TextTop + yoff + ((32 - face->size->metrics.descender) >> 6);
IntEngBitBlt(
- BitmapObj,
+ &BitmapObj->SurfObj,
NULL,
NULL,
dc->CombinedClip,
&SourcePoint,
&BrushBgInst.BrushObject,
&BrushOrigin,
- PATCOPY);
+ ROP3_TO_ROP4(PATCOPY));
BackgroundLeft = DestRect.right;
}
* 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.
*/
- HSourceGlyph = EngCreateBitmap(bitSize, pitch, (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ? BMF_8BPP : BMF_1BPP, BMF_TOPDOWN, glyph->bitmap.buffer);
+ HSourceGlyph = EngCreateBitmap(bitSize, glyph->bitmap.pitch,
+ (glyph->bitmap.pixel_mode == ft_pixel_mode_grays) ?
+ BMF_8BPP : BMF_1BPP, BMF_TOPDOWN,
+ glyph->bitmap.buffer);
if ( !HSourceGlyph )
{
DPRINT1("WARNING: EngLockSurface() failed!\n");
+ IntUnLockFreeType;
goto fail;
}
SourceGlyphSurf = EngLockSurface((HSURF)HSourceGlyph);
{
EngDeleteSurface((HSURF)HSourceGlyph);
DPRINT1("WARNING: EngLockSurface() failed!\n");
+ IntUnLockFreeType;
goto fail;
}
* brush.
*/
+ if (lprc &&
+ (fuOptions & ETO_CLIPPED) &&
+ DestRect.right >= SpecifiedDestRect.right + dc->w.DCOrgX)
+ {
+ // 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->w.DCOrgX;
+ DoBreak = TRUE;
+ }
+
IntEngMaskBlt(
SurfObj,
SourceGlyphSurf,
EngUnlockSurface(SourceGlyphSurf);
EngDeleteSurface((HSURF)HSourceGlyph);
+ if (DoBreak)
+ {
+ break;
+ }
+
if (NULL == Dx)
{
TextLeft += glyph->advance.x;
String++;
}
+ IntUnLockFreeType;
+
EngDeleteXlate(XlateObj);
EngDeleteXlate(XlateObj2);
- BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
if(TextObj != NULL)
- TEXTOBJ_UnlockText(dc->w.hFont);
+ TEXTOBJ_UnlockText(TextObj);
if (hBrushBg != NULL)
{
- BRUSHOBJ_UnlockBrush(hBrushBg);
+ BRUSHOBJ_UnlockBrush(BrushBg);
NtGdiDeleteObject(hBrushBg);
}
- BRUSHOBJ_UnlockBrush(hBrushFg);
+ BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg);
if (NULL != Dx)
{
ExFreePool(Dx);
}
- DC_UnlockDc( hDC );
+ DC_UnlockDc( dc );
return TRUE;
if ( XlateObj != NULL )
EngDeleteXlate(XlateObj);
if(TextObj != NULL)
- TEXTOBJ_UnlockText(dc->w.hFont);
- BITMAPOBJ_UnlockBitmap(dc->w.hBitmap);
+ TEXTOBJ_UnlockText(TextObj);
+ BITMAPOBJ_UnlockBitmap(BitmapObj);
if (hBrushBg != NULL)
{
- BRUSHOBJ_UnlockBrush(hBrushBg);
+ BRUSHOBJ_UnlockBrush(BrushBg);
NtGdiDeleteObject(hBrushBg);
}
if (hBrushFg != NULL)
{
- BRUSHOBJ_UnlockBrush(hBrushFg);
+ BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg);
}
if (NULL != Dx)
{
ExFreePool(Dx);
}
- DC_UnlockDc(hDC);
+ DC_UnlockDc(dc);
return FALSE;
}
}
hFont = dc->w.hFont;
TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(hDC);
+ DC_UnlockDc(dc);
if (TextObj == NULL)
{
SafeBuffer[i - FirstChar] = (face->glyph->advance.x + 32) >> 6;
}
IntUnLockFreeType;
- TEXTOBJ_UnlockText(hFont);
+ TEXTOBJ_UnlockText(TextObj);
MmCopyToCaller(Buffer, SafeBuffer, BufferSize);
ExFreePool(SafeBuffer);
return TRUE;
return 0;
}
-DWORD
-STDCALL
-NtGdiGetGlyphOutline(HDC hDC,
- UINT Char,
- UINT Format,
- LPGLYPHMETRICS gm,
- DWORD Bufsize,
- LPVOID Buffer,
- CONST LPMAT2 mat2)
+ULONG
+APIENTRY
+NtGdiGetGlyphOutline(
+ IN HDC hdc,
+ IN WCHAR wch,
+ IN UINT iFormat,
+ OUT LPGLYPHMETRICS pgm,
+ IN ULONG cjBuf,
+ OUT OPTIONAL PVOID pvBuf,
+ IN LPMAT2 pmat2,
+ IN BOOL bIgnoreRotation)
{
UNIMPLEMENTED;
return 0;
}
BOOL
-STDCALL
-NtGdiGetRasterizerCaps(LPRASTERIZER_STATUS rs,
- UINT Size)
+APIENTRY
+NtGdiGetRasterizerCaps(
+ OUT LPRASTERIZER_STATUS praststat,
+ IN ULONG cjBytes)
{
UNIMPLEMENTED;
return FALSE;
return 0;
}
-UINT
-STDCALL
-NtGdiGetTextCharsetInfo(HDC hDC,
- LPFONTSIGNATURE Sig,
- DWORD Flags)
+INT
+APIENTRY
+NtGdiGetTextCharsetInfo(
+ IN HDC hdc,
+ OUT OPTIONAL LPFONTSIGNATURE lpSig,
+ IN DWORD dwFlags)
{
UNIMPLEMENTED;
return 0;
}
else
Result = FALSE;
- TEXTOBJ_UnlockText(dc->w.hFont);
- DC_UnlockDc(hDC);
+ TEXTOBJ_UnlockText(TextObj);
+ DC_UnlockDc(dc);
ExFreePool(String);
if (! Result)
{
Result = TextIntGetTextExtentPoint (
dc, TextObj, String, Count, 0, NULL, NULL, &Size);
- TEXTOBJ_UnlockText(dc->w.hFont);
+ TEXTOBJ_UnlockText(TextObj);
}
else
Result = FALSE;
- DC_UnlockDc(hDC);
+ DC_UnlockDc(dc);
ExFreePool(String);
if (! Result)
NtGdiGetTextFace(HDC hDC, INT Count, LPWSTR FaceName)
{
PDC Dc;
+ HFONT hFont;
PTEXTOBJ TextObj;
NTSTATUS Status;
SetLastWin32Error(ERROR_INVALID_HANDLE);
return FALSE;
}
- TextObj = TEXTOBJ_LockText(Dc->w.hFont);
- DC_UnlockDc(hDC);
+ hFont = Dc->w.hFont;
+ DC_UnlockDc(Dc);
+ TextObj = TEXTOBJ_LockText(hFont);
+ ASSERT(TextObj != NULL);
Count = min(Count, wcslen(TextObj->logfont.lfFaceName));
Status = MmCopyToCaller(FaceName, TextObj->logfont.lfFaceName, Count * sizeof(WCHAR));
+ TEXTOBJ_UnlockText(TextObj);
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
Status = MmCopyToCaller(tm, &SafeTm, sizeof(TEXTMETRICW));
}
}
- TEXTOBJ_UnlockText(dc->w.hFont);
+ TEXTOBJ_UnlockText(TextObj);
}
else
{
Status = STATUS_INVALID_HANDLE;
}
- DC_UnlockDc(hDC);
+ DC_UnlockDc(dc);
if(!NT_SUCCESS(Status))
{
STDCALL
NtGdiRemoveFontResource(LPCWSTR FileName)
{
- UNIMPLEMENTED;
+ DPRINT1("NtGdiRemoveFontResource is UNIMPLEMENTED\n");
return FALSE;
}
}
prevAlign = dc->w.textAlign;
dc->w.textAlign = Mode;
- DC_UnlockDc( hDC );
+ DC_UnlockDc( dc );
return prevAlign;
}
oldColor = dc->w.textColor;
dc->w.textColor = color;
hBrush = dc->w.hBrush;
- DC_UnlockDc( hDC );
+ DC_UnlockDc( dc );
NtGdiSelectObject(hDC, hBrush);
return oldColor;
}
}
hFont = Dc->w.hFont;
TextObj = TEXTOBJ_LockText(hFont);
- DC_UnlockDc(hDC);
+ DC_UnlockDc(Dc);
if (TextObj == NULL)
{
IntUnLockFreeType;
- TEXTOBJ_UnlockText(hFont);
+ TEXTOBJ_UnlockText(TextObj);
return Result;
}
return Score;
}
-static inline VOID
+static __inline VOID
FindBestFontFromList(FONTOBJ **FontObj, UINT *MatchScore, LOGFONTW *LogFont,
PUNICODE_STRING FaceName, PLIST_ENTRY Head)
{
}
}
-static inline BOOLEAN
+static __inline BOOLEAN
SubstituteFontFamilyKey(PUNICODE_STRING FaceName,
LPCWSTR Key)
{
return NT_SUCCESS(Status);
}
-static inline void
+static __inline void
SubstituteFontFamily(PUNICODE_STRING FaceName, UINT Level)
{
if (10 < Level) /* Enough is enough */
return STATUS_INVALID_HANDLE;
}
+ if (TextObj->Initialized)
+ {
+ TEXTOBJ_UnlockText(TextObj);
+ return STATUS_SUCCESS;
+ }
+
if (! RtlCreateUnicodeString(&FaceName, TextObj->logfont.lfFaceName))
{
- TEXTOBJ_UnlockText(FontHandle);
+ TEXTOBJ_UnlockText(TextObj);
return STATUS_NO_MEMORY;
}
SubstituteFontFamily(&FaceName, 0);
}
else
{
+ TextObj->Initialized = TRUE;
Status = STATUS_SUCCESS;
}
RtlFreeUnicodeString(&FaceName);
- TEXTOBJ_UnlockText(FontHandle);
+ TEXTOBJ_UnlockText(TextObj);
ASSERT((NT_SUCCESS(Status) ^ (NULL == TextObj->Font)) != 0);