Bug 84989

Summary: [Qt] Gesture tap highlighter needs to take overflow clip into account.
Product: WebKit Reporter: zalan <zalan>
Component: Layout and RenderingAssignee: zalan <zalan>
Status: RESOLVED FIXED    
Severity: Normal CC: dglazkov, kenneth, tonikitoo, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Attachments:
Description Flags
Patch
none
Archive of layout-test-results from ec2-cr-linux-03
none
Patch
none
Patch
none
Patch none

Description zalan 2012-04-26 12:32:36 PDT
Focus ring includes clipped content when overflow::hidden is present.


<html>
<head>
<style type="text/css">
div.hidden 
{
width:100px;
height:100px;
overflow:hidden;
}
</style>
</head><body><div class="hidden"><a href="#">Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</a></div></body></html>
Comment 1 zalan 2012-04-26 13:03:57 PDT
Created attachment 139051 [details]
Patch
Comment 2 Kenneth Rohde Christiansen 2012-04-26 17:09:58 PDT
Comment on attachment 139051 [details]
Patch

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

> Source/WebCore/page/GestureTapHighlighter.cpp:61
> +AffineTransform localToAbsoluteTransformWithApplyingOverflowClip(RenderObject* o, Vector<LayoutRect>& drawableRects)

Would be nice to split this up into two methods :/ don't see an easy way though. The method name is also quite confusing. It return ths transform and modifies the drawableRects.
Comment 3 zalan 2012-04-26 22:23:41 PDT
(In reply to comment #2)
> (From update of attachment 139051 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=139051&action=review
> 
> > Source/WebCore/page/GestureTapHighlighter.cpp:61
> > +AffineTransform localToAbsoluteTransformWithApplyingOverflowClip(RenderObject* o, Vector<LayoutRect>& drawableRects)
> 
> Would be nice to split this up into two methods :/ don't see an easy way though. The method name is also quite confusing. It return ths transform and modifies the drawableRects.

Yes, I had hard time coming up with a name as it really does 2 different tasks. Splitting up is not really optimal as we need to traverse the tree again. The other option would be to not to have this function at all.
Comment 4 WebKit Review Bot 2012-04-26 22:40:06 PDT
Comment on attachment 139051 [details]
Patch

Attachment 139051 [details] did not pass chromium-ews (chromium-xvfb):
Output: http://queues.webkit.org/results/12557108

New failing tests:
fast/images/gif-large-checkerboard.html
Comment 5 WebKit Review Bot 2012-04-26 22:40:12 PDT
Created attachment 139134 [details]
Archive of layout-test-results from ec2-cr-linux-03

The attached test failures were seen while running run-webkit-tests on the chromium-ews.
Bot: ec2-cr-linux-03  Port: <class 'webkitpy.common.config.ports.ChromiumXVFBPort'>  Platform: Linux-2.6.35-28-virtual-x86_64-with-Ubuntu-10.10-maverick
Comment 6 zalan 2012-05-15 12:52:03 PDT
Created attachment 142035 [details]
Patch
Comment 7 Kenneth Rohde Christiansen 2012-05-15 13:11:41 PDT
Comment on attachment 142035 [details]
Patch

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

> Source/WebCore/page/GestureTapHighlighter.cpp:188
> +    // ensure rounded highlight rects. This clipping has the problem with nested
> +    // divs with transforms, which could be resolved by proper Path::intersecting.

Any test plus bug report for that case?
Comment 8 Antonio Gomes 2012-05-15 13:47:18 PDT
Comment on attachment 142035 [details]
Patch

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

> Source/WebCore/page/GestureTapHighlighter.cpp:214
> +        while (object) {
> +            RenderBox* container = toRenderBox(object->container());
> +            if (!container)
> +                break;
> +
> +            LayoutSize ringLocationOffset = object->offsetFromContainer(container, ringRect.location());
> +
> +            // Move focus ring rect to container coordinates to be able to intersect.
> +            ringRect.move(ringLocationOffset);
> +            if (container->hasOverflowClip()) {
> +                ringRect.intersect(container->borderBoxRect());
> +
> +                if (ringRect.isEmpty())
> +                    break;
> +            }
> +            object = container;
> +        }
> +
> +        if (ringRect.isEmpty())
> +            drawableRects.remove(i);
> +        else {

is not it faster to go renderlayer by renderlayer instead of container by container?
Comment 9 zalan 2012-05-16 10:36:09 PDT
(In reply to comment #7)
> (From update of attachment 142035 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=142035&action=review
> 
> > Source/WebCore/page/GestureTapHighlighter.cpp:188
> > +    // ensure rounded highlight rects. This clipping has the problem with nested
> > +    // divs with transforms, which could be resolved by proper Path::intersecting.
> 
> Any test plus bug report for that case?
[Qt] Gesture tap highlighter should take parent iframe's transform into account.
bug#86645

[Qt] Gesture tap highlighter needs to take frame clipping into account.
bug#86646

[Qt] Gesture tap highlighter's overflow clip is not always correct when nested enclosing containers have transforms.
bug#86641
Comment 10 zalan 2012-05-16 10:38:16 PDT
(In reply to comment #8)
> (From update of attachment 142035 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=142035&action=review
> 
> > Source/WebCore/page/GestureTapHighlighter.cpp:214
> > +        while (object) {
> > +            RenderBox* container = toRenderBox(object->container());
> > +            if (!container)
> > +                break;
> > +
> > +            LayoutSize ringLocationOffset = object->offsetFromContainer(container, ringRect.location());
> > +
> > +            // Move focus ring rect to container coordinates to be able to intersect.
> > +            ringRect.move(ringLocationOffset);
> > +            if (container->hasOverflowClip()) {
> > +                ringRect.intersect(container->borderBoxRect());
> > +
> > +                if (ringRect.isEmpty())
> > +                    break;
> > +            }
> > +            object = container;
> > +        }
> > +
> > +        if (ringRect.isEmpty())
> > +            drawableRects.remove(i);
> > +        else {
> 
> is not it faster to go renderlayer by renderlayer instead of container by container?
Yes, most of the cases it is indeed faster and since overflow clip requires RenderLayer, it is safe to go from layer to parent layer, instead of container to container. Thanks.
Comment 11 zalan 2012-05-16 10:39:31 PDT
Created attachment 142295 [details]
Patch
Comment 12 Kenneth Rohde Christiansen 2012-05-16 13:12:25 PDT
Comment on attachment 142295 [details]
Patch

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

> Source/WebCore/page/GestureTapHighlighter.cpp:193
> +        LayoutPoint ringRectLocation = ringRect.location();

I find this a bit confusing. What about localLocation ?

> Source/WebCore/page/GestureTapHighlighter.cpp:205
> +            LayoutSize ringLocationOffset = current->offsetFromContainer(layerRenderer, ringRect.location());
> +            ringRect.move(ringLocationOffset);

Why not just merge those two, it is not that the variable name is that good

> Source/WebCore/page/GestureTapHighlighter.cpp:212
> +                if (ringRect.isEmpty())
> +                    break;

I like if (ringRect.isEmpty()) { remove(i); break; } more

> Source/WebCore/page/GestureTapHighlighter.cpp:220
> +        if (ringRect.isEmpty())
> +            drawableRects.remove(i);

then here you would just do a 'continue'.

> Source/WebCore/page/GestureTapHighlighter.cpp:221
> +        else {

I would do that in any case and remove this else clause

> Source/WebCore/page/GestureTapHighlighter.cpp:223
> +            // Move ring rect back to its original position, so that
> +            // parents' tranforms can be applied properly later.

// After clipping, reset the original position so that parents' transforms apply correctly.
Comment 13 Antonio Gomes 2012-05-16 21:52:50 PDT
Comment on attachment 142295 [details]
Patch

It looks good to me, but fix Kenneth's remarks before landing.

I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )
Comment 14 Kenneth Rohde Christiansen 2012-05-17 05:10:11 PDT
(In reply to comment #13)
> (From update of attachment 142295 [details])
> It looks good to me, but fix Kenneth's remarks before landing.
> 
> I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )

Yeah that would be great! We would also like Chrome on board.
Comment 15 Antonio Gomes 2012-05-17 05:41:10 PDT
(In reply to comment #14)
> (In reply to comment #13)
> > (From update of attachment 142295 [details] [details])
> > It looks good to me, but fix Kenneth's remarks before landing.
> > 
> > I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )
> 
> Yeah that would be great! We would also like Chrome on board.

btw, would clipping logic is simpler:

we clip against any scrollable box, and clip against the already clipped parent viewport frame view :)
Comment 16 Antonio Gomes 2012-05-17 05:41:44 PDT
(In reply to comment #15)
> (In reply to comment #14)
> > (In reply to comment #13)
> > > (From update of attachment 142295 [details] [details] [details])
> > > It looks good to me, but fix Kenneth's remarks before landing.
> > > 
> > > I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )
> > 
> > Yeah that would be great! We would also like Chrome on board.
> 
> btw, would clipping logic is simpler:
> 
> we clip against any scrollable box, and clip against the already clipped parent viewport frame view :)

err, s/would/our
Comment 17 zalan 2012-05-17 05:47:29 PDT
(In reply to comment #16)
> (In reply to comment #15)
> > (In reply to comment #14)
> > > (In reply to comment #13)
> > > > (From update of attachment 142295 [details] [details] [details] [details])
> > > > It looks good to me, but fix Kenneth's remarks before landing.
> > > > 
> > > > I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )
> > > 
> > > Yeah that would be great! We would also like Chrome on board.
> > 
> > btw, would clipping logic is simpler:
> > 
> > we clip against any scrollable box, and clip against the already clipped parent viewport frame view :)
> 
> err, s/would/our
Reading your TouchEventHandler and the corresponding comment at RenderObject::absoluteFocusRingQuads(), wondering if your highlighting is transform aware.
Comment 18 zalan 2012-05-17 06:11:38 PDT
(In reply to comment #13)
> (From update of attachment 142295 [details])
> It looks good to me, but fix Kenneth's remarks before landing.
> 
> I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )

It seems the Layer approach won't work (turned out to be as a result of an assert in offsetFromContainer()). 
::offsetFromContainer() looks to expect direct container (unless positioned), which is not always the case as o->container() not necessarily equals o->enclosingLayer()->renderer();. There is this other function called ::offsetFromAncestorContainer(), which can take any parent container, but it loops from 'this' to 'ancestor', so no save there (and it asserts if any parent has transform())
So I started looking at RenderLayer to see if there's a helper functions somewhere, but all I found was convertToLayerCoords(). It could work when jumping from layer to layer, but then there's still the problem of getting to the first layer, the offset of object<->enclosing layer, which apparently needs to be done through the normal o->container() way.
Any ideas or something I am missing?
Comment 19 zalan 2012-05-17 06:28:55 PDT
(In reply to comment #18)
> (In reply to comment #13)
> > (From update of attachment 142295 [details] [details])
> > It looks good to me, but fix Kenneth's remarks before landing.
> > 
> > I should look closer to that, but make use of it for the BlackBerry port, instead of using my own (see http://trac.webkit.org/browser/trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp#L343 )
> 
> It seems the Layer approach won't work (turned out to be as a result of an assert in offsetFromContainer()). 
> ::offsetFromContainer() looks to expect direct container (unless positioned), which is not always the case as o->container() not necessarily equals o->enclosingLayer()->renderer();. There is this other function called ::offsetFromAncestorContainer(), which can take any parent container, but it loops from 'this' to 'ancestor', so no save there (and it asserts if any parent has transform())
> So I started looking at RenderLayer to see if there's a helper functions somewhere, but all I found was convertToLayerCoords(). It could work when jumping from layer to layer, but then there's still the problem of getting to the first layer, the offset of object<->enclosing layer, which apparently needs to be done through the normal o->container() way.
> Any ideas or something I am missing?
I could jump from layer to layer and mimic offsetFromAncestorContainer() only when clipping (so that would eliminate the assert on hasTransform)
Comment 20 Antonio Gomes 2012-05-17 06:43:02 PDT
> Reading your TouchEventHandler and the corresponding comment at RenderObject::absoluteFocusRingQuads(), wondering if your highlighting is transform aware.

It is not. But it has not shown up as a real world problem.
Comment 21 zalan 2012-05-17 12:32:14 PDT
Created attachment 142526 [details]
Patch
Comment 22 zalan 2012-05-17 12:37:51 PDT
> > Source/WebCore/page/GestureTapHighlighter.cpp:212
> > +                if (ringRect.isEmpty())
> > +                    break;
> 
> I like if (ringRect.isEmpty()) { remove(i); break; } more
> 
> > Source/WebCore/page/GestureTapHighlighter.cpp:220
> > +        if (ringRect.isEmpty())
> > +            drawableRects.remove(i);
> 
> then here you would just do a 'continue'.
Since ringRect is a reference and remove(i) calls its d'tor, not sure if it is safe to use later. I am happy to flip a flag and check it later, instead of the double ringRect.isEmpty() call.
Comment 23 WebKit Review Bot 2012-05-18 00:36:17 PDT
Comment on attachment 142526 [details]
Patch

Clearing flags on attachment: 142526

Committed r117555: <http://trac.webkit.org/changeset/117555>
Comment 24 WebKit Review Bot 2012-05-18 00:36:23 PDT
All reviewed patches have been landed.  Closing bug.