Lazarus

Programming => Widgetset => Cocoa => Topic started by: ChristianH on June 22, 2021, 09:22:33 pm

Title: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 22, 2021, 09:22:33 pm
Hi,

the font of the spktoolbar looks extremely blurry. Is there something what can be done when it comes to text rendering in third party classes? I saw that virtualtreeview has a couple of "hacks" in order to draw the output in the correct scaling.

Regards
Christian
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 23, 2021, 12:10:28 am
What is your OS?

In Windows blurry fonts are caused by incorrect compatibility settings. Right-click on the application with the blurry text, select "Properties" > "Compatibility" > "Change High DPI settings". This opens another window where no checkbox is checked on my system. It has also a link into the Windows Settings ("Enhanced scaling settings" (my translation)) where the option "Windows can try to fix blurred presentation" is checked.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: trev on June 23, 2021, 04:14:56 am
What is your OS?

As he's using the Cocoa widgetset, I'd guess macOS ;-)
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 23, 2021, 10:15:31 am
As he's using the Cocoa widgetset, I'd guess macOS ;-)
And it's even in the title... Reading every word would be a benefit for me...
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 23, 2021, 12:06:24 pm
Big Sur on an M1. I saw that in virtualtreeeview a bunch of tweaks has been done to get it working.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChrisR on June 23, 2021, 12:54:55 pm
All widgets will look blurry on MacOS retina displays unless the Info.plist describes the application as NSHighResolutionCapable. Lazarus will include this setting when you create a new application, but you may want to manually check your Info.plist for this key:value pair:

  <key>NSHighResolutionCapable</key>
  <true/>
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 23, 2021, 02:41:58 pm
Thanks, but this is not the case. The NSHighResolutionCapable property is in the plist.
VirtualTreeview uses CGContextScaleCTM while drawing nodes and headers. I will try to figure it out.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 23, 2021, 03:17:42 pm
I think I fixed the issue:

procedure TSpkToolbar.ValidateMetrics;
var
  i: integer;
  x: integer;
  TabWidth: integer;
  TabAppearance: TSpkToolbarAppearance;
  MenuButtonWidth: Integer;
  AdditionalPadding: Boolean;
  MenuButtonTextWidth: Integer;
begin
  if FInternalUpdating or FUpdating then
    exit;
  if FMetricsValid then
    exit;

  FBuffer.Free;
  FBuffer := TBitmap.Create;
  {$ifdef LCLCocoa}
   FBuffer.SetSize(round(GetCanvasScaleFactor*Width), round(GetCanvasScaleFactor*CalcToolbarHeight));
   CGContextScaleCTM(TCocoaBitmapContext(FBuffer.Canvas.Handle).CGContext, GetCanvasScaleFactor, GetCanvasScaleFactor);
  {$ELSE}

   FBuffer.SetSize(Width, CalcToolbarHeight);
  {$ENDIF} 

Christian
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 23, 2021, 05:05:11 pm
Thanks. Since your modification is inside an {$IFDEF LCLCocoa} directive it is not harmful for the other widgetsets and I will apply it although I cannot test it (I do not have a mac).

Nevertheless, I think this is only a workaround for a problem which must be deeper inside the canvas because SpkToolbar uses only standard canvas routines to draw the text (Canvas.TextOut) - therefore, text output should be correct for all platforms.

Maybe you can help to further narrow down the issue at least for a bugreport: Create a form and add the following OnPaint handler:
Code: Text  [Select][+][-]
  1. procedure TForm1.FormPaint(Sender: TObject);
  2. begin
  3.   Canvas.Font.Assign(Font);
  4.   Canvas.TextOut(10, 10, 'Hello world');
  5. end;  
When run at high-dpi, is this output blurred?

BTW, do you work with Laz trunk? There's a lot of activity with cocoa, and there is some chance that this issue already has been fixed.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 23, 2021, 05:42:21 pm
I assume this problem comes into action when you use a bitmap for buffering. I also had to fix the paint function like this:

{$IFDEF LCLCocoa}
  StretchBlt(canvas.handle,0,0,Width,Height,FBuffer.Canvas.Handle,0,0,
   FBuffer.Width, FBuffer.Height, SRCCOPY);
{$ELSE}
  canvas.draw(0, 0, FBuffer);
{$ENDIF}

