[CSS Exclusions] shape-outside on floats for polygon shapes
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2013 18:19:36 +0000 (18:19 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 5 Mar 2013 18:19:36 +0000 (18:19 +0000)
https://bugs.webkit.org/show_bug.cgi?id=98676

Patch by Bem Jones-Bey <bjonesbe@adobe.com> on 2013-03-05
Reviewed by David Hyatt.

Source/WebCore:

Implement support for polygonal shape-outside on floats. The basic
tack taken here is to keep using the bounding box of the shape to
position the float, but to compute the offset (caused by the shape)
from the bounding box for each line when creating and positioning
other inline content.

Test: fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html

* rendering/ExclusionShapeInfo.cpp:
(WebCore):
(WebCore::::computedShape): Add new template parameter.
(WebCore::::logicalTopOffset): Add new template parameter.
(WebCore::::computeSegmentsForLine): Move here from
    ExclusionShapeInsideInfo, since ExclusionShapeOutsideInfo needs it
    as well. Make virtual since there is slightly different behavior
    between each class even though the vast majority of the code is
    common.
* rendering/ExclusionShapeInfo.h:
(WebCore):
(WebCore::ExclusionShapeInfo::~ExclusionShapeInfo): Since
    computeSegmentsForLine is virtual, the destructor must be virtual
    as well.
(ExclusionShapeInfo): Add new data members to support
    computeSegmentsForLine.
(WebCore::ExclusionShapeInfo::shapeLogicalRight): Fix bug, the logical
    right is based off of maxX, not y. (it's a logical bounding box!)
(WebCore::ExclusionShapeInfo::logicalLineTop): Moved from
    ExclusionShapeInsideInfo for use by computeSegmentsForLine and
    lineOverlapsShapeBounds.
(WebCore::ExclusionShapeInfo::logicalLineBottom): Moved from
    ExclusionShapeInsideInfo for use by computeSegmentsForLine and
    lineOverlapsShapeBounds.
(WebCore::ExclusionShapeInfo::lineOverlapsShapeBounds): Moved from
    ExclusionShapeInsideInfo for use by computeSegmentsForLine.
* rendering/ExclusionShapeInsideInfo.cpp: Moved common code from
    computeSegmentsForLine into ExclusionShapeInfo.
* rendering/ExclusionShapeInsideInfo.h:
(WebCore): Moved some methods to ExclusionShapeInfo.
(ExclusionShapeInsideInfo): Update for new template parameter.
(WebCore::ExclusionShapeInsideInfo::compyteSegmentsForLine): Override
    superclass method to clear the segment ranges. Segement ranges
    aren't used by shape outside, and have some complex dependencies
    that make it very hard to try and move up into ExclusionShapeInfo.
(WebCore::ExclusionShapeInsideInfo::ExclusionShapeInsideInfo): Update
    for new template parameter.
* rendering/ExclusionShapeOutsideInfo.cpp:
(WebCore::ExclusionShapeOutsideInfo::isEnabledFor): Add polygons as a
    supported shape.
(WebCore::ExclusionShapeOutsideInfo::computeSegmentsForLine): Override
    superclass method to not recompute if it isn't needed (this isn't
    straightfoward for shape inside, which is why it isn't common),
    and to save the left and right offsets caused by the shape
    outside, since that's all that is needed to properly do layout in
    the case of floats.
* rendering/ExclusionShapeOutsideInfo.h:
(WebCore::ExclusionShapeOutsideInfo::shapeLogicalOffset): Reformat to
    be on a single line, like most other methods of it's type in
    WebKit headers.
(ExclusionShapeOutsideInfo): Update for new template parameter.
(WebCore::ExclusionShapeOutsideInfo::logicalLeftOffsetForLine):
    Accessor method to get the left offset between the shape and the
    shape's bounding box.
(WebCore::ExclusionShapeOutsideInfo::logicalRightOffsetForLine):
    Accessor method to get the left offset between the shape and the
    shape's bounding box.
(WebCore::ExclusionShapeOutsideInfo::ExclusionShapeOutsideInfo):
    Update for new template parameter.
* rendering/RenderBlock.cpp:
(WebCore::::collectIfNeeded): Save the last float encountered so that
    the shape outside offset can be accounted for.
(WebCore::RenderBlock::logicalLeftOffsetForLine): Account for the
    shape outside offset on the outermost float.
(WebCore::RenderBlock::logicalRightOffsetForLine): Account for the
    shape outside offset on the outermost float.
* rendering/RenderBlock.h:
(WebCore::RenderBlock::FloatIntervalSearchAdapter::FloatIntervalSearchAdapter):
    Initialize the lastFloat member.
(WebCore::RenderBlock::FloatIntervalSearchAdapter::lastFloat): Get the
    last float encountered.
(FloatIntervalSearchAdapter): Add a pointer to the last float
    encountered. Note that the variable is mutable because
    collectIfNeeded is declared as a const method even though it isn't
    (it uses loopholes to update m_offset and m_heightRemaining).
    Instead of trying to come up with a hack to stick with the
    loopholes, I decided to be explicit about it.
* rendering/RenderBlockLineLayout.cpp:
(WebCore::LineWidth::shrinkAvailableWidthForNewFloatIfNeeded): Take
    into account the offset from any polygonal shape outside.
(WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Add a FIXME
    because the current code will not work properly with stacked
    floats that have polygonal shape outside.

LayoutTests:

Simple test for floats with polygonal shape-outside.

* fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon-expected.html: Added.
* fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@144776 268f45cc-cd09-0410-ab3c-d52691b4dbfc

13 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon-expected.html [new file with mode: 0644]
LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/ExclusionShapeInfo.cpp
Source/WebCore/rendering/ExclusionShapeInfo.h
Source/WebCore/rendering/ExclusionShapeInsideInfo.cpp
Source/WebCore/rendering/ExclusionShapeInsideInfo.h
Source/WebCore/rendering/ExclusionShapeOutsideInfo.cpp
Source/WebCore/rendering/ExclusionShapeOutsideInfo.h
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderBlockLineLayout.cpp

index 363664e..adb1b16 100644 (file)
@@ -1,3 +1,15 @@
+2013-03-05  Bem Jones-Bey  <bjonesbe@adobe.com>
+
+        [CSS Exclusions] shape-outside on floats for polygon shapes
+        https://bugs.webkit.org/show_bug.cgi?id=98676
+
+        Reviewed by David Hyatt.
+
+        Simple test for floats with polygonal shape-outside.
+
+        * fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon-expected.html: Added.
+        * fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html: Added.
+
 2013-03-05  Chris Fleizach  <cfleizach@apple.com>
 
         AX: aria-label does not override text content on iOS
diff --git a/LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon-expected.html b/LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon-expected.html
new file mode 100644 (file)
index 0000000..ec3d351
--- /dev/null
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.container {
+    font: 10px/1 Ahem, sans-serif;
+    width: 200px;
+    height: 200px;
+    background: blue;
+}
+.float-left {
+    height: 10px;
+    float: left;
+}
+.float-right {
+    height: 10px;
+    float: right;
+}
+.float-left-vertical {
+    width: 10px;
+    float: left;
+}
+.float-right-vertical {
+    width: 10px;
+    float: right;
+}
+</style>
+</head>
+<body>
+  <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=98676">Bug 98676</a> - [CSS Exclusions] shape-outside on floats for polygon shapes</h1>
+  <h2>The following tests should display a square with blue triangles in opposite corners.</h2>
+  <div class="container">
+    <div style="width: 100px" class="float-left"></div>
+    XXXXXXXXXX
+    <div style="width: 90px" class="float-left"></div>
+    XXXXXXXXXXX
+    <div style="width: 80px" class="float-left"></div>
+    XXXXXXXXXXXX
+    <div style="width: 70px" class="float-left"></div>
+    XXXXXXXXXXXXX
+    <div style="width: 60px" class="float-left"></div>
+    XXXXXXXXXXXXXX
+    <div style="width: 50px" class="float-left"></div>
+    XXXXXXXXXXXXXXX
+    <div style="width: 40px" class="float-left"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="width: 30px" class="float-left"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="width: 20px" class="float-left"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="width: 10px" class="float-left"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="width: 10px" class="float-right"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="width: 20px" class="float-right"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="width: 30px" class="float-right"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="width: 40px" class="float-right"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="width: 50px" class="float-right"></div>
+    XXXXXXXXXXXXXXX
+    <div style="width: 60px" class="float-right"></div>
+    XXXXXXXXXXXXXX
+    <div style="width: 70px" class="float-right"></div>
+    XXXXXXXXXXXXX
+    <div style="width: 80px" class="float-right"></div>
+    XXXXXXXXXXXX
+    <div style="width: 90px" class="float-right"></div>
+    XXXXXXXXXXX
+    <div style="width: 100px" class="float-right"></div>
+    XXXXXXXXXX
+  </div>
+  <h3>vertical lr</h3>
+  <div style="-webkit-writing-mode: vertical-lr" class="container">
+    <div style="height: 100px" class="float-left-vertical"></div>
+    XXXXXXXXXX
+    <div style="height: 90px" class="float-left-vertical"></div>
+    XXXXXXXXXXX
+    <div style="height: 80px" class="float-left-vertical"></div>
+    XXXXXXXXXXXX
+    <div style="height: 70px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXX
+    <div style="height: 60px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXX
+    <div style="height: 50px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXX
+    <div style="height: 40px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="height: 30px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="height: 20px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="height: 10px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="height: 10px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="height: 20px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="height: 30px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="height: 40px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="height: 50px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXX
+    <div style="height: 60px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXX
+    <div style="height: 70px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXX
+    <div style="height: 80px" class="float-right-vertical"></div>
+    XXXXXXXXXXXX
+    <div style="height: 90px" class="float-right-vertical"></div>
+    XXXXXXXXXXX
+    <div style="height: 100px" class="float-right-vertical"></div>
+    XXXXXXXXXX
+  </div>
+  <h3>vertical rl</h3>
+  <div style="-webkit-writing-mode: vertical-rl" class="container">
+    <div style="height: 100px" class="float-left-vertical"></div>
+    XXXXXXXXXX
+    <div style="height: 90px" class="float-left-vertical"></div>
+    XXXXXXXXXXX
+    <div style="height: 80px" class="float-left-vertical"></div>
+    XXXXXXXXXXXX
+    <div style="height: 70px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXX
+    <div style="height: 60px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXX
+    <div style="height: 50px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXX
+    <div style="height: 40px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="height: 30px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="height: 20px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="height: 10px" class="float-left-vertical"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="height: 10px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXXXX
+    <div style="height: 20px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXXX
+    <div style="height: 30px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXXX
+    <div style="height: 40px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXXX
+    <div style="height: 50px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXXX
+    <div style="height: 60px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXXX
+    <div style="height: 70px" class="float-right-vertical"></div>
+    XXXXXXXXXXXXX
+    <div style="height: 80px" class="float-right-vertical"></div>
+    XXXXXXXXXXXX
+    <div style="height: 90px" class="float-right-vertical"></div>
+    XXXXXXXXXXX
+    <div style="height: 100px" class="float-right-vertical"></div>
+    XXXXXXXXXX
+  </div>
+</body>
+</html>
diff --git a/LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html b/LayoutTests/fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html
new file mode 100644 (file)
index 0000000..0900b8a
--- /dev/null
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script>
+    if (window.internals)
+        window.internals.settings.setCSSExclusionsEnabled(true);
+</script>
+<style>
+.container {
+    font: 10px/1 Ahem, sans-serif;
+    width: 200px;
+    height: 200px;
+    background: blue;
+}
+.float-left {
+    width: 50px;
+    height: 100px;
+    -webkit-shape-outside: polygon(0px 0px, 100px 0px, 0px 100px);
+    float: left;
+}
+.float-right {
+    width: 50px;
+    height: 100px;
+    -webkit-shape-outside: polygon(50px 0px, -50px 100px, 50px 100px);
+    float: right;
+}
+.float-left-vertical-lr {
+    width: 100px;
+    height: 50px;
+    -webkit-shape-outside: polygon(0px 0px, 0px 100px, 100px 0px);
+    float: left;
+}
+.float-right-vertical-lr {
+    width: 100px;
+    height: 50px;
+    -webkit-shape-outside: polygon(0px 50px, 100px -50px, 100px 50px);
+    float: right;
+}
+.float-left-vertical-rl {
+    width: 100px;
+    height: 50px;
+    -webkit-shape-outside: polygon(0px 0px, 100px 100px, 100px 0px);
+    float: left;
+}
+.float-right-vertical-rl {
+    width: 100px;
+    height: 50px;
+    -webkit-shape-outside: polygon(0px 50px, 0px -50px, 100px 50px);
+    float: right;
+}
+</style>
+</head>
+<body>
+  <h1><a href="https://bugs.webkit.org/show_bug.cgi?id=98676">Bug 98676</a> - [CSS Exclusions] shape-outside on floats for polygon shapes</h1>
+  <h2>The following tests should display a square with blue triangles in opposite corners.</h2>
+  <div class="container">
+    <div class="float-left"></div>
+    XXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXXX
+    <div class="float-right"></div>
+    XXXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXX
+  </div>
+  <h3>vertical lr</h3>
+  <div style="-webkit-writing-mode: vertical-lr" class="container">
+    <div class="float-left-vertical-lr"></div>
+    XXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXXX
+    <div class="float-right-vertical-lr"></div>
+    XXXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXX
+  </div>
+  <h3>vertical rl</h3>
+  <div style="-webkit-writing-mode: vertical-rl" class="container">
+    <div class="float-left-vertical-rl"></div>
+    XXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXXX
+    <div class="float-right-vertical-rl"></div>
+    XXXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXXX
+    XXXXXXXXXXXXXX
+    XXXXXXXXXXXXX
+    XXXXXXXXXXXX
+    XXXXXXXXXXX
+    XXXXXXXXXX
+  </div>
+</body>
+</html>
index be5c001..8b66d8a 100644 (file)
@@ -1,3 +1,102 @@
+2013-03-05  Bem Jones-Bey  <bjonesbe@adobe.com>
+
+        [CSS Exclusions] shape-outside on floats for polygon shapes
+        https://bugs.webkit.org/show_bug.cgi?id=98676
+
+        Reviewed by David Hyatt.
+
+        Implement support for polygonal shape-outside on floats. The basic
+        tack taken here is to keep using the bounding box of the shape to
+        position the float, but to compute the offset (caused by the shape)
+        from the bounding box for each line when creating and positioning
+        other inline content.
+
+        Test: fast/exclusions/shape-outside-floats/shape-outside-floats-simple-polygon.html
+
+        * rendering/ExclusionShapeInfo.cpp:
+        (WebCore):
+        (WebCore::::computedShape): Add new template parameter.
+        (WebCore::::logicalTopOffset): Add new template parameter.
+        (WebCore::::computeSegmentsForLine): Move here from
+            ExclusionShapeInsideInfo, since ExclusionShapeOutsideInfo needs it
+            as well. Make virtual since there is slightly different behavior
+            between each class even though the vast majority of the code is
+            common.
+        * rendering/ExclusionShapeInfo.h:
+        (WebCore):
+        (WebCore::ExclusionShapeInfo::~ExclusionShapeInfo): Since
+            computeSegmentsForLine is virtual, the destructor must be virtual
+            as well.
+        (ExclusionShapeInfo): Add new data members to support
+            computeSegmentsForLine.
+        (WebCore::ExclusionShapeInfo::shapeLogicalRight): Fix bug, the logical
+            right is based off of maxX, not y. (it's a logical bounding box!)
+        (WebCore::ExclusionShapeInfo::logicalLineTop): Moved from
+            ExclusionShapeInsideInfo for use by computeSegmentsForLine and
+            lineOverlapsShapeBounds.
+        (WebCore::ExclusionShapeInfo::logicalLineBottom): Moved from
+            ExclusionShapeInsideInfo for use by computeSegmentsForLine and
+            lineOverlapsShapeBounds.
+        (WebCore::ExclusionShapeInfo::lineOverlapsShapeBounds): Moved from
+            ExclusionShapeInsideInfo for use by computeSegmentsForLine.
+        * rendering/ExclusionShapeInsideInfo.cpp: Moved common code from
+            computeSegmentsForLine into ExclusionShapeInfo.
+        * rendering/ExclusionShapeInsideInfo.h:
+        (WebCore): Moved some methods to ExclusionShapeInfo.
+        (ExclusionShapeInsideInfo): Update for new template parameter.
+        (WebCore::ExclusionShapeInsideInfo::compyteSegmentsForLine): Override
+            superclass method to clear the segment ranges. Segement ranges
+            aren't used by shape outside, and have some complex dependencies
+            that make it very hard to try and move up into ExclusionShapeInfo.
+        (WebCore::ExclusionShapeInsideInfo::ExclusionShapeInsideInfo): Update
+            for new template parameter.
+        * rendering/ExclusionShapeOutsideInfo.cpp:
+        (WebCore::ExclusionShapeOutsideInfo::isEnabledFor): Add polygons as a
+            supported shape.
+        (WebCore::ExclusionShapeOutsideInfo::computeSegmentsForLine): Override
+            superclass method to not recompute if it isn't needed (this isn't
+            straightfoward for shape inside, which is why it isn't common),
+            and to save the left and right offsets caused by the shape
+            outside, since that's all that is needed to properly do layout in
+            the case of floats.
+        * rendering/ExclusionShapeOutsideInfo.h:
+        (WebCore::ExclusionShapeOutsideInfo::shapeLogicalOffset): Reformat to
+            be on a single line, like most other methods of it's type in
+            WebKit headers.
+        (ExclusionShapeOutsideInfo): Update for new template parameter.
+        (WebCore::ExclusionShapeOutsideInfo::logicalLeftOffsetForLine):
+            Accessor method to get the left offset between the shape and the
+            shape's bounding box.
+        (WebCore::ExclusionShapeOutsideInfo::logicalRightOffsetForLine):
+            Accessor method to get the left offset between the shape and the
+            shape's bounding box.
+        (WebCore::ExclusionShapeOutsideInfo::ExclusionShapeOutsideInfo):
+            Update for new template parameter.
+        * rendering/RenderBlock.cpp:
+        (WebCore::::collectIfNeeded): Save the last float encountered so that
+            the shape outside offset can be accounted for.
+        (WebCore::RenderBlock::logicalLeftOffsetForLine): Account for the
+            shape outside offset on the outermost float.
+        (WebCore::RenderBlock::logicalRightOffsetForLine): Account for the
+            shape outside offset on the outermost float.
+        * rendering/RenderBlock.h:
+        (WebCore::RenderBlock::FloatIntervalSearchAdapter::FloatIntervalSearchAdapter):
+            Initialize the lastFloat member.
+        (WebCore::RenderBlock::FloatIntervalSearchAdapter::lastFloat): Get the
+            last float encountered.
+        (FloatIntervalSearchAdapter): Add a pointer to the last float
+            encountered. Note that the variable is mutable because
+            collectIfNeeded is declared as a const method even though it isn't
+            (it uses loopholes to update m_offset and m_heightRemaining).
+            Instead of trying to come up with a hack to stick with the
+            loopholes, I decided to be explicit about it.
+        * rendering/RenderBlockLineLayout.cpp:
+        (WebCore::LineWidth::shrinkAvailableWidthForNewFloatIfNeeded): Take
+            into account the offset from any polygonal shape outside.
+        (WebCore::RenderBlock::LineBreaker::nextSegmentBreak): Add a FIXME
+            because the current code will not work properly with stacked
+            floats that have polygonal shape outside.
+
 2013-03-04  David Hyatt  <hyatt@apple.com>
 
         [New Multicolumn] Autogenerate regions for columns.
index f6cb097..8484dc6 100644 (file)
@@ -39,8 +39,8 @@
 #include "RenderStyle.h"
 
 namespace WebCore {
-template <class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const>
-const ExclusionShape* ExclusionShapeInfo<RenderType, shapeGetter>::computedShape() const
+template<class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const, void (ExclusionShape::*intervalGetter)(float, float, SegmentList&) const>
+const ExclusionShape* ExclusionShapeInfo<RenderType, shapeGetter, intervalGetter>::computedShape() const
 {
     if (ExclusionShape* exclusionShape = m_shape.get())
         return exclusionShape;
@@ -55,8 +55,8 @@ const ExclusionShape* ExclusionShapeInfo<RenderType, shapeGetter>::computedShape
     return m_shape.get();
 }
 
-template <class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const>
-LayoutUnit ExclusionShapeInfo<RenderType, shapeGetter>::logicalTopOffset() const
+template<class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const, void (ExclusionShape::*intervalGetter)(float, float, SegmentList&) const>
+LayoutUnit ExclusionShapeInfo<RenderType, shapeGetter, intervalGetter>::logicalTopOffset() const
 {
     LayoutUnit logicalTopOffset = m_renderer->style()->boxSizing() == CONTENT_BOX ? m_renderer->borderBefore() + m_renderer->paddingBefore() : LayoutUnit();
     // Content in a flow thread is relative to the beginning of the thread, but the shape calculation should be relative to the current region.
@@ -65,7 +65,27 @@ LayoutUnit ExclusionShapeInfo<RenderType, shapeGetter>::logicalTopOffset() const
     return logicalTopOffset;
 }
 
-template class ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside>;
-template class ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside>;
+template<class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const, void (ExclusionShape::*intervalGetter)(float, float, SegmentList&) const>
+bool ExclusionShapeInfo<RenderType, shapeGetter, intervalGetter>::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+    ASSERT(lineHeight >= 0);
+    m_shapeLineTop = lineTop - logicalTopOffset();
+    m_lineHeight = lineHeight;
+    m_segments.clear();
+
+    if (lineOverlapsShapeBounds())
+        (computedShape()->*intervalGetter)(m_shapeLineTop, std::min(m_lineHeight, shapeLogicalBottom() - lineTop), m_segments);
+
+    LayoutUnit logicalLeftOffset = this->logicalLeftOffset();
+    for (size_t i = 0; i < m_segments.size(); i++) {
+        m_segments[i].logicalLeft += logicalLeftOffset;
+        m_segments[i].logicalRight += logicalLeftOffset;
+    }
+
+    return m_segments.size();
+}
+
+template class ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &ExclusionShape::getIncludedIntervals>;
+template class ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside, &ExclusionShape::getExcludedIntervals>;
 }
 #endif
index f13ee85..7fc1bef 100644 (file)
@@ -64,11 +64,11 @@ private:
     }
 };
 
-template <class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const>
+template<class RenderType, ExclusionShapeValue* (RenderStyle::*shapeGetter)() const, void (ExclusionShape::*intervalGetter)(float, float, SegmentList&) const>
 class ExclusionShapeInfo {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    ~ExclusionShapeInfo() { }
+    virtual ~ExclusionShapeInfo() { }
 
     void setShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight)
     {
@@ -84,13 +84,20 @@ public:
         m_shapeLogicalHeight = logicalHeight;
     }
 
+    virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
+
     LayoutUnit shapeLogicalTop() const { return floatLogicalTopToLayoutUnit(computedShape()->shapeLogicalBoundingBox().y()) + logicalTopOffset(); }
     LayoutUnit shapeLogicalBottom() const { return floatLogicalBottomToLayoutUnit(computedShape()->shapeLogicalBoundingBox().maxY()) + logicalTopOffset(); }
     LayoutUnit shapeLogicalLeft() const { return computedShape()->shapeLogicalBoundingBox().x() + logicalLeftOffset(); }
-    LayoutUnit shapeLogicalRight() const { return computedShape()->shapeLogicalBoundingBox().y() + logicalLeftOffset(); }
+    LayoutUnit shapeLogicalRight() const { return computedShape()->shapeLogicalBoundingBox().maxX() + logicalLeftOffset(); }
     LayoutUnit shapeLogicalWidth() const { return computedShape()->shapeLogicalBoundingBox().width(); }
     LayoutUnit shapeLogicalHeight() const { return computedShape()->shapeLogicalBoundingBox().height(); }
 
+    LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); }
+    LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); }
+
+    bool lineOverlapsShapeBounds() const { return logicalLineTop() < shapeLogicalBottom() && logicalLineBottom() >= shapeLogicalTop(); }
+
     void dirtyShapeSize() { m_shape.clear(); }
     bool shapeSizeDirty() { return !m_shape.get(); }
     const RenderType* owner() const { return m_renderer; }
@@ -107,6 +114,10 @@ protected:
     LayoutUnit logicalTopOffset() const;
     LayoutUnit logicalLeftOffset() const { return m_renderer->style()->boxSizing() == CONTENT_BOX ? m_renderer->borderStart() + m_renderer->paddingStart() : LayoutUnit(); }
 
+    LayoutUnit m_shapeLineTop;
+    LayoutUnit m_lineHeight;
+    SegmentList m_segments;
+
 private:
     mutable OwnPtr<ExclusionShape> m_shape;
 
index 3480196..1d4e383 100644 (file)
 #include "RenderBlock.h"
 
 namespace WebCore {
-bool ExclusionShapeInsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
-{
-    ASSERT(lineHeight >= 0);
-    m_shapeLineTop = lineTop - logicalTopOffset();
-    m_lineHeight = lineHeight;
-    m_segments.clear();
-    m_segmentRanges.clear();
-
-    if (lineOverlapsShapeBounds())
-        computedShape()->getIncludedIntervals(m_shapeLineTop, std::min(m_lineHeight, shapeLogicalBottom() - lineTop), m_segments);
-
-    LayoutUnit logicalLeftOffset = this->logicalLeftOffset();
-    for (size_t i = 0; i < m_segments.size(); i++) {
-        m_segments[i].logicalLeft += logicalLeftOffset;
-        m_segments[i].logicalRight += logicalLeftOffset;
-    }
-    return m_segments.size();
-}
-
 bool ExclusionShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth)
 {
     const ExclusionShape* shape = computedShape();
index ad868e5..60fec4c 100644 (file)
@@ -52,7 +52,8 @@ struct LineSegmentRange {
 };
 typedef Vector<LineSegmentRange> SegmentRangeList;
 
-class ExclusionShapeInsideInfo : public ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside>, public MappedInfo<RenderBlock, ExclusionShapeInsideInfo> {
+
+class ExclusionShapeInsideInfo : public ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &ExclusionShape::getIncludedIntervals>, public MappedInfo<RenderBlock, ExclusionShapeInsideInfo> {
 public:
     static PassOwnPtr<ExclusionShapeInsideInfo> createInfo(const RenderBlock* renderer) { return adoptPtr(new ExclusionShapeInsideInfo(renderer)); }
 
@@ -61,7 +62,12 @@ public:
         ExclusionShapeValue* shapeValue = renderer->style()->resolvedShapeInside();
         return (shapeValue && shapeValue->type() == ExclusionShapeValue::SHAPE) ? shapeValue->shape() : 0;
     }
-    bool lineOverlapsShapeBounds() const { return logicalLineTop() < shapeLogicalBottom() && logicalLineBottom() >= shapeLogicalTop(); }
+
+    virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) OVERRIDE
+    {
+        m_segmentRanges.clear();
+        return ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &ExclusionShape::getIncludedIntervals>::computeSegmentsForLine(lineTop, lineHeight);
+    }
 
     bool hasSegments() const
     {
@@ -81,24 +87,17 @@ public:
         ASSERT(m_segmentRanges.size() < m_segments.size());
         return &m_segments[m_segmentRanges.size()];
     }
-    bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight);
     bool adjustLogicalLineTop(float minSegmentWidth);
-    LayoutUnit logicalLineTop() const { return m_shapeLineTop + logicalTopOffset(); }
-    LayoutUnit logicalLineBottom() const { return m_shapeLineTop + m_lineHeight + logicalTopOffset(); }
 
     void setNeedsLayout(bool value) { m_needsLayout = value; }
     bool needsLayout() { return m_needsLayout; }
 
 private:
     ExclusionShapeInsideInfo(const RenderBlock* renderer)
-    : ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside> (renderer)
+    : ExclusionShapeInfo<RenderBlock, &RenderStyle::resolvedShapeInside, &ExclusionShape::getIncludedIntervals> (renderer)
     , m_needsLayout(false)
     { }
 
-    LayoutUnit m_shapeLineTop;
-    LayoutUnit m_lineHeight;
-
-    SegmentList m_segments;
     SegmentRangeList m_segmentRanges;
     bool m_needsLayout;
 };
index 87fa8c6..cb15df2 100644 (file)
@@ -40,7 +40,27 @@ bool ExclusionShapeOutsideInfo::isEnabledFor(const RenderBox* box)
 {
     // FIXME: Enable shape outside for non-rectangular shapes! (bug 98664)
     ExclusionShapeValue* value = box->style()->shapeOutside();
-    return value && (value->type() == ExclusionShapeValue::SHAPE) && (value->shape()->type() == BasicShape::BASIC_SHAPE_RECTANGLE);
+    return value && (value->type() == ExclusionShapeValue::SHAPE)
+        && (
+            (value->shape()->type() == BasicShape::BASIC_SHAPE_RECTANGLE)
+            || (value->shape()->type() == BasicShape::BASIC_SHAPE_POLYGON)
+        );
+}
+
+bool ExclusionShapeOutsideInfo::computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight)
+{
+    if (shapeSizeDirty() || m_lineTop != lineTop || m_lineHeight != lineHeight) {
+        if (ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside, &ExclusionShape::getExcludedIntervals>::computeSegmentsForLine(lineTop, lineHeight)) {
+            m_leftSegmentShapeBoundingBoxDelta = m_segments[0].logicalLeft - shapeLogicalLeft();
+            m_rightSegmentShapeBoundingBoxDelta = m_segments[m_segments.size()-1].logicalRight - shapeLogicalRight();
+        } else {
+            m_leftSegmentShapeBoundingBoxDelta = 0;
+            m_rightSegmentShapeBoundingBoxDelta = 0;
+        }
+        m_lineTop = lineTop;
+    }
+
+    return m_segments.size();
 }
 
 }
index a4b8128..f543d56 100644 (file)
@@ -39,17 +39,23 @@ namespace WebCore {
 
 class RenderBox;
 
-class ExclusionShapeOutsideInfo : public ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside>, public MappedInfo<RenderBox, ExclusionShapeOutsideInfo> {
+class ExclusionShapeOutsideInfo : public ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside, &ExclusionShape::getExcludedIntervals>, public MappedInfo<RenderBox, ExclusionShapeOutsideInfo> {
 public:
-    LayoutSize shapeLogicalOffset() const
-    {
-        return LayoutSize(shapeLogicalLeft(), shapeLogicalTop());
-    }
+    LayoutSize shapeLogicalOffset() const { return LayoutSize(shapeLogicalLeft(), shapeLogicalTop()); }
+
+    LayoutUnit leftSegmentShapeBoundingBoxDelta() const { return m_leftSegmentShapeBoundingBoxDelta; }
+    LayoutUnit rightSegmentShapeBoundingBoxDelta() const { return m_rightSegmentShapeBoundingBoxDelta; }
+
+    virtual bool computeSegmentsForLine(LayoutUnit lineTop, LayoutUnit lineHeight) OVERRIDE;
 
     static PassOwnPtr<ExclusionShapeOutsideInfo> createInfo(const RenderBox* renderer) { return adoptPtr(new ExclusionShapeOutsideInfo(renderer)); }
     static bool isEnabledFor(const RenderBox*);
 private:
-    ExclusionShapeOutsideInfo(const RenderBox* renderer) : ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside>(renderer) { }
+    ExclusionShapeOutsideInfo(const RenderBox* renderer) : ExclusionShapeInfo<RenderBox, &RenderStyle::shapeOutside, &ExclusionShape::getExcludedIntervals>(renderer) { }
+
+    LayoutUnit m_leftSegmentShapeBoundingBoxDelta;
+    LayoutUnit m_rightSegmentShapeBoundingBoxDelta;
+    LayoutUnit m_lineTop;
 };
 
 }
index 777ce75..bdd21cc 100644 (file)
@@ -4279,6 +4279,10 @@ inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNe
         if (m_heightRemaining)
             *m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
     }
+
+#if ENABLE(CSS_EXCLUSIONS)
+    m_last = r;
+#endif
 }
 
 LayoutUnit RenderBlock::textIndentOffset() const
@@ -4320,6 +4324,15 @@ LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUn
 
         FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining);
         m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_EXCLUSIONS)
+        if (const FloatingObject* lastFloat = adapter.lastFloat()) {
+            if (ExclusionShapeOutsideInfo* shapeOutside = lastFloat->renderer()->exclusionShapeOutsideInfo()) {
+                shapeOutside->computeSegmentsForLine(logicalTop - logicalTopForFloat(lastFloat), logicalHeight);
+                left += shapeOutside->rightSegmentShapeBoundingBoxDelta();
+            }
+        }
+#endif
     }
 
     if (applyTextIndent && style()->isLeftToRightDirection())
@@ -4368,6 +4381,16 @@ LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutU
         LayoutUnit rightFloatOffset = fixedOffset;
         FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining);
         m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
+
+#if ENABLE(CSS_EXCLUSIONS)
+        if (const FloatingObject* lastFloat = adapter.lastFloat()) {
+            if (ExclusionShapeOutsideInfo* shapeOutside = lastFloat->renderer()->exclusionShapeOutsideInfo()) {
+                shapeOutside->computeSegmentsForLine(logicalTop - logicalTopForFloat(lastFloat), logicalHeight);
+                rightFloatOffset += shapeOutside->leftSegmentShapeBoundingBoxDelta();
+            }
+        }
+#endif
+
         right = min(right, rightFloatOffset);
     }
     
