Recent

Author Topic: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow  (Read 10577 times)

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2763
    • havefunsoft.com
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #15 on: February 18, 2022, 02:48:40 am »
I'm observing some differences in text drawing before and after the patch.

It does appear that the text is drawn a pixel lower than before and the bottom part is cutoff.

This might be due to a differences in the text measurement as the screen shot is made based on SynEdit component.
update
that seems to do the trick... but it doesn't feel to be the proper fix.
Code: Diff  [Select][+][-]
  1. Index: lcl/interfaces/cocoa/cocoagdiobjects.pas
  2. ===================================================================
  3. --- lcl/interfaces/cocoa/cocoagdiobjects.pas    (revision 67313)
  4. +++ lcl/interfaces/cocoa/cocoagdiobjects.pas    (working copy)
  5. @@ -1934,7 +1934,7 @@
  6.  
  7.            CGContextTranslateCTM(cg, 0, FSize.Height);
  8.            CGContextScaleCTM(cg, 1, -1);
  9. -          YPrime := FSize.Height - y - Font.Font.ascender;
  10. +          YPrime := FSize.Height - y - Font.Font.ascender+1;
  11.            CGContextSetTextPosition(cg, x, YPrime);
  12.  
  13.            if CharsDelta = nil then
« Last Edit: February 18, 2022, 03:08:51 am by skalogryz »

Zoë

  • New Member
  • *
  • Posts: 24
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #16 on: February 18, 2022, 03:06:16 am »
What font and size are you using?

There is some difference between CoreText and the higher level APIs, which is discussed here: https://stackoverflow.com/questions/5511830/how-does-line-spacing-work-in-core-text-and-why-is-it-different-from-nslayoutm

David’s second patch solved the issue of clipped text for us, and most fonts look correct, but we did see a few that were drawing at the top of the rect and we couldn’t figure out a fix. I haven’t seen any that were too low though. It seems to be an issue with specific font constructions (e.g., no external leading).

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2763
    • havefunsoft.com
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #17 on: February 18, 2022, 03:11:34 am »
What font and size are you using?
the default preselected on TSynEdit.

on Monterey it's reported as "Andale Mono", Height 10

It seems to be an issue with specific font constructions (e.g., no external leading).
I'd think that the vertical placement is off. (as shown in the patch above).
(on the screenshot, the post-patched lines are drawn one pixel lower, than before the patch)

As always - Cocoa necessity to flip Y coordinates back and worth doesn't help.

There is some difference between CoreText and the higher level APIs, which is discussed here: https://stackoverflow.com/questions/5511830/how-does-line-spacing-work-in-core-text-and-why-is-it-different-from-nslayoutm
I don't believe the line spacing is involved in here.
SynEdit draws the text per line and does it's own line spacing (not related to the font line spacing at all)
« Last Edit: February 18, 2022, 03:17:13 am by skalogryz »

davidfjenkins

  • New member
  • *
  • Posts: 7
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #18 on: February 18, 2022, 10:08:03 pm »
Dmitry,

What are you using to generate the screen shot with the lower part of the y cut off?  I know it is synedit related but in what format?

I've tried building trunk laz-ide and I am not seeing the descent values of text getting cut off like in your screen shot.

I would like to test out some thoughts about rounding error but need to be able to repeat the problem

Thanks
David

davidfjenkins

  • New member
  • *
  • Posts: 7
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #19 on: February 19, 2022, 12:48:19 am »
I think the change that is actually making the difference might be the changes to TCocoaContext.GetTextExtentPoint().

The original code, before any of our cocoagdiobjects.pas patches were applied created an NSMutableAttributedString, set the current font and then used:

r :=M.boundingRectWithSize_options(NSMakeSize(Maxint, Maxint), 0);
height := ROund(r.size.height).

New code uses CTLineGetTypographicBounds() and then

height := Round(ascent + abs(descent) + lead);

I put the boundingRectwithsize() code back in and checked the two different results before they were rounded. 

For one font I got
original code: height = 17.0 , new code: height = 15.31

for another font:
original code: height = 16.0 , new code: height = 14.13

and
original code: height = 14.0 , new code: height = 12.96.

This is important, I believe, because SynEdit spaces its text lines by
FTextHeight := CharHeight + FCurrentExtraLineSpace.  Where CharHeight initial calculation is based on calling GetTextExtentPoint.

I could not repeat the clipping you were seeing when I compiled Laz IDE at first.  But if I went into preferences and changed Current Extra Line Space and made it smaller then I did get clipping.  You can probably make your clipping go away by increasing Current Extra Line Space.

You could also test this by removing the +1 in .TextOUt and instead doing a +1 on the height returned in GetTextExtentPoint().

