[CSS Exclusions] Minimal support for using an image to define a shape
authorhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Aug 2013 23:24:45 +0000 (23:24 +0000)
committerhmuller@adobe.com <hmuller@adobe.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 14 Aug 2013 23:24:45 +0000 (23:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=116643

Source/WebCore:

Reviewed by Alexandru Chiculita.

This is a first small step towards supporting CSS shapes defined by an
image URL and a alpha channel threshold. To keep the patch as small as
possible, there are many limitations and remaining work items. For
example images are currently restricted to same-origin, although CORS
should be supported. See https://bugs.webkit.org/show_bug.cgi?id=116348
for the current list.

Test: fast/exclusions/shape-inside/shape-inside-image-001.html
Test: fast/exclusions/shape-inside/shape-inside-image-002.html

* CMakeLists.txt:
* GNUmakefile.list.am:
* Target.pri:
* WebCore.vcxproj/WebCore.vcxproj:
* WebCore.xcodeproj/project.pbxproj:
* rendering/RenderBlock.cpp:
(WebCore::RenderBlock::imageChanged): When the image has finished loading, request a layout.
* rendering/RenderBlock.h:
* rendering/RenderObject.cpp:
(WebCore::RenderObject::setStyle): Add notify clients for shape images.
(WebCore::RenderObject::updateShapeImage):
(WebCore::removeShapeImageClient):
(WebCore::RenderObject::arenaDelete): Remove notify clients for shape images.
* rendering/RenderObject.h:
* rendering/shapes/RasterShape.cpp: Added. A Shape defined by thresholding an image's alpha channel.
(WebCore::RasterShapeIntervals::bounds):
(WebCore::RasterShapeIntervals::addInterval): Add a single run to the shape.
(WebCore::alignedRect):
(WebCore::RasterShapeIntervals::getIntervals): Return the shape's runs that fall within a horizonal box.
(WebCore::RasterShape::marginIntervals): Internal representation of the shape with shape-margin factored in.  Currently only a stub.
(WebCore::RasterShape::paddingIntervals): Internal representation of the shape with shape-padding factored in.  Currently only a stub.
(WebCore::RasterShape::getExcludedIntervals):
(WebCore::RasterShape::getIncludedIntervals):
(WebCore::RasterShape::firstIncludedIntervalLogicalTop):
* rendering/shapes/RasterShape.h:
(WebCore::RasterShapeIntervals::RasterShapeIntervals): Internal run length encoded representation of a RasterShape.
(WebCore::RasterShapeIntervals::isEmpty):
(WebCore::RasterShape::RasterShape):
* rendering/shapes/Shape.cpp:
(WebCore::Shape::createShape): Support for creating a Shape based on a RasterShapeIntervals object.
* rendering/shapes/Shape.h:
* rendering/shapes/ShapeInfo.cpp:
(WebCore::::computedShape): Added support for the Image ShapeValue type.
* rendering/shapes/ShapeInsideInfo.cpp:
(WebCore::ShapeInsideInfo::isEnabledFor): Added support for the Image ShapeValue type.
* rendering/shapes/ShapeOutsideInfo.cpp:
(WebCore::ShapeOutsideInfo::isEnabledFor): Added support for the Image ShapeValue type.
* rendering/style/ShapeValue.h:
(WebCore::ShapeValue::isImageValid): True if the shape's image is ready to be be processed.

LayoutTests:

Two tests to verify that the initial implementation of shape valued images is working
for shape-inside.

Reviewed by Alexandru Chiculita.

* fast/exclusions/shape-inside/shape-inside-image-001-expected.html: Added.
* fast/exclusions/shape-inside/shape-inside-image-001.html: Added.
* fast/exclusions/shape-inside/shape-inside-image-002-expected.html: Added.
* fast/exclusions/shape-inside/shape-inside-image-002.html: Added.

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

23 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/shapes/shape-inside/shape-inside-image-001-expected.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-inside/shape-inside-image-001.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-inside/shape-inside-image-002-expected.html [new file with mode: 0644]
LayoutTests/fast/shapes/shape-inside/shape-inside-image-002.html [new file with mode: 0644]
Source/WebCore/CMakeLists.txt
Source/WebCore/ChangeLog
Source/WebCore/GNUmakefile.list.am
Source/WebCore/Target.pri
Source/WebCore/WebCore.vcxproj/WebCore.vcxproj
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBlock.h
Source/WebCore/rendering/RenderObject.cpp
Source/WebCore/rendering/RenderObject.h
Source/WebCore/rendering/shapes/RasterShape.cpp [new file with mode: 0644]
Source/WebCore/rendering/shapes/RasterShape.h [new file with mode: 0644]
Source/WebCore/rendering/shapes/Shape.cpp
Source/WebCore/rendering/shapes/Shape.h
Source/WebCore/rendering/shapes/ShapeInfo.cpp
Source/WebCore/rendering/shapes/ShapeInsideInfo.cpp
Source/WebCore/rendering/shapes/ShapeOutsideInfo.cpp
Source/WebCore/rendering/style/ShapeValue.h

index 950aaf1..170f53e 100644 (file)
@@ -1,3 +1,18 @@
+2013-08-14  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Exclusions] Minimal support for using an image to define a shape
+        https://bugs.webkit.org/show_bug.cgi?id=116643
+
+        Two tests to verify that the initial implementation of shape valued images is working
+        for shape-inside.
+
+        Reviewed by Alexandru Chiculita.
+
+        * fast/exclusions/shape-inside/shape-inside-image-001-expected.html: Added.
+        * fast/exclusions/shape-inside/shape-inside-image-001.html: Added.
+        * fast/exclusions/shape-inside/shape-inside-image-002-expected.html: Added.
+        * fast/exclusions/shape-inside/shape-inside-image-002.html: Added.
+
 2013-08-14  Brent Fulgham  <bfulgham@apple.com>
 
         [Windows] Unreviewed build gardening.
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-image-001-expected.html b/LayoutTests/fast/shapes/shape-inside/shape-inside-image-001-expected.html
new file mode 100644 (file)
index 0000000..fdbaa72
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #image-shape {
+        border: solid black 1px;
+        font: 12px/1 Ahem, sans-serif;
+        padding: 4px;
+        color: green;
+        width: 24px;
+        height: 24px;
+        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAASklEQVRYCe3XIQ4AMAhD0XXh/lfuMkeCJjUfhSt5YJDtk6ybDP/ZDFBjBdLuUdjqmawAAQQQQAABBBBAAAEE4gLiN+xfSqKP38ADuQMJO6LNbr4AAAAASUVORK5CYII=");
+        background-repeat: no-repeat;
+    }
+</style>
+</head>
+<body>
+  <p id="informative-text">
+      This test requires the Ahem font. It uses a 32x32 PNG image with a 24x24 red square in the center
+      to define a shape-inside. The content should just cover the shape with solid green.</p>
+
+  <div id="image-shape">XX<br/>XX</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-image-001.html b/LayoutTests/fast/shapes/shape-inside/shape-inside-image-001.html
new file mode 100644 (file)
index 0000000..46ec7b1
--- /dev/null
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #image-shape {
+        border: solid black 1px;
+        font: 12px/1 Ahem, sans-serif;
+        color: green;
+        width: 32px;
+        height: 32px;
+        -webkit-shape-inside: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAASklEQVRYCe3XIQ4AMAhD0XXh/lfuMkeCJjUfhSt5YJDtk6ybDP/ZDFBjBdLuUdjqmawAAQQQQAABBBBAAAEE4gLiN+xfSqKP38ADuQMJO6LNbr4AAAAASUVORK5CYII=");
+        -webkit-shape-image-threshold: 0;
+        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAASklEQVRYCe3XIQ4AMAhD0XXh/lfuMkeCJjUfhSt5YJDtk6ybDP/ZDFBjBdLuUdjqmawAAQQQQAABBBBAAAEE4gLiN+xfSqKP38ADuQMJO6LNbr4AAAAASUVORK5CYII=");
+        background-repeat: no-repeat;
+    }
+</style>
+</head>
+<body>
+  <p id="informative-text">
+      This test requires the Ahem font. It uses a 32x32 PNG image with a 24x24 red square in the center
+      to define a shape-inside. The content should just cover the shape with solid green.</p>
+
+  <div id="image-shape">XX XX</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-image-002-expected.html b/LayoutTests/fast/shapes/shape-inside/shape-inside-image-002-expected.html
new file mode 100644 (file)
index 0000000..5a53fe8
--- /dev/null
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #image-shape {
+        font: 12px/1 Ahem, sans-serif;
+        color: green;
+        width: 24px;
+        height: 24px;
+        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAARElEQVRYCe3XsQ0AIAgEQHH/nV8n0AptjtCREHI0UBljZ2Mkdeo+T8UXNQMQIECAAAECBAgQIFBJ71twO+2tgACB7wILoI8HOaOmzFsAAAAASUVORK5CYII=");
+        background-repeat: no-repeat;
+    }
+</style>
+</head>
+<body>
+  <p id="informative-text">
+      This test requires the Ahem font. It uses a 24x24 square PNG image where all pixels are red,
+      to define a shape-inside. The content should just cover the shape with solid green.</p>
+  <div id="image-shape">XX<br/>XX</div>
+</body>
+</html>
diff --git a/LayoutTests/fast/shapes/shape-inside/shape-inside-image-002.html b/LayoutTests/fast/shapes/shape-inside/shape-inside-image-002.html
new file mode 100644 (file)
index 0000000..07984e0
--- /dev/null
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    #image-shape {
+        font: 12px/1 Ahem, sans-serif;
+        color: green;
+        width: 24px;
+        height: 24px;
+        -webkit-shape-inside: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAARElEQVRYCe3XsQ0AIAgEQHH/nV8n0AptjtCREHI0UBljZ2Mkdeo+T8UXNQMQIECAAAECBAgQIFBJ71twO+2tgACB7wILoI8HOaOmzFsAAAAASUVORK5CYII=");
+        -webkit-shape-image-threshold: 0;
+        background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAARElEQVRYCe3XsQ0AIAgEQHH/nV8n0AptjtCREHI0UBljZ2Mkdeo+T8UXNQMQIECAAAECBAgQIFBJ71twO+2tgACB7wILoI8HOaOmzFsAAAAASUVORK5CYII=");
+        background-repeat: no-repeat;
+    }
+</style>
+</head>
+<body>
+  <p id="informative-text">
+      This test requires the Ahem font. It uses a 24x24 square PNG image where all pixels are red,
+      to define a shape-inside. The content should just cover the shape with solid green.</p>
+
+  <div id="image-shape">XX XX</div>
+</body>
+</html>
index dade76f..0fa6cd7 100644 (file)
@@ -2221,6 +2221,7 @@ set(WebCore_SOURCES
     rendering/mathml/RenderMathMLUnderOver.cpp
 
     rendering/shapes/PolygonShape.cpp
+    rendering/shapes/RasterShape.cpp
     rendering/shapes/RectangleShape.cpp
     rendering/shapes/Shape.cpp
     rendering/shapes/ShapeInfo.cpp
index 8cb61b4..90afd22 100644 (file)
@@ -1,3 +1,60 @@
+2013-08-14  Hans Muller  <hmuller@adobe.com>
+
+        [CSS Exclusions] Minimal support for using an image to define a shape
+        https://bugs.webkit.org/show_bug.cgi?id=116643
+
+        Reviewed by Alexandru Chiculita.
+
+        This is a first small step towards supporting CSS shapes defined by an
+        image URL and a alpha channel threshold. To keep the patch as small as
+        possible, there are many limitations and remaining work items. For
+        example images are currently restricted to same-origin, although CORS
+        should be supported. See https://bugs.webkit.org/show_bug.cgi?id=116348
+        for the current list.
+
+        Test: fast/exclusions/shape-inside/shape-inside-image-001.html
+        Test: fast/exclusions/shape-inside/shape-inside-image-002.html
+
+        * CMakeLists.txt:
+        * GNUmakefile.list.am:
+        * Target.pri:
+        * WebCore.vcxproj/WebCore.vcxproj:
+        * WebCore.xcodeproj/project.pbxproj:
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::imageChanged): When the image has finished loading, request a layout.
+        * rendering/RenderBlock.h:
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::setStyle): Add notify clients for shape images.
+        (WebCore::RenderObject::updateShapeImage):
+        (WebCore::removeShapeImageClient):
+        (WebCore::RenderObject::arenaDelete): Remove notify clients for shape images.
+        * rendering/RenderObject.h:
+        * rendering/shapes/RasterShape.cpp: Added. A Shape defined by thresholding an image's alpha channel.
+        (WebCore::RasterShapeIntervals::bounds):
+        (WebCore::RasterShapeIntervals::addInterval): Add a single run to the shape.
+        (WebCore::alignedRect):
+        (WebCore::RasterShapeIntervals::getIntervals): Return the shape's runs that fall within a horizonal box.
+        (WebCore::RasterShape::marginIntervals): Internal representation of the shape with shape-margin factored in.  Currently only a stub.
+        (WebCore::RasterShape::paddingIntervals): Internal representation of the shape with shape-padding factored in.  Currently only a stub.
+        (WebCore::RasterShape::getExcludedIntervals):
+        (WebCore::RasterShape::getIncludedIntervals):
+        (WebCore::RasterShape::firstIncludedIntervalLogicalTop):
+        * rendering/shapes/RasterShape.h:
+        (WebCore::RasterShapeIntervals::RasterShapeIntervals): Internal run length encoded representation of a RasterShape.
+        (WebCore::RasterShapeIntervals::isEmpty):
+        (WebCore::RasterShape::RasterShape):
+        * rendering/shapes/Shape.cpp:
+        (WebCore::Shape::createShape): Support for creating a Shape based on a RasterShapeIntervals object.
+        * rendering/shapes/Shape.h:
+        * rendering/shapes/ShapeInfo.cpp:
+        (WebCore::::computedShape): Added support for the Image ShapeValue type.
+        * rendering/shapes/ShapeInsideInfo.cpp:
+        (WebCore::ShapeInsideInfo::isEnabledFor): Added support for the Image ShapeValue type.
+        * rendering/shapes/ShapeOutsideInfo.cpp:
+        (WebCore::ShapeOutsideInfo::isEnabledFor): Added support for the Image ShapeValue type.
+        * rendering/style/ShapeValue.h:
+        (WebCore::ShapeValue::isImageValid): True if the shape's image is ready to be be processed.
+
 2013-08-14  Alexandru Chiculita  <achicu@adobe.com>
 
         [CSS Regions] RenderRegions should have a RenderLayer+Backing when they contain a Composited RenderLayer