index 241d133..421c05a 100644 (file)
@@ -1133,6 +1133,9 @@ protected:
             , m_highValue(highValue)
             , m_offset(offset)
             , m_heightRemaining(heightRemaining)
+#if ENABLE(CSS_EXCLUSIONS)
+            , m_last(0)
+#endif
         {
         }
         
@@ -1140,12 +1143,30 @@ protected:
         inline int highValue() const { return m_highValue; }
         void collectIfNeeded(const IntervalType&) const;
 
+#if ENABLE(CSS_EXCLUSIONS)
+        // When computing the offset caused by the floats on a given line, if
+        // the outermost float on that line has a shape-outside, the inline
+        // content that butts up against that float must be positioned using
+        // the contours of the shape, not the shape's bounding box. We save the
+        // last float encountered so that the offset can be computed correctly
+        // by the code using this adapter.
+        const FloatingObject* lastFloat() const { return m_last; }
+#endif
+
     private:
         const RenderBlock* m_renderer;
         int m_lowValue;
         int m_highValue;
         LayoutUnit& m_offset;
         LayoutUnit* m_heightRemaining;
+#if ENABLE(CSS_EXCLUSIONS)
+        // This member variable is mutable because the collectIfNeeded method
+        // is declared as const, even though it doesn't actually respect that
+        // contract. It modifies other member variables via loopholes in the
+        // const behavior. Instead of using loopholes, I decided it was better
+        // to make the fact that this is modified in a const method explicit.
+        mutable const FloatingObject* m_last;
+#endif
     };
 
     void createFloatingObjects();
