Bug 81057

Summary: Fix rounding and usage of LayoutUnits in RenderBoxModelObject
Product: WebKit Reporter: Emil A Eklund <eae>
Component: Layout and RenderingAssignee: Emil A Eklund <eae>
Status: RESOLVED FIXED    
Severity: Normal CC: abarth, eric, jamesr, jchaffraix, leviw, simon.fraser, webkit.review.bot
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Unspecified   
OS: Unspecified   
Bug Depends on:    
Bug Blocks: 60318    
Attachments:
Description Flags
Patch
none
Patch none

Description Emil A Eklund 2012-03-13 16:41:20 PDT
LayoutUnits and ints are currently used interchangeably in RenderBoxModelObject, specifically in background and border image calculations.
Comment 1 Emil A Eklund 2012-03-13 16:50:13 PDT
Created attachment 131750 [details]
Patch
Comment 2 Emil A Eklund 2012-03-14 14:55:10 PDT
Ping?
Comment 3 Julien Chaffraix 2012-03-14 20:30:23 PDT
Comment on attachment 131750 [details]
Patch

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

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1084
> +    IntRect alignedRect = pixelSnappedIntRect(paintRect);

It should be named alignedPaintRect. Maybe even better: snappedPaintRect?

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1127
> +            positioningAreaSize = IntSize(alignedRect.width() - left - right, alignedRect.height() - top - bottom);

Is it possible that we would want to snap after doing the subtractions as all the directions are LayoutUnits? Or is it better to be coherent with the width / height snapping above?

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1142
> +        geometry.setPhaseX(geometry.tileSize().width() ? layoutMod(geometry.tileSize().width() - (xPosition + left), geometry.tileSize().width()) : zeroLayoutUnit);

BackgroundImageGeometry::setPhaseX takes an |int| not a LayoutUnit. AFAICT we want to keep the integer there as we are manipulating a replaced element. Is this really what we want to do here?

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1148
> +        geometry.setPhaseY(geometry.tileSize().height() ? layoutMod(geometry.tileSize().height() - (yPosition + top), geometry.tileSize().height()) : zeroLayoutUnit);

Ditto.
Comment 4 Emil A Eklund 2012-03-15 14:57:50 PDT
Created attachment 132126 [details]
Patch
Comment 5 Emil A Eklund 2012-03-15 15:00:58 PDT
Thanks for your thorough review Julien!

(In reply to comment #3)
> (From update of attachment 131750 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=131750&action=review
> 
> > Source/WebCore/rendering/RenderBoxModelObject.cpp:1084
> > +    IntRect alignedRect = pixelSnappedIntRect(paintRect);
> 
> It should be named alignedPaintRect. Maybe even better: snappedPaintRect?

Renamed to snappedPaintRect

> 
> > Source/WebCore/rendering/RenderBoxModelObject.cpp:1127
> > +            positioningAreaSize = IntSize(alignedRect.width() - left - right, alignedRect.height() - top - bottom);
> 
> Is it possible that we would want to snap after doing the subtractions as all the directions are LayoutUnits? Or is it better to be coherent with the width / height snapping above?

Good idea, the padding values could have subpixel precision and would be floored otherwise. Changed to snap after subtracting the padding/border.

> 
> > Source/WebCore/rendering/RenderBoxModelObject.cpp:1142
> > +        geometry.setPhaseX(geometry.tileSize().width() ? layoutMod(geometry.tileSize().width() - (xPosition + left), geometry.tileSize().width()) : zeroLayoutUnit);
> 
> BackgroundImageGeometry::setPhaseX takes an |int| not a LayoutUnit. AFAICT we want to keep the integer there as we are manipulating a replaced element. Is this really what we want to do here?

Changed this to use integers throughout.
Comment 6 Julien Chaffraix 2012-03-15 16:06:06 PDT
Comment on attachment 132126 [details]
Patch

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

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1144
> -        geometry.setPhaseX(geometry.tileSize().width() ? layoutMod(geometry.tileSize().width() - (xPosition + left), geometry.tileSize().width()) : LayoutUnit(0));
> +        geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - (xPosition + left) % geometry.tileSize().width() : 0);

Those 2 lines are not equivalent due to % being of higher priority that -. It's sad that our tests are not catching that. Extra points if you can find a test to catch that regression.

> Source/WebCore/rendering/RenderBoxModelObject.cpp:1150
> +        geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - (yPosition + top) % geometry.tileSize().height() : 0);