index fc7a632..d57f4c0 100644 (file)
@@ -4598,6 +4598,8 @@ webcore_sources += \
        Source/WebCore/rendering/mathml/RenderMathMLUnderOver.h \
        Source/WebCore/rendering/shapes/PolygonShape.cpp \
        Source/WebCore/rendering/shapes/PolygonShape.h \
+       Source/WebCore/rendering/shapes/RasterShape.cpp \
+       Source/WebCore/rendering/shapes/RasterShape.h \
        Source/WebCore/rendering/shapes/RectangleShape.cpp \
        Source/WebCore/rendering/shapes/RectangleShape.h \
        Source/WebCore/rendering/shapes/Shape.cpp \
index ad01a51..634da2e 100644 (file)
@@ -1232,6 +1232,7 @@ SOURCES += \
     rendering/RootInlineBox.cpp \
     rendering/ScrollBehavior.cpp \
     rendering/shapes/PolygonShape.cpp \
+    rendering/shapes/RasterShape.cpp \
     rendering/shapes/RectangleShape.cpp \
     rendering/shapes/Shape.cpp \
     rendering/shapes/ShapeInfo.cpp \
@@ -2493,6 +2494,7 @@ HEADERS += \
     rendering/RootInlineBox.h \
     rendering/ScrollBehavior.h \
     rendering/shapes/PolygonShape.h \
+    rendering/shapes/RasterShape.h \
     rendering/shapes/RectangleShape.h \
     rendering/shapes/Shape.h \
     rendering/shapes/ShapeInfo.h \
index 5a488b0..8bc5a85 100644 (file)
       <ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Production|x64'">true</ExcludedFromBuild>
     </ClCompile>
     <ClCompile Include="..\rendering\shapes\PolygonShape.cpp" />
+    <ClCompile Include="..\rendering\shapes\RasterShape.cpp" />
     <ClCompile Include="..\rendering\shapes\RectangleShape.cpp" />
     <ClCompile Include="..\rendering\shapes\Shape.cpp" />
     <ClCompile Include="..\rendering\shapes\ShapeInsideInfo.cpp" />
     <ClInclude Include="..\rendering\RenderSlider.h" />
     <ClInclude Include="..\rendering\RenderSnapshottedPlugIn.h" />
     <ClInclude Include="..\rendering\shapes\PolygonShape.h" />
+    <ClInclude Include="..\rendering\shapes\RasterShape.h" />
     <ClInclude Include="..\rendering\shapes\RectangleShape.h" />
     <ClInclude Include="..\rendering\shapes\Shape.h" />
     <ClInclude Include="..\rendering\shapes\ShapeInsideInfo.h" />
