image/src/OrientedImage.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <algorithm>
     8 #include "gfxDrawable.h"
     9 #include "gfxPlatform.h"
    10 #include "gfxUtils.h"
    12 #include "OrientedImage.h"
    14 using namespace mozilla::gfx;
    16 using std::swap;
    17 using mozilla::layers::LayerManager;
    18 using mozilla::layers::ImageContainer;
    20 namespace mozilla {
    21 namespace image {
    23 NS_IMPL_ISUPPORTS(OrientedImage, imgIContainer)
    25 nsIntRect
    26 OrientedImage::FrameRect(uint32_t aWhichFrame)
    27 {
    28   if (mOrientation.SwapsWidthAndHeight()) {
    29     nsIntRect innerRect = InnerImage()->FrameRect(aWhichFrame);
    30     return nsIntRect(innerRect.x, innerRect.y, innerRect.height, innerRect.width);
    31   } else {
    32     return InnerImage()->FrameRect(aWhichFrame);
    33   }
    34 }
    36 NS_IMETHODIMP
    37 OrientedImage::GetWidth(int32_t* aWidth)
    38 {
    39   if (mOrientation.SwapsWidthAndHeight()) {
    40     return InnerImage()->GetHeight(aWidth);
    41   } else {
    42     return InnerImage()->GetWidth(aWidth);
    43   }
    44 }
    46 NS_IMETHODIMP
    47 OrientedImage::GetHeight(int32_t* aHeight)
    48 {
    49   if (mOrientation.SwapsWidthAndHeight()) {
    50     return InnerImage()->GetWidth(aHeight);
    51   } else {
    52     return InnerImage()->GetHeight(aHeight);
    53   }
    54 }
    56 NS_IMETHODIMP
    57 OrientedImage::GetIntrinsicSize(nsSize* aSize)
    58 {
    59   nsresult rv = InnerImage()->GetIntrinsicSize(aSize);
    61   if (mOrientation.SwapsWidthAndHeight()) {
    62     swap(aSize->width, aSize->height);
    63   }
    65   return rv;
    66 }
    68 NS_IMETHODIMP
    69 OrientedImage::GetIntrinsicRatio(nsSize* aRatio)
    70 {
    71   nsresult rv = InnerImage()->GetIntrinsicRatio(aRatio);
    73   if (mOrientation.SwapsWidthAndHeight()) {
    74     swap(aRatio->width, aRatio->height);
    75   }
    77   return rv;
    78 }
    80 NS_IMETHODIMP_(TemporaryRef<SourceSurface>)
    81 OrientedImage::GetFrame(uint32_t aWhichFrame,
    82                         uint32_t aFlags)
    83 {
    84   nsresult rv;
    86   if (mOrientation.IsIdentity()) {
    87     return InnerImage()->GetFrame(aWhichFrame, aFlags);
    88   }
    90   // Get the underlying dimensions.
    91   int32_t width, height;
    92   rv = InnerImage()->GetWidth(&width);
    93   NS_ENSURE_SUCCESS(rv, nullptr);
    94   rv = InnerImage()->GetHeight(&height);
    95   NS_ENSURE_SUCCESS(rv, nullptr);
    96   if (mOrientation.SwapsWidthAndHeight()) {
    97     swap(width, height);
    98   }
    99   NS_ENSURE_SUCCESS(rv, nullptr);
   101   // Determine an appropriate format for the surface.
   102   gfx::SurfaceFormat surfaceFormat;
   103   gfxImageFormat imageFormat;
   104   if (InnerImage()->FrameIsOpaque(aWhichFrame)) {
   105     surfaceFormat = gfx::SurfaceFormat::B8G8R8X8;
   106     imageFormat = gfxImageFormat::ARGB32;
   107   } else {
   108     surfaceFormat = gfx::SurfaceFormat::B8G8R8A8;
   109     imageFormat = gfxImageFormat::ARGB32;
   110   }
   112   // Create a surface to draw into.
   113   mozilla::RefPtr<DrawTarget> target =
   114     gfxPlatform::GetPlatform()->
   115       CreateOffscreenContentDrawTarget(IntSize(width, height), surfaceFormat);
   117   // Create our drawable.
   118   RefPtr<SourceSurface> innerSurface =
   119     InnerImage()->GetFrame(aWhichFrame, aFlags);
   120   NS_ENSURE_TRUE(innerSurface, nullptr);
   121   nsRefPtr<gfxDrawable> drawable =
   122     new gfxSurfaceDrawable(innerSurface, gfxIntSize(width, height));
   124   // Draw.
   125   nsRefPtr<gfxContext> ctx = new gfxContext(target);
   126   gfxRect imageRect(0, 0, width, height);
   127   gfxUtils::DrawPixelSnapped(ctx, drawable, OrientationMatrix(nsIntSize(width, height)),
   128                              imageRect, imageRect, imageRect, imageRect,
   129                              imageFormat, GraphicsFilter::FILTER_FAST);
   131   return target->Snapshot();
   132 }
   134 NS_IMETHODIMP
   135 OrientedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval)
   136 {
   137   // XXX(seth): We currently don't have a way of orienting the result of
   138   // GetImageContainer. We work around this by always returning null, but if it
   139   // ever turns out that OrientedImage is widely used on codepaths that can
   140   // actually benefit from GetImageContainer, it would be a good idea to fix
   141   // that method for performance reasons.
   143   if (mOrientation.IsIdentity()) {
   144     return InnerImage()->GetImageContainer(aManager, _retval);
   145   }
   147   *_retval = nullptr;
   148   return NS_OK;
   149 }
   151 gfxMatrix
   152 OrientedImage::OrientationMatrix(const nsIntSize& aViewportSize)
   153 {
   154     gfxMatrix matrix;
   156     int32_t width, height;
   157     if (InnerImage()->GetType() == imgIContainer::TYPE_VECTOR) {
   158       width = mOrientation.SwapsWidthAndHeight() ? aViewportSize.height : aViewportSize.width;
   159       height = mOrientation.SwapsWidthAndHeight() ? aViewportSize.width : aViewportSize.height;
   160     } else {
   161       nsresult rv = InnerImage()->GetWidth(&width);
   162       rv = NS_FAILED(rv) ? rv : InnerImage()->GetHeight(&height);
   163       if (NS_FAILED(rv)) {
   164         // Fall back to identity if the width and height aren't available.
   165         return matrix;
   166       }
   167     }
   169     // Apply reflection, if present. (This logically happens second, but we
   170     // apply it first because these transformations are all premultiplied.) A
   171     // translation is necessary to place the image back in the first quadrant.
   172     switch (mOrientation.flip) {
   173       case Flip::Unflipped:
   174         break;
   175       case Flip::Horizontal:
   176         if (mOrientation.SwapsWidthAndHeight()) {
   177           // In the coordinate system after the rotation the reflection we want
   178           // is across the x-axis rather than the y-axis.
   179           matrix.Translate(gfxPoint(0, height));
   180           matrix.Scale(1.0, -1.0);
   181         } else {
   182           matrix.Translate(gfxPoint(width, 0));
   183           matrix.Scale(-1.0, 1.0);
   184         }
   185         break;
   186       default:
   187         MOZ_ASSERT(false, "Invalid flip value");
   188     }
   190     // Apply rotation, if present. Again, a translation is used to place the
   191     // image back in the first quadrant.
   192     switch (mOrientation.rotation) {
   193       case Angle::D0:
   194         break;
   195       case Angle::D90:
   196         matrix.Translate(gfxPoint(0, height));
   197         matrix.Rotate(-0.5 * M_PI);
   198         break;
   199       case Angle::D180:
   200         matrix.Translate(gfxPoint(width, height));
   201         matrix.Rotate(-1.0 * M_PI);
   202         break;
   203       case Angle::D270:
   204         matrix.Translate(gfxPoint(width, 0));
   205         matrix.Rotate(-1.5 * M_PI);
   206         break;
   207       default:
   208         MOZ_ASSERT(false, "Invalid rotation value");
   209     }
   211     return matrix;
   212 }
   214 NS_IMETHODIMP
   215 OrientedImage::Draw(gfxContext* aContext,
   216                     GraphicsFilter aFilter,
   217                     const gfxMatrix& aUserSpaceToImageSpace,
   218                     const gfxRect& aFill,
   219                     const nsIntRect& aSubimage,
   220                     const nsIntSize& aViewportSize,
   221                     const SVGImageContext* aSVGContext,
   222                     uint32_t aWhichFrame,
   223                     uint32_t aFlags)
   224 {
   225   if (mOrientation.IsIdentity()) {
   226     return InnerImage()->Draw(aContext, aFilter, aUserSpaceToImageSpace,
   227                               aFill, aSubimage, aViewportSize, aSVGContext,
   228                               aWhichFrame, aFlags);
   229   }
   231   // Update the matrix to reorient the image.
   232   gfxMatrix matrix(OrientationMatrix(aViewportSize));
   233   gfxMatrix userSpaceToImageSpace(aUserSpaceToImageSpace * matrix);
   235   // Update the subimage.
   236   gfxRect gfxSubimage(matrix.TransformBounds(gfxRect(aSubimage.x, aSubimage.y, aSubimage.width, aSubimage.height)));
   237   nsIntRect subimage(gfxSubimage.x, gfxSubimage.y, gfxSubimage.width, gfxSubimage.height);
   239   // Update the viewport size. (This could be done using TransformBounds but
   240   // since it's only a size a swap is enough.)
   241   nsIntSize viewportSize(aViewportSize);
   242   if (mOrientation.SwapsWidthAndHeight()) {
   243     swap(viewportSize.width, viewportSize.height);
   244   }
   246   return InnerImage()->Draw(aContext, aFilter, userSpaceToImageSpace,
   247                             aFill, subimage, viewportSize, aSVGContext,
   248                             aWhichFrame, aFlags);
   249 }
   251 } // namespace image
   252 } // namespace mozilla

mercurial