Bug 1264809 - (Part 2) Preserve scale ratio if SVG dosen't have viewport size and viewBox. r=dholbert
authorKevin Chen <kechen@mozilla.com>
Fri, 01 Jul 2016 02:27:00 +0200
changeset 328542 8a7eb4a7864c6de79d798d16a57f37a8cab4eb25
parent 328541 5bd0b92309c75a6eb587fe5b1e7fab5d590562cf
child 328543 d19e8687583ef3af3c48b73fb783fbc0fe55f61e
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1264809
milestone50.0a1
Bug 1264809 - (Part 2) Preserve scale ratio if SVG dosen't have viewport size and viewBox. r=dholbert
image/ClippedImage.cpp
image/imgIContainer.idl
layout/base/nsCSSRendering.cpp
--- a/image/ClippedImage.cpp
+++ b/image/ClippedImage.cpp
@@ -1,15 +1,16 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "ClippedImage.h"
 
+#include <algorithm>
 #include <new>      // Workaround for bug in VS10; see bug 981264.
 #include <cmath>
 #include <utility>
 
 #include "gfxDrawable.h"
 #include "gfxPlatform.h"
 #include "gfxUtils.h"
 #include "mozilla/gfx/2D.h"
@@ -23,16 +24,17 @@
 #include "SVGImageContext.h"
 
 namespace mozilla {
 
 using namespace gfx;
 using layers::LayerManager;
 using layers::ImageContainer;
 using std::make_pair;
+using std::max;
 using std::modf;
 using std::pair;
 
 namespace image {
 
 class ClippedImageCachedSurface
 {
 public:
@@ -496,34 +498,40 @@ ClippedImage::OptimalImageSizeForDest(co
 {
   if (!ShouldClip()) {
     return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame,
                                                  aSamplingFilter, aFlags);
   }
 
   int32_t imgWidth, imgHeight;
   bool needScale = false;
+  bool forceUniformScaling = false;
   if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) {
     imgWidth = mSVGViewportSize->width;
     imgHeight = mSVGViewportSize->height;
     needScale = true;
+    forceUniformScaling = (aFlags & imgIContainer::FLAG_FORCE_UNIFORM_SCALING);
   } else if (NS_SUCCEEDED(InnerImage()->GetWidth(&imgWidth)) &&
              NS_SUCCEEDED(InnerImage()->GetHeight(&imgHeight))) {
     needScale = true;
   }
 
   if (needScale) {
     // To avoid ugly sampling artifacts, ClippedImage needs the image size to
     // be chosen such that the clipping region lies on pixel boundaries.
 
     // First, we select a scale that's good for ClippedImage. An integer
     // multiple of the size of the clipping region is always fine.
     nsIntSize scale(ceil(aDest.width / mClip.width),
                     ceil(aDest.height / mClip.height));
 
+    if (forceUniformScaling) {
+      scale.width = scale.height = max(scale.height, scale.width);
+    }
+
     // Determine the size we'd prefer to render the inner image at, and ask the
     // inner image what size we should actually use.
     gfxSize desiredSize(imgWidth * scale.width, imgHeight * scale.height);
     nsIntSize innerDesiredSize =
       InnerImage()->OptimalImageSizeForDest(desiredSize, aWhichFrame,
                                             aSamplingFilter, aFlags);
 
     // To get our final result, we take the inner image's desired size and
--- a/image/imgIContainer.idl
+++ b/image/imgIContainer.idl
@@ -202,16 +202,17 @@ interface imgIContainer : nsISupports
   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;
+  const unsigned long FLAG_FORCE_UNIFORM_SCALING           = 0x400;
 
   /**
    * 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
@@ -5516,16 +5516,22 @@ nsImageRenderer::DrawBorderImageComponen
     // 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;
+    // For those SVG image sources which don't have fixed aspect ratio (i.e.
+    // without viewport size and viewBox), we should scale the source uniformly
+    // after the viewport size is decided by "Default Sizing Algorithm".
+    if (!ComputeIntrinsicSize().HasRatio()) {
+      drawFlags = drawFlags | imgIContainer::FLAG_FORCE_UNIFORM_SCALING;
+    }
     // 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 {