mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Bug 619500: Part 1. Default sizing for specified size of SVG images which have no constraints; r=dholbert r=seth
MozReview-Commit-ID: 8DI86w6Ni8T
This commit is contained in:
parent
ff383edaf7
commit
19414f3998
@ -137,11 +137,18 @@ private:
|
||||
};
|
||||
|
||||
ClippedImage::ClippedImage(Image* aImage,
|
||||
nsIntRect aClip)
|
||||
nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize)
|
||||
: ImageWrapper(aImage)
|
||||
, mClip(aClip)
|
||||
{
|
||||
MOZ_ASSERT(aImage != nullptr, "ClippedImage requires an existing Image");
|
||||
MOZ_ASSERT_IF(aSVGViewportSize,
|
||||
aImage->GetType() == imgIContainer::TYPE_VECTOR);
|
||||
if (aSVGViewportSize) {
|
||||
mSVGViewportSize = Some(aSVGViewportSize->ToNearestPixels(
|
||||
nsPresContext::AppUnitsPerCSSPixel()));
|
||||
}
|
||||
}
|
||||
|
||||
ClippedImage::~ClippedImage()
|
||||
@ -162,6 +169,15 @@ ClippedImage::ShouldClip()
|
||||
// If there's a problem with the inner image we'll let it handle
|
||||
// everything.
|
||||
mShouldClip.emplace(false);
|
||||
} else if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) {
|
||||
// Clamp the clipping region to the size of the SVG viewport.
|
||||
nsIntRect svgViewportRect(nsIntPoint(0,0), *mSVGViewportSize);
|
||||
|
||||
mClip = mClip.Intersect(svgViewportRect);
|
||||
|
||||
// If the clipping region is the same size as the SVG viewport size
|
||||
// we don't have to do anything.
|
||||
mShouldClip.emplace(!mClip.IsEqualInterior(svgViewportRect));
|
||||
} else if (NS_SUCCEEDED(InnerImage()->GetWidth(&width)) && width > 0 &&
|
||||
NS_SUCCEEDED(InnerImage()->GetHeight(&height)) && height > 0) {
|
||||
// Clamp the clipping region to the size of the underlying image.
|
||||
@ -420,8 +436,19 @@ ClippedImage::DrawSingleTile(gfxContext* aContext,
|
||||
|
||||
gfxRect clip(mClip.x, mClip.y, mClip.width, mClip.height);
|
||||
nsIntSize size(aSize), innerSize(aSize);
|
||||
if (NS_SUCCEEDED(InnerImage()->GetWidth(&innerSize.width)) &&
|
||||
NS_SUCCEEDED(InnerImage()->GetHeight(&innerSize.height))) {
|
||||
bool needScale = false;
|
||||
if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) {
|
||||
innerSize = *mSVGViewportSize;
|
||||
needScale = true;
|
||||
} else if (NS_SUCCEEDED(InnerImage()->GetWidth(&innerSize.width)) &&
|
||||
NS_SUCCEEDED(InnerImage()->GetHeight(&innerSize.height))) {
|
||||
needScale = true;
|
||||
} else {
|
||||
MOZ_ASSERT_UNREACHABLE(
|
||||
"If ShouldClip() led us to draw then we should never get here");
|
||||
}
|
||||
|
||||
if (needScale) {
|
||||
double scaleX = aSize.width / clip.width;
|
||||
double scaleY = aSize.height / clip.height;
|
||||
|
||||
@ -429,9 +456,6 @@ ClippedImage::DrawSingleTile(gfxContext* aContext,
|
||||
clip.Scale(scaleX, scaleY);
|
||||
size = innerSize;
|
||||
size.Scale(scaleX, scaleY);
|
||||
} else {
|
||||
MOZ_ASSERT(false,
|
||||
"If ShouldClip() led us to draw then we should never get here");
|
||||
}
|
||||
|
||||
// We restrict our drawing to only the clipping region, and translate so that
|
||||
@ -478,8 +502,17 @@ ClippedImage::OptimalImageSizeForDest(const gfxSize& aDest,
|
||||
}
|
||||
|
||||
int32_t imgWidth, imgHeight;
|
||||
if (NS_SUCCEEDED(InnerImage()->GetWidth(&imgWidth)) &&
|
||||
NS_SUCCEEDED(InnerImage()->GetHeight(&imgHeight))) {
|
||||
bool needScale = false;
|
||||
if (mSVGViewportSize && !mSVGViewportSize->IsEmpty()) {
|
||||
imgWidth = mSVGViewportSize->width;
|
||||
imgHeight = mSVGViewportSize->height;
|
||||
needScale = true;
|
||||
} 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.
|
||||
|
||||
@ -501,12 +534,12 @@ ClippedImage::OptimalImageSizeForDest(const gfxSize& aDest,
|
||||
nsIntSize finalScale(ceil(double(innerDesiredSize.width) / imgWidth),
|
||||
ceil(double(innerDesiredSize.height) / imgHeight));
|
||||
return mClip.Size() * finalScale;
|
||||
} else {
|
||||
MOZ_ASSERT(false,
|
||||
"If ShouldClip() led us to draw then we should never get here");
|
||||
return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame, aFilter,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(false,
|
||||
"If ShouldClip() led us to draw then we should never get here");
|
||||
return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame, aFilter,
|
||||
aFlags);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(nsIntRect)
|
||||
|
@ -64,7 +64,8 @@ public:
|
||||
uint32_t aFlags) override;
|
||||
|
||||
protected:
|
||||
ClippedImage(Image* aImage, nsIntRect aClip);
|
||||
ClippedImage(Image* aImage, nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize);
|
||||
|
||||
virtual ~ClippedImage();
|
||||
|
||||
@ -86,9 +87,10 @@ private:
|
||||
// If we are forced to draw a temporary surface, we cache it here.
|
||||
UniquePtr<ClippedImageCachedSurface> mCachedSurface;
|
||||
|
||||
nsIntRect mClip; // The region to clip to.
|
||||
Maybe<bool> mShouldClip; // Memoized ShouldClip() if present.
|
||||
|
||||
nsIntRect mClip; // The region to clip to.
|
||||
Maybe<bool> mShouldClip; // Memoized ShouldClip() if present.
|
||||
Maybe<nsIntSize> mSVGViewportSize; // If we're clipping a VectorImage, this
|
||||
// is the size of viewport of that image.
|
||||
friend class DrawSingleTileCallback;
|
||||
friend class ImageOps;
|
||||
};
|
||||
|
@ -40,17 +40,19 @@ ImageOps::Freeze(imgIContainer* aImage)
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Image>
|
||||
ImageOps::Clip(Image* aImage, nsIntRect aClip)
|
||||
ImageOps::Clip(Image* aImage, nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize)
|
||||
{
|
||||
RefPtr<Image> clippedImage = new ClippedImage(aImage, aClip);
|
||||
RefPtr<Image> clippedImage = new ClippedImage(aImage, aClip, aSVGViewportSize);
|
||||
return clippedImage.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<imgIContainer>
|
||||
ImageOps::Clip(imgIContainer* aImage, nsIntRect aClip)
|
||||
ImageOps::Clip(imgIContainer* aImage, nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize)
|
||||
{
|
||||
nsCOMPtr<imgIContainer> clippedImage =
|
||||
new ClippedImage(static_cast<Image*>(aImage), aClip);
|
||||
new ClippedImage(static_cast<Image*>(aImage), aClip, aSVGViewportSize);
|
||||
return clippedImage.forget();
|
||||
}
|
||||
|
||||
|
@ -40,12 +40,19 @@ public:
|
||||
/**
|
||||
* Creates a clipped version of an existing image. Animation is unaffected.
|
||||
*
|
||||
* @param aImage The existing image.
|
||||
* @param aClip The rectangle to clip the image against.
|
||||
* @param aImage The existing image.
|
||||
* @param aClip The rectangle to clip the image against.
|
||||
* @param aSVGViewportSize The specific viewort size of aImage. Unless aImage
|
||||
* is a vector image without intrinsic size, this
|
||||
* argument should be pass as Nothing().
|
||||
*/
|
||||
static already_AddRefed<Image> Clip(Image* aImage, nsIntRect aClip);
|
||||
static already_AddRefed<Image> Clip(Image* aImage, nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize =
|
||||
Nothing());
|
||||
static already_AddRefed<imgIContainer> Clip(imgIContainer* aImage,
|
||||
nsIntRect aClip);
|
||||
nsIntRect aClip,
|
||||
const Maybe<nsSize>& aSVGViewportSize =
|
||||
Nothing());
|
||||
|
||||
/**
|
||||
* Creates a version of an existing image which is rotated and/or flipped to
|
||||
|
@ -3700,7 +3700,16 @@ DrawBorderImage(nsPresContext* aPresContext,
|
||||
|
||||
nsRect destArea(borderX[i], borderY[j], borderWidth[i], borderHeight[j]);
|
||||
nsRect subArea(sliceX[i], sliceY[j], sliceWidth[i], sliceHeight[j]);
|
||||
if (subArea.IsEmpty())
|
||||
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,
|
||||
@ -3710,7 +3719,8 @@ DrawBorderImage(nsPresContext* aPresContext,
|
||||
intSubArea.width,
|
||||
intSubArea.height),
|
||||
fillStyleH, fillStyleV,
|
||||
unitSize, j * (RIGHT + 1) + i);
|
||||
unitSize, j * (RIGHT + 1) + i,
|
||||
svgViewportSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4785,7 +4795,9 @@ nsImageRenderer::PrepareImage()
|
||||
// The cropped image is identical to the source image
|
||||
mImageContainer.swap(srcImage);
|
||||
} else {
|
||||
nsCOMPtr<imgIContainer> subImage = ImageOps::Clip(srcImage, actualCropRect);
|
||||
nsCOMPtr<imgIContainer> subImage = ImageOps::Clip(srcImage,
|
||||
actualCropRect,
|
||||
Nothing());
|
||||
mImageContainer.swap(subImage);
|
||||
}
|
||||
}
|
||||
@ -5254,7 +5266,8 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
|
||||
uint8_t aHFill,
|
||||
uint8_t aVFill,
|
||||
const nsSize& aUnitSize,
|
||||
uint8_t aIndex)
|
||||
uint8_t aIndex,
|
||||
const Maybe<nsSize>& aSVGViewportSize)
|
||||
{
|
||||
if (!IsReady()) {
|
||||
NS_NOTREACHED("Ensure PrepareImage() has returned true before calling me");
|
||||
@ -5271,7 +5284,7 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
|
||||
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);
|
||||
subImage = ImageOps::Clip(mImageContainer, srcRect, aSVGViewportSize);
|
||||
mImage->SetSubImage(aIndex, subImage);
|
||||
}
|
||||
} else {
|
||||
@ -5291,9 +5304,12 @@ nsImageRenderer::DrawBorderImageComponent(nsPresContext* aPresContext,
|
||||
}
|
||||
|
||||
nsCOMPtr<imgIContainer> image(ImageOps::CreateFromDrawable(drawable));
|
||||
subImage = ImageOps::Clip(image, srcRect);
|
||||
subImage = ImageOps::Clip(image, srcRect, aSVGViewportSize);
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(aSVGViewportSize,
|
||||
subImage->GetType() == imgIContainer::TYPE_VECTOR);
|
||||
|
||||
Filter filter = nsLayoutUtils::GetGraphicsFilterForFrame(mForFrame);
|
||||
|
||||
if (!RequiresScaling(aFill, aHFill, aVFill, aUnitSize)) {
|
||||
|
@ -231,6 +231,10 @@ public:
|
||||
* aIndex identifies the component: 0 1 2
|
||||
* 3 4 5
|
||||
* 6 7 8
|
||||
* aSVGViewportSize The image size evaluated by default sizing algorithm.
|
||||
* 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.
|
||||
*/
|
||||
DrawResult
|
||||
DrawBorderImageComponent(nsPresContext* aPresContext,
|
||||
@ -241,7 +245,8 @@ public:
|
||||
uint8_t aHFill,
|
||||
uint8_t aVFill,
|
||||
const nsSize& aUnitSize,
|
||||
uint8_t aIndex);
|
||||
uint8_t aIndex,
|
||||
const mozilla::Maybe<nsSize>& aSVGViewportSize);
|
||||
|
||||
bool IsRasterImage();
|
||||
bool IsAnimatedImage();
|
||||
|
Loading…
Reference in New Issue
Block a user