📄 text.c
字号:
Status = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
L"SysFontSubstitutes",
QueryTable,
&Context,
NULL);
if (NT_SUCCESS(Status))
{
*Count = Context.Count;
}
return NT_SUCCESS(Status) || STATUS_OBJECT_NAME_NOT_FOUND == Status;
}
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;
}
int
STDCALL
NtGdiEnumFonts(HDC hDC,
LPCWSTR FaceName,
FONTENUMPROCW FontFunc,
LPARAM lParam)
{
UNIMPLEMENTED;
return 0;
}
FT_Glyph STDCALL
NtGdiGlyphCacheGet(
FT_Face Face,
INT GlyphIndex,
INT Height)
{
PLIST_ENTRY CurrentEntry;
PFONT_CACHE_ENTRY FontEntry;
// DbgPrint("CacheGet\n");
CurrentEntry = FontCacheListHead.Flink;
while (CurrentEntry != &FontCacheListHead)
{
FontEntry = (PFONT_CACHE_ENTRY)CurrentEntry;
if (FontEntry->Face == Face &&
FontEntry->GlyphIndex == GlyphIndex &&
FontEntry->Height == Height)
break;
CurrentEntry = CurrentEntry->Flink;
}
if (CurrentEntry == &FontCacheListHead) {
// DbgPrint("Miss! %x\n", FontEntry->Glyph);
/*
Misses++;
if (Misses>100) {
DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
Hits = Misses = 0;
}
*/
return NULL;
}
RemoveEntryList(CurrentEntry);
InsertHeadList(&FontCacheListHead, CurrentEntry);
// DbgPrint("Hit! %x\n", FontEntry->Glyph);
/*
Hits++;
if (Hits>100) {
DbgPrint ("Hits: %d Misses: %d\n", Hits, Misses);
Hits = Misses = 0;
}
*/
return FontEntry->Glyph;
}
FT_Glyph STDCALL
NtGdiGlyphCacheSet(
FT_Face Face,
INT GlyphIndex,
INT Height,
FT_GlyphSlot GlyphSlot,
FT_Render_Mode RenderMode)
{
FT_Glyph GlyphCopy;
INT error;
PFONT_CACHE_ENTRY NewEntry;
// DbgPrint("CacheSet.\n");
error = FT_Get_Glyph(GlyphSlot, &GlyphCopy);
if (error)
{
DbgPrint("Failure caching glyph.\n");
return NULL;
};
error = FT_Glyph_To_Bitmap(&GlyphCopy, RenderMode, 0, 1);
if (error)
{
DbgPrint("Failure rendering glyph.\n");
return NULL;
};
NewEntry = ExAllocatePoolWithTag(PagedPool, sizeof(FONT_CACHE_ENTRY), TAG_FONT);
if (!NewEntry)
{
DbgPrint("Alloc failure caching glyph.\n");
FT_Done_Glyph(GlyphCopy);
return NULL;
}
NewEntry->GlyphIndex = GlyphIndex;
NewEntry->Face = Face;
NewEntry->Glyph = GlyphCopy;
NewEntry->Height = Height;
InsertHeadList(&FontCacheListHead, &NewEntry->ListEntry);
if (FontCacheNumEntries++ > MAX_FONT_CACHE) {
NewEntry = (PFONT_CACHE_ENTRY)FontCacheListHead.Blink;
FT_Done_Glyph(NewEntry->Glyph);
RemoveTailList(&FontCacheListHead);
ExFreePool(NewEntry);
FontCacheNumEntries--;
}
// DbgPrint("Returning the glyphcopy: %x\n", GlyphCopy);
return GlyphCopy;
}
BOOL STDCALL
NtGdiExtTextOut(
HDC hDC,
INT XStart,
INT YStart,
UINT fuOptions,
CONST RECT *lprc,
LPCWSTR UnsafeString,
UINT Count,
CONST INT *UnsafeDx)
{
/*
* FIXME:
* Call EngTextOut, which does the real work (calling DrvTextOut where
* appropriate)
*/
DC *dc;
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;
// 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->IsIC)
{
DC_UnlockDc(dc);
/* Yes, Windows really returns TRUE in this case */
return TRUE;
}
/* 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->w.DCOrgX) << 6;
YStart = Start.y + dc->w.DCOrgY;
/* Create the brushes */
PalDestGDI = PALETTE_LockPalette(dc->w.hPalette);
if ( !PalDestGDI )
Mode = PAL_RGB;
else
{
Mode = PalDestGDI->Mode;
PALETTE_UnlockPalette(PalDestGDI);
}
XlateObj = (XLATEOBJ*)IntEngCreateXlate(Mode, PAL_RGB, dc->w.hPalette, NULL);
if ( !XlateObj )
{
goto fail;
}
hBrushFg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->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->Dc_Attr.jBkMode == OPAQUE)
{
hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->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, dc->w.hPalette);
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->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->SurfObj,
NULL,
NULL,
dc->CombinedClip,
NULL,
&DestRect,
&SourcePoint,
&SourcePoint,
&BrushBgInst.BrushObject,
&BrushOrigin,
ROP3_TO_ROP4(PATCOPY));
fuOptions &= ~ETO_OPAQUE;
}
else
{
if (dc->Dc_Attr.jBkMode == OPAQUE)
{
fuOptions |= ETO_OPAQUE;
}
}
TextObj = TEXTOBJ_LockText(dc->Dc_Attr.hlfntNew);
if(TextObj == NULL)
{
goto fail;
}
FontObj = TextObj->Font;
ASSERT(FontObj);
FontGDI = ObjToGDI(FontObj, FONT);
ASSERT(FontGDI);
IntLockFreeType;
face = FontGDI->face;
if (face->charmap == NULL)
{
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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -