Bug 720531 - Part 2. Implement rendering of border-image-repeat: space. r=dbaron
authorEthan Lin <ethlin@mozilla.com>
Fri, 15 Jul 2016 03:37:00 +0200
changeset 346706 d2b5441aa9fe80d6e74d8f64d87960073c3a0adc
parent 346705 9760f28f2343f558032fc073607d18588a2f9187
child 346707 45b4eb6943c86dfe30e84a31f595523c54196dea
push id6389
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:38:22 +0000
treeherdermozilla-beta@01d67bfe6c81 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs720531
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 720531 - Part 2. Implement rendering of border-image-repeat: space. r=dbaron
layout/base/nsCSSRendering.cpp
--- a/layout/base/nsCSSRendering.cpp
+++ b/layout/base/nsCSSRendering.cpp
@@ -3367,34 +3367,50 @@ ComputeDrawnSizeForBackground(const CSSS
   }
 
   return imageSize;
 }
 
 /* ComputeSpacedRepeatSize
  * aImageDimension: the image width/height
  * aAvailableSpace: the background positioning area width/height
- * aRepeatSize: the image size plus gap size of app units for use as spacing
  * aRepeat: determine whether the image is repeated
+ * Returns the image size plus gap size of app units for use as spacing
  */
 static nscoord
 ComputeSpacedRepeatSize(nscoord aImageDimension,
                         nscoord aAvailableSpace,
                         bool& aRepeat) {
   float ratio = static_cast<float>(aAvailableSpace) / aImageDimension;
 
   if (ratio < 2.0f) { // If you can't repeat at least twice, then don't repeat.
     aRepeat = false;
     return aImageDimension;
   } else {
     aRepeat = true;
     return (aAvailableSpace - aImageDimension) / (NSToIntFloor(ratio) - 1);
   }
 }
 
