FireMonkey 源码学习(6)

摘要:
(6) GetGlyph和GetBaselineTFontGlyphManager是抽象类,在不同的平台上有不同的实现。以Windows为例,TWinFontGlyphManager=class(TFontGlyphManager)保护函数DoGetGlyph(constChar:UCS4Char;con

(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, 1, 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(0, 0, 0));
    SetBkColor(Bitmap.DC, RGB(255, 255, 255));

    {
       设置文字对齐方式
    }
    SetTextAlign(Bitmap.DC, TA_TOP);
    {
       将字符绘制在Bitmap的画布上
    }
    SelectObject(Bitmap.DC, FFont);
    TextOut(Bitmap.DC, -Trunc(Abc.abcfA), 0, @Char, 1);

    {
      找到最小的,不透明的位置
    }
    GlyphRect := TRect.Create(Bitmap.Width, CharSize.cy, 0, 0);
    for I := 0 to Bitmap.Width - 1 do
      for J := 0 to CharSize.cy - 1 do
      begin
        C := Bitmap.Bits[J * Bitmap.Width + I].R;
        if C > 0 then
        begin
          if J < GlyphRect.Top then
            GlyphRect.Top := J;
          if I < GlyphRect.Left then
            GlyphRect.Left := I;
        end;
      end;
    for I := Bitmap.Width - 1 downto GlyphRect.Left do
      for J := CharSize.cy - 1 downto GlyphRect.Top do
      begin
        C := Bitmap.Bits[J * Bitmap.Width + I].R;
        if C > 0 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 + 1);
    GlyphRect.Bottom := Max(CharSize.cy, GlyphRect.Bottom + 1);
  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 - 1 do
      for J := GlyphRect.Top to GlyphRect.Bottom - 1 do
      begin
        Color := Bitmap.Bits[J * Bitmap.Width + I];
        if Color.R < 255 then
        begin
          { Faster integer variant of formula:
            Result = R * 0.2126 + G * 0.7152 + B * 0.0722 }
          C := 255 - ((Integer(Color.R * 54) + Integer(Color.G * 183) + Integer(Color.B * 19)) div 256);
          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 := 1
  else
    dwItalic := 0;
  {
    Windows的API创建Font
  }
  FFont := CreateFont(Height, 0, 0, 0, dwBold, dwItalic,
    0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
    CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
    DEFAULT_PITCH or FF_DONTCARE, PChar(CurrentSettings.Family));
  if FFont = 0 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;

免责声明:文章转载自《FireMonkey 源码学习(6)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇dell笔记本耳机没有声音getpass不起作用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Spring5源码分析(020)——IoC篇之解析自定义标签

注:《Spring5源码分析》汇总可参考:Spring5源码分析(002)——博客汇总   默认标签的解析,前面已基本分析完毕。剩下的就是自定义标签的解析这一块: /** * Parse the elements at the root level in the document: * "import", "alias", "bean". * &l...

NDK+MSYS2+Android sdk编译opencv源码

由于今天太晚了,详细笔记有空再记。     要添加的有ANDROID_ABI,这个根据需求添加自己需要的ABI          然后是ANDROID_STL,因为gunstl已经不被支持,这里使用c++_shared或c++_static都可以。    然后是ANDROID_STL,因为gunstl已经不被支持,这里使用c++_shared或c++_st...

【源码分析】FastJson全局配置日期格式导致@JSONField(format = "yyyy-MM-dd")注解失效

出现的问题 我全局配置的时间格式是:yyyy-MM-dd HH:mm:ss @JSONField注解配置的时间格式是:yyyy-MM-dd 最终的返回结果是:yyyy-MM-dd HH:mm:ss 问题:为啥不是以注解定义的时间格式为主呢?先说答案,后面再分析: FastJson的全局配置日期格式会导致@JSONField注解失效 使用建议: 1.若全局配...

微信小程序 授权登录详解(附完整源码)

一、前言 由于微信官方修改了 getUserInfo 接口,所以现在无法实现一进入微信小程序就弹出授权窗口,只能通过 button 去触发。 官方连接:https://developers.weixin.qq.com/community/develop/doc/0000a26e1aca6012e896a517556c01 二、实现思路 自己写一个微信授权登...

关于map 容器insert顺序

  今天测试我的节点,maya一次次死掉,一点一点的打印测试,良久才知:我想当然的将插入map的顺序,作为我执行的顺序直接遍历,打印数据显示,map有自动将键值排序的功能,比如以字符串为例,会按照a、b、c....顺序排好。    而且对于map,如果一个元素key不存在,但是直接map[key],那么map的size就增加1,我感觉有点儿相当于inser...

最简单的7z API接口

7z官网提供的SDK下载地址:http://www.7-zip.org/sdk.html 我觉得还是有点复杂,就把里面的例子LzmaUtil改了改,并把不需要的其它源文件删掉了,现在,使用此源码生成的dll、lib,就可以通过以下的两个接口对文件进行压缩、解压缩了: MY_STDAPI LzmaCompress(char* pSrcFile, char*...