FireMonkey 源码学习(6)

时间:2021-07-30 12:23:19

(6)GetGlyph和GetBaseline

TFontGlyphManager是一个抽象类,在不同平台上的实现是不同的,以Windows为例,在FMX.FontGlyphs.Win.pas文件中定义了:

TWinFontGlyphManager = class(TFontGlyphManager)
...
protected
function DoGetGlyph(const Char: UCS4Char; const Settings: TFontGlyphSettings): TFontGlyph; override;
function DoGetBaseline: Single; override;
...

DoGetGlyph的实现代码如下:

function TWinFontGlyphManager.DoGetGlyph(const Char: UCS4Char; const Settings: TFontGlyphSettings): TFontGlyph;
var
CharsString: string;
Abc: TABCFLOAT;
CharSize: TSize;
GlyphRect: TRect;
I, J: Integer;
C: Byte;
Color: TAlphaColorRec;
GlyphStyle: TFontGlyphStyles;
Bitmap: TWinBitmap;
begin
{
获取字符在画布上的宽度和高度
}
CharsString := System.Char.ConvertFromUtf32(Char);
GetTextExtentPoint32W(FMeasureBitmap.DC, CharsString, , CharSize);
GetCharABCWidthsFloat(FMeasureBitmap.DC, Char, Char, Abc); {
采用Bitmap模式
}
if TFontGlyphSetting.Bitmap in Settings then
begin
{
构建Bitmap
}
Bitmap := CreateBitmap(Max(Ceil(Abs(Abc.abcfA) + Abs(Abc.abcfB) + Abs(Abc.abcfC)), CharSize.cx), CharSize.cy);
FillLongword(Bitmap.Bits, Bitmap.Width * Bitmap.Height, TAlphaColorRec.White); {
设置颜色
}
SetTextColor(Bitmap.DC, RGB(, , ));
SetBkColor(Bitmap.DC, RGB(, , )); {
设置文字对齐方式
}
SetTextAlign(Bitmap.DC, TA_TOP);
{
将字符绘制在Bitmap的画布上
}
SelectObject(Bitmap.DC, FFont);
TextOut(Bitmap.DC, -Trunc(Abc.abcfA), , @Char, ); {
找到最小的,不透明的位置
}
GlyphRect := TRect.Create(Bitmap.Width, CharSize.cy, , );
for I := to Bitmap.Width - do
for J := to CharSize.cy - do
begin
C := Bitmap.Bits[J * Bitmap.Width + I].R;
if C > then
begin
if J < GlyphRect.Top then
GlyphRect.Top := J;
if I < GlyphRect.Left then
GlyphRect.Left := I;
end;
end;
for I := Bitmap.Width - downto GlyphRect.Left do
for J := CharSize.cy - downto GlyphRect.Top do
begin
C := Bitmap.Bits[J * Bitmap.Width + I].R;
if C > then
begin
if J > GlyphRect.Bottom then
GlyphRect.Bottom := J;
if I > GlyphRect.Right then
GlyphRect.Right := I;
end;
end;
GlyphRect.Left := Min(CharSize.cx, GlyphRect.Left);
GlyphRect.Top := Min(CharSize.cy, GlyphRect.Top);
GlyphRect.Right := Max(CharSize.cx, GlyphRect.Right + );
GlyphRect.Bottom := Max(CharSize.cy, GlyphRect.Bottom + );
end; {
判断是否存在Glyph
}
GlyphStyle := [];
if not HasGlyph(Char) then
GlyphStyle := [TFontGlyphStyle.NoGlyph]; {
构建该字体下、该字符的Glyph
}
Result := TFontGlyph.Create(TPoint.Create(GlyphRect.Left + Trunc(Abc.abcfA), GlyphRect.Top),
Abc.abcfA + Abc.abcfB + Abc.abcfC, CharSize.Height, GlyphStyle); {
Bitmap模式下,将Glyph复制到Bitmap
}
if TFontGlyphSetting.Bitmap in Settings then
begin
Result.Bitmap.SetSize(Max(GlyphRect.Width, GlyphRect.Right), GlyphRect.Height, TPixelFormat.BGRA); for I := GlyphRect.Left to GlyphRect.Right - do
for J := GlyphRect.Top to GlyphRect.Bottom - do
begin
Color := Bitmap.Bits[J * Bitmap.Width + I];
if Color.R < then
begin
{ Faster integer variant of formula:
Result = R * 0.2126 + G * 0.7152 + B * 0.0722 }
C := - ((Integer(Color.R * ) + Integer(Color.G * ) + Integer(Color.B * )) div );
if TFontGlyphSetting.PremultipliedAlpha in Settings then
Result.Bitmap.Pixels[I - GlyphRect.Left, J - GlyphRect.Top] := MakeColor(C, C, C, C)
else
Result.Bitmap.Pixels[I - GlyphRect.Left, J - GlyphRect.Top] := MakeColor($FF, $FF, $FF, C);
end;
end;
DestroyBitmap(Bitmap);
end;
end;

DoGetBaseline的实现代码直接返回了FBaseline的值,FBaseline是在载入资源时生成,其核心函数为LoadResource,代码分析如下:

procedure TWinFontGlyphManager.LoadResource;
var
Height: Integer;
dwBold, dwItalic: Cardinal;
Metrics: TTextMetric;
begin
{
字体高度、Style属性等
}
Height := -Round(CurrentSettings.Size * CurrentSettings.Scale);
if TFontStyle.fsBold in CurrentSettings.Style then
dwBold := FW_BOLD
else
dwBold := FW_NORMAL;
if TFontStyle.fsItalic in CurrentSettings.Style then
dwItalic :=
else
dwItalic := ;
{
Windows的API创建Font
}
FFont := CreateFont(Height, , , , dwBold, dwItalic,
, , DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH or FF_DONTCARE, PChar(CurrentSettings.Family));
if FFont = then
Exit;
SelectObject(FMeasureBitmap.DC, FFont);
{
获取画布的字体各种信息,其中Metrics的定义如下:
tagTEXTMETRICW = record
tmHeight: Longint;
tmAscent: Longint; //Specifies the ascent (units above the base line) of characters.
tmDescent: Longint;
tmInternalLeading: Longint;
tmExternalLeading: Longint;
tmAveCharWidth: Longint;
tmMaxCharWidth: Longint;
tmWeight: Longint;
tmOverhang: Longint;
tmDigitizedAspectX: Longint;
tmDigitizedAspectY: Longint;
tmFirstChar: WideChar;
tmLastChar: WideChar;
tmDefaultChar: WideChar;
tmBreakChar: WideChar;
tmItalic: Byte;
tmUnderlined: Byte;
tmStruckOut: Byte;
tmPitchAndFamily: Byte;
tmCharSet: Byte;
end;
}
GetTextMetrics(FMeasureBitmap.DC, Metrics);
FBaseline := Metrics.tmAscent;
end;