Bug 1381453 - Support SVG context paint on ::-moz-tree-twisty list-style-image. r=dholbert draft
authorTim Nguyen <ntim.bugs@gmail.com>
Tue, 27 Mar 2018 00:08:16 +0000
changeset 772807 03c52902209811ccde4b9c6359042cc34af0438f
parent 772729 5f697a19ee4fbe592d2677b82f4d0cce97593c03
push id104053
push userbmo:ntim.bugs@gmail.com
push dateTue, 27 Mar 2018 00:09:41 +0000
reviewersdholbert
bugs1381453
milestone61.0a1
Bug 1381453 - Support SVG context paint on ::-moz-tree-twisty list-style-image. r=dholbert MozReview-Commit-ID: E9966Bwog5W
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/reftests/xul/reftest.list
layout/reftests/xul/treetwisty-context-paint.svg
layout/reftests/xul/treetwisty-no-context-paint.svg
layout/reftests/xul/treetwisty-svg-context-paint-1-ref.xul
layout/reftests/xul/treetwisty-svg-context-paint-1.xul
layout/svg/nsSVGImageFrame.cpp
layout/xul/tree/nsTreeBodyFrame.cpp
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -7007,16 +7007,17 @@ DrawImageInternal(gfxContext&           
 
 /* static */ ImgDrawResult
 nsLayoutUtils::DrawSingleUnscaledImage(gfxContext&          aContext,
                                        nsPresContext*       aPresContext,
                                        imgIContainer*       aImage,
                                        const SamplingFilter aSamplingFilter,
                                        const nsPoint&       aDest,
                                        const nsRect*        aDirty,
+                                       const Maybe<SVGImageContext>& aSVGContext,
                                        uint32_t             aImageFlags,
                                        const nsRect*        aSourceArea)
 {
   CSSIntSize imageSize;
   aImage->GetWidth(&imageSize.width);
   aImage->GetHeight(&imageSize.height);
   if (imageSize.width < 1 || imageSize.height < 1) {
     NS_WARNING("Image width or height is non-positive");
@@ -7035,17 +7036,17 @@ nsLayoutUtils::DrawSingleUnscaledImage(g
   nsRect fill(aDest, source.Size());
   // Ensure that only a single image tile is drawn. If aSourceArea extends
   // outside the image bounds, we want to honor the aSourceArea-to-aDest
   // translation but we don't want to actually tile the image.
   fill.IntersectRect(fill, dest);
   return DrawImageInternal(aContext, aPresContext,
                            aImage, aSamplingFilter,
                            dest, fill, aDest, aDirty ? *aDirty : dest,
-                           /* no SVGImageContext */ Nothing(), aImageFlags);
+                           aSVGContext, aImageFlags);
 }
 
 /* static */ ImgDrawResult
 nsLayoutUtils::DrawSingleImage(gfxContext&            aContext,
                                nsPresContext*         aPresContext,
                                imgIContainer*         aImage,
                                const SamplingFilter   aSamplingFilter,
                                const nsRect&          aDest,
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -1864,28 +1864,37 @@ public:
    *
    *   @param aRenderingContext Where to draw the image, set up with an
    *                            appropriate scale and transform for drawing in
    *                            app units.
    *   @param aImage            The image.
    *   @param aDest             The top-left where the image should be drawn.
    *   @param aDirty            If non-null, then pixels outside this area may
    *                            be skipped.
+   *   @param aSVGContext       Optionally provides an SVGImageContext.
+   *                            Callers should pass an SVGImageContext with at
+   *                            least the viewport size set if aImage may be of
+   *                            type imgIContainer::TYPE_VECTOR, or pass
+   *                            Nothing() if it is of type
+   *                            imgIContainer::TYPE_RASTER (to save cycles
+   *                            constructing an SVGImageContext, since this
+   *                            argument will be ignored for raster images).
    *   @param aImageFlags       Image flags of the imgIContainer::FLAG_* variety
    *   @param aSourceArea       If non-null, this area is extracted from
    *                            the image and drawn at aDest. It's
    *                            in appunits. For best results it should
    *                            be aligned with image pixels.
    */
   static ImgDrawResult DrawSingleUnscaledImage(gfxContext&          aContext,
                                             nsPresContext*       aPresContext,
                                             imgIContainer*       aImage,
                                             const SamplingFilter aSamplingFilter,
                                             const nsPoint&       aDest,
                                             const nsRect*        aDirty,
+                                            const mozilla::Maybe<SVGImageContext>& aSVGContext,
                                             uint32_t             aImageFlags,
                                             const nsRect*        aSourceArea = nullptr);
 
   /**
    * Draw a whole image without tiling.
    *
    *   @param aRenderingContext Where to draw the image, set up with an
    *                            appropriate scale and transform for drawing in
--- a/layout/reftests/xul/reftest.list
+++ b/layout/reftests/xul/reftest.list
@@ -70,8 +70,9 @@ fails == object-fit-fill-svg-006.xul obj
 # Tests for rendering SVG images in a XUL <treecell>:
 # XXXdholbert: These are marked as "random" right now, since they might not
 # render the images they trying to test in time for the reftest snapshot, per
 # bug 1218954.
 skip == treecell-image-svg-1a.xul treecell-image-svg-1-ref.xul # bug 1218954
 skip == treecell-image-svg-1b.xul treecell-image-svg-1-ref.xul # bug 1218954
 
 == treechildren-padding-percent-1.xul treechildren-padding-percent-1-ref.xul
+test-pref(svg.context-properties.content.enabled,true) == treetwisty-svg-context-paint-1.xul treetwisty-svg-context-paint-1-ref.xul
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/xul/treetwisty-context-paint.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"
+     fill="context-fill" stroke="context-stroke" fill-opacity="context-fill-opacity" stroke-opacity="context-stroke-opacity">
+  <circle cx="8" cy="8" r="7"/>
+</svg>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/layout/reftests/xul/treetwisty-no-context-paint.svg
@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"
+     fill="green" stroke="purple" fill-opacity="0.5" stroke-opacity="0.2">
+  <circle cx="8" cy="8" r="7"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/xul/treetwisty-svg-context-paint-1-ref.xul
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        xmlns:html="http://www.w3.org/1999/xhtml">
+  <html:style>
+    treechildren::-moz-tree-twisty {
+      -moz-appearance: none !important;
+      -moz-context-properties: none !important;
+      list-style-image: url(treetwisty-no-context-paint.svg);
+    }
+  </html:style>
+  <tree seltype="single" flex="1">
+    <treecols>
+      <treecol flex="1" primary="true"/>
+    </treecols>
+    <treechildren>
+      <treeitem>
+        <treerow>
+          <treecell label="I am a treecell"></treecell>
+        </treerow>
+      </treeitem>
+      <treeitem container="true" open="true">
+        <treerow>
+          <treecell label="Folder"></treecell>
+        </treerow>
+        <treechildren>
+          <treeitem>
+            <treerow>
+              <treecell label="I am a treecell"></treecell>
+            </treerow>
+          </treeitem>
+        </treechildren>
+      </treeitem>
+    </treechildren>
+  </tree>
+</window>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/xul/treetwisty-svg-context-paint-1.xul
@@ -0,0 +1,41 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
+
+<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+        xmlns:html="http://www.w3.org/1999/xhtml">
+  <html:style>
+    treechildren::-moz-tree-twisty {
+      -moz-appearance: none !important;
+      -moz-context-properties: fill, fill-opacity, stroke, stroke-opacity !important;
+      fill: green;
+      fill-opacity: 0.5;
+      stroke: purple;
+      stroke-opacity: 0.2;
+      list-style-image: url(treetwisty-context-paint.svg);
+    }
+  </html:style>
+  <tree seltype="single" flex="1">
+    <treecols>
+      <treecol flex="1" primary="true"/>
+    </treecols>
+    <treechildren>
+      <treeitem>
+        <treerow>
+          <treecell label="I am a treecell"></treecell>
+        </treerow>
+      </treeitem>
+      <treeitem container="true" open="true">
+        <treerow>
+          <treecell label="Folder"></treecell>
+        </treerow>
+        <treechildren>
+          <treeitem>
+            <treerow>
+              <treecell label="I am a treecell"></treecell>
+            </treerow>
+          </treeitem>
+        </treechildren>
+      </treeitem>
+    </treechildren>
+  </tree>
+</window>
--- a/layout/svg/nsSVGImageFrame.cpp
+++ b/layout/svg/nsSVGImageFrame.cpp
@@ -351,16 +351,17 @@ nsSVGImageFrame::PaintSVG(gfxContext& aC
     } else { // mImageContainer->GetType() == TYPE_RASTER
       aImgParams.result &= nsLayoutUtils::DrawSingleUnscaledImage(
         aContext,
         PresContext(),
         mImageContainer,
         nsLayoutUtils::GetSamplingFilterForFrame(this),
         nsPoint(0, 0),
         aDirtyRect ? &dirtyRect : nullptr,
+        Nothing(),
         flags);
     }
 
     if (opacity != 1.0f || StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
       aContext.PopGroupAndBlend();
     }
     // gfxContextAutoSaveRestore goes out of scope & cleans up our gfxContext
   }
--- a/layout/xul/tree/nsTreeBodyFrame.cpp
+++ b/layout/xul/tree/nsTreeBodyFrame.cpp
@@ -3489,29 +3489,34 @@ nsTreeBodyFrame::PaintTwisty(int32_t    
         twistyRect.x = rightEdge - twistyRect.width;
       imageSize.Deflate(bp);
 
       // Get the image for drawing.
       nsCOMPtr<imgIContainer> image;
       bool useImageRegion = true;
       GetImage(aRowIndex, aColumn, true, twistyContext, useImageRegion, getter_AddRefs(image));
       if (image) {
-        nsPoint pt = twistyRect.TopLeft();
+        nsPoint anchorPoint = twistyRect.TopLeft();
 
         // Center the image. XXX Obey vertical-align style prop?
         if (imageSize.height < twistyRect.height) {
-          pt.y += (twistyRect.height - imageSize.height)/2;
+          anchorPoint.y += (twistyRect.height - imageSize.height)/2;
         }
 
+        // Apply context paint if applicable
+        Maybe<SVGImageContext> svgContext;
+        SVGImageContext::MaybeStoreContextPaint(svgContext, twistyContext,
+                                                image);
+
         // Paint the image.
         result &=
           nsLayoutUtils::DrawSingleUnscaledImage(
               aRenderingContext, aPresContext, image,
-              SamplingFilter::POINT, pt, &aDirtyRect,
-              imgIContainer::FLAG_NONE, &imageSize);
+              SamplingFilter::POINT, anchorPoint, &aDirtyRect,
+              svgContext, imgIContainer::FLAG_NONE, &imageSize);
       }
     }
   }
 
   return result;
 }
 
 ImgDrawResult
@@ -3876,22 +3881,26 @@ nsTreeBodyFrame::PaintCheckbox(int32_t  
     if (imageSize.height < checkboxRect.height) {
       pt.y += (checkboxRect.height - imageSize.height)/2;
     }
 
     if (imageSize.width < checkboxRect.width) {
       pt.x += (checkboxRect.width - imageSize.width)/2;
     }
 
+    // Apply context paint if applicable
+    Maybe<SVGImageContext> svgContext;
+    SVGImageContext::MaybeStoreContextPaint(svgContext, checkboxContext,
+                                            image);
     // Paint the image.
     result &=
       nsLayoutUtils::DrawSingleUnscaledImage(aRenderingContext,
         aPresContext,
         image, SamplingFilter::POINT, pt, &aDirtyRect,
-        imgIContainer::FLAG_NONE, &imageSize);
+        svgContext, imgIContainer::FLAG_NONE, &imageSize);
   }
 
   return result;
 }
 
 ImgDrawResult
 nsTreeBodyFrame::PaintDropFeedback(const nsRect&        aDropFeedbackRect,
                                    nsPresContext*      aPresContext,