index e7c4463..ebc5cc3 100644 (file)
                6E67D2A61280E8A4008758F7 /* Extensions3DOpenGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6E67D2A41280E8A4008758F7 /* Extensions3DOpenGL.cpp */; };
                6E67D2A71280E8A4008758F7 /* Extensions3DOpenGL.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E67D2A51280E8A4008758F7 /* Extensions3DOpenGL.h */; };
                6E67D2A91280E8BD008758F7 /* Extensions3D.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E67D2A81280E8BD008758F7 /* Extensions3D.h */; };
+               6E84E9E017668BEE00815B68 /* RasterShape.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6E84E9DE17668BAD00815B68 /* RasterShape.cpp */; };
+               6E84E9E117668BF100815B68 /* RasterShape.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E84E9DF17668BAD00815B68 /* RasterShape.h */; settings = {ATTRIBUTES = (Private, ); }; };
                6EBC5EAF138B50F200A0CF8A /* JSFloat64Array.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EBC5EAD138B50F200A0CF8A /* JSFloat64Array.cpp */; };
                6EBC5EB0138B50F200A0CF8A /* JSFloat64Array.h in Headers */ = {isa = PBXBuildFile; fileRef = 6EBC5EAE138B50F200A0CF8A /* JSFloat64Array.h */; };
                6EBF0E4812A8926100DB1709 /* OESTextureFloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6EBF0E4512A8926100DB1709 /* OESTextureFloat.cpp */; };
                6E67D2A41280E8A4008758F7 /* Extensions3DOpenGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Extensions3DOpenGL.cpp; sourceTree = "<group>"; };
                6E67D2A51280E8A4008758F7 /* Extensions3DOpenGL.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Extensions3DOpenGL.h; sourceTree = "<group>"; };
                6E67D2A81280E8BD008758F7 /* Extensions3D.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Extensions3D.h; sourceTree = "<group>"; };
+               6E84E9DE17668BAD00815B68 /* RasterShape.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RasterShape.cpp; sourceTree = "<group>"; };
+               6E84E9DF17668BAD00815B68 /* RasterShape.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RasterShape.h; sourceTree = "<group>"; };
                6EBC5D80138B4C4E00A0CF8A /* Float64Array.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = Float64Array.idl; path = canvas/Float64Array.idl; sourceTree = "<group>"; };
                6EBC5EAD138B50F200A0CF8A /* JSFloat64Array.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFloat64Array.cpp; sourceTree = "<group>"; };
                6EBC5EAE138B50F200A0CF8A /* JSFloat64Array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSFloat64Array.h; sourceTree = "<group>"; };
                        children = (
                                FD08A87A175D3926002CD360 /* PolygonShape.cpp */,
                                FD08A87B175D3926002CD360 /* PolygonShape.h */,
