Bug 115734 - Changing the selection pseudo style does not trigger a selection repaint
Summary: Changing the selection pseudo style does not trigger a selection repaint
Status: RESOLVED WORKSFORME
Alias: None
Product: WebKit
Classification: Unclassified
Component: Text (show other bugs)
Version: 528+ (Nightly build)
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Sergio Villar Senin
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2013-05-07 10:17 PDT by Sergio Villar Senin
Modified: 2020-01-13 03:57 PST (History)
14 users (show)

See Also:


Attachments
Patch (4.48 KB, patch)
2013-05-07 10:29 PDT, Sergio Villar Senin
no flags Details | Formatted Diff | Diff
Patch (4.44 KB, patch)
2013-05-21 11:25 PDT, Sergio Villar Senin
hyatt: review-
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Sergio Villar Senin 2013-05-07 10:17:15 PDT
Let's suppose that we have some CSS rules like:

h1.red::selection {
  background: red;
}
h1.green::selection {
  background: green;
}

and this HTML code in the body:

<h1 id="header" class="red">Hello World</h1>

a JavaScript code doing something this:

document.getElementById("header").className = green;

won't trigger a selection repaint (and it should) because we're only changing a pseudo style.
Comment 1 Sergio Villar Senin 2013-05-07 10:29:29 PDT
Created attachment 200925 [details]
Patch
Comment 2 Ryosuke Niwa 2013-05-07 10:34:54 PDT
Comment on attachment 200925 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=200925&action=review

> Source/WebCore/rendering/RenderText.cpp:222
> +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))

Is it expected that diff is StyleDifferenceEqual in this case?
Comment 3 Sergio Villar Senin 2013-05-07 11:58:49 PDT
(In reply to comment #2)
> (From update of attachment 200925 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=200925&action=review
> 
> > Source/WebCore/rendering/RenderText.cpp:222
> > +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))
> 
> Is it expected that diff is StyleDifferenceEqual in this case?

At least is what I got from my testing, but I can double check if that's in the spec.
Comment 4 Benjamin Poulain 2013-05-07 20:54:33 PDT
Comment on attachment 200925 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=200925&action=review

No idea about correctness, but I think there are enough issues with the test to have a second round:

> LayoutTests/ChangeLog:13
> +        * fast/backgrounds/selection-change-style-expected.html: Added.
> +        * fast/backgrounds/selection-change-style.html: Added.

Why is the test here and not in fast/repaint?

> LayoutTests/fast/backgrounds/selection-change-style-expected.html:4
> +<!--
> +This test checks that changing the selection style triggers a selection redraw.
> +-->

In the expectations?

> LayoutTests/fast/backgrounds/selection-change-style.html:4
> +<!--
> +This test checks that changing the selection style triggers a selection redraw.
> +-->

Since this test can be run manually, it would be better to have the text in the test + an explanation of the expected results for someone trying the test in their browser.

> LayoutTests/fast/backgrounds/selection-change-style.html:26
> +        setTimeout(function() {redDiv.className = "green";testRunner.notifyDone();}, 100);

Shouldn't this be using runRepaintTest?
Otherwise you will slow down testing quite a bit.
Comment 5 Sergio Villar Senin 2013-05-08 02:09:04 PDT
(In reply to comment #4)
> (From update of attachment 200925 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=200925&action=review
> 
> No idea about correctness, but I think there are enough issues with the test to have a second round:
> 
> > LayoutTests/ChangeLog:13
> > +        * fast/backgrounds/selection-change-style-expected.html: Added.
> > +        * fast/backgrounds/selection-change-style.html: Added.
> 
> Why is the test here and not in fast/repaint?

Just because there was already a similar test there, I don't mind moving it.

> > LayoutTests/fast/backgrounds/selection-change-style.html:4
> > +<!--
> > +This test checks that changing the selection style triggers a selection redraw.
> > +-->
> 
> Since this test can be run manually, it would be better to have the text in the test + an explanation of the expected results for someone trying the test in their browser.

OK, I'll move it into a <p>. Regarding the explanation of results I guess the <div> contents are pretty much what you ask for.
 
> > LayoutTests/fast/backgrounds/selection-change-style.html:26
> > +        setTimeout(function() {redDiv.className = "green";testRunner.notifyDone();}, 100);
> 
> Shouldn't this be using runRepaintTest?
> Otherwise you will slow down testing quite a bit.

I tried with runRepaintTest() but it looks like running it in onload it's "too early". The bug only appears after finishing all pending rendering operations because if for some reason the text is rendered again then the selection will be properly repainted as well. I used the timeout to try to isolate the selection class change as much as possible. There are other tests using a similar approach.
Comment 6 Sergio Villar Senin 2013-05-21 11:25:03 PDT
Created attachment 202453 [details]
Patch
Comment 7 Sergio Villar Senin 2013-05-21 11:29:38 PDT
So after checking how the differences in style are evaluated I can conclude that indeed StyleDifferenceEqual is expected as the function that compares changes between style changes do not take into account the selection. I don't think we should change that because it'll trigger some style recomputing that is not really needed.

And regarding using runRepaintTest is not really possible because that forces a style recalc, something that we want to avoid in the test (we want to check that just changing the style of the selection triggers a repaint of the selection).
Comment 8 Simon Fraser (smfr) 2013-05-21 22:45:13 PDT
Comment on attachment 202453 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=202453&action=review

> Source/WebCore/rendering/RenderText.cpp:222
> +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))
> +        view()->repaintSelection();

