Change global cursor without recalculating style
Reported by
insensi...@gmail.com,
Nov 10 2016
|
|||||||||||||||||||||||||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.87 Safari/537.36 Steps to reproduce the problem: 1. Go to https://jsfiddle.net/no3xo5we/ 2. Open Chrome Developer Tools and record timeline for 5-7 seconds 3. Look at the recorded timeline: you will see large 'Recalculate style' blocks (on my machine it takes 0,5 seconds to recalculate) What is the expected behavior? Timeline should be almost empty What went wrong? Chrome takes much amount of time to recalculate styles, but we *just* need to change mouse cursor on the page. Did this work before? N/A Does this work in other browsers? N/A Chrome version: 54.0.2840.87 Channel: stable OS Version: 10.0 Flash Version: Shockwave Flash 23.0 r0 We need an ability to simply change global mouse cursor based on some condition in a program. When page has large number of elements, cursor changing is very expensive and slow because it causes style recalculations for entire page. Speed/performance is very critical for our case. Maybe it makes sense to provide an ability to just set css property and prevent its inheritance to child elements to avoid style recalculations in such cases? Or is there another possibility to set global cursor like Mouse.cursor = '<value>' not using css?
,
Dec 7 2016
Tagging with current canary milestone.
,
Jan 16 2017
,
Jan 17 2017
,
Jan 17 2017
You can't prevent the inheritance from the parent. In this specific situation though, you could create a single div with a higher z-index which can overlay the whole page, and set the cursor on that. It's not without drawbacks though. I'll leave this open in case there is some performance issue in style recalc, but I Think it's the 100k elements in the example that are causing the 300ms recalcs.
,
Jan 17 2017
,
Jan 18 2017
This sounds relevant to the style inheritance optimisation project that ktyliu is working on.
,
Jan 18 2017
Yes https://bugs.chromium.org/p/chromium/issues/detail?id=622138 is the overall bug that aims to make inheritance faster. cursor is not a simple property to make independent though; https://docs.google.com/spreadsheets/d/1mUuJEs8cPWyNTR7tQw27oxq6fDTvWiAwgatf_g--B4w/edit#gid=0 shows the CSS properties that are simple, of which many (11) have been done https://chromium.googlesource.com/chromium/src/+/master/third_party/WebKit/LayoutTests/fast/css/invalidation/independent-inheritance-fast-path.html
,
Jan 18 2017
+esprehn fyi
,
Jan 19 2017
,
Jan 19 2017
ktyliu@ I think it's safe to say you're the owner of this for now. :-)
,
Jan 19 2017
Is there a reason to inherit the cursor at all? What if we change to dynamically computing the cursor by walking up the document tree instead whenever it's needed (which is rare), so then we never need to propagate the value downward.
,
Jan 19 2017
The cursor property is specified to be inherited in the spec. There's benefits of adhering to it in our internal implementation: https://developer.mozilla.org/en-US/docs/Web/CSS/cursor Performance-wise, I am not sure it's better if we implemented computing the cursor walking up the document tree. It may mean there's lag when user moves the cursor around the document.
,
Jan 19 2017
Right it's inherited, but we don't need to cache those values. Walking up the document from the node that's being hit tested shouldn't be expensive. We need to hit test as you move the mouse anyway.
,
Jan 19 2017
I am not sure the current style implementation supports lazy computation of properties up the tree. Adding Sasha and Eddy who might be able to chime in -- there may be potentials of doing bottom-up styles for certain css properties but that may be quite a lot of work.
,
Jan 19 2017
Looks like we already walk up the tree to find the cursor for taps when doing touch adjustment: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/web/WebViewImpl.cpp?rcl=0&l=1390 though not always, some code paths use the value directly. https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/input/EventHandler.cpp?rcl=1484842630&l=389 So we'd need to unify all those code paths into a single one that walks ancestors. Looking at this I think the path iterating parents in the layout tree in WebViewImpl is actually busted for top layer since your parent is the LayoutView instead of the ancestor you inherited your style from. It needs to use LayoutTreeBuilderTraversal::parent() for that. That situation is probably super rare since you'd need to put a link around a <dialog> so I suspect no one has noticed. I think the two projects here are: 1. See if we can make cursor independently inherited. This will make it faster, but still does a whole page worth of setStyle() and diffing which is going to take a while on 100k elements. 2. Switch to dynamically computing the cursor walking up the tree. This will make changing the cursor super fast since we don't need to recompute the style of anything in the document at all. #1 is probably easier so we can start there?
,
Jan 20 2017
Yup -- I endorse this plan :^). There's actually two projects in (1), which we can perf benchmark as we build them: 1) Make cursor independently inherited only when cursor is set to a single enum value. Do some tests on a bunch of sites to see the perf impact of doing this, since the cost is only a single bit, this is an easy win. 2) Make cursor independently inherited when cursors are set to complex values, such as lists. The memory cost of this might be large, but the benefits of not doing a style recalc are large too. Investigation needed for the tradeoff for this. 3) Switch to dynamically walking up the tree -- no memory cost, but possible performance cost if the cursor is defined very high up in a deep tree (and may be more expensive than a recalc). An alternative to this would be storing a pointer to the element in which the cursor is defined, so its a memory cost of one pointer but only a single jump is needed. We can also balance the space/speed by storing pointers at some elements but not others. I'd rather hold off on structurally changing ComputedStyle until its all generated, since it will be much easier to experiment with changes like this once we have the flexibility to do so. And we can test them for all properties. But (1) and (2) support the existing iteration structure so they should be OK to work on now.
,
Jan 20 2017
It's hard for me to believe that walking up the tree will be more expensive than propagating down the tree. Remember that even with independent inheritance you're still calling setStyle() which does a ton of work (50% of the recalcStyle costs in many cases). Also remember that the DOM is very shallow typically, maybe 32 nodes deep, but the entire DOM is thousands of nodes you're updating the style of, so O(32) should be much cheaper than O(1500) calling setStyle() even with the fast path.
,
Jan 23 2017
If we switch to walking up, wouldn't we have to do that for every mousemove? So it's fast, but unless we cache the cursor value (and we'd have to know when to invalidate it), the extra cost seems to add up pretty quickly. I'd expect changing the cursor to be pretty rare, but moving the mouse to be common. I'm sure I'm missing something about the suggested implementation.
,
Jan 23 2017
,
Jan 23 2017
We have to do a hit test on every mouse move to figure out what cursor to show. That's going to walk the entire document doing geometry operations and is much more expensive than walking up the tree comparing enum values. Trees also tend to be very shallow (typically 32 deep on normal content), so this should be cheap.
,
Jan 23 2017
Could you postpone cursor shape update after StyleClean or LayoutClean? Since EventHandler::selectAutoCursor() checks editability of mouse position to use I-beam cursor. I've tried http://crrev.co/2531003002, but some layout test failed. I think we don't need to calculate cursor shape of each mousemove. It is enough for update cursor shape on each V-sync frame.
,
Jan 24 2017
I am author of this issue and i would like to make some clarifications if you don't mind. First, when I opened this issue I understood that due to current DOM structure with style inheritance it would always take significant amount of time to recalculate styles to find actual cursor value to show. So my original question was: is it possible to provide some *programmatic* only method to take control over cursor like setting in javascript 'Mouse.cursor = hand' and not use any DOM style inheritance at all? This method could be extremely fast and can be useful in some cases. I understand that there are no such method described in W3C, but maybe it is possible to make a suggestion there?..
,
Jan 24 2017
Mouse cursor is supposed to change when moving over various elements (eg, hyperlink). Would Mike's suggestion in #5 work for you? That is, use an overlay div and just change the cursor on that
,
Jan 24 2017
Unfortunately overlay div will not work for out needs because we still need mouse events to go through it. If we set 'pointer-events: none' to this overlay div - we will get exactly the same behavior as currently have.
,
Feb 13 2017
,
Mar 5 2017
,
Mar 6 2017
,
Mar 8 2017
,
Mar 27 2017
meade: Can you clarify what the next step should be for this issue? Also, does responsibility for this issue lie with Blink>CSS or Blink>Editing>Selection?
,
Mar 27 2017
There's definitely things to do for Blink>CSS (see comments 16 and 17), but I can't confirm that there's nothing for Blink>Editing>Selection. yosin@ may be able to comment on that. For now I'll remove it.
,
Apr 18 2017
,
Apr 18 2017
Issue 710825 has been merged into this issue.
,
Apr 18 2017
This issue makes desktop PWAs laggy. It affects Construct 3 (https://editor.construct.net) - changing the cursor to do something like resize a pane causes a full document layout.
,
Jun 13 2017
,
Oct 5 2017
,
Oct 30 2017
,
Oct 31 2017
,
Dec 6 2017
,
Dec 6
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Dec 12
|
|||||||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||||||
Comment 1 by kkaluri@chromium.org
, Nov 14 2016Status: Untriaged (was: Unconfirmed)
1.5 MB
1.5 MB View Download