diff --git a/layout/base/nsCSSRendering.cpp b/layout/base/nsCSSRendering.cpp index 44fa40c91bc0..08283aa453ed 100644 --- a/layout/base/nsCSSRendering.cpp +++ b/layout/base/nsCSSRendering.cpp @@ -3953,6 +3953,15 @@ DrawBorderImage(nsPresContext* aPresContext, DrawResult result = DrawResult::SUCCESS; + // 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 svgViewportSize = intrinsicSize.CanComputeConcreteSize() ? + Nothing() : Some(imageSize); + bool hasIntrinsicRatio = intrinsicSize.HasRatio(); + renderer.PurgeCacheForViewportChange(svgViewportSize, hasIntrinsicRatio); + for (int i = LEFT; i <= RIGHT; i++) { for (int j = TOP; j <= BOTTOM; j++) { uint8_t fillStyleH, fillStyleV; @@ -4039,12 +4048,6 @@ DrawBorderImage(nsPresContext* aPresContext, continue; 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 svgViewportSize = intrinsicSize.CanComputeConcreteSize() ? - Nothing() : Some(imageSize); result &= renderer.DrawBorderImageComponent(aPresContext, aRenderingContext, aDirtyRect, @@ -4054,7 +4057,7 @@ DrawBorderImage(nsPresContext* aPresContext, intSubArea.height), fillStyleH, fillStyleV, unitSize, j * (RIGHT + 1) + i, - svgViewportSize); + svgViewportSize, hasIntrinsicRatio); } } @@ -5681,7 +5684,8 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext, uint8_t aVFill, const nsSize& aUnitSize, uint8_t aIndex, - const Maybe& aSVGViewportSize) + const Maybe& aSVGViewportSize, + const bool aHasIntrinsicRatio) { if (!IsReady()) { NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me"); @@ -5705,7 +5709,7 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext, // 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()) { + if (!aHasIntrinsicRatio) { drawFlags = drawFlags | imgIContainer::FLAG_FORCE_UNIFORM_SCALING; } // Retrieve or create the subimage we'll draw. @@ -5804,6 +5808,18 @@ nsImageRenderer::GetImage() return image.forget(); } +void +nsImageRenderer::PurgeCacheForViewportChange( + const Maybe& aSVGViewportSize, const bool aHasIntrinsicRatio) +{ + // Check if we should flush the cached data - only vector images need to do + // the check since they might not have fixed ratio. + if (mImageContainer && + mImageContainer->GetType() == imgIContainer::TYPE_VECTOR) { + mImage->PurgeCacheForViewportChange(aSVGViewportSize, aHasIntrinsicRatio); + } +} + #define MAX_BLUR_RADIUS 300 #define MAX_SPREAD_RADIUS 50 diff --git a/layout/base/nsCSSRendering.h b/layout/base/nsCSSRendering.h index 213060892357..e504f336b575 100644 --- a/layout/base/nsCSSRendering.h +++ b/layout/base/nsCSSRendering.h @@ -236,6 +236,8 @@ public: * Pass Nothing() if we can read a valid viewport size or aspect-ratio from * the drawing image directly, otherwise, pass Some() with viewport size * evaluated from default sizing algorithm. + * aHasIntrinsicRatio is used to record if the source image has fixed + * intrinsic ratio. */ DrawResult DrawBorderImageComponent(nsPresContext* aPresContext, @@ -247,7 +249,8 @@ public: uint8_t aVFill, const nsSize& aUnitSize, uint8_t aIndex, - const mozilla::Maybe& aSVGViewportSize); + const mozilla::Maybe& aSVGViewportSize, + const bool aHasIntrinsicRatio); bool IsRasterImage(); bool IsAnimatedImage(); @@ -259,6 +262,8 @@ public: DrawResult PrepareResult() const { return mPrepareResult; } void SetExtendMode(mozilla::gfx::ExtendMode aMode) { mExtendMode = aMode; } void SetMaskOp(uint8_t aMaskOp) { mMaskOp = aMaskOp; } + void PurgeCacheForViewportChange(const mozilla::Maybe& aSVGViewportSize, + const bool aHasRatio); private: /** diff --git a/layout/reftests/border-image/reftest.list b/layout/reftests/border-image/reftest.list index 9c8b8f931906..b95f1afd8f4c 100644 --- a/layout/reftests/border-image/reftest.list +++ b/layout/reftests/border-image/reftest.list @@ -89,3 +89,4 @@ fuzzy(125,5808) fuzzy-if(B2G,151,5809) == border-image-element.html border-image == svg-as-border-image-1c.html svg-as-border-image-1-ref.html == svg-as-border-image-2.html svg-as-border-image-2-ref.html == svg-as-border-image-3.html svg-as-border-image-3-ref.html +== svg-as-border-image-4.html svg-as-border-image-4-ref.html diff --git a/layout/reftests/border-image/svg-as-border-image-4-ref.html b/layout/reftests/border-image/svg-as-border-image-4-ref.html new file mode 100644 index 000000000000..41833c316295 --- /dev/null +++ b/layout/reftests/border-image/svg-as-border-image-4-ref.html @@ -0,0 +1,18 @@ + + +reference of svg-as-border-image + + + +
+ + diff --git a/layout/reftests/border-image/svg-as-border-image-4.html b/layout/reftests/border-image/svg-as-border-image-4.html new file mode 100644 index 000000000000..81574ba637ce --- /dev/null +++ b/layout/reftests/border-image/svg-as-border-image-4.html @@ -0,0 +1,26 @@ + + +test of svg-as-border-image + + + + +
+ + diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp index 7b8ce971f799..76db8ccf19a7 100644 --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -1912,6 +1912,19 @@ nsStyleGradient::HasCalc() // -------------------- // CachedBorderImageData // +void +CachedBorderImageData::SetCachedSVGViewportSize( + const mozilla::Maybe& aSVGViewportSize) +{ + mCachedSVGViewportSize = aSVGViewportSize; +} + +const mozilla::Maybe& +CachedBorderImageData::GetCachedSVGViewportSize() +{ + return mCachedSVGViewportSize; +} + void CachedBorderImageData::PurgeCachedImages() { @@ -2295,6 +2308,26 @@ nsStyleImage::operator==(const nsStyleImage& aOther) const return true; } +void +nsStyleImage::PurgeCacheForViewportChange( + const mozilla::Maybe& aSVGViewportSize, + const bool aHasIntrinsicRatio) const +{ + EnsureCachedBIData(); + + // If we're redrawing with a different viewport-size than we used for our + // cached subimages, then we can't trust that our subimages are valid; + // any percent sizes/positions in our SVG doc may be different now. Purge! + // (We don't have to purge if the SVG document has an intrinsic ratio, + // though, because the actual size of elements in SVG documant's coordinate + // axis are fixed in this case.) + if (aSVGViewportSize != mCachedBIData->GetCachedSVGViewportSize() && + !aHasIntrinsicRatio) { + mCachedBIData->PurgeCachedImages(); + mCachedBIData->SetCachedSVGViewportSize(aSVGViewportSize); + } +} + // -------------------- // nsStyleImageLayers // diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h index cd479f0460f3..d2b3dde9f17b 100644 --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -15,6 +15,7 @@ #include "mozilla/ArenaObjectID.h" #include "mozilla/Attributes.h" #include "mozilla/CSSVariableValues.h" +#include "mozilla/Maybe.h" #include "mozilla/SheetType.h" #include "mozilla/StaticPtr.h" #include "mozilla/StyleStructContext.h" @@ -249,11 +250,19 @@ enum nsStyleImageType { struct CachedBorderImageData { + // Caller are expected to ensure that the value of aSVGViewportSize is + // different from the cached one since the method won't do the check. + void SetCachedSVGViewportSize(const mozilla::Maybe& aSVGViewportSize); + const mozilla::Maybe& GetCachedSVGViewportSize(); void PurgeCachedImages(); void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage); imgIContainer* GetSubImage(uint8_t aIndex); private: + // If this is a SVG border-image, we save the size of the SVG viewport that + // we used when rasterizing any cached border-image subimages. (The viewport + // size matters for percent-valued sizes & positions in inner SVG doc). + mozilla::Maybe mCachedSVGViewportSize; nsCOMArray mSubImages; }; @@ -369,6 +378,9 @@ struct nsStyleImage // during a border-image paint operation inline void SetSubImage(uint8_t aIndex, imgIContainer* aSubImage) const; inline imgIContainer* GetSubImage(uint8_t aIndex) const; + void PurgeCacheForViewportChange( + const mozilla::Maybe& aSVGViewportSize, + const bool aHasIntrinsicRatio) const; private: void DoCopy(const nsStyleImage& aOther);