What if there was another style change that happened at the same time as the ::selection style change?
Comment 9 Sergio Villar Senin 2013-05-22 02:41:27 PDT
(In reply to comment #8)
> (From update of attachment 202453 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=202453&action=review
> 
> > Source/WebCore/rendering/RenderText.cpp:222
> > +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))
> > +        view()->repaintSelection();
> 
> What if there was another style change that happened at the same time as the ::selection style change?

That's a good question, and it's the reason why I was so restrictive in the conditions. If any other style change happens then the element whose style has changed will trigger a style recalc. That style recalc will end up calling the paint() method of the ChromeClient which will force a repaint of the text and the selection. That's why this change is only needed in the special case that only the style of the selection is changed.
Comment 10 Simon Fraser (smfr) 2013-05-22 08:00:52 PDT
(In reply to comment #9)
> (In reply to comment #8)
> > (From update of attachment 202453 [details] [details])
> > View in context: https://bugs.webkit.org/attachment.cgi?id=202453&action=review
> > 
> > > Source/WebCore/rendering/RenderText.cpp:222
> > > +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))
> > > +        view()->repaintSelection();
> > 
> > What if there was another style change that happened at the same time as the ::selection style change?
> 
> That's a good question, and it's the reason why I was so restrictive in the conditions. If any other style change happens then the element whose style has changed will trigger a style recalc. That style recalc will end up calling the paint() method of the ChromeClient which will force a repaint of the text and the selection. That's why this change is only needed in the special case that only the style of the selection is changed.

But repainting the selection is a different thing than repainting renderers. The selection can cover gaps between renderers, which will need to be repainted even if elements themselves repaint.

I'd expect to see problems with selection repaint when, say, 'color' also changes.
Comment 11 Sergio Villar Senin 2013-05-22 08:13:33 PDT
(In reply to comment #10)
> (In reply to comment #9)
> > (In reply to comment #8)
> > > (From update of attachment 202453 [details] [details] [details])
> > > View in context: https://bugs.webkit.org/attachment.cgi?id=202453&action=review
> > > 
> > > > Source/WebCore/rendering/RenderText.cpp:222
> > > > +    if (diff == StyleDifferenceEqual && hasSelectedChildren() && (newStyle->hasPseudoStyle(SELECTION) || oldStyle->hasPseudoStyle(SELECTION)))
> > > > +        view()->repaintSelection();
> > > 
> > > What if there was another style change that happened at the same time as the ::selection style change?
> > 
> > That's a good question, and it's the reason why I was so restrictive in the conditions. If any other style change happens then the element whose style has changed will trigger a style recalc. That style recalc will end up calling the paint() method of the ChromeClient which will force a repaint of the text and the selection. That's why this change is only needed in the special case that only the style of the selection is changed.
> 
> But repainting the selection is a different thing than repainting renderers. The selection can cover gaps between renderers, which will need to be repainted even if elements themselves repaint.

I must be missing something because this potential problem that you mention should happen even without the patch, shouldn't it?

Just to ensure that we're on the same page, this patch only repaints selection when the selection style changes _and_ that's the only style change happening. For any other case the current behavior remains the same.
Comment 12 Dave Hyatt 2013-08-14 13:03:55 PDT
Comment on attachment 202453 [details]
Patch

RenderText is the wrong place to put this. You might have nothing but a selected image and no selected text. You need to do this in RenderObject. Let's see a new patch that handles images as well as text.
Comment 13 Sergio Villar Senin 2020-01-13 03:57:22 PST
This is working as expected now