LCOV - code coverage report
Current view: top level - gfx/thebes - gfxImageSurface.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 35 181 19.3 %
Date: 2017-07-14 16:53:18 Functions: 4 25 16.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
       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/. */
       5             : 
       6             : 
       7             : #include "mozilla/MemoryReporting.h"
       8             : #if defined(HAVE_POSIX_MEMALIGN)
       9             : #include "gfxAlphaRecovery.h"
      10             : #endif
      11             : #include "gfxImageSurface.h"
      12             : 
      13             : #include "cairo.h"
      14             : #include "mozilla/gfx/2D.h"
      15             : #include "mozilla/gfx/HelpersCairo.h"
      16             : #include "gfx2DGlue.h"
      17             : #include <algorithm>
      18             : 
      19             : using namespace mozilla;
      20             : using namespace mozilla::gfx;
      21             : 
      22           0 : gfxImageSurface::gfxImageSurface()
      23             :   : mSize(0, 0),
      24             :     mOwnsData(false),
      25             :     mFormat(SurfaceFormat::UNKNOWN),
      26           0 :     mStride(0)
      27             : {
      28           0 : }
      29             : 
      30             : void
      31           0 : gfxImageSurface::InitFromSurface(cairo_surface_t *csurf)
      32             : {
      33           0 :     if (!csurf || cairo_surface_status(csurf)) {
      34           0 :         MakeInvalid();
      35           0 :         return;
      36             :     }
      37             : 
      38           0 :     mSize.width = cairo_image_surface_get_width(csurf);
      39           0 :     mSize.height = cairo_image_surface_get_height(csurf);
      40           0 :     mData = cairo_image_surface_get_data(csurf);
      41           0 :     mFormat = CairoFormatToGfxFormat(cairo_image_surface_get_format(csurf));
      42           0 :     mOwnsData = false;
      43           0 :     mStride = cairo_image_surface_get_stride(csurf);
      44             : 
      45           0 :     Init(csurf, true);
      46             : }
      47             : 
      48           0 : gfxImageSurface::gfxImageSurface(unsigned char *aData, const IntSize& aSize,
      49           0 :                                  long aStride, gfxImageFormat aFormat)
      50             : {
      51           0 :     InitWithData(aData, aSize, aStride, aFormat);
      52           0 : }
      53             : 
      54             : void
      55           0 : gfxImageSurface::MakeInvalid()
      56             : {
      57           0 :     mSize = IntSize(-1, -1);
      58           0 :     mData = nullptr;
      59           0 :     mStride = 0;
      60           0 : }
      61             : 
      62             : void
      63           0 : gfxImageSurface::InitWithData(unsigned char *aData, const IntSize& aSize,
      64             :                               long aStride, gfxImageFormat aFormat)
      65             : {
      66           0 :     mSize = aSize;
      67           0 :     mOwnsData = false;
      68           0 :     mData = aData;
      69           0 :     mFormat = aFormat;
      70           0 :     mStride = aStride;
      71             : 
      72           0 :     if (!Factory::CheckSurfaceSize(aSize))
      73           0 :         MakeInvalid();
      74             : 
      75           0 :     cairo_format_t cformat = GfxFormatToCairoFormat(mFormat);
      76             :     cairo_surface_t *surface =
      77           0 :         cairo_image_surface_create_for_data((unsigned char*)mData,
      78             :                                             cformat,
      79             :                                             mSize.width,
      80             :                                             mSize.height,
      81           0 :                                             mStride);
      82             : 
      83             :     // cairo_image_surface_create_for_data can return a 'null' surface
      84             :     // in out of memory conditions. The gfxASurface::Init call checks
      85             :     // the surface it receives to see if there is an error with the
      86             :     // surface and handles it appropriately. That is why there is
      87             :     // no check here.
      88           0 :     Init(surface);
      89           0 : }
      90             : 
      91             : static void*
      92           3 : TryAllocAlignedBytes(size_t aSize)
      93             : {
      94             :     // Use fallible allocators here
      95             : #if defined(HAVE_POSIX_MEMALIGN)
      96             :     void* ptr;
      97             :     // Try to align for fast alpha recovery.  This should only help
      98             :     // cairo too, can't hurt.
      99           3 :     return moz_posix_memalign(&ptr,
     100           3 :                               1 << gfxAlphaRecovery::GoodAlignmentLog2(),
     101           3 :                               aSize) ?
     102           3 :              nullptr : ptr;
     103             : #else
     104             :     // Oh well, hope that luck is with us in the allocator
     105             :     return malloc(aSize);
     106             : #endif
     107             : }
     108             : 
     109           3 : gfxImageSurface::gfxImageSurface(const IntSize& size, gfxImageFormat format, bool aClear)
     110           3 :  : mSize(size), mData(nullptr), mFormat(format)
     111             : {
     112           3 :     AllocateAndInit(0, 0, aClear);
     113           3 : }
     114             : 
     115             : void 
     116           3 : gfxImageSurface::AllocateAndInit(long aStride, int32_t aMinimalAllocation,
     117             :                                  bool aClear)
     118             : {
     119             :     // The callers should set mSize and mFormat.
     120           3 :     MOZ_ASSERT(!mData);
     121           3 :     mData = nullptr;
     122           3 :     mOwnsData = false;
     123             : 
     124           3 :     mStride = aStride > 0 ? aStride : ComputeStride();
     125           3 :     if (aMinimalAllocation < mSize.height * mStride)
     126           3 :         aMinimalAllocation = mSize.height * mStride;
     127             : 
     128           3 :     if (!Factory::CheckSurfaceSize(mSize))
     129           0 :         MakeInvalid();
     130             : 
     131             :     // if we have a zero-sized surface, just leave mData nullptr
     132           3 :     if (mSize.height * mStride > 0) {
     133             : 
     134             :         // This can fail to allocate memory aligned as we requested,
     135             :         // or it can fail to allocate any memory at all.
     136           3 :         mData = (unsigned char *) TryAllocAlignedBytes(aMinimalAllocation);
     137           3 :         if (!mData)
     138           0 :             return;
     139           3 :         if (aClear)
     140           3 :             memset(mData, 0, aMinimalAllocation);
     141             :     }
     142             : 
     143           3 :     mOwnsData = true;
     144             : 
     145           3 :     cairo_format_t cformat = GfxFormatToCairoFormat(mFormat);
     146             :     cairo_surface_t *surface =
     147           3 :         cairo_image_surface_create_for_data((unsigned char*)mData,
     148             :                                             cformat,
     149             :                                             mSize.width,
     150             :                                             mSize.height,
     151           6 :                                             mStride);
     152             : 
     153           3 :     Init(surface);
     154             : 
     155           3 :     if (mSurfaceValid) {
     156           3 :         RecordMemoryUsed(mSize.height * ComputeStride() +
     157           3 :                          sizeof(gfxImageSurface));
     158             :     }
     159             : }
     160             : 
     161           0 : gfxImageSurface::gfxImageSurface(const IntSize& size, gfxImageFormat format,
     162           0 :                                  long aStride, int32_t aExtraBytes, bool aClear)
     163           0 :  : mSize(size), mData(nullptr), mFormat(format)
     164             : {
     165           0 :     AllocateAndInit(aStride, aExtraBytes, aClear);
     166           0 : }
     167             : 
     168           0 : gfxImageSurface::gfxImageSurface(cairo_surface_t *csurf)
     169             : {
     170           0 :     mSize.width = cairo_image_surface_get_width(csurf);
     171           0 :     mSize.height = cairo_image_surface_get_height(csurf);
     172           0 :     mData = cairo_image_surface_get_data(csurf);
     173           0 :     mFormat = CairoFormatToGfxFormat(cairo_image_surface_get_format(csurf));
     174           0 :     mOwnsData = false;
     175           0 :     mStride = cairo_image_surface_get_stride(csurf);
     176             : 
     177           0 :     Init(csurf, true);
     178           0 : }
     179             : 
     180           0 : gfxImageSurface::~gfxImageSurface()
     181             : {
     182           0 :     if (mOwnsData)
     183           0 :         free(mData);
     184           0 : }
     185             : 
     186             : /*static*/ long
     187           6 : gfxImageSurface::ComputeStride(const IntSize& aSize, gfxImageFormat aFormat)
     188             : {
     189             :     long stride;
     190             : 
     191           6 :     if (aFormat == SurfaceFormat::A8R8G8B8_UINT32)
     192           6 :         stride = aSize.width * 4;
     193           0 :     else if (aFormat == SurfaceFormat::X8R8G8B8_UINT32)
     194           0 :         stride = aSize.width * 4;
     195           0 :     else if (aFormat == SurfaceFormat::R5G6B5_UINT16)
     196           0 :         stride = aSize.width * 2;
     197           0 :     else if (aFormat == SurfaceFormat::A8)
     198           0 :         stride = aSize.width;
     199             :     else {
     200           0 :         NS_WARNING("Unknown format specified to gfxImageSurface!");
     201           0 :         stride = aSize.width * 4;
     202             :     }
     203             : 
     204           6 :     stride = ((stride + 3) / 4) * 4;
     205             : 
     206           6 :     return stride;
     207             : }
     208             : 
     209             : size_t
     210           0 : gfxImageSurface::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     211             : {
     212           0 :     size_t n = gfxASurface::SizeOfExcludingThis(aMallocSizeOf);
     213           0 :     if (mOwnsData) {
     214           0 :         n += aMallocSizeOf(mData);
     215             :     }
     216           0 :     return n;
     217             : }
     218             : 
     219             : size_t
     220           0 : gfxImageSurface::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
     221             : {
     222           0 :     return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
     223             : }
     224             : 
     225             : bool
     226           0 : gfxImageSurface::SizeOfIsMeasured() const
     227             : {
     228           0 :     return true;
     229             : }
     230             : 
     231             : // helper function for the CopyFrom methods
     232             : static void
     233           0 : CopyForStride(unsigned char* aDest, unsigned char* aSrc, const IntSize& aSize, long aDestStride, long aSrcStride)
     234             : {
     235           0 :     if (aDestStride == aSrcStride) {
     236           0 :         memcpy (aDest, aSrc, aSrcStride * aSize.height);
     237             :     } else {
     238           0 :         int lineSize = std::min(aDestStride, aSrcStride);
     239           0 :         for (int i = 0; i < aSize.height; i++) {
     240           0 :             unsigned char* src = aSrc + aSrcStride * i;
     241           0 :             unsigned char* dst = aDest + aDestStride * i;
     242             : 
     243           0 :             memcpy (dst, src, lineSize);
     244             :         }
     245             :     }
     246           0 : }
     247             : 
     248             : // helper function for the CopyFrom methods
     249             : static bool
     250           0 : FormatsAreCompatible(gfxImageFormat a1, gfxImageFormat a2)
     251             : {
     252           0 :     if (a1 != a2 &&
     253           0 :         !(a1 == SurfaceFormat::A8R8G8B8_UINT32 &&
     254           0 :           a2 == SurfaceFormat::X8R8G8B8_UINT32) &&
     255           0 :         !(a1 == SurfaceFormat::X8R8G8B8_UINT32 &&
     256             :           a2 == SurfaceFormat::A8R8G8B8_UINT32)) {
     257           0 :         return false;
     258             :     }
     259             : 
     260           0 :     return true;
     261             : }
     262             : 
     263             : bool
     264           0 : gfxImageSurface::CopyFrom (SourceSurface *aSurface)
     265             : {
     266           0 :     RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
     267             : 
     268           0 :     if (!data) {
     269           0 :         return false;
     270             :     }
     271             : 
     272           0 :     IntSize size(data->GetSize().width, data->GetSize().height);
     273           0 :     if (size != mSize) {
     274           0 :         return false;
     275             :     }
     276             : 
     277           0 :     if (!FormatsAreCompatible(SurfaceFormatToImageFormat(aSurface->GetFormat()),
     278             :                               mFormat)) {
     279           0 :         return false;
     280             :     }
     281             : 
     282           0 :     CopyForStride(mData, data->GetData(), size, mStride, data->Stride());
     283             : 
     284           0 :     return true;
     285             : }
     286             : 
     287             : 
     288             : bool
     289           0 : gfxImageSurface::CopyFrom(gfxImageSurface *other)
     290             : {
     291           0 :     if (other->mSize != mSize) {
     292           0 :         return false;
     293             :     }
     294             : 
     295           0 :     if (!FormatsAreCompatible(other->mFormat, mFormat)) {
     296           0 :         return false;
     297             :     }
     298             : 
     299           0 :     CopyForStride(mData, other->mData, mSize, mStride, other->mStride);
     300             : 
     301           0 :     return true;
     302             : }
     303             : 
     304             : bool
     305           0 : gfxImageSurface::CopyTo(SourceSurface *aSurface) {
     306           0 :     RefPtr<DataSourceSurface> data = aSurface->GetDataSurface();
     307             : 
     308           0 :     if (!data) {
     309           0 :         return false;
     310             :     }
     311             : 
     312           0 :     IntSize size(data->GetSize().width, data->GetSize().height);
     313           0 :     if (size != mSize) {
     314           0 :         return false;
     315             :     }
     316             : 
     317           0 :     if (!FormatsAreCompatible(SurfaceFormatToImageFormat(aSurface->GetFormat()),
     318             :                               mFormat)) {
     319           0 :         return false;
     320             :     }
     321             : 
     322           0 :     CopyForStride(data->GetData(), mData, size, data->Stride(), mStride);
     323             : 
     324           0 :     return true;
     325             : }
     326             : 
     327             : already_AddRefed<DataSourceSurface>
     328           0 : gfxImageSurface::CopyToB8G8R8A8DataSourceSurface()
     329             : {
     330             :   RefPtr<DataSourceSurface> dataSurface =
     331           0 :     Factory::CreateDataSourceSurface(IntSize(GetSize().width, GetSize().height),
     332           0 :                                      SurfaceFormat::B8G8R8A8);
     333           0 :   if (dataSurface) {
     334           0 :     CopyTo(dataSurface);
     335             :   }
     336           0 :   return dataSurface.forget();
     337             : }
     338             : 
     339             : already_AddRefed<gfxSubimageSurface>
     340           0 : gfxImageSurface::GetSubimage(const gfxRect& aRect)
     341             : {
     342           0 :     gfxRect r(aRect);
     343           0 :     r.Round();
     344           0 :     MOZ_ASSERT(gfxRect(0, 0, mSize.width, mSize.height).Contains(r));
     345             : 
     346           0 :     gfxImageFormat format = Format();
     347             : 
     348           0 :     unsigned char* subData = Data() +
     349           0 :         (Stride() * (int)r.Y()) +
     350           0 :         (int)r.X() * gfxASurface::BytePerPixelFromFormat(Format());
     351             : 
     352           0 :     if (format == SurfaceFormat::A8R8G8B8_UINT32 &&
     353           0 :         GetOpaqueRect().Contains(aRect)) {
     354           0 :         format = SurfaceFormat::X8R8G8B8_UINT32;
     355             :     }
     356             : 
     357             :     RefPtr<gfxSubimageSurface> image =
     358             :         new gfxSubimageSurface(this, subData,
     359           0 :                                IntSize((int)r.Width(), (int)r.Height()),
     360           0 :                                format);
     361             : 
     362           0 :     return image.forget();
     363             : }
     364             : 
     365           0 : gfxSubimageSurface::gfxSubimageSurface(gfxImageSurface* aParent,
     366             :                                        unsigned char* aData,
     367             :                                        const IntSize& aSize,
     368           0 :                                        gfxImageFormat aFormat)
     369           0 :   : gfxImageSurface(aData, aSize, aParent->Stride(), aFormat)
     370           0 :   , mParent(aParent)
     371             : {
     372           0 : }
     373             : 
     374             : already_AddRefed<gfxImageSurface>
     375           0 : gfxImageSurface::GetAsImageSurface()
     376             : {
     377           0 :   RefPtr<gfxImageSurface> surface = this;
     378           0 :   return surface.forget();
     379             : }

Generated by: LCOV version 1.13