index 2120899..8951535 100644 (file)
@@ -175,13 +175,29 @@ inline void LineWidth::shrinkAvailableWidthForNewFloatIfNeeded(RenderBlock::Floa
     if (height < m_block->logicalTopForFloat(newFloat) || height >= m_block->logicalBottomForFloat(newFloat))
         return;
 
+#if ENABLE(CSS_EXCLUSIONS)
+    ExclusionShapeOutsideInfo* shapeOutsideInfo = newFloat->renderer()->exclusionShapeOutsideInfo();
+    if (shapeOutsideInfo)
+        shapeOutsideInfo->computeSegmentsForLine(m_block->logicalHeight() - m_block->logicalTopForFloat(newFloat), logicalHeightForLine(m_block, m_isFirstLine));
+#endif
+
     if (newFloat->type() == RenderBlock::FloatingObject::FloatLeft) {
         float newLeft = m_block->logicalRightForFloat(newFloat);
+#if ENABLE(CSS_EXCLUSIONS)
+        if (shapeOutsideInfo)
+            newLeft += shapeOutsideInfo->rightSegmentShapeBoundingBoxDelta();
+#endif
+
         if (m_isFirstLine && m_block->style()->isLeftToRightDirection())
             newLeft += floorToInt(m_block->textIndentOffset());
         m_left = max<float>(m_left, newLeft);
     } else {
         float newRight = m_block->logicalLeftForFloat(newFloat);
+#if ENABLE(CSS_EXCLUSIONS)
+        if (shapeOutsideInfo)
+            newRight += shapeOutsideInfo->leftSegmentShapeBoundingBoxDelta();
+#endif
+
         if (m_isFirstLine && !m_block->style()->isLeftToRightDirection())
             newRight -= floorToInt(m_block->textIndentOffset());
         m_right = min<float>(m_right, newRight);
@@ -2711,6 +2727,7 @@ InlineIterator RenderBlock::LineBreaker::nextSegmentBreak(InlineBidiResolver& re
             // check if it fits in the current line.
             // If it does, position it now, otherwise, position
             // it after moving to next line (in newLine() func)
+            // FIXME: Bug 110372: Properly position multiple stacked floats with non-rectangular shape outside.
             if (floatsFitOnLine && width.fitsOnLine(m_block->logicalWidthForFloat(f))) {
                 m_block->positionNewFloatOnLine(f, lastFloatFromPreviousLine, lineInfo, width);
                 if (lBreak.m_obj == current.m_obj) {