Bug 1285320 - (Part 2) Purge border-image cache when hypothetical SVG viewport changes, if using SVG image with no aspect ratio. r=dholbert

--HG--
extra : rebase_source : 76dd4f87d83b7435870a9d4cc4262d2938f7e5c4
This commit is contained in:
Kevin Chen 2016-07-29 01:05:00 +02:00
Родитель 2850db7128
Коммит 904a5a0513
7 изменённых файлов: 121 добавлений и 10 удалений

Просмотреть файл

@ -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<nsSize> 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<nsSize> 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<nsSize>& aSVGViewportSize)
const Maybe<nsSize>& 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<nsSize>& 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

Просмотреть файл

@ -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<nsSize>& aSVGViewportSize);
const mozilla::Maybe<nsSize>& 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<nsSize>& aSVGViewportSize,
const bool aHasRatio);
private:
/**

Просмотреть файл

@ -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

Просмотреть файл

@ -0,0 +1,18 @@
<html>
<head>
<title>reference of svg-as-border-image</title>
<style type="text/css">
div {
width: 100px;
height: 100px;
margin: 30px;
border-width: 30px;
border-style: solid;
border-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><circle cx="50%" cy="50%" r="50%" fill="red"/></svg>') 5% stretch;
}
</style>
</head>
<body>
<div></div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,26 @@
<html class="reftest-wait">
<head>
<title>test of svg-as-border-image</title>
<style type="text/css">
div {
width: 400px;
height: 100px;
margin: 30px;
border-width: 30px;
border-style: solid;
border-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg"><circle cx="50%" cy="50%" r="50%" fill="red"/></svg>') 5% stretch;
}
</style>
<script>
function resizeDiv() {
document.getElementById('borderdiv').style.width = '100px';
document.documentElement.removeAttribute('class');
}
document.addEventListener('MozReftestInvalidate', resizeDiv, false);
</script>
</head>
<body>
<div id="borderdiv"></div>
</body>
</html>

Просмотреть файл

@ -1912,6 +1912,19 @@ nsStyleGradient::HasCalc()
// --------------------
// CachedBorderImageData
//
void
CachedBorderImageData::SetCachedSVGViewportSize(
const mozilla::Maybe<nsSize>& aSVGViewportSize)
{
mCachedSVGViewportSize = aSVGViewportSize;
}
const mozilla::Maybe<nsSize>&
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<nsSize>& 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
//

Просмотреть файл

@ -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<nsSize>& aSVGViewportSize);
const mozilla::Maybe<nsSize>& 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<nsSize> mCachedSVGViewportSize;
nsCOMArray<imgIContainer> 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<nsSize>& aSVGViewportSize,
const bool aHasIntrinsicRatio) const;
private:
void DoCopy(const nsStyleImage& aOther);