зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1616411 - Part 1: Split out some helper methods from OrientedImage. r=tnikkel
RasterImage will make use of them. Note that there is one bug fix in this patch, which is that OrientedImage::OrientSurface now creates a surface of the correct size. (Previously this code was creating a surface with the underlying image's size, rather than the correctly oriented size. But we must not have been calling into that code with our current uses of OrientedImage.) Differential Revision: https://phabricator.services.mozilla.com/D70271
This commit is contained in:
Родитель
21c9b8214f
Коммит
75f9b3902d
|
@ -75,37 +75,33 @@ Maybe<AspectRatio> OrientedImage::GetIntrinsicRatio() {
|
|||
return ratio;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
|
||||
OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
|
||||
nsresult rv;
|
||||
already_AddRefed<SourceSurface> OrientedImage::OrientSurface(
|
||||
Orientation aOrientation, SourceSurface* aSurface, const nsIntSize& aSize) {
|
||||
MOZ_ASSERT(aSurface);
|
||||
|
||||
if (mOrientation.IsIdentity()) {
|
||||
return InnerImage()->GetFrame(aWhichFrame, aFlags);
|
||||
// If the image does not require any re-orientation, return aSurface itself.
|
||||
if (aOrientation.IsIdentity()) {
|
||||
return do_AddRef(aSurface);
|
||||
}
|
||||
|
||||
// Get the underlying dimensions.
|
||||
IntSize size;
|
||||
rv = InnerImage()->GetWidth(&size.width);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
rv = InnerImage()->GetHeight(&size.height);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
RefPtr<SourceSurface> innerSurface =
|
||||
InnerImage()->GetFrame(aWhichFrame, aFlags);
|
||||
NS_ENSURE_TRUE(innerSurface, nullptr);
|
||||
// Determine the size of the new surface.
|
||||
nsIntSize targetSize = aSize;
|
||||
if (aOrientation.SwapsWidthAndHeight()) {
|
||||
swap(targetSize.width, targetSize.height);
|
||||
}
|
||||
|
||||
// Create our drawable.
|
||||
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(innerSurface, size);
|
||||
RefPtr<gfxDrawable> drawable = new gfxSurfaceDrawable(aSurface, aSize);
|
||||
|
||||
// Determine an appropriate format for the surface.
|
||||
gfx::SurfaceFormat surfaceFormat = IsOpaque(innerSurface->GetFormat())
|
||||
gfx::SurfaceFormat surfaceFormat = IsOpaque(aSurface->GetFormat())
|
||||
? gfx::SurfaceFormat::OS_RGBX
|
||||
: gfx::SurfaceFormat::OS_RGBA;
|
||||
|
||||
// Create a surface to draw into.
|
||||
// Create the new surface to draw into.
|
||||
RefPtr<DrawTarget> target =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
size, surfaceFormat);
|
||||
targetSize, surfaceFormat);
|
||||
if (!target || !target->IsValid()) {
|
||||
NS_ERROR("Could not create a DrawTarget");
|
||||
return nullptr;
|
||||
|
@ -114,14 +110,34 @@ OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
|
|||
// Draw.
|
||||
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(target);
|
||||
MOZ_ASSERT(ctx); // already checked the draw target above
|
||||
ctx->Multiply(OrientationMatrix(size));
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, SizeDouble(size),
|
||||
ImageRegion::Create(size), surfaceFormat,
|
||||
ctx->Multiply(OrientationMatrix(aOrientation, aSize));
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, SizeDouble(aSize),
|
||||
ImageRegion::Create(aSize), surfaceFormat,
|
||||
SamplingFilter::LINEAR);
|
||||
|
||||
return target->Snapshot();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
|
||||
OrientedImage::GetFrame(uint32_t aWhichFrame, uint32_t aFlags) {
|
||||
nsresult rv;
|
||||
|
||||
// Get a SourceSurface for the inner image then orient it according to
|
||||
// mOrientation.
|
||||
RefPtr<SourceSurface> innerSurface =
|
||||
InnerImage()->GetFrame(aWhichFrame, aFlags);
|
||||
NS_ENSURE_TRUE(innerSurface, nullptr);
|
||||
|
||||
// Get the underlying dimensions.
|
||||
IntSize size;
|
||||
rv = InnerImage()->GetWidth(&size.width);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
rv = InnerImage()->GetHeight(&size.height);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
|
||||
return OrientSurface(mOrientation, innerSurface, size);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP_(already_AddRefed<SourceSurface>)
|
||||
OrientedImage::GetFrameAtSize(const IntSize& aSize, uint32_t aWhichFrame,
|
||||
uint32_t aFlags) {
|
||||
|
@ -218,31 +234,19 @@ struct MatrixBuilder {
|
|||
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,
|
||||
gfxMatrix OrientedImage::OrientationMatrix(Orientation aOrientation,
|
||||
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) {
|
||||
switch (aOrientation.flip) {
|
||||
case Flip::Unflipped:
|
||||
break;
|
||||
case Flip::Horizontal:
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
if (aOrientation.SwapsWidthAndHeight()) {
|
||||
builder.Translate(gfxPoint(aSize.height, 0));
|
||||
} else {
|
||||
builder.Translate(gfxPoint(aSize.width, 0));
|
||||
|
@ -255,7 +259,7 @@ gfxMatrix OrientedImage::OrientationMatrix(const nsIntSize& aSize,
|
|||
|
||||
// Apply rotation, if present. Again, a translation is used to place the
|
||||
// image back in the first quadrant.
|
||||
switch (mOrientation.rotation) {
|
||||
switch (aOrientation.rotation) {
|
||||
case Angle::D0:
|
||||
break;
|
||||
case Angle::D90:
|
||||
|
|
|
@ -63,13 +63,42 @@ class OrientedImage : public ImageWrapper {
|
|||
gfx::SamplingFilter aSamplingFilter,
|
||||
uint32_t aFlags) override;
|
||||
|
||||
/**
|
||||
* Computes a matrix that applies the rotation and reflection specified by
|
||||
* aOrientation, 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.
|
||||
*/
|
||||
static gfxMatrix OrientationMatrix(Orientation aOrientation,
|
||||
const nsIntSize& aSize,
|
||||
bool aInvert = false);
|
||||
|
||||
/**
|
||||
* Returns a SourceSurface that is the result of rotating and flipping
|
||||
* aSurface according to aOrientation.
|
||||
*
|
||||
* @param aSize The size of aSurface.
|
||||
*/
|
||||
static already_AddRefed<SourceSurface> OrientSurface(Orientation aOrientation,
|
||||
SourceSurface* aSurface,
|
||||
const nsIntSize& aSize);
|
||||
|
||||
protected:
|
||||
OrientedImage(Image* aImage, Orientation aOrientation)
|
||||
: ImageWrapper(aImage), mOrientation(aOrientation) {}
|
||||
|
||||
virtual ~OrientedImage() {}
|
||||
|
||||
gfxMatrix OrientationMatrix(const nsIntSize& aSize, bool aInvert = false);
|
||||
gfxMatrix OrientationMatrix(const nsIntSize& aSize, bool aInvert = false) {
|
||||
return OrientationMatrix(mOrientation, aSize, aInvert);
|
||||
}
|
||||
|
||||
private:
|
||||
Orientation mOrientation;
|
||||
|
|
Загрузка…
Ссылка в новой задаче