LCOV - code coverage report
Current view: directory - gfx/thebes - gfxImageSurface.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 142 29 20.4 %
Date: 2012-06-02 Functions: 16 5 31.2 %

       1                 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       2                 :  * ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is Oracle Corporation code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Oracle Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Stuart Parmenter <pavlov@pavlov.net>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : #include "prmem.h"
      39                 : 
      40                 : #include "gfxAlphaRecovery.h"
      41                 : #include "gfxImageSurface.h"
      42                 : 
      43                 : #include "cairo.h"
      44                 : 
      45               0 : gfxImageSurface::gfxImageSurface()
      46                 :   : mSize(0, 0),
      47                 :     mOwnsData(false),
      48                 :     mFormat(ImageFormatUnknown),
      49               0 :     mStride(0)
      50                 : {
      51               0 : }
      52                 : 
      53                 : void
      54               0 : gfxImageSurface::InitFromSurface(cairo_surface_t *csurf)
      55                 : {
      56               0 :     mSize.width = cairo_image_surface_get_width(csurf);
      57               0 :     mSize.height = cairo_image_surface_get_height(csurf);
      58               0 :     mData = cairo_image_surface_get_data(csurf);
      59               0 :     mFormat = (gfxImageFormat) cairo_image_surface_get_format(csurf);
      60               0 :     mOwnsData = false;
      61               0 :     mStride = cairo_image_surface_get_stride(csurf);
      62                 : 
      63               0 :     Init(csurf, true);
      64               0 : }
      65                 : 
      66               0 : gfxImageSurface::gfxImageSurface(unsigned char *aData, const gfxIntSize& aSize,
      67               0 :                                  long aStride, gfxImageFormat aFormat)
      68                 : {
      69               0 :     InitWithData(aData, aSize, aStride, aFormat);
      70               0 : }
      71                 : 
      72                 : void
      73               0 : gfxImageSurface::MakeInvalid()
      74                 : {
      75               0 :     mSize = gfxIntSize(-1, -1);
      76               0 :     mData = NULL;
      77               0 :     mStride = 0;
      78               0 : }
      79                 : 
      80                 : void
      81               0 : gfxImageSurface::InitWithData(unsigned char *aData, const gfxIntSize& aSize,
      82                 :                               long aStride, gfxImageFormat aFormat)
      83                 : {
      84               0 :     mSize = aSize;
      85               0 :     mOwnsData = false;
      86               0 :     mData = aData;
      87               0 :     mFormat = aFormat;
      88               0 :     mStride = aStride;
      89                 : 
      90               0 :     if (!CheckSurfaceSize(aSize))
      91               0 :         MakeInvalid();
      92                 : 
      93                 :     cairo_surface_t *surface =
      94                 :         cairo_image_surface_create_for_data((unsigned char*)mData,
      95                 :                                             (cairo_format_t)mFormat,
      96                 :                                             mSize.width,
      97                 :                                             mSize.height,
      98               0 :                                             mStride);
      99                 : 
     100                 :     // cairo_image_surface_create_for_data can return a 'null' surface
     101                 :     // in out of memory conditions. The gfxASurface::Init call checks
     102                 :     // the surface it receives to see if there is an error with the
     103                 :     // surface and handles it appropriately. That is why there is
     104                 :     // no check here.
     105               0 :     Init(surface);
     106               0 : }
     107                 : 
     108                 : static void*
     109              65 : TryAllocAlignedBytes(size_t aSize)
     110                 : {
     111                 :     // Use fallible allocators here
     112                 : #if defined(HAVE_POSIX_MEMALIGN) || defined(HAVE_JEMALLOC_POSIX_MEMALIGN)
     113                 :     void* ptr;
     114                 :     // Try to align for fast alpha recovery.  This should only help
     115                 :     // cairo too, can't hurt.
     116                 :     return moz_posix_memalign(&ptr,
     117              65 :                               1 << gfxAlphaRecovery::GoodAlignmentLog2(),
     118              65 :                               aSize) ?
     119              65 :              nsnull : ptr;
     120                 : #else
     121                 :     // Oh well, hope that luck is with us in the allocator
     122                 :     return moz_malloc(aSize);
     123                 : #endif
     124                 : }
     125                 : 
     126              65 : gfxImageSurface::gfxImageSurface(const gfxIntSize& size, gfxImageFormat format) :
     127              65 :     mSize(size), mOwnsData(false), mData(nsnull), mFormat(format)
     128                 : {
     129              65 :     mStride = ComputeStride();
     130                 : 
     131              65 :     if (!CheckSurfaceSize(size))
     132               0 :         MakeInvalid();
     133                 : 
     134                 :     // if we have a zero-sized surface, just leave mData nsnull
     135              65 :     if (mSize.height * mStride > 0) {
     136                 : 
     137                 :         // This can fail to allocate memory aligned as we requested,
     138                 :         // or it can fail to allocate any memory at all.
     139              65 :         mData = (unsigned char *) TryAllocAlignedBytes(mSize.height * mStride);
     140              65 :         if (!mData)
     141               0 :             return;
     142              65 :         memset(mData, 0, mSize.height * mStride);
     143                 :     }
     144                 : 
     145              65 :     mOwnsData = true;
     146                 : 
     147                 :     cairo_surface_t *surface =
     148                 :         cairo_image_surface_create_for_data((unsigned char*)mData,
     149                 :                                             (cairo_format_t)format,
     150                 :                                             mSize.width,
     151                 :                                             mSize.height,
     152              65 :                                             mStride);
     153                 : 
     154              65 :     Init(surface);
     155                 : 
     156              65 :     if (mSurfaceValid) {
     157              65 :         RecordMemoryUsed(mSize.height * ComputeStride() +
     158             130 :                          sizeof(gfxImageSurface));
     159                 :     }
     160                 : }
     161                 : 
     162               0 : gfxImageSurface::gfxImageSurface(cairo_surface_t *csurf)
     163                 : {
     164               0 :     mSize.width = cairo_image_surface_get_width(csurf);
     165               0 :     mSize.height = cairo_image_surface_get_height(csurf);
     166               0 :     mData = cairo_image_surface_get_data(csurf);
     167               0 :     mFormat = (gfxImageFormat) cairo_image_surface_get_format(csurf);
     168               0 :     mOwnsData = false;
     169               0 :     mStride = cairo_image_surface_get_stride(csurf);
     170                 : 
     171               0 :     Init(csurf, true);
     172               0 : }
     173                 : 
     174             195 : gfxImageSurface::~gfxImageSurface()
     175                 : {
     176              65 :     if (mOwnsData)
     177              65 :         free(mData);
     178             260 : }
     179                 : 
     180                 : /*static*/ long
     181             130 : gfxImageSurface::ComputeStride(const gfxIntSize& aSize, gfxImageFormat aFormat)
     182                 : {
     183                 :     long stride;
     184                 : 
     185             130 :     if (aFormat == ImageFormatARGB32)
     186             102 :         stride = aSize.width * 4;
     187              28 :     else if (aFormat == ImageFormatRGB24)
     188              28 :         stride = aSize.width * 4;
     189               0 :     else if (aFormat == ImageFormatRGB16_565)
     190               0 :         stride = aSize.width * 2;
     191               0 :     else if (aFormat == ImageFormatA8)
     192               0 :         stride = aSize.width;
     193               0 :     else if (aFormat == ImageFormatA1) {
     194               0 :         stride = (aSize.width + 7) / 8;
     195                 :     } else {
     196               0 :         NS_WARNING("Unknown format specified to gfxImageSurface!");
     197               0 :         stride = aSize.width * 4;
     198                 :     }
     199                 : 
     200             130 :     stride = ((stride + 3) / 4) * 4;
     201                 : 
     202             130 :     return stride;
     203                 : }
     204                 : 
     205                 : bool
     206               0 : gfxImageSurface::CopyFrom(gfxImageSurface *other)
     207                 : {
     208               0 :     if (other->mSize != mSize)
     209                 :     {
     210               0 :         return false;
     211                 :     }
     212                 : 
     213               0 :     if (other->mFormat != mFormat &&
     214               0 :         !(other->mFormat == ImageFormatARGB32 && mFormat == ImageFormatRGB24) &&
     215               0 :         !(other->mFormat == ImageFormatRGB24 && mFormat == ImageFormatARGB32))
     216                 :     {
     217               0 :         return false;
     218                 :     }
     219                 : 
     220               0 :     if (other->mStride == mStride) {
     221               0 :         memcpy (mData, other->mData, mStride * mSize.height);
     222                 :     } else {
     223               0 :         int lineSize = NS_MIN(other->mStride, mStride);
     224               0 :         for (int i = 0; i < mSize.height; i++) {
     225               0 :             unsigned char *src = other->mData + other->mStride * i;
     226               0 :             unsigned char *dst = mData + mStride * i;
     227                 : 
     228               0 :             memcpy (dst, src, lineSize);
     229                 :         }
     230                 :     }
     231                 : 
     232               0 :     return true;
     233                 : }
     234                 : 
     235                 : already_AddRefed<gfxSubimageSurface>
     236               0 : gfxImageSurface::GetSubimage(const gfxRect& aRect)
     237                 : {
     238               0 :     gfxRect r(aRect);
     239               0 :     r.Round();
     240               0 :     unsigned char* subData = Data() +
     241               0 :         (Stride() * (int)r.Y()) +
     242               0 :         (int)r.X() * gfxASurface::BytePerPixelFromFormat(Format());
     243                 : 
     244                 :     nsRefPtr<gfxSubimageSurface> image =
     245                 :         new gfxSubimageSurface(this, subData,
     246               0 :                                gfxIntSize((int)r.Width(), (int)r.Height()));
     247                 : 
     248               0 :     return image.forget().get();
     249                 : }
     250                 : 
     251               0 : gfxSubimageSurface::gfxSubimageSurface(gfxImageSurface* aParent,
     252                 :                                        unsigned char* aData,
     253                 :                                        const gfxIntSize& aSize)
     254               0 :   : gfxImageSurface(aData, aSize, aParent->Stride(), aParent->Format())
     255               0 :   , mParent(aParent)
     256                 : {
     257               0 : }
     258                 : 
     259                 : already_AddRefed<gfxImageSurface>
     260               0 : gfxImageSurface::GetAsImageSurface()
     261                 : {
     262               0 :   nsRefPtr<gfxImageSurface> surface = this;
     263               0 :   return surface.forget();
     264                 : }
     265                 : 
     266                 : void
     267               0 : gfxImageSurface::MovePixels(const nsIntRect& aSourceRect,
     268                 :                             const nsIntPoint& aDestTopLeft)
     269                 : {
     270               0 :     const nsIntRect bounds(0, 0, mSize.width, mSize.height);
     271               0 :     nsIntPoint offset = aDestTopLeft - aSourceRect.TopLeft(); 
     272               0 :     nsIntRect clippedSource = aSourceRect;
     273               0 :     clippedSource.IntersectRect(clippedSource, bounds);
     274               0 :     nsIntRect clippedDest = clippedSource + offset;
     275               0 :     clippedDest.IntersectRect(clippedDest, bounds);
     276               0 :     const nsIntRect dest = clippedDest;
     277               0 :     const nsIntRect source = dest - offset;
     278                 :     // NB: this relies on IntersectRect() and operator+/- preserving
     279                 :     // x/y for empty rectangles
     280               0 :     NS_ABORT_IF_FALSE(bounds.Contains(dest) && bounds.Contains(source) &&
     281                 :                       aSourceRect.Contains(source) &&
     282                 :                       nsIntRect(aDestTopLeft, aSourceRect.Size()).Contains(dest) &&
     283                 :                       source.Size() == dest.Size() &&
     284                 :                       offset == (dest.TopLeft() - source.TopLeft()),
     285                 :                       "Messed up clipping, crash or corruption will follow");
     286               0 :     if (source.IsEmpty() || source.IsEqualInterior(dest)) {
     287               0 :         return;
     288                 :     }
     289                 : 
     290               0 :     long naturalStride = ComputeStride(mSize, mFormat);
     291               0 :     if (mStride == naturalStride && dest.width == bounds.width) {
     292                 :         // Fast path: this is a vertical shift of some rows in a
     293                 :         // "normal" image surface.  We can directly memmove and
     294                 :         // hopefully stay in SIMD land.
     295               0 :         unsigned char* dst = mData + dest.y * mStride;
     296               0 :         const unsigned char* src = mData + source.y * mStride;
     297               0 :         size_t nBytes = dest.height * mStride;
     298               0 :         memmove(dst, src, nBytes);
     299               0 :         return;
     300                 :     }
     301                 : 
     302                 :     // Slow(er) path: have to move row-by-row.
     303               0 :     const PRInt32 bpp = BytePerPixelFromFormat(mFormat);
     304               0 :     const size_t nRowBytes = dest.width * bpp;
     305                 :     // dstRow points at the first pixel within the current destination
     306                 :     // row, and similarly for srcRow.  endSrcRow is one row beyond the
     307                 :     // last row we need to copy.  stride is either +mStride or
     308                 :     // -mStride, depending on which direction we're copying.
     309                 :     unsigned char* dstRow;
     310                 :     unsigned char* srcRow;
     311                 :     unsigned char* endSrcRow;   // NB: this may point outside the image
     312                 :     long stride;
     313               0 :     if (dest.y > source.y) {
     314                 :         // We're copying down from source to dest, so walk backwards
     315                 :         // starting from the last rows to avoid stomping pixels we
     316                 :         // need.
     317               0 :         stride = -mStride;
     318               0 :         dstRow = mData + dest.x * bpp + (dest.YMost() - 1) * mStride;
     319               0 :         srcRow = mData + source.x * bpp + (source.YMost() - 1) * mStride;
     320               0 :         endSrcRow = mData + source.x * bpp + (source.y - 1) * mStride;
     321                 :     } else {
     322               0 :         stride = mStride;
     323               0 :         dstRow = mData + dest.x * bpp + dest.y * mStride;
     324               0 :         srcRow = mData + source.x * bpp + source.y * mStride;
     325               0 :         endSrcRow = mData + source.x * bpp + source.YMost() * mStride;
     326                 :     }
     327                 : 
     328               0 :     for (; srcRow != endSrcRow; dstRow += stride, srcRow += stride) {
     329               0 :         memmove(dstRow, srcRow, nRowBytes);
     330                 :     }
     331                 : }

Generated by: LCOV version 1.7