text.c
来自「一个类似windows」· C语言 代码 · 共 2,305 行 · 第 1/5 页
C
2,305 行
Count = 0;
if (! GetFontFamilyInfoForList(&LogFont, Info, &Count, Size, &FontListHead) )
{
IntUnLockGlobalFonts;
ExFreePool(Info);
return -1;
}
IntUnLockGlobalFonts;
/* Enumerate font families in the process local list */
Win32Process = PsGetWin32Process();
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;
}
BOOL STDCALL
NtGdiExtTextOut(
HDC hDC,
INT XStart,
INT YStart,
UINT fuOptions,
CONST RECT *lprc,
LPCWSTR String,
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;
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;
// 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;
}
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;
}
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->w.textColor), 0);
if ( !hBrushFg )
{
goto fail;
}
BrushFg = BRUSHOBJ_LockBrush(hBrushFg);
if ( !BrushFg )
{
goto fail;
}
IntGdiInitBrushInstance(&BrushFgInst, BrushFg, NULL);
if ((fuOptions & ETO_OPAQUE) || dc->w.backgroundMode == OPAQUE)
{
hBrushBg = NtGdiCreateSolidBrush(XLATEOBJ_iXlate(XlateObj, dc->w.backgroundColor), 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->w.backgroundMode == OPAQUE)
{
fuOptions |= ETO_OPAQUE;
}
}
TextObj = TEXTOBJ_LockText(dc->w.hFont);
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)
{
DPRINT1("WARNING: Could not set the charmap!\n");
}
}
Render = IntIsFontRenderingEnabled();
if (Render)
RenderMode = IntGetFontRenderMode(&TextObj->logfont);
else
RenderMode = FT_RENDER_MODE_MONO;
error = FT_Set_Pixel_Sizes(
face,
TextObj->logfont.lfWidth,
/* FIXME should set character height if neg */
(TextObj->logfont.lfHeight < 0 ?
- TextObj->logfont.lfHeight :
TextObj->logfont.lfHeight == 0 ? 11 : TextObj->logfont.lfHeight));
if (error)
{
DPRINT1("Error in setting pixel sizes: %u\n", error);
IntUnLockFreeType;
goto fail;
}
/*
* Process the vertical alignment and determine the yoff.
*/
if (dc->w.textAlign & TA_BASELINE)
yoff = 0;
else if (dc->w.textAlign & 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;
/*
* Process the horizontal alignment and modify XStart accordingly.
*/
if (dc->w.textAlign & (TA_RIGHT | TA_CENTER))
{
ULONGLONG TextWidth = 0;
LPCWSTR TempText = String;
int Start;
/*
* Calculate width of the text.
*/
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++)
{
glyph_index = FT_Get_Char_Index(face, *TempText);
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;
/* retrieve kerning distance */
if (use_kerning && previous && glyph_index)
{
FT_Vector delta;
FT_Get_Kerning(face, previous, glyph_index, 0, &delta);
TextWidth += delta.x;
}
TextWidth += glyph->advance.x;
previous = glyph_index;
TempText++;
}
previous = 0;
if (dc->w.textAlign & TA_RIGHT)
{
RealXStart -= TextWidth;
}
else
{
RealXStart -= TextWidth / 2;
}
}
TextLeft = RealXStart;
TextTop = YStart;
BackgroundLeft = (RealXStart + 32) >> 6;
/*
* The main rendering loop.
*/
for (i = 0; i < Count; i++)
{
glyph_index = FT_Get_Char_Index(face, *String);
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);
IntUnLockFreeType;
goto fail;
}
glyph = face->glyph;
/* 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;
}
if (glyph->format == ft_glyph_format_outline)
{
error = FT_Render_Glyph(glyph, RenderMode);
if (error)
{
DPRINT1("WARNING: Failed to render glyph!\n");
goto fail;
}
}
if (fuOptions & ETO_OPAQUE)
{
DestRect.left = BackgroundLeft;
DestRect.right = (TextLeft + glyph->advance.x + 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) + glyph->bitmap_left;
DestRect.right = DestRect.left + glyph->bitmap.width;
DestRect.top = TextTop + yoff - glyph->bitmap_top;
DestRect.bottom = DestRect.top + glyph->bitmap.rows;
bitSize.cx = glyph->bitmap.width;
bitSize.cy = glyph->bitmap.rows;
MaskRect.right = glyph->bitmap.width;
MaskRect.bottom = glyph->bitmap.rows;
/*
* 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.
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?