Disclosure Statement: This site contains affiliate links, which means that I may receive a commission if you make a purchase using these links. As an eBay Partner, I earn from qualifying purchases.

Pinch zoom vs ZoomPct

Post Reply
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Pinch zoom vs ZoomPct

Post by petko »

I have a zoom combo box allowing users to change the zoom of the chromium component. Everything works OK there. However, if the user changes chromium zoom using touch (pinch), then the ZoomPct property of the component still shows the old (no longer correct value).

Do you think that this is an issue in CEF4Delphi, or is it something related to CEF or Chromium itself?
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Pinch zoom vs ZoomPct

Post by salvadordf »

Hi,

What you ask is a bit tricky but it can be done.

TChromium.ZoomPct is a CEF4Delphi property based on the TChromium.ZoomLevel property, which is a value returned from a CEF function.

If you need to keep your zoom combo box value updated then you need to intercept the windows messages for touch events (WM_TOUCH) and read the ZoomPct property.

If your browser uses the OSR mode then you only have to use the Delphi touch events but if you use a browser in normal mode then you have to intercept the WM_TOUCH messages by using TChromium.RenderHandle with SetWindowLongPtr.

The CEF code comments state that the ZoomLevel value can only be read in a CEF thread called "UI". That means that you would have do any of these things :
  • Read the ZoomPct value in the next TChromium event executed in the "UI" thread.
  • Create a custom class inheriting from TCefTaskOwn and call CefPostTask(TID_UI, myCustomTask). Then myCustomTask.execute will be executed in the "UI" thread and you can read ZoomPct. TChromium has 2 examples about this : TChromium.SavePreferences and TChromium.UpdatePreferences. Those examples have custom tasks that execute TChromium.doSavePreferences and TChromium.doUpdatePreferences in the UI thread.
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Re: Pinch zoom vs ZoomPct

Post by petko »

salvadordf wrote: Thu Oct 17, 2019 8:42 pm ...if you use a browser in normal mode then you have to intercept the WM_TOUCH messages by using TChromium.RenderHandle with SetWindowLongPtr.

The CEF code comments state that the ZoomLevel value can only be read in a CEF thread called "UI". That means that you would have do any of these things :
  • Read the ZoomPct value in the next TChromium event executed in the "UI" thread.
  • Create a custom class inheriting from TCefTaskOwn and call CefPostTask(TID_UI, myCustomTask). Then myCustomTask.execute will be executed in the "UI" thread and you can read ZoomPct. TChromium has 2 examples about this : TChromium.SavePreferences and TChromium.UpdatePreferences. Those examples have custom tasks that execute TChromium.doSavePreferences and TChromium.doUpdatePreferences in the UI thread.
I am not sure that I understand all of it correctly, but here is my take on it:
1. I need to intercept WM_TOUCH messages to know when a zoom was changed
2. Then I need to read the ZoomPct value while in the UI thread to know what the new zoom value is

I think that I understand 2) and how to create a task the read the value there, but I am not sure about 1). Is there the approach from 1) used anywhere in the CEF4Delphi code (or demo) that I can study?
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Pinch zoom vs ZoomPct

Post by salvadordf »

TChromium has a TChromium.OnRenderCompMsg event that can be used to intercept that message but it has a bug and it only work for the first page :
https://github.com/salvadordf/CEF4Delphi/issues/130

There are multiple code examples when you search this in Google :
delphi "SetWindowLongPtr" example
Other possible solution is to catch the zoom event in JavaScript and use a JavaScript extension to notify Delphi that it has to read the ZoomPct value :
https://stackoverflow.com/questions/995 ... javascript

Perhaps it's also possible to use a low level hook to intercept touch messages but I'm not sure. It seems to me that catching the zoom event in JavaScript is the easiest solution.
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Re: Pinch zoom vs ZoomPct

Post by petko »

Thanks, I've found out that the JS zoom detection from the SO link do not work on desktop browsers anymore, but I can intercept the event using a JS library called Hammer.js.

However, I have another and probably last question: should I read the TChromium ZoomPct or some other value? It seems that reading TChromium ZoomPct in my task executed on the UI thread still returns 100, even though the editor was pinch zoomed..
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Pinch zoom vs ZoomPct

Post by salvadordf »

Please, download CEF4Delphi again from GitHub.

I just added a few features you might use :
  • Added the GlobalCEFApp.TouchEvents property.
  • Added TChromium.ExecuteTaskOnCefThread function.
  • Added TChromium.OnExecuteTaskOnCefThread event.
  • Added a context menu option in the MiniBrowser demo to show the TChromium.ZoomPct value in the StatusBar using TChromium.ExecuteTaskOnCefThread and TChromium.OnExecuteTaskOnCefThread.
Calling the TChromium.ExecuteTaskOnCefThread function will trigger the TChromium.OnExecuteTaskOnCefThread event on the indicated CEF thread. It has these parameters :
  • aCefThreadId indicates the CEF thread on which TChromium.OnExecuteTaskOnCefThread will be executed.
  • aTaskID is a custom ID used to identify the task that triggered the TChromium.OnExecuteTaskOnCefThread event.
  • aDelayMs is an optional delay in milliseconds to trigger the TChromium.OnExecuteTaskOnCefThread event.
I don't have a touch screen and I can't test what happens when you pinch the document but I used the main menu option in the MiniBrowser demo to change the zoom and then I used the context menu option to show the ZoomPct value and it seemed correct.

Edit : The new context menu option is just a way to test the new ExecuteTaskOnCefThread function. The context menu events are already executed in the CEF UI thread and you could skip the ExecuteTaskOnCefThread call in this case.
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Re: Pinch zoom vs ZoomPct

Post by petko »

I've added your code to the Cef4Delphi version I use (72.xxx), but the problem persists. If the page was zoomed using pinch gesture, the OnExecuteTaskOnCefThread still reports wrong ZoomPct. I assume that this is a bug in CEF or Chromium in this case..

P.S.: I didn't test it with the latest version, because I use C++Builder and I have first to convert packages to C++Builder, etc and it takes too much time just for a test. If there is a compiled demo with the code however, I can test it on a HighDPI machine.
User avatar
salvadordf
Posts: 4016
Joined: Thu Feb 02, 2017 12:24 pm
Location: Spain
Contact:

Re: Pinch zoom vs ZoomPct

Post by salvadordf »

I just found this command line switch for Chromium :
--enable-use-zoom-for-dsf
The description for that switch is this :
Enable the mode that uses zooming to implement device scale factor behavior.
https://peter.sh/experiments/chromium-c ... -switches/

Perhaps Chromium changes the scale factor when you pinch the screen instead of setting a new zoom value, or perhaps there's a bug in the function that gives the current zoom level.
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Re: Pinch zoom vs ZoomPct

Post by petko »

I think that it is somehow related to this, because now I notice that if I use pinch zoom the editor looks different than when setting the zoom via code. In the second case content in the editor is resized responsively, while in the first it is just magnified.

P.S.: It seems that this flag is turned on by default now..
petko
Posts: 52
Joined: Sun Jul 02, 2017 9:58 am

Re: Pinch zoom vs ZoomPct

Post by petko »

I've just tested with Chromium and Chrome web browsers, pinch zoom there works differently like in CEF. I will ask in Chromium community what it works that way, because it seems wrong to me.

Thank you very much for the help!
Post Reply