Bug 619500: Part 2. When drawing an SVG image as a CSS border-image, use preverveAspectRatio="none"; r=dholbert
authorCJKu <cku@mozilla.com>
Tue, 08 Mar 2016 15:54:13 +0800
changeset 287145 055cc694bc2635b4c2cfcc94945cee1b8a6d1f77
parent 287144 5d03f2103664bbc4b024fe73213883f32afe8535
child 287146 ada8d43117654c9164a437f484ea7c9db901225b
push id73076
push usercku@mozilla.com
push dateTue, 08 Mar 2016 07:55:14 +0000
treeherdermozilla-inbound@bc277a82a03e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs619500
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 619500: Part 2. When drawing an SVG image as a CSS border-image, use preverveAspectRatio="none"; r=dholbert MozReview-Commit-ID: JH5E3An4opJ
image/VectorImage.cpp
image/imgIContainer.idl
layout/base/nsCSSRendering.cpp
--- a/image/VectorImage.cpp
+++ b/image/VectorImage.cpp
@@ -823,25 +823,42 @@ VectorImage::Draw(gfxContext* aContext,
 
   if (mAnimationConsumers == 0 && mProgressTracker) {
     mProgressTracker->OnUnlockedDraw();
   }
 
   AutoRestore<bool> autoRestoreIsDrawing(mIsDrawing);
   mIsDrawing = true;
 
+  Maybe<SVGImageContext> svgContext;
+  // If FLAG_FORCE_PRESERVEASPECTRATIO_NONE bit is set, that mean we should
+  // overwrite SVG preserveAspectRatio attibute of this image with none, and
+  // always stretch this image to viewport non-uniformly.
+  // And we can do this only if the caller pass in the the SVG viewport, via
+  // aSVGContext.
+  if ((aFlags & FLAG_FORCE_PRESERVEASPECTRATIO_NONE) && aSVGContext.isSome()) {
+    Maybe<SVGPreserveAspectRatio> aspectRatio =
+      Some(SVGPreserveAspectRatio(SVG_PRESERVEASPECTRATIO_NONE,
+                                  SVG_MEETORSLICE_UNKNOWN));
+    svgContext =
+      Some(SVGImageContext(aSVGContext->GetViewportSize(),
+                           aspectRatio));
+  } else {
+    svgContext = aSVGContext;
+  }
+
   float animTime =
     (aWhichFrame == FRAME_FIRST) ? 0.0f
                                  : mSVGDocumentWrapper->GetCurrentTime();
-  AutoSVGRenderingState autoSVGState(aSVGContext, animTime,
+  AutoSVGRenderingState autoSVGState(svgContext, animTime,
                                      mSVGDocumentWrapper->GetRootSVGElem());
 
-  // Pack up the drawing parameters.
+
   SVGDrawingParameters params(aContext, aSize, aRegion, aFilter,
-                              aSVGContext, animTime, aFlags);
+                              svgContext, animTime, aFlags);
 
   if (aFlags & FLAG_BYPASS_SURFACE_CACHE) {
     CreateSurfaceAndShow(params);
     return DrawResult::SUCCESS;
   }
 
   LookupResult result =
     SurfaceCache::Lookup(ImageKey(this),
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -176,27 +176,38 @@ interface imgIContainer : nsISupports
    * DataSourceSurface instead of a hardware accelerated surface. This can be
    * important for performance (by avoiding an upload to/readback from the GPU)
    * when the caller knows they want a SourceSurface of type DATA.
    *
    * FLAG_BYPASS_SURFACE_CACHE: Forces drawing to happen rather than taking
    * cached rendering from the surface cache. This is used when we are printing,
    * for example, where we want the vector commands from VectorImages to end up
    * in the PDF output rather than a cached rendering at screen resolution.
+   *
+   * FLAG_FORCE_PRESERVEASPECTRATIO_NONE: Force scaling this image
+   * non-uniformly if necessary. This flag is for vector image only. A raster
+   * image should ignore this flag. While drawing a vector image with this
+   * flag, do not force uniform scaling even if its root <svg> node has a
+   * preserveAspectRatio attribute that would otherwise require uniform
+   * scaling , such as xMinYMin/ xMidYMin. Always scale the graphic content of
+   * the given image non-uniformly if necessary such that the image's
+   * viewBox (if specified or implied by height/width attributes) exactly
+   * matches the viewport rectangle.
    */
   const unsigned long FLAG_NONE                            = 0x0;
   const unsigned long FLAG_SYNC_DECODE                     = 0x1;
   const unsigned long FLAG_SYNC_DECODE_IF_FAST             = 0x2;
   const unsigned long FLAG_ASYNC_NOTIFY                    = 0x4;
   const unsigned long FLAG_DECODE_NO_PREMULTIPLY_ALPHA     = 0x8;
   const unsigned long FLAG_DECODE_NO_COLORSPACE_CONVERSION = 0x10;
   const unsigned long FLAG_CLAMP                           = 0x20;
   const unsigned long FLAG_HIGH_QUALITY_SCALING            = 0x40;
   const unsigned long FLAG_WANT_DATA_SURFACE               = 0x80;
   const unsigned long FLAG_BYPASS_SURFACE_CACHE            = 0x100;
+  const unsigned long FLAG_FORCE_PRESERVEASPECTRATIO_NONE  = 0x200;
 
   /**
    * A constant specifying the default set of decode flags (i.e., the default
    * values for FLAG_DECODE_*).
    */
   const unsigned long DECODE_FLAGS_DEFAULT = 0;
 
   /**
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -5275,16 +5275,24 @@ nsImageRenderer::DrawBorderImageComponen
   }
   if (aFill.IsEmpty() || aSrc.IsEmpty()) {
     return DrawResult::SUCCESS;
   }
 
   if (mType == eStyleImageType_Image || mType == eStyleImageType_Element) {
     nsCOMPtr<imgIContainer> subImage;
 
+    // To draw one portion of an image into a border component, we stretch that
+    // portion to match the size of that border component and then draw onto.
+    // However, preserveAspectRatio attribute of a SVG image may break this rule.
+    // To get correct rendering result, we add
+    // FLAG_FORCE_PRESERVEASPECTRATIO_NONE flag here, to tell mImage to ignore
+    // preserveAspectRatio attribute, and always do non-uniform stretch.
+    uint32_t drawFlags = ConvertImageRendererToDrawFlags(mFlags) |
+                           imgIContainer::FLAG_FORCE_PRESERVEASPECTRATIO_NONE;
     // Retrieve or create the subimage we'll draw.
     nsIntRect srcRect(aSrc.x, aSrc.y, aSrc.width, aSrc.height);
     if (mType == eStyleImageType_Image) {
       if ((subImage = mImage->GetSubImage(aIndex)) == nullptr) {
         subImage = ImageOps::Clip(mImageContainer, srcRect, aSVGViewportSize);
         mImage->SetSubImage(aIndex, subImage);
       }
     } else {
@@ -5314,26 +5322,26 @@ nsImageRenderer::DrawBorderImageComponen
 
     if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
       return nsLayoutUtils::DrawSingleImage(*aRenderingContext.ThebesContext(),
                                             aPresContext,
                                             subImage,
                                             filter,
                                             aFill, aDirtyRect,
                                             nullptr,
-                                            ConvertImageRendererToDrawFlags(mFlags));
+                                            drawFlags);
     }
 
     nsRect tile = ComputeTile(aFill, aHFill, aVFill, aUnitSize);
     return nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
                                     aPresContext,
                                     subImage,
                                     filter,
                                     tile, aFill, tile.TopLeft(), aDirtyRect,
-                                    ConvertImageRendererToDrawFlags(mFlags));
+                                    drawFlags);
   }
 
   nsRect destTile = RequiresScaling(aFill, aHFill, aVFill, aUnitSize)
                   ? ComputeTile(aFill, aHFill, aVFill, aUnitSize)
                   : aFill;
 
   return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
               aFill, destTile.TopLeft(), aSrc);