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 303478 8a7eb4a7864c6de79d798d16a57f37a8cab4eb25
parent 303477 5bd0b92309c75a6eb587fe5b1e7fab5d590562cf
child 303479 d19e8687583ef3af3c48b73fb783fbc0fe55f61e
push id30390
push usercbook@mozilla.com
push dateMon, 04 Jul 2016 11:02:39 +0000
treeherdermozilla-central@4191df8e4b8e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdholbert
bugs1264809
milestone50.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 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 {