That's my theory.  This issue is that I spent particular time trying to get GetTextExtentPoint() correct.  This is the second patch I sent in.  The initial patch had replaced the NSMutableAttributedString call and was using CTLineGetBoundswithOptions() instead.  I looked the height value returned for CTLineGetBOundsWithOptions() and noticed that it was larger than ascent+descent+lead.  I haven't checked this but is probably pretty close to what the NSMutableAttributedString.boundRectWithSize.

I wasn't sure which of the values was correct.  The one that matched ascent+descent+lead (which is what GetTextMetrics returns) or the larger values from the two functions that returned bounds. 

So I went and looked at what windows GetTextExtentPoint returns.  It appears to me that GetTextExtentPoint() on windows returns ascent+descent+lead.  And the GetTextMetrics on windows also returns that same value for Tm.height.

So my last patch made GetTextExtentPoint() return a height that matches what I saw Windows doing.  That value IS smaller than previous code and could well be what is causing the difference you are seeing.

If ascent+descent+lead is not the correct value for GetTextExtentPoint() to return for height and if that is what is causing the SynEdit clipping you are seeing then I suggest reverting my last patch on cocoagdiobjects.pas and seeing if that fixes the problem.





skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2763
    • havefunsoft.com
Re: [Solved] Demo to benchmark TextOut on win64/gtk2/Cocoa - Cocoa is very slow
« Reply #20 on: February 19, 2022, 03:51:24 am »
What are you using to generate the screen shot with the lower part of the y cut off?  I know it is synedit related but in what format?
a plain project with TSynEdit on it and a bunch of lines "SynEdit" set.
nothing special really.
The TSynEdits font is not modified.

davidfjenkins

  • New member
  • *
  • Posts: 7
I was able to repeat the clipping by setting up the simple SynEdit app.  At first it only repeated if I compiled on macos 10.14 and not my 11.6 machine.  But then we noticed that the default font size for TSynEdit was different between the two

10.14 Font.Height = $0000000A
11.6 Font.Height = -13

When I change to font.height = 10, I was able to repeat the clipping.

I have submitted a new patch in bug report 39660.  The specific issue the patch fixes that caused the clipping is described in the report.  Summary is that I needed to make sure that whereever ascent and/or descent values are used, they are converted from float->integer in the same fashion.

I looked at GetTextMetrics on Windows to see how the conversion ws done there.  It is always Round(ascent) and Round(descent).  cocoagdiobjects.pas now emulates that behavior and is consistent across the three functions GetTextMetrics, GetTextExtentPoint, and TextOut

Zoë

  • New Member
  • *
  • Posts: 24
Some additional info related to line layout that we ran into that David's patch doesn't touch on:

There are fonts installed on macOS by default that draw flush to the top of the rect with excessive empty space at the bottom (e.g., DIN Condensed).  Using those same fonts on Windows draws them in the middle of the rect with space both above and below the text like you'd expect.  This is not a bug in LCL.  It turns out the TTF font files actually have two different headers that store the ascent/descent/leading values, and they aren't guaranteed to be in sync.  Windows reads one and macOS uses the other.  Using TextEdit with those same fonts shows the same behavior.
« Last Edit: March 03, 2022, 12:48:57 pm by Zoë »

davidfjenkins

  • New member
  • *
  • Posts: 7
The two headers are HHEA - Horizontal Table Header

  https://docs.microsoft.com/en-us/typography/opentype/spec/hhea

and OS/2 Windows Metrics Table. 

  https://docs.microsoft.com/en-us/typography/opentype/spec/os2

The HHEA has one set of ascent/descent/lead values. that are described as typographic values and are Apple specific (see the msdn documentation above).

ascender
descender
LineGap

The OS/2 windows tables has two sets of values:

sTypoAscender
sTypoDescender
sTypoLineGap

usWinAscent
usWinDescent

I have looked at ttf files that have different values for all three sets though the hhea values and teh sTypo values can be the same.  There is a flag USE_TYPO_METRICS that indicates to use sTypo values instead of usWin values. 

But as Zoe points out, the important point is that the same font file can easily result in different vertical placement of text between Windows and Cocoa.

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1998
  • Former Delphi 1-7, 10.2 user
Quote
Dependencies

A number of fields in the 'OS/2' table replicate data found elsewhere in the font; most notably, the various ascent and descent fields mirror some of the contents of the horizontal header table. The macOS derives ascent and descent information from the latter; Windows from the former.

Fonts intended to be used on both platforms must have consistent values for the font's ascent and descent in these two tables.

Source: https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6OS2.html

So perhaps some fonts are not intended to be used on macOS but only Windows etc.
Lazarus 2.3, FPC 3.3.1 macOS 12.3.1 x86_64 Xcode 13.4
Lazarus 2.3, FPC 3.3.1 macOS 12.3.1 aarch64 Xcode 13.4

 

TinyPortal © 2005-2018