New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 664066 link

Starred by 6 users

Issue metadata

Status: Available
Owner: ----
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Linux , Windows , Mac
Pri: 2
Type: Bug

Blocking:
issue 668579
issue 698661


Show other hotlists

Hotlists containing this issue:
style-dev-current


Sign in to add a comment

Change global cursor without recalculating style

Reported by insensi...@gmail.com, Nov 10 2016

Issue description

UserAgent: 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?
 
recalculate_cursor_style.png
26.1 KB View Download
Cc: kkaluri@chromium.org
Status: Untriaged (was: Unconfirmed)
Able to reproduce this issue on windows 10,Ubuntu 14.04 and Mac 10.12.1 using chrome stable M54-54.0.2840.87 
and earlier version of chrome M30-30.0.1549.0. This is a non-regression issue and marking it as untriaged.

Please look into the attached screencast.

Issue 664066.mp4
1.5 MB View Download

Comment 2 by ajha@chromium.org, Dec 7 2016

Labels: M-57 OS-Linux OS-Mac
Tagging with current canary milestone.
Components: Blink>Layout

Comment 4 by e...@chromium.org, Jan 17 2017

Components: -Blink>Layout Blink>Editing Blink>CSS
Status: Available (was: Untriaged)
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.
Labels: Performance
Cc: ktyliu@chromium.org
This sounds relevant to the style inheritance optimisation project that ktyliu is working on.

Comment 8 by ktyliu@chromium.org, 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

Comment 9 by sashab@chromium.org, Jan 18 2017

Cc: esprehn@chromium.org
+esprehn fyi
Cc: amoylan@chromium.org
Owner: ktyliu@chromium.org
ktyliu@ I think it's safe to say you're the owner of this for now. :-)
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.
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.


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.
Cc: meade@chromium.org sashab@chromium.org
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.
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?
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.
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.
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.

Comment 20 by yosin@chromium.org, Jan 23 2017

Components: -Blink>Editing Blink>Editing>Selection
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.

Comment 22 by yosin@chromium.org, Jan 23 2017

Blocking: 668579
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.



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?..
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
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.

Comment 26 by meade@chromium.org, Feb 13 2017

Labels: Update-Monthly
Owner: meade@chromium.org
Blocking: 698661
Owner: ----

Comment 30 by suzyh@chromium.org, Mar 27 2017

Cc: suzyh@chromium.org
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?

Comment 31 by meade@chromium.org, Mar 27 2017

Cc: yosin@chromium.org
Components: -Blink>Editing>Selection
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.
Cc: -sashab@chromium.org
 Issue 710825  has been merged into this issue.

Comment 34 by a...@scirra.com, 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.

Comment 35 by suzyh@chromium.org, Jun 13 2017

Cc: -suzyh@chromium.org
Labels: -Performance Performance-Responsiveness
Labels: Code-RecalcStyle

Comment 38 by meade@chromium.org, Oct 31 2017

Labels: HardBug
Labels: -Update-Monthly
Project Member

Comment 40 by sheriffbot@chromium.org, Dec 6

Labels: Hotlist-Recharge-Cold
Status: Untriaged (was: Available)
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
Status: Available (was: Untriaged)

Sign in to add a comment