and of course in the uses clause there has to be a:

uses
  {$ifdef LCLCocoa}
  CocoaGDIObjects, MacOSAll,
  {$endif}

Christian
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 23, 2021, 07:05:18 pm
I applied your patch, please test carefully - I could not test myself...
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: ChristianH on June 23, 2021, 09:44:01 pm
Many thanks,

since I use this in a real project which I am currently port to Mac I test this through its paces.

Oh there is one thing I probably did not copied properly:

 SetBounds(Left, Top, FBuffer.Width, FBuffer.Height);

Code: Pascal  [Select][+][-]
  1. procedure TSpkToolbar.ValidateMetrics;
  2. var
  3.   i: integer;
  4.   x: integer;
  5.   TabWidth: integer;
  6.   TabAppearance: TSpkToolbarAppearance;
  7.   MenuButtonWidth: Integer;
  8.   AdditionalPadding: Boolean;
  9.   MenuButtonTextWidth: Integer;
  10.  {$IFDEF LCLCocoa}
  11.   scalefactor: Double;
  12.  {$ENDIF}
  13. begin
  14.   if FInternalUpdating or FUpdating then
  15.     exit;
  16.   if FMetricsValid then
  17.     exit;
  18.  
  19.   FBuffer.Free;
  20.   FBuffer := TBitmap.Create;
  21.  {$IFDEF LCLCocoa}
  22.   scalefactor := GetCanvasScaleFactor;
  23.   FBuffer.SetSize(round(scaleFactor*Width), round(scaleFactor*CalcToolbarHeight));
  24.   CGContextScaleCTM(TCocoaBitmapContext(FBuffer.Canvas.Handle).CGContext, scaleFactor, scaleFactor);
  25.  {$ELSE}
  26.   FBuffer.SetSize(Width, CalcToolbarHeight);
  27.  {$ENDIF}
  28.   SetBounds(Left, Top, Width, CalcToolbarHeight);
The SetBounds should be like if there is no scaling.

Sorry, I forgot to post this line in the previous post.

Christian
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 23, 2021, 10:28:46 pm
This makes sense. You scale the buffer but paint the buffer on the unscaled canvas; therefore the bounds must have the unscaled size.

Fixed.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: skalogryz on June 24, 2021, 08:19:04 pm
I saw that virtualtreeview has a couple of "hacks" in order to draw the output in the correct scaling.
Not a hacks but the adaptation to the designed behavior (https://wiki.freepascal.org/Cocoa_DPI)

What is happening with VirtualTreeView is that the "backbuffer" drawn is "twice" (actually GetCanvasScaleFactor) as large as the "logical" size of the control.
When the backbuffer is drawn it would actually fill out every physical pixel of the screen and would not  be blurred.
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: wp on June 24, 2021, 09:48:46 pm
I saw that virtualtreeview has a couple of "hacks" in order to draw the output in the correct scaling.
Not a hacks but the adaptation to the designed behavior (https://wiki.freepascal.org/Cocoa_DPI)
Don't blame the OP: Your own word in r63695 commit message "VTV: adding mac Retina support hack.", and in the laz.virtualtrees unit
Code: Pascal  [Select][+][-]
  1. uses
  2.   {$ifdef LCLCocoa}
  3.   MacOSAll, // hack: low-level access to Cocoa drawins is going to be used
  4.             //       in order to support Cocoa HighDPI implementation
;)
Title: Re: Blurry Rendering of SPKToolbar under cocoa
Post by: skalogryz on June 24, 2021, 10:50:55 pm
Don't blame the OP: Your own word in r63695 commit message "VTV: adding mac Retina support hack.", and in the laz.virtualtrees unit
"hacks" could be voided. They're used for two things: 1) scale the image, 2) detect if the bitmap was changed and requires scaling).
And they're there only due to the internal structure of VirtualTree and me not being the primary maintainer of the component.

Yet the "adaptation" for the "designed behavior" remains.
So other control doesn't need to replicate those "hacks" exactly, they only need to follow the "designed behaviour".
TinyPortal © 2005-2018