+/* ComputeBorderSpacedRepeatSize
+ * aImageDimension: the image width/height
+ * aAvailableSpace: the background positioning area width/height
+ * aSpace: the space between each image
+ * Returns the image size plus gap size of app units for use as spacing
+ */
+static nscoord
+ComputeBorderSpacedRepeatSize(nscoord aImageDimension,
+                              nscoord aAvailableSpace,
+                              nscoord& aSpace)
+{
+  int32_t count = aAvailableSpace / aImageDimension;
+  aSpace = (aAvailableSpace - aImageDimension * count) / (count + 1);
+  return aSpace + aImageDimension;
+}
+
 nsBackgroundLayerState
 nsCSSRendering::PrepareImageLayer(nsPresContext* aPresContext,
                                   nsIFrame* aForFrame,
                                   uint32_t aFlags,
                                   const nsRect& aBorderArea,
                                   const nsRect& aBGClipRect,
                                   const nsStyleImageLayers::Layer& aLayer,
                                   bool* aOutIsTransformedFixed,
@@ -3916,17 +3932,16 @@ DrawBorderImage(nsPresContext*       aPr
 
       nsIntRect intSubArea = subArea.ToOutsidePixels(nsPresContext::AppUnitsPerCSSPixel());
       // intrinsicSize.CanComputeConcreteSize() return false means we can not
       // read intrinsic size from aStyleBorder.mBorderImageSource.
       // In this condition, we pass imageSize(a resolved size comes from
       // default sizing algorithm) to renderer as the viewport size.
       Maybe<nsSize> svgViewportSize = intrinsicSize.CanComputeConcreteSize() ?
         Nothing() : Some(imageSize);
-
       result &=
         renderer.DrawBorderImageComponent(aPresContext,
                                           aRenderingContext, aDirtyRect,
                                           destArea, CSSIntRect(intSubArea.x,
                                                                intSubArea.y,
                                                                intSubArea.width,
                                                                intSubArea.height),
                                           fillStyleH, fillStyleV,
@@ -5450,51 +5465,80 @@ nsImageRenderer::DrawBackground(nsPresCo
  * Compute the size and position of the master copy of the image. I.e., a single
  * tile used to fill the dest rect.
  * aFill The destination rect to be filled
  * aHFill and aVFill are the repeat patterns for the component -
  * NS_STYLE_BORDER_IMAGE_REPEAT_* - i.e., how a tiling unit is used to fill aFill
  * aUnitSize The size of the source rect in dest coords.
  */
 static nsRect
-ComputeTile(const nsRect&        aFill,
+ComputeTile(nsRect&              aFill,
             uint8_t              aHFill,
             uint8_t              aVFill,
-            const nsSize&        aUnitSize)
+            const nsSize&        aUnitSize,
+            nsSize&              aRepeatSize)
 {
   nsRect tile;
   switch (aHFill) {
   case NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH:
     tile.x = aFill.x;
     tile.width = aFill.width;
+    aRepeatSize.width = tile.width;
     break;
   case NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT:
     tile.x = aFill.x + aFill.width/2 - aUnitSize.width/2;
     tile.width = aUnitSize.width;
+    aRepeatSize.width = tile.width;
     break;
   case NS_STYLE_BORDER_IMAGE_REPEAT_ROUND:
     tile.x = aFill.x;
     tile.width = ComputeRoundedSize(aUnitSize.width, aFill.width);
+    aRepeatSize.width = tile.width;
+    break;
+  case NS_STYLE_BORDER_IMAGE_REPEAT_SPACE:
+    {
+      nscoord space;
+      aRepeatSize.width =
+        ComputeBorderSpacedRepeatSize(aUnitSize.width, aFill.width, space);
+      tile.x = aFill.x + space;
+      tile.width = aUnitSize.width;
+      aFill.x = tile.x;
+      aFill.width = aFill.width - space * 2;
+    }
     break;
   default:
     NS_NOTREACHED("unrecognized border-image fill style");
   }
 
   switch (aVFill) {
   case NS_STYLE_BORDER_IMAGE_REPEAT_STRETCH:
     tile.y = aFill.y;
     tile.height = aFill.height;
+    aRepeatSize.height = tile.height;
     break;
   case NS_STYLE_BORDER_IMAGE_REPEAT_REPEAT:
     tile.y = aFill.y + aFill.height/2 - aUnitSize.height/2;
     tile.height = aUnitSize.height;
+    aRepeatSize.height = tile.height;
     break;
   case NS_STYLE_BORDER_IMAGE_REPEAT_ROUND:
     tile.y = aFill.y;
     tile.height = ComputeRoundedSize(aUnitSize.height, aFill.height);
+    aRepeatSize.height = tile.height;
+    break;
+  case NS_STYLE_BORDER_IMAGE_REPEAT_SPACE:
+    {
+      nscoord space;
+      aRepeatSize.height =
+        ComputeBorderSpacedRepeatSize(aUnitSize.height, aFill.height, space);
+      tile.y = aFill.y + space;
+      tile.height = aUnitSize.height;
+      aFill.y = tile.y;
+      aFill.height = aFill.height - space * 2;
+    }
     break;
   default:
     NS_NOTREACHED("unrecognized border-image fill style");
   }
 
   return tile;
 }
 
@@ -5591,31 +5635,37 @@ nsImageRenderer::DrawBorderImageComponen
                                             aPresContext,
                                             subImage,
                                             samplingFilter,
                                             aFill, aDirtyRect,
                                             nullptr,
                                             drawFlags);
     }
 
-    nsRect tile = ComputeTile(aFill, aHFill, aVFill, aUnitSize);
-    return nsLayoutUtils::DrawImage(*aRenderingContext.ThebesContext(),
-                                    aPresContext,
-                                    subImage,
-                                    samplingFilter,
-                                    tile, aFill, tile.TopLeft(), aDirtyRect,
-                                    drawFlags);
-  }
-
-  nsRect destTile = RequiresScaling(aFill, aHFill, aVFill, aUnitSize)
-                  ? ComputeTile(aFill, aHFill, aVFill, aUnitSize)
-                  : aFill;
-
+    nsSize repeatSize;
+    nsRect fillRect(aFill);
+    nsRect tile = ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize);
+    CSSIntSize imageSize(nsPresContext::AppUnitsToIntCSSPixels(srcRect.width),
+                         nsPresContext::AppUnitsToIntCSSPixels(srcRect.height));
+    return nsLayoutUtils::DrawBackgroundImage(*aRenderingContext.ThebesContext(),
+                                              aPresContext,
+                                              subImage, imageSize, samplingFilter,
+                                              tile, fillRect, repeatSize,
+                                              tile.TopLeft(), aDirtyRect,
+                                              drawFlags,
+                                              ExtendMode::CLAMP);
+  }
+
+  nsSize repeatSize(aFill.Size());
+  nsRect fillRect(aFill);
+  nsRect destTile = RequiresScaling(fillRect, aHFill, aVFill, aUnitSize)
+                  ? ComputeTile(fillRect, aHFill, aVFill, aUnitSize, repeatSize)
+                  : fillRect;
   return Draw(aPresContext, aRenderingContext, aDirtyRect, destTile,
-              aFill, destTile.TopLeft(), destTile.Size(), aSrc);
+              fillRect, destTile.TopLeft(), repeatSize, aSrc);
 }
 
 bool
 nsImageRenderer::IsRasterImage()
 {
   if (mType != eStyleImageType_Image || !mImageContainer)
     return false;
   return mImageContainer->GetType() == imgIContainer::TYPE_RASTER;