Firemonkey ' s abstract Tcanvas class has been providing the dimensions of the bounding rectangle of some in itself. On recent updates it had deprecated providing text rectangle directly in the canvas with stead encouraged users to use Ttex Tlayout abstract class which handles several text-based operations on the native context of the platforms. So it's possible to get the bounding rectangle of a string in any canvas. Is this enough? Though I am sure this class would improve to involve many new textual features in current time it lacks some major needs o f A developer who designs text drawing applications.
When words in different sizes aligned from top can ' t get a proper sentence view
For the first time, I had faced a feature lack when I saw even TMS ' s HTML Text is unable to align words in an HTML Notat Ion that has got different sizes. Because have text rectangle is not enough to locate words in different sizes Because of the missing baseline information . If you align the words from the top the smaller word ' s baseline would be upper (as in the above image), if you align the bo Ttoms the baseline'll be lower, so-make a correct match you should know where is the baselines of each word exactly Located. So we need to know the Ascent value of the text. If the got the ascent value, we can easily align the words on the baseline as seen on following image. For a complete information on typography see this article on Wikipedia.
For a proper drawing of words in different sizes, should align them on their baselines.
As seen on the above image, have the information of the ascent values for each word we can align them properly on the Baseli NE of the sentence. However FMX Ttextlayout doesn ' t provide this information. So I decided to add a new function to my platformextensions unit to provide metrics information that is gathered from the Drawing of that specific font in a specific size. The new function is gettextmetrics and hast this following structure.
123 |
Class Procedure GetTextMetrics(Text:
String
; Font:TFont;
var TextRect:TRectF;
var Ascent,Descent:
Single
;
var CapHeight,XHeight:
Single
);virtual;abstract;
|
Getting Text Metrics in Windows
Firemonkey uses, different context types on Windows platform, is Windows Gdip and direct2d. The default one is Windows GDI plus context which are a set of device independent drawing API based on the old GDI. Because of its device independency Gdip lacks of some important drawing features such as XOR brush, but it's always Possi BLE to handle these extra operations by locking the context to device dependent HDC and doing things on the device bitmap. What I mean is; Getting font metrics is isn't as easy as it's old GDI based on HDC, so I used the limited information of the GDIP and Esti Mated some others like (x height of text) by using statistical multipliers. However someone other can collapse the context to HDC level and calculate more detailed font metrics on the. I didn ' t prefer it to is consistent with the design logic of Gdip, and used tgpfontfamily class of Gdip to get the Informa tion about the font. Note that the metrics values gathered from this class are in LOgical units so should is converted to pixels using the proportions.
Here is my calculations:
1234567891011 |
fSize := FGPFont
.
GetHeight(FGraphics);
cAscent := FGpFamily
.
GetCellAscent(FontStyle);
cDescent := FGpFamily
.
GetCellDescent(FontStyle);
emHeight := FGpFamily
.
GetEmHeight(FontStyle);
lSpacing := FGPFamily
.
GetLineSpacing(FontStyle);
iLeading := cAscent+cDescent - emHeight;
eLeading := lSpacing - cAscent-cDescent;
Ascent := fSize * (cAscent)/lSpacing;
Descent := fSize * (descent)/lSpacing;
CapHeight := fSize * (cAscent-iLeading)/lSpacing;
XHeight := fsize * (cAscent-iLeading) *(
7
/
10
) /lSpacing;
|
Note that the calculations use Tgpfont, tgpfontfamily and Tgpgraphics classes-deal with font metrics. The Fgpfont and Fgpgraphics objects is not accessible through standard class hierarchy, however we can use RTTI functions To access them.
123456789101112 |
RttiField := RttiContext
.
GetType(Layout
.
ClassType).GetField(
‘FGPFont‘
);
if assigned(RttiField)
then
begin
FGPFont := TGpFont(RttiField
.
GetValue(Layout).AsObject);
RttiField := RttiContext
.
GetType(Layout
.
ClassType).GetField(
‘FGraphics‘
);
FGraphics := TGpGraphics(RttiField
.
GetValue(Layout).AsObject);
FGPFamily := TGPFontFamily
.
Create;
FGPFont
.
GetFamily(FGPFamily);
// Get Metrics
// ...
end
;
|
Another point-to-be-mentioned here's, above calculations work only if the Defaultcanvas are a gdip canvas. If the developer selects to use the D2d canvas, because of the absence of the Fgpfont object in RTTI the text metrics would Not being updated. Since I don ' t has any experience on direct2d I haven ' t worked on it, but I'll be happy if someone does it and send me s O that I can put it in the class code by giving credits to his/her name.
Getting Text Metrics in Mac OS X
Things is always easier for programmers in Mac side. You can see below how it's easy getting font metrics using Coretext API of Cocoa.
123456 |
< Code class= "Delphi Plain" >lfontref: = Ctfontcreatewithname (Cfstr (Layout font family), Layout font size, nil ascent: = Ctfontgetascent (lfontref); descent: = Ctfontgetdescent (lfontref); capheight: = Ctfontgetcapheight (lfontref); xheight: = Ctfontgetxheight (lfontref); cfrelease (lfontref); |
You can see all the details of the with using Ttextlayout class and how to extend it to get Text/font Metrics in my Platformextensi ONS units. You can get the source code of the "Platformextensions classes with the" demo application from this SVN link. For Non-programmers the CompiledWin32, Win64, MacOSX (Thanks to Firemonkey) applications is also available to download.
https://delphiscience.wordpress.com/2013/01/06/getting-text-metrics-in-firemonkey/
Getting Text Metrics in Firemonkey (Delphiscience's blog)