2013-08-25 11:19:43 +04:00
|
|
|
/* -*- 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/. */
|
|
|
|
|
2016-06-30 20:27:03 +03:00
|
|
|
#include "OrientedImage.h"
|
|
|
|
|
2013-08-25 11:19:43 +04:00
|
|
|
#include <algorithm>
|
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
#include "gfx2DGlue.h"
|
2013-08-25 11:19:43 +04:00
|
|
|
#include "gfxDrawable.h"
|
|
|
|
#include "gfxPlatform.h"
|
|
|
|
#include "gfxUtils.h"
|
2014-08-23 00:12:38 +04:00
|
|
|
#include "ImageRegion.h"
|
|
|
|
#include "SVGImageContext.h"
|
2013-08-25 11:19:43 +04:00
|
|
|
|
|
|
|
using std::swap;
|
|
|
|
|
|
|
|
namespace mozilla {
|
2014-07-10 19:00:31 +04:00
|
|
|
|
|
|
|
using namespace gfx;
|
|
|
|
using layers::ImageContainer;
|
|
|
|
using layers::LayerManager;
|
|
|
|
|
2013-08-25 11:19:43 +04:00
|
|
|
namespace image {
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
OrientedImage::GetWidth(int32_t* aWidth) {
|
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
return InnerImage()->GetHeight(aWidth);
|
|
|
|
} else {
|
|
|
|
return InnerImage()->GetWidth(aWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
OrientedImage::GetHeight(int32_t* aHeight) {
|
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
return InnerImage()->GetWidth(aHeight);
|
|
|
|
} else {
|
|
|
|
return InnerImage()->GetHeight(aHeight);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-22 16:05:36 +03:00
|
|
|
nsresult OrientedImage::GetNativeSizes(nsTArray<IntSize>& aNativeSizes) const {
|
|
|
|
nsresult rv = InnerImage()->GetNativeSizes(aNativeSizes);
|
|
|
|
|
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
auto i = aNativeSizes.Length();
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
swap(aNativeSizes[i].width, aNativeSizes[i].height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2013-08-25 11:19:43 +04:00
|
|
|
NS_IMETHODIMP
|
|
|
|
OrientedImage::GetIntrinsicSize(nsSize* aSize) {
|
|
|
|
nsresult rv = InnerImage()->GetIntrinsicSize(aSize);
|
|
|
|
|
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
swap(aSize->width, aSize->height);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2019-05-03 02:28:21 +03:00
|
|
|
Maybe<AspectRatio> OrientedImage::GetIntrinsicRatio() {
|
|
|
|
Maybe<AspectRatio> ratio = InnerImage()->GetIntrinsicRatio();
|
|
|
|
if (ratio && mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
ratio = Some(ratio->Inverted());
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
2019-05-03 02:28:21 +03:00
|
|
|
return ratio;
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2015-06-17 17:00:52 +03:00
|
|
|
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
|
2013-08-25 11:19:43 +04:00
|
|
|
OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
|
|
|
|
nsresult rv;
|
|
|
|
|
|
|
|
if (mOrientation.IsIdentity()) {
|
2013-12-13 12:34:24 +04:00
|
|
|
return InnerImage()->GetFrame(aWhichFrame, aFlags);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the underlying dimensions.
|
2015-09-23 21:49:05 +03:00
|
|
|
IntSize size;
|
2014-08-23 00:12:38 +04:00
|
|
|
rv = InnerImage()->GetWidth(&size.width);
|
2014-04-15 22:02:23 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2014-08-23 00:12:38 +04:00
|
|
|
rv = InnerImage()->GetHeight(&size.height);
|
2013-12-13 12:34:24 +04:00
|
|
|
NS_ENSURE_SUCCESS(rv, nullptr);
|
2013-08-25 11:19:43 +04:00
|
|
|
|
|
|
|
// Determine an appropriate format for the surface.
|
|
|
|
gfx::SurfaceFormat surfaceFormat;
|
2016-08-23 05:15:38 +03:00
|
|
|
if (InnerImage()->WillDrawOpaqueNow()) {
|
2014-01-10 23:06:16 +04:00
|
|
|
surfaceFormat = gfx::SurfaceFormat::B8G8R8X8;
|
2013-08-25 11:19:43 +04:00
|
|
|
} else {
|
2014-01-10 23:06:16 +04:00
|
|
|
surfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create a surface to draw into.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<DrawTarget> target =
|
2015-04-07 17:08:57 +03:00
|
|
|
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
|
|
|
size, surfaceFormat);
|
2016-04-12 22:18:11 +03:00
|
|
|
if (!target || !target->IsValid()) {
|
2014-05-31 14:26:04 +04:00
|
|
|
NS_ERROR("Could not create a DrawTarget");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-08-25 11:19:43 +04:00
|
|
|
// Create our drawable.
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<SourceSurface> innerSurface =
|
2013-12-13 12:34:24 +04:00
|
|
|
InnerImage()->GetFrame(aWhichFrame, aFlags);
|
|
|
|
NS_ENSURE_TRUE(innerSurface, nullptr);
|
2014-08-23 00:12:38 +04:00
|
|
|
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(innerSurface, size);
|
2013-08-25 11:19:43 +04:00
|
|
|
|
|
|
|
// Draw.
|
2016-06-07 02:39:56 +03:00
|
|
|
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(target);
|
2016-04-12 22:18:11 +03:00
|
|
|
MOZ_ASSERT(ctx); // already checked the draw target above
|
2014-08-23 00:12:38 +04:00
|
|
|
ctx->Multiply(OrientationMatrix(size));
|
2017-06-28 18:41:21 +03:00
|
|
|
gfxUtils::DrawPixelSnapped(ctx, drawable, SizeDouble(size),
|
|
|
|
ImageRegion::Create(size), surfaceFormat,
|
2016-05-25 19:01:18 +03:00
|
|
|
SamplingFilter::LINEAR);
|
2014-12-06 02:58:00 +03:00
|
|
|
|
2014-04-15 22:02:23 +04:00
|
|
|
return target->Snapshot();
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2015-09-19 23:34:09 +03:00
|
|
|
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
|
|
|
|
OrientedImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
|
|
|
|
uint32_t aFlags) {
|
|
|
|
// XXX(seth): It'd be nice to support downscale-during-decode for this case,
|
|
|
|
// but right now we just fall back to the intrinsic size.
|
|
|
|
return GetFrame(aWhichFrame, aFlags);
|
|
|
|
}
|
|
|
|
|
2015-05-13 10:23:44 +03:00
|
|
|
NS_IMETHODIMP_(bool)
|
|
|
|
OrientedImage::IsImageContainerAvailable(LayerManager* aManager,
|
|
|
|
uint32_t aFlags) {
|
|
|
|
if (mOrientation.IsIdentity()) {
|
|
|
|
return InnerImage()->IsImageContainerAvailable(aManager, aFlags);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-03-18 05:40:16 +03:00
|
|
|
NS_IMETHODIMP_(already_AddRefed<ImageContainer>)
|
|
|
|
OrientedImage::GetImageContainer(LayerManager* aManager, uint32_t aFlags) {
|
2013-08-25 11:19:43 +04:00
|
|
|
// XXX(seth): We currently don't have a way of orienting the result of
|
|
|
|
// GetImageContainer. We work around this by always returning null, but if it
|
|
|
|
// ever turns out that OrientedImage is widely used on codepaths that can
|
|
|
|
// actually benefit from GetImageContainer, it would be a good idea to fix
|
|
|
|
// that method for performance reasons.
|
|
|
|
|
|
|
|
if (mOrientation.IsIdentity()) {
|
2015-03-18 05:40:16 +03:00
|
|
|
return InnerImage()->GetImageContainer(aManager, aFlags);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2015-03-18 05:40:16 +03:00
|
|
|
return nullptr;
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2017-11-17 14:45:26 +03:00
|
|
|
NS_IMETHODIMP_(bool)
|
|
|
|
OrientedImage::IsImageContainerAvailableAtSize(LayerManager* aManager,
|
|
|
|
const IntSize& aSize,
|
|
|
|
uint32_t aFlags) {
|
|
|
|
if (mOrientation.IsIdentity()) {
|
|
|
|
return InnerImage()->IsImageContainerAvailableAtSize(aManager, aSize,
|
|
|
|
aFlags);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-09-14 02:48:21 +03:00
|
|
|
NS_IMETHODIMP_(ImgDrawResult)
|
|
|
|
OrientedImage::GetImageContainerAtSize(
|
|
|
|
layers::LayerManager* aManager, const gfx::IntSize& aSize,
|
2017-11-17 22:08:52 +03:00
|
|
|
const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags,
|
2018-09-14 02:48:21 +03:00
|
|
|
layers::ImageContainer** aOutContainer) {
|
2017-11-17 14:45:26 +03:00
|
|
|
// XXX(seth): We currently don't have a way of orienting the result of
|
|
|
|
// GetImageContainer. We work around this by always returning null, but if it
|
|
|
|
// ever turns out that OrientedImage is widely used on codepaths that can
|
|
|
|
// actually benefit from GetImageContainer, it would be a good idea to fix
|
|
|
|
// that method for performance reasons.
|
|
|
|
|
|
|
|
if (mOrientation.IsIdentity()) {
|
2018-09-14 02:48:21 +03:00
|
|
|
return InnerImage()->GetImageContainerAtSize(aManager, aSize, aSVGContext,
|
|
|
|
aFlags, aOutContainer);
|
2017-11-17 14:45:26 +03:00
|
|
|
}
|
|
|
|
|
2018-09-14 02:48:21 +03:00
|
|
|
return ImgDrawResult::NOT_SUPPORTED;
|
2017-11-17 14:45:26 +03:00
|
|
|
}
|
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
struct MatrixBuilder {
|
2014-09-02 20:20:24 +04:00
|
|
|
explicit MatrixBuilder(bool aInvert) : mInvert(aInvert) {}
|
2014-08-23 00:12:38 +04:00
|
|
|
|
|
|
|
gfxMatrix Build() { return mMatrix; }
|
2013-08-25 11:19:43 +04:00
|
|
|
|
2014-12-06 02:58:00 +03:00
|
|
|
void Scale(gfxFloat aX, gfxFloat aY) {
|
2014-08-23 00:12:38 +04:00
|
|
|
if (mInvert) {
|
|
|
|
mMatrix *= gfxMatrix::Scaling(1.0 / aX, 1.0 / aY);
|
2013-08-25 11:19:43 +04:00
|
|
|
} else {
|
2017-07-05 18:18:49 +03:00
|
|
|
mMatrix.PreScale(aX, aY);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
2014-08-23 00:12:38 +04:00
|
|
|
}
|
2013-08-25 11:19:43 +04:00
|
|
|
|
2014-12-06 02:58:00 +03:00
|
|
|
void Rotate(gfxFloat aPhi) {
|
2014-08-23 00:12:38 +04:00
|
|
|
if (mInvert) {
|
|
|
|
mMatrix *= gfxMatrix::Rotation(-aPhi);
|
|
|
|
} else {
|
2017-07-05 18:18:49 +03:00
|
|
|
mMatrix.PreRotate(aPhi);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
2014-08-23 00:12:38 +04:00
|
|
|
}
|
2013-08-25 11:19:43 +04:00
|
|
|
|
2014-12-06 02:58:00 +03:00
|
|
|
void Translate(gfxPoint aDelta) {
|
2014-08-23 00:12:38 +04:00
|
|
|
if (mInvert) {
|
|
|
|
mMatrix *= gfxMatrix::Translation(-aDelta);
|
|
|
|
} else {
|
2017-07-05 18:18:49 +03:00
|
|
|
mMatrix.PreTranslate(aDelta);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
2014-08-23 00:12:38 +04:00
|
|
|
}
|
2013-08-25 11:19:43 +04:00
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
private:
|
|
|
|
gfxMatrix mMatrix;
|
|
|
|
bool mInvert;
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* OrientationMatrix() computes a matrix that applies the rotation and
|
|
|
|
* reflection specified by mOrientation, or that matrix's inverse if aInvert is
|
|
|
|
* true.
|
|
|
|
*
|
|
|
|
* @param aSize The scaled size of the inner image. (When outside code specifies
|
|
|
|
* the scaled size, as with imgIContainer::Draw and its aSize
|
|
|
|
* parameter, it's necessary to swap the width and height if
|
|
|
|
* mOrientation.SwapsWidthAndHeight() is true.)
|
|
|
|
* @param aInvert If true, compute the inverse of the orientation matrix. Prefer
|
|
|
|
* this approach to OrientationMatrix(..).Invert(), because it's
|
|
|
|
* more numerically accurate.
|
|
|
|
*/
|
|
|
|
gfxMatrix OrientedImage::OrientationMatrix(const nsIntSize& aSize,
|
|
|
|
bool aInvert /* = false */) {
|
|
|
|
MatrixBuilder builder(aInvert);
|
|
|
|
|
|
|
|
// Apply reflection, if present. (This logically happens second, but we
|
|
|
|
// apply it first because these transformations are all premultiplied.) A
|
|
|
|
// translation is necessary to place the image back in the first quadrant.
|
|
|
|
switch (mOrientation.flip) {
|
|
|
|
case Flip::Unflipped:
|
|
|
|
break;
|
|
|
|
case Flip::Horizontal:
|
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
builder.Translate(gfxPoint(aSize.height, 0));
|
|
|
|
} else {
|
|
|
|
builder.Translate(gfxPoint(aSize.width, 0));
|
|
|
|
}
|
|
|
|
builder.Scale(-1.0, 1.0);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT(false, "Invalid flip value");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Apply rotation, if present. Again, a translation is used to place the
|
|
|
|
// image back in the first quadrant.
|
|
|
|
switch (mOrientation.rotation) {
|
|
|
|
case Angle::D0:
|
|
|
|
break;
|
|
|
|
case Angle::D90:
|
|
|
|
builder.Translate(gfxPoint(aSize.height, 0));
|
|
|
|
builder.Rotate(-1.5 * M_PI);
|
|
|
|
break;
|
|
|
|
case Angle::D180:
|
|
|
|
builder.Translate(gfxPoint(aSize.width, aSize.height));
|
|
|
|
builder.Rotate(-1.0 * M_PI);
|
|
|
|
break;
|
|
|
|
case Angle::D270:
|
|
|
|
builder.Translate(gfxPoint(0, aSize.width));
|
|
|
|
builder.Rotate(-0.5 * M_PI);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
MOZ_ASSERT(false, "Invalid rotation value");
|
|
|
|
}
|
|
|
|
|
|
|
|
return builder.Build();
|
|
|
|
}
|
|
|
|
|
2017-12-11 18:37:59 +03:00
|
|
|
NS_IMETHODIMP_(ImgDrawResult)
|
2013-08-25 11:19:43 +04:00
|
|
|
OrientedImage::Draw(gfxContext* aContext, const nsIntSize& aSize,
|
2014-08-23 00:12:38 +04:00
|
|
|
const ImageRegion& aRegion, uint32_t aWhichFrame,
|
2016-05-25 19:01:18 +03:00
|
|
|
SamplingFilter aSamplingFilter,
|
2014-08-23 00:12:38 +04:00
|
|
|
const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags,
|
2017-01-03 08:53:22 +03:00
|
|
|
float aOpacity) {
|
2013-08-25 11:19:43 +04:00
|
|
|
if (mOrientation.IsIdentity()) {
|
2014-08-23 00:12:38 +04:00
|
|
|
return InnerImage()->Draw(aContext, aSize, aRegion, aWhichFrame,
|
2017-01-03 08:53:22 +03:00
|
|
|
aSamplingFilter, aSVGContext, aFlags, aOpacity);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
// Update the image size to match the image's coordinate system. (This could
|
|
|
|
// be done using TransformBounds but since it's only a size a swap is enough.)
|
|
|
|
nsIntSize size(aSize);
|
2013-08-25 11:19:43 +04:00
|
|
|
if (mOrientation.SwapsWidthAndHeight()) {
|
2014-08-23 00:12:38 +04:00
|
|
|
swap(size.width, size.height);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
// Update the matrix so that we transform the image into the orientation
|
|
|
|
// expected by the caller before drawing.
|
|
|
|
gfxMatrix matrix(OrientationMatrix(size));
|
|
|
|
gfxContextMatrixAutoSaveRestore saveMatrix(aContext);
|
|
|
|
aContext->Multiply(matrix);
|
|
|
|
|
|
|
|
// The region is already in the orientation expected by the caller, but we
|
|
|
|
// need it to be in the image's coordinate system, so we transform it using
|
|
|
|
// the inverse of the orientation matrix.
|
|
|
|
gfxMatrix inverseMatrix(OrientationMatrix(size, /* aInvert = */ true));
|
|
|
|
ImageRegion region(aRegion);
|
|
|
|
region.TransformBoundsBy(inverseMatrix);
|
|
|
|
|
2016-06-22 23:34:07 +03:00
|
|
|
auto orientViewport = [&](const SVGImageContext& aOldContext) {
|
2017-01-09 22:12:02 +03:00
|
|
|
SVGImageContext context(aOldContext);
|
2017-01-30 16:25:00 +03:00
|
|
|
auto oldViewport = aOldContext.GetViewportSize();
|
|
|
|
if (oldViewport && mOrientation.SwapsWidthAndHeight()) {
|
|
|
|
// Swap width and height:
|
|
|
|
CSSIntSize newViewport(oldViewport->height, oldViewport->width);
|
|
|
|
context.SetViewportSize(Some(newViewport));
|
|
|
|
}
|
2017-01-09 22:12:02 +03:00
|
|
|
return context;
|
2016-06-22 23:34:07 +03:00
|
|
|
};
|
|
|
|
|
2017-01-03 08:53:22 +03:00
|
|
|
return InnerImage()->Draw(aContext, size, region, aWhichFrame,
|
|
|
|
aSamplingFilter, aSVGContext.map(orientViewport),
|
|
|
|
aFlags, aOpacity);
|
2013-08-25 11:19:43 +04:00
|
|
|
}
|
|
|
|
|
2014-12-06 02:58:00 +03:00
|
|
|
nsIntSize OrientedImage::OptimalImageSizeForDest(const gfxSize& aDest,
|
|
|
|
uint32_t aWhichFrame,
|
2016-05-25 19:01:18 +03:00
|
|
|
SamplingFilter aSamplingFilter,
|
|
|
|
uint32_t aFlags) {
|
2014-07-29 01:27:40 +04:00
|
|
|
if (!mOrientation.SwapsWidthAndHeight()) {
|
2016-05-25 19:01:18 +03:00
|
|
|
return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame,
|
|
|
|
aSamplingFilter, aFlags);
|
2014-07-29 01:27:40 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Swap the size for the calculation, then swap it back for the caller.
|
|
|
|
gfxSize destSize(aDest.height, aDest.width);
|
|
|
|
nsIntSize innerImageSize(InnerImage()->OptimalImageSizeForDest(
|
2016-05-25 19:01:18 +03:00
|
|
|
destSize, aWhichFrame, aSamplingFilter, aFlags));
|
2014-07-29 01:27:40 +04:00
|
|
|
return nsIntSize(innerImageSize.height, innerImageSize.width);
|
|
|
|
}
|
|
|
|
|
2014-06-27 03:02:04 +04:00
|
|
|
NS_IMETHODIMP_(nsIntRect)
|
|
|
|
OrientedImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) {
|
|
|
|
nsIntRect rect(InnerImage()->GetImageSpaceInvalidationRect(aRect));
|
|
|
|
|
|
|
|
if (mOrientation.IsIdentity()) {
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2014-08-23 00:12:38 +04:00
|
|
|
nsIntSize innerSize;
|
|
|
|
nsresult rv = InnerImage()->GetWidth(&innerSize.width);
|
|
|
|
rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&innerSize.height);
|
2014-06-27 03:02:04 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// Fall back to identity if the width and height aren't available.
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transform the invalidation rect into the correct orientation.
|
2015-09-26 09:26:18 +03:00
|
|
|
gfxMatrix matrix(OrientationMatrix(innerSize));
|
2017-12-21 00:46:28 +03:00
|
|
|
gfxRect invalidRect(matrix.TransformBounds(
|
2017-08-14 15:29:56 +03:00
|
|
|
gfxRect(rect.X(), rect.Y(), rect.Width(), rect.Height())));
|
2014-06-27 03:02:04 +04:00
|
|
|
|
2017-12-21 00:46:28 +03:00
|
|
|
return IntRect::RoundOut(invalidRect.X(), invalidRect.Y(),
|
2017-08-14 15:29:56 +03:00
|
|
|
invalidRect.Width(), invalidRect.Height());
|
2014-06-27 03:02:04 +04:00
|
|
|
}
|
|
|
|
|
2013-08-25 11:19:43 +04:00
|
|
|
} // namespace image
|
|
|
|
} // namespace mozilla
|