Ditto.
Comment 7 Emil A Eklund 2012-03-15 17:03:07 PDT
(In reply to comment #6)
> (From update of attachment 132126 [details])
> View in context: https://bugs.webkit.org/attachment.cgi?id=132126&action=review
> 
> > Source/WebCore/rendering/RenderBoxModelObject.cpp:1144
> > -        geometry.setPhaseX(geometry.tileSize().width() ? layoutMod(geometry.tileSize().width() - (xPosition + left), geometry.tileSize().width()) : LayoutUnit(0));
> > +        geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - (xPosition + left) % geometry.tileSize().width() : 0);
> 
> Those 2 lines are not equivalent due to % being of higher priority that -. It's sad that our tests are not catching that. Extra points if you can find a test to catch that regression.
> 
> > Source/WebCore/rendering/RenderBoxModelObject.cpp:1150
> > +        geometry.setPhaseY(geometry.tileSize().height() ? geometry.tileSize().height() - (yPosition + top) % geometry.tileSize().height() : 0);
> 
> Ditto.

Good catch but this actually restores the code to the exact same state as it was before we changed it to use LayoutUnits. Which means that this been broken for the last seven months (!).

http://trac.webkit.org/browser/trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp?rev=92529#L932
Comment 8 Levi Weintraub 2012-03-15 17:04:27 PDT
Comment on attachment 132126 [details]
Patch

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

>>> Source/WebCore/rendering/RenderBoxModelObject.cpp:1144
>>> +        geometry.setPhaseX(geometry.tileSize().width() ? geometry.tileSize().width() - (xPosition + left) % geometry.tileSize().width() : 0);
>> 
>> Those 2 lines are not equivalent due to % being of higher priority that -. It's sad that our tests are not catching that. Extra points if you can find a test to catch that regression.
> 
> Good catch but this actually restores the code to the exact same state as it was before we changed it to use LayoutUnits. Which means that this been broken for the last seven months (!).
> 
> http://trac.webkit.org/browser/trunk/Source/WebCore/rendering/RenderBoxModelObject.cpp?rev=92529#L932

This seems difficult to believe...!
Comment 9 Emil A Eklund 2012-03-15 22:52:04 PDT
Having looked into this in detail it turns out to be quite interesting, the way this is computed means that the two calculations will produce different numbers in cases where the background offset is larger than the size of the image. This isn't very common in the wild but is certainly valid.

However it turns out that this doesn't effect the visual representation at all as it will be off by the full width (or height) of the image, resulting in the same offset and thus the same rendering.
Comment 10 Julien Chaffraix 2012-03-16 12:47:20 PDT
Comment on attachment 132126 [details]
Patch

> However it turns out that this doesn't effect the visual representation at all as it will be off by the full width (or height) of the image, resulting in the same offset and thus the same rendering.

OK... Could you file about a bug about this craziness / the fact that calculateBackgroundImageGeometry code should definitely be made less error-prone?
Comment 11 Emil A Eklund 2012-03-16 13:35:11 PDT
Filed bug 81396 to track the calculateBackgroundImageGeometry crazies.
Comment 12 WebKit Review Bot 2012-03-16 14:30:26 PDT
Comment on attachment 132126 [details]
Patch

Clearing flags on attachment: 132126

Committed r111066: <http://trac.webkit.org/changeset/111066>
Comment 13 WebKit Review Bot 2012-03-16 14:30:32 PDT
All reviewed patches have been landed.  Closing bug.