+                               6E84E9DE17668BAD00815B68 /* RasterShape.cpp */,
+                               6E84E9DF17668BAD00815B68 /* RasterShape.h */,
                                FD08A87C175D3926002CD360 /* RectangleShape.cpp */,
                                FD08A87D175D3926002CD360 /* RectangleShape.h */,
                                FD08A87E175D3926002CD360 /* Shape.cpp */,
                        files = (
                                FE115FAB167988CD00249134 /* AbstractDatabaseServer.h in Headers */,
                                FE4AADEE16D2C37400026FFC /* AbstractSQLStatement.h in Headers */,
+                               6E84E9E117668BF100815B68 /* RasterShape.h in Headers */,
                                FE4AADEF16D2C37400026FFC /* AbstractSQLStatementBackend.h in Headers */,
                                41E1B1D10FF5986900576B3B /* AbstractWorker.h in Headers */,
                                29A8122E0FBB9C1D00510293 /* AccessibilityARIAGridCell.h in Headers */,
                                FD537352137B651800008DCE /* ZeroPole.cpp in Sources */,
                                FD1762DF176686D900D836A8 /* UpSampler.cpp in Sources */,
                                FD1762E3176686EA00D836A8 /* DownSampler.cpp in Sources */,
+                               6E84E9E017668BEE00815B68 /* RasterShape.cpp in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index fd5e404..a1e912f 100644 (file)
@@ -1436,6 +1436,21 @@ void RenderBlock::layout()
 }
 
 #if ENABLE(CSS_SHAPES)
+void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
+{
+    RenderBox::imageChanged(image);
+
+    if (!parent())
+        return;
+
+    ShapeValue* shapeValue = style()->shapeInside();
+    if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) {
+        ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
+        shapeInsideInfo->dirtyShapeSize();
+        markShapeInsideDescendantsForLayout();
+    }
+}
+
 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
 {
     // FIXME: A future optimization would do a deep comparison for equality.
index 3a27559..cd441a1 100644 (file)
@@ -472,6 +472,7 @@ public:
     void markShapeInsideDescendantsForLayout();
     ShapeInsideInfo* layoutShapeInsideInfo() const;
     bool allowsShapeInsideInfoSharing() const { return !isInline() && !isFloating(); }
+    virtual void imageChanged(WrappedImagePtr, const IntRect* = 0) OVERRIDE;
 #endif
 
 protected:
index 9819175..172ee7d 100644 (file)
@@ -1850,6 +1850,10 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
     updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0);
     updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0);
 
+#if ENABLE(CSS_SHAPES)
+    updateShapeImage(oldStyle ? oldStyle->shapeInside() : 0, m_style ? m_style->shapeInside() : 0);
+#endif
+
     // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen
     // during styleDidChange (it's used by clippedOverflowRectForRepaint()).
     if (m_style->outlineWidth() > 0 && m_style->outlineSize() > maximalOutlineSize(PaintPhaseOutline))
@@ -2102,6 +2106,14 @@ void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
     }
 }
 
+#if ENABLE(CSS_SHAPES)
+void RenderObject::updateShapeImage(const ShapeValue* oldShapeValue, const ShapeValue* newShapeValue)
+{
+    if (oldShapeValue || newShapeValue)
+        updateImage(oldShapeValue ? oldShapeValue->image() : 0, newShapeValue ? newShapeValue->image() : 0);
+}
+#endif
+
 LayoutRect RenderObject::viewRect() const
 {
     return view()->viewRect();
@@ -2620,6 +2632,16 @@ void RenderObject::destroy()
     arenaDelete(renderArena(), this);
 }
 
+#if ENABLE(CSS_SHAPES)
+void RenderObject::removeShapeImageClient(ShapeValue* shapeValue)
+{
+    if (!shapeValue)
+        return;
+    if (StyleImage* shapeImage = shapeValue->image())
+        shapeImage->removeClient(this);
+}
+#endif
+
 void RenderObject::arenaDelete(RenderArena* arena, void* base)
 {
     if (m_style) {
@@ -2638,6 +2660,10 @@ void RenderObject::arenaDelete(RenderArena* arena, void* base)
 
         if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
             maskBoxImage->removeClient(this);
+
+#if ENABLE(CSS_SHAPES)
+        removeShapeImageClient(m_style->shapeInside());
+#endif
     }
 
 #ifndef NDEBUG
index 3a1350a..eed03db 100644 (file)
@@ -694,6 +694,9 @@ public:
 
     void updateFillImages(const FillLayer*, const FillLayer*);
     void updateImage(StyleImage*, StyleImage*);
+#if ENABLE(CSS_SHAPES)
+    void updateShapeImage(const ShapeValue*, const ShapeValue*);
+#endif
 
     virtual void paint(PaintInfo&, const LayoutPoint&);
 
@@ -1026,6 +1029,10 @@ private:
 
     Color selectionColor(int colorProperty) const;
 
+#if ENABLE(CSS_SHAPES)
+    void removeShapeImageClient(ShapeValue*);
+#endif
+
 #ifndef NDEBUG
     void checkBlockPositionedObjectsNeedLayout();
 #endif
diff --git a/Source/WebCore/rendering/shapes/RasterShape.cpp b/Source/WebCore/rendering/shapes/RasterShape.cpp
new file mode 100644 (file)
index 0000000..86ae253
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "RasterShape.h"
+
+#include "ShapeInterval.h"
+#include <wtf/MathExtras.h>
+
+namespace WebCore {
+
+IntRect RasterShapeIntervals::bounds() const
+{
+    if (!m_bounds)
+        m_bounds = adoptPtr(new IntRect(m_region.bounds()));
+    return *m_bounds;
+}
+
+void RasterShapeIntervals::addInterval(int y, int x1, int x2)
+{
+    m_region.unite(Region(IntRect(x1, y, x2 - x1, 1)));
+    m_bounds.clear();
+}
+
+static inline IntRect alignedRect(IntRect r, int y1, int y2)
+{
+    return IntRect(r.x(), y1, r.width(), y2 - y1);
+}
+
+void RasterShapeIntervals::getIncludedIntervals(int y1, int y2, SegmentList& result) const
+{
+    ASSERT(y2 >= y1);
+
+    IntRect lineRect(bounds().x(), y1, bounds().width(), y2 - y1);
+    Region lineRegion(lineRect);
+    lineRegion.intersect(m_region);
+    if (lineRegion.isEmpty())
+        return;
+
+    Vector<IntRect> lineRects = lineRegion.rects();
+    ASSERT(lineRects.size() > 0);
+
+    Region segmentsRegion(lineRect);
+    Region intervalsRegion;
+
+    // The loop below uses Regions to compute the intersection of the horizontal
+    // shape intervals that fall within the line's box.
+    int lineY = lineRects[0].y();
+    for (unsigned i = 0; i < lineRects.size(); ++i) {
+        if (lineRects[i].y() != lineY) {
+            segmentsRegion.intersect(intervalsRegion);
+            intervalsRegion = Region();
+        }
+        intervalsRegion.unite(Region(alignedRect(lineRects[i], y1, y2)));
+        lineY = lineRects[i].y();
+    }
+    if (!intervalsRegion.isEmpty())
+        segmentsRegion.intersect(intervalsRegion);
+
+    Vector<IntRect> segmentRects = segmentsRegion.rects();
+    for (unsigned i = 0; i < segmentRects.size(); ++i)
+        result.append(LineSegment(segmentRects[i].x(), segmentRects[i].maxX()));
+}
+
+const RasterShapeIntervals& RasterShape::marginIntervals() const
+{
+    ASSERT(shapeMargin() >= 0);
+    if (!shapeMargin())
+        return *m_intervals;
+
+    // FIXME: Add support for non-zero margin, see https://bugs.webkit.org/show_bug.cgi?id=116348.
+    return *m_intervals;
+}
+
+const RasterShapeIntervals& RasterShape::paddingIntervals() const
+{
+    ASSERT(shapePadding() >= 0);
+    if (!shapePadding())
+        return *m_intervals;
+
+    // FIXME: Add support for non-zero padding, see https://bugs.webkit.org/show_bug.cgi?id=116348.
+    return *m_intervals;
+}
+
+void RasterShape::getExcludedIntervals(LayoutUnit, LayoutUnit, SegmentList&) const
+{
+    // FIXME: this method is only a stub, see https://bugs.webkit.org/show_bug.cgi?id=119809.
+}
+
+void RasterShape::getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList& result) const
+{
+    const RasterShapeIntervals& intervals = paddingIntervals();
+    if (intervals.isEmpty())
+        return;
+
+    float y1 = logicalTop;
+    float y2 = logicalTop + logicalHeight;
+
+    if (y1 < intervals.bounds().y() || y2 > intervals.bounds().maxY())
+        return;
+
+    intervals.getIncludedIntervals(y1, y2, result);
+}
+
+bool RasterShape::firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit& result) const
+{
+    float minIntervalTop = minLogicalIntervalTop;
+    float minIntervalHeight = minLogicalIntervalSize.height();
+    float minIntervalWidth = minLogicalIntervalSize.width();
+
+    const RasterShapeIntervals& intervals = paddingIntervals();
+    if (intervals.isEmpty() || minIntervalWidth > intervals.bounds().width())
+        return false;
+
+    float minY = std::max<float>(intervals.bounds().y(), minIntervalTop);
+    float maxY = minY + minIntervalHeight;
+
+    if (maxY > intervals.bounds().maxY())
+        return false;
+
+    // FIXME: Complete this method, see https://bugs.webkit.org/show_bug.cgi?id=116348.
+    result = minY;
+    return true;
+}
+
+} // namespace WebCore
diff --git a/Source/WebCore/rendering/shapes/RasterShape.h b/Source/WebCore/rendering/shapes/RasterShape.h
new file mode 100644 (file)
index 0000000..a305d43
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef RasterShape_h
+#define RasterShape_h
+
+#include "FloatRect.h"
+#include "Region.h"
+#include "Shape.h"
+#include <wtf/Assertions.h>
+#include <wtf/Vector.h>
+
+namespace WebCore {
+
+class RasterShapeIntervals {
+public:
+    RasterShapeIntervals() { }
+
+    IntRect bounds() const;
+    bool isEmpty() const  { return m_region.isEmpty(); }
+    void addInterval(int y, int x1, int x2);
+    void getIncludedIntervals(int y1, int y2, SegmentList&) const;
+
+private:
+    Region m_region;
+    mutable OwnPtr<IntRect> m_bounds; // Cached value of m_region.bounds().
+};
+
+class RasterShape : public Shape {
+    WTF_MAKE_NONCOPYABLE(RasterShape);
+public:
+    RasterShape(PassOwnPtr<RasterShapeIntervals> intervals)
+        : Shape()
+        , m_intervals(intervals)
+    {
+    }
+
+    virtual LayoutRect shapeMarginLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(marginIntervals().bounds()); }
+    virtual LayoutRect shapePaddingLogicalBoundingBox() const OVERRIDE { return static_cast<LayoutRect>(paddingIntervals().bounds()); }
+    virtual bool isEmpty() const OVERRIDE { return m_intervals->isEmpty(); }
+    virtual void getExcludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+    virtual void getIncludedIntervals(LayoutUnit logicalTop, LayoutUnit logicalHeight, SegmentList&) const OVERRIDE;
+    virtual bool firstIncludedIntervalLogicalTop(LayoutUnit minLogicalIntervalTop, const LayoutSize& minLogicalIntervalSize, LayoutUnit&) const OVERRIDE;
+
+private:
+    const RasterShapeIntervals& marginIntervals() const;
+    const RasterShapeIntervals& paddingIntervals() const;
+
+    OwnPtr<RasterShapeIntervals> m_intervals;
+};
+
+} // namespace WebCore
+
+#endif // RasterShape_h
index 810ac55..b3b9d6d 100644 (file)
 #include "Shape.h"
 
 #include "BasicShapeFunctions.h"
+#include "CachedImage.h"
 #include "FloatSize.h"
+#include "ImageBuffer.h"
 #include "LengthFunctions.h"
 #include "PolygonShape.h"
+#include "RasterShape.h"
 #include "RectangleShape.h"
 #include "WindRule.h"
 #include <wtf/MathExtras.h>
@@ -200,4 +203,46 @@ PassOwnPtr<Shape> Shape::createShape(const BasicShape* basicShape, const LayoutS
     return shape.release();
 }
 
+PassOwnPtr<Shape> Shape::createShape(const StyleImage* styleImage, float threshold, const LayoutSize&, WritingMode writingMode, Length margin, Length padding)
+{
+    ASSERT(styleImage && styleImage->isCachedImage() && styleImage->cachedImage() && styleImage->cachedImage()->image());
+
+    OwnPtr<RasterShapeIntervals> intervals = adoptPtr(new RasterShapeIntervals());
+
+    Image* image = styleImage->cachedImage()->image();
+    const IntSize& imageSize = image->size();
+    OwnPtr<ImageBuffer> imageBuffer = ImageBuffer::create(imageSize);
+    if (imageBuffer) {
+        GraphicsContext* graphicsContext = imageBuffer->context();
+        graphicsContext->drawImage(image, ColorSpaceDeviceRGB, IntPoint());
+
+        RefPtr<Uint8ClampedArray> pixelArray = imageBuffer->getUnmultipliedImageData(IntRect(IntPoint(), imageSize));
+        unsigned pixelArrayLength = pixelArray->length();
+        unsigned pixelArrayOffset = 3; // Each pixel is four bytes: RGBA.
+        uint8_t alphaPixelThreshold = threshold * 255;
+
+        if (static_cast<unsigned>(imageSize.width() * imageSize.height() * 4) == pixelArrayLength) { // sanity check
+            for (int y = 0; y < imageSize.height(); ++y) {
+                int startX = -1;
+                for (int x = 0; x < imageSize.width(); ++x, pixelArrayOffset += 4) {
+                    uint8_t alpha = pixelArray->item(pixelArrayOffset);
+                    bool alphaAboveThreshold = alpha > alphaPixelThreshold;
+                    if (startX == -1 && alphaAboveThreshold) {
+                        startX = x;
+                    } else if (startX != -1 && (!alphaAboveThreshold || x == imageSize.width() - 1)) {
+                        intervals->addInterval(y, startX, x);
+                        startX = -1;
+                    }
+                }
+            }
+        }
+    }
+
+    OwnPtr<RasterShape> rasterShape = adoptPtr(new RasterShape(intervals.release()));
+    rasterShape->m_writingMode = writingMode;
+    rasterShape->m_margin = floatValueForLength(margin, 0);
+    rasterShape->m_padding = floatValueForLength(padding, 0);
+    return rasterShape.release();
+}
+
 } // namespace WebCore
index 0d9ecfd..f775e5e 100644 (file)
@@ -32,6 +32,7 @@
 
 #include "BasicShapes.h"
 #include "LayoutRect.h"
+#include "StyleImage.h"
 #include "WritingMode.h"
 #include <wtf/PassOwnPtr.h>
 #include <wtf/Vector.h>
@@ -60,6 +61,7 @@ typedef Vector<LineSegment> SegmentList;
 class Shape {
 public:
     static PassOwnPtr<Shape> createShape(const BasicShape*, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding);
+    static PassOwnPtr<Shape> createShape(const StyleImage*, float threshold, const LayoutSize& logicalBoxSize, WritingMode, Length margin, Length padding);
 
     virtual ~Shape() { }
 
index e115583..bf94e42 100644 (file)
@@ -45,12 +45,26 @@ const Shape* ShapeInfo<RenderType, shapeGetter, intervalGetter>::computedShape()
     if (Shape* shape = m_shape.get())
         return shape;
 
-    ShapeValue* shapeValue = (m_renderer->style()->*shapeGetter)();
-    BasicShape* shape = (shapeValue && shapeValue->type() == ShapeValue::Shape) ? shapeValue->shape() : 0;
+    const LayoutSize logicalBoxSize(m_shapeLogicalWidth, m_shapeLogicalHeight);
+    WritingMode writingMode = m_renderer->style()->writingMode();
+    Length margin = m_renderer->style()->shapeMargin();
+    Length padding = m_renderer->style()->shapePadding();
+    const ShapeValue* shapeValue = (m_renderer->style()->*shapeGetter)();
+    ASSERT(shapeValue);
 
-    ASSERT(shape);
+    switch (shapeValue->type()) {
+    case ShapeValue::Shape:
+        ASSERT(shapeValue->shape());
+        m_shape = Shape::createShape(shapeValue->shape(), logicalBoxSize, writingMode, margin, padding);
+        break;
+    case ShapeValue::Image:
+        ASSERT(shapeValue->image());
+        m_shape = Shape::createShape(shapeValue->image(), 0, logicalBoxSize, writingMode, margin, padding);
+        break;
+    default:
+        ASSERT_NOT_REACHED();
+    }
 
-    m_shape = Shape::createShape(shape, LayoutSize(m_shapeLogicalWidth, m_shapeLogicalHeight), m_renderer->style()->writingMode(), m_renderer->style()->shapeMargin(), m_renderer->style()->shapePadding());
     ASSERT(m_shape);
     return m_shape.get();
 }
index d1295d0..1c8e113 100644 (file)
@@ -46,11 +46,17 @@ LineSegmentRange::LineSegmentRange(const InlineIterator& start, const InlineIter
 bool ShapeInsideInfo::isEnabledFor(const RenderBlock* renderer)
 {
     ShapeValue* shapeValue = renderer->style()->resolvedShapeInside();
-    if (!shapeValue || shapeValue->type() != ShapeValue::Shape)
+    if (!shapeValue)
         return false;
 
-    BasicShape* shape = shapeValue->shape();
-    return shape && shape->type() != BasicShape::BasicShapeInsetRectangleType;
+    switch (shapeValue->type()) {
+    case ShapeValue::Shape:
+        return shapeValue->shape() && shapeValue->shape()->type() != BasicShape::BasicShapeInsetRectangleType;
+    case ShapeValue::Image:
+        return shapeValue->isImageValid();
+    default:
+        return false;
+    }
 }
 
 bool ShapeInsideInfo::adjustLogicalLineTop(float minSegmentWidth)
index 9ffe7dc..3dc4af6 100644 (file)
 namespace WebCore {
 bool ShapeOutsideInfo::isEnabledFor(const RenderBox* box)
 {
-    ShapeValue* value = box->style()->shapeOutside();
-    return box->isFloatingWithShapeOutside() && value->type() == ShapeValue::Shape && value->shape();
+    ShapeValue* shapeValue = box->style()->shapeOutside();
+    if (!box->isFloatingWithShapeOutside() || !shapeValue)
+        return false;
+
+    switch (shapeValue->type()) {
+    case ShapeValue::Shape:
+        return shapeValue->shape();
+    case ShapeValue::Image:
+        return false; // FIXME, see https://bugs.webkit.org/show_bug.cgi?id=119809.
+    default:
+        return false;
+    }
 }
 
 bool ShapeOutsideInfo::computeSegmentsForContainingBlockLine(LayoutUnit lineTop, LayoutUnit floatTop, LayoutUnit lineHeight)
index 674aeeb..a47ed0a 100644 (file)
@@ -31,6 +31,7 @@
 #define ShapeValue_h
 
 #include "BasicShapes.h"
+#include "CachedImage.h"
 #include "StyleImage.h"
 #include <wtf/PassRefPtr.h>
 
@@ -62,12 +63,16 @@ public:
 
     ShapeValueType type() const { return m_type; }
     BasicShape* shape() const { return m_shape.get(); }
+
     StyleImage* image() const { return m_image.get(); }
+    bool isImageValid() const { return image() && image()->cachedImage() && image()->cachedImage()->hasImage(); }
     void setImage(PassRefPtr<StyleImage> image)
     {
+        ASSERT(type() == Image);
         if (m_image != image)
             m_image = image;
     }
+
     bool operator==(const ShapeValue& other) const { return type() == other.type(); }
 
 private: