mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 19:04:45 +00:00
Bug 869723 (Part 4) - Add OrientedImage. r=joe
This commit is contained in:
parent
c217638415
commit
9d09a6075a
@ -7,6 +7,7 @@
|
||||
#include "imgIContainer.h"
|
||||
#include "ClippedImage.h"
|
||||
#include "FrozenImage.h"
|
||||
#include "OrientedImage.h"
|
||||
#include "Image.h"
|
||||
|
||||
#include "ImageOps.h"
|
||||
@ -44,5 +45,20 @@ ImageOps::Clip(imgIContainer* aImage, nsIntRect aClip)
|
||||
return clippedImage.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<Image>
|
||||
ImageOps::Orient(Image* aImage, Orientation aOrientation)
|
||||
{
|
||||
nsRefPtr<Image> orientedImage = new OrientedImage(aImage, aOrientation);
|
||||
return orientedImage.forget();
|
||||
}
|
||||
|
||||
/* static */ already_AddRefed<imgIContainer>
|
||||
ImageOps::Orient(imgIContainer* aImage, Orientation aOrientation)
|
||||
{
|
||||
nsCOMPtr<imgIContainer> orientedImage =
|
||||
new OrientedImage(static_cast<Image*>(aImage), aOrientation);
|
||||
return orientedImage.forget();
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsRect.h"
|
||||
#include "Orientation.h"
|
||||
|
||||
class imgIContainer;
|
||||
|
||||
@ -38,6 +39,16 @@ public:
|
||||
static already_AddRefed<Image> Clip(Image* aImage, nsIntRect aClip);
|
||||
static already_AddRefed<imgIContainer> Clip(imgIContainer* aImage, nsIntRect aClip);
|
||||
|
||||
/**
|
||||
* Creates a version of an existing image which is rotated and/or flipped to
|
||||
* the specified orientation.
|
||||
*
|
||||
* @param aImage The existing image.
|
||||
* @param aOrientation The desired orientation.
|
||||
*/
|
||||
static already_AddRefed<Image> Orient(Image* aImage, Orientation aOrientation);
|
||||
static already_AddRefed<imgIContainer> Orient(imgIContainer* aImage, Orientation aOrientation);
|
||||
|
||||
private:
|
||||
// This is a static utility class, so disallow instantiation.
|
||||
virtual ~ImageOps() = 0;
|
||||
|
254
image/src/OrientedImage.cpp
Normal file
254
image/src/OrientedImage.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "gfxDrawable.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxUtils.h"
|
||||
|
||||
#include "OrientedImage.h"
|
||||
|
||||
using std::swap;
|
||||
using mozilla::layers::LayerManager;
|
||||
using mozilla::layers::ImageContainer;
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
NS_IMPL_ISUPPORTS1(OrientedImage, imgIContainer)
|
||||
|
||||
nsIntRect
|
||||
OrientedImage::FrameRect(uint32_t aWhichFrame)
|
||||
{
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
nsIntRect innerRect = InnerImage()->FrameRect(aWhichFrame);
|
||||
return nsIntRect(innerRect.x, innerRect.y, innerRect.height, innerRect.width);
|
||||
} else {
|
||||
return InnerImage()->FrameRect(aWhichFrame);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OrientedImage::GetIntrinsicSize(nsSize* aSize)
|
||||
{
|
||||
nsresult rv = InnerImage()->GetIntrinsicSize(aSize);
|
||||
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
swap(aSize->width, aSize->height);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OrientedImage::GetIntrinsicRatio(nsSize* aRatio)
|
||||
{
|
||||
nsresult rv = InnerImage()->GetIntrinsicRatio(aRatio);
|
||||
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
swap(aRatio->width, aRatio->height);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OrientedImage::GetFrame(uint32_t aWhichFrame,
|
||||
uint32_t aFlags,
|
||||
gfxASurface** _retval)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
if (mOrientation.IsIdentity()) {
|
||||
return InnerImage()->GetFrame(aWhichFrame, aFlags, _retval);
|
||||
}
|
||||
|
||||
// Get the underlying dimensions.
|
||||
int32_t width, height;
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
rv = InnerImage()->GetWidth(&height);
|
||||
rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&width);
|
||||
} else {
|
||||
rv = InnerImage()->GetWidth(&width);
|
||||
rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Determine an appropriate format for the surface.
|
||||
gfx::SurfaceFormat surfaceFormat;
|
||||
gfxImageFormat imageFormat;
|
||||
if (InnerImage()->FrameIsOpaque(aWhichFrame)) {
|
||||
surfaceFormat = gfx::FORMAT_B8G8R8X8;
|
||||
imageFormat = gfxASurface::ImageFormatARGB32;
|
||||
} else {
|
||||
surfaceFormat = gfx::FORMAT_B8G8R8A8;
|
||||
imageFormat = gfxASurface::ImageFormatARGB32;
|
||||
}
|
||||
|
||||
// Create a surface to draw into.
|
||||
mozilla::RefPtr<mozilla::gfx::DrawTarget> target;
|
||||
target = gfxPlatform::GetPlatform()->
|
||||
CreateOffscreenDrawTarget(gfx::IntSize(width, height), surfaceFormat);
|
||||
nsRefPtr<gfxASurface> surface = gfxPlatform::GetPlatform()->
|
||||
GetThebesSurfaceForDrawTarget(target);
|
||||
|
||||
// Create our drawable.
|
||||
nsRefPtr<gfxASurface> innerSurface;
|
||||
rv = InnerImage()->GetFrame(aWhichFrame, aFlags, getter_AddRefs(innerSurface));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsRefPtr<gfxDrawable> drawable =
|
||||
new gfxSurfaceDrawable(innerSurface, gfxIntSize(width, height));
|
||||
|
||||
// Draw.
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(surface);
|
||||
gfxRect imageRect(0, 0, width, height);
|
||||
gfxUtils::DrawPixelSnapped(ctx, drawable, OrientationMatrix(nsIntSize(width, height)),
|
||||
imageRect, imageRect, imageRect, imageRect,
|
||||
imageFormat, gfxPattern::FILTER_FAST);
|
||||
|
||||
surface.forget(_retval);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OrientedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
|
||||
{
|
||||
// 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()) {
|
||||
return InnerImage()->GetImageContainer(aManager, _retval);
|
||||
}
|
||||
|
||||
*_retval = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
OrientedImage::OrientationMatrix(const nsIntSize& aViewportSize)
|
||||
{
|
||||
gfxMatrix matrix;
|
||||
|
||||
int32_t width, height;
|
||||
if (InnerImage()->GetType() == imgIContainer::TYPE_VECTOR) {
|
||||
width = mOrientation.SwapsWidthAndHeight() ? aViewportSize.height : aViewportSize.width;
|
||||
height = mOrientation.SwapsWidthAndHeight() ? aViewportSize.width : aViewportSize.height;
|
||||
} else {
|
||||
nsresult rv = InnerImage()->GetWidth(&width);
|
||||
rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height);
|
||||
if (NS_FAILED(rv)) {
|
||||
// Fall back to identity if the width and height aren't available.
|
||||
return matrix;
|
||||
}
|
||||
}
|
||||
|
||||
// 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()) {
|
||||
// In the coordinate system after the rotation the reflection we want
|
||||
// is across the x-axis rather than the y-axis.
|
||||
matrix.Translate(gfxPoint(0, height));
|
||||
matrix.Scale(1.0, -1.0);
|
||||
} else {
|
||||
matrix.Translate(gfxPoint(width, 0));
|
||||
matrix.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:
|
||||
matrix.Translate(gfxPoint(0, height));
|
||||
matrix.Rotate(-0.5 * M_PI);
|
||||
break;
|
||||
case Angle::D180:
|
||||
matrix.Translate(gfxPoint(width, height));
|
||||
matrix.Rotate(-1.0 * M_PI);
|
||||
break;
|
||||
case Angle::D270:
|
||||
matrix.Translate(gfxPoint(width, 0));
|
||||
matrix.Rotate(-1.5 * M_PI);
|
||||
break;
|
||||
default:
|
||||
MOZ_ASSERT(false, "Invalid rotation value");
|
||||
}
|
||||
|
||||
return matrix;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OrientedImage::Draw(gfxContext* aContext,
|
||||
gfxPattern::GraphicsFilter aFilter,
|
||||
const gfxMatrix& aUserSpaceToImageSpace,
|
||||
const gfxRect& aFill,
|
||||
const nsIntRect& aSubimage,
|
||||
const nsIntSize& aViewportSize,
|
||||
const SVGImageContext* aSVGContext,
|
||||
uint32_t aWhichFrame,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
if (mOrientation.IsIdentity()) {
|
||||
return InnerImage()->Draw(aContext, aFilter, aUserSpaceToImageSpace,
|
||||
aFill, aSubimage, aViewportSize, aSVGContext,
|
||||
aWhichFrame, aFlags);
|
||||
}
|
||||
|
||||
// Update the matrix to reorient the image.
|
||||
gfxMatrix matrix(OrientationMatrix(aViewportSize));
|
||||
gfxMatrix userSpaceToImageSpace(aUserSpaceToImageSpace * matrix);
|
||||
|
||||
// Update the subimage.
|
||||
gfxRect gfxSubimage(matrix.TransformBounds(gfxRect(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height)));
|
||||
nsIntRect subimage(gfxSubimage.x, gfxSubimage.y, gfxSubimage.width, gfxSubimage.height);
|
||||
|
||||
// Update the viewport size. (This could be done using TransformBounds but
|
||||
// since it's only a size a swap is enough.)
|
||||
nsIntSize viewportSize(aViewportSize);
|
||||
if (mOrientation.SwapsWidthAndHeight()) {
|
||||
swap(viewportSize.width, viewportSize.height);
|
||||
}
|
||||
|
||||
return InnerImage()->Draw(aContext, aFilter, userSpaceToImageSpace,
|
||||
aFill, subimage, viewportSize, aSVGContext,
|
||||
aWhichFrame, aFlags);
|
||||
}
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
67
image/src/OrientedImage.h
Normal file
67
image/src/OrientedImage.h
Normal file
@ -0,0 +1,67 @@
|
||||
/* -*- 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/. */
|
||||
|
||||
#ifndef MOZILLA_IMAGELIB_ORIENTEDIMAGE_H_
|
||||
#define MOZILLA_IMAGELIB_ORIENTEDIMAGE_H_
|
||||
|
||||
#include "ImageWrapper.h"
|
||||
#include "Orientation.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
/**
|
||||
* An Image wrapper that rotates and/or flips an image according to a specified
|
||||
* Orientation.
|
||||
*
|
||||
* XXX(seth): There a known (performance, not correctness) issue with
|
||||
* GetImageContainer. See the comments for that method for more information.
|
||||
*/
|
||||
class OrientedImage : public ImageWrapper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual ~OrientedImage() { }
|
||||
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
|
||||
NS_IMETHOD GetWidth(int32_t* aWidth) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetHeight(int32_t* aHeight) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetIntrinsicSize(nsSize* aSize) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetIntrinsicRatio(nsSize* aRatio) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetFrame(uint32_t aWhichFrame,
|
||||
uint32_t aFlags,
|
||||
gfxASurface** _retval) MOZ_OVERRIDE;
|
||||
NS_IMETHOD GetImageContainer(mozilla::layers::LayerManager* aManager,
|
||||
mozilla::layers::ImageContainer** _retval) MOZ_OVERRIDE;
|
||||
NS_IMETHOD Draw(gfxContext* aContext,
|
||||
gfxPattern::GraphicsFilter aFilter,
|
||||
const gfxMatrix& aUserSpaceToImageSpace,
|
||||
const gfxRect& aFill,
|
||||
const nsIntRect& aSubimage,
|
||||
const nsIntSize& aViewportSize,
|
||||
const SVGImageContext* aSVGContext,
|
||||
uint32_t aWhichFrame,
|
||||
uint32_t aFlags) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
OrientedImage(Image* aImage, Orientation aOrientation)
|
||||
: ImageWrapper(aImage)
|
||||
, mOrientation(aOrientation)
|
||||
{ }
|
||||
|
||||
gfxMatrix OrientationMatrix(const nsIntSize& aViewportSize);
|
||||
|
||||
private:
|
||||
Orientation mOrientation;
|
||||
|
||||
friend class ImageOps;
|
||||
};
|
||||
|
||||
} // namespace image
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // MOZILLA_IMAGELIB_ORIENTEDIMAGE_H_
|
@ -468,7 +468,7 @@ void imgFrame::Draw(gfxContext *aContext, gfxPattern::GraphicsFilter aFilter,
|
||||
}
|
||||
|
||||
gfxMatrix userSpaceToImageSpace = aUserSpaceToImageSpace;
|
||||
gfxRect sourceRect = userSpaceToImageSpace.Transform(aFill);
|
||||
gfxRect sourceRect = userSpaceToImageSpace.TransformBounds(aFill);
|
||||
gfxRect imageRect(0, 0, mSize.width + aPadding.LeftRight(),
|
||||
mSize.height + aPadding.TopBottom());
|
||||
gfxRect subimage(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height);
|
||||
|
@ -8,6 +8,7 @@ MODULE = 'imglib2'
|
||||
|
||||
EXPORTS += [
|
||||
'ImageOps.h',
|
||||
'Orientation.h',
|
||||
'imgLoader.h',
|
||||
'imgRequest.h',
|
||||
'imgRequestProxy.h',
|
||||
@ -26,6 +27,7 @@ CPP_SOURCES += [
|
||||
'ImageMetadata.cpp',
|
||||
'ImageOps.cpp',
|
||||
'ImageWrapper.cpp',
|
||||
'OrientedImage.cpp',
|
||||
'RasterImage.cpp',
|
||||
'SVGDocumentWrapper.cpp',
|
||||
'ScriptedNotificationObserver.cpp',
|
||||
|
Loading…
Reference in New Issue
Block a user