1 /* -*- Mode: C++; tab-width: 20; 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 "mozilla/MemoryReporting.h"
7 #if defined(HAVE_POSIX_MEMALIGN)
8 # include "gfxAlphaRecovery.h"
10 #include "gfxImageSurface.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/gfx/HelpersCairo.h"
15 #include "gfx2DGlue.h"
18 using namespace mozilla
;
19 using namespace mozilla::gfx
;
21 gfxImageSurface::gfxImageSurface()
25 mFormat(SurfaceFormat::UNKNOWN
),
28 void gfxImageSurface::InitFromSurface(cairo_surface_t
* csurf
) {
29 if (!csurf
|| cairo_surface_status(csurf
)) {
34 mSize
.width
= cairo_image_surface_get_width(csurf
);
35 mSize
.height
= cairo_image_surface_get_height(csurf
);
36 mData
= cairo_image_surface_get_data(csurf
);
37 mFormat
= CairoFormatToGfxFormat(cairo_image_surface_get_format(csurf
));
39 mStride
= cairo_image_surface_get_stride(csurf
);
44 gfxImageSurface::gfxImageSurface(unsigned char* aData
, const IntSize
& aSize
,
45 long aStride
, gfxImageFormat aFormat
) {
46 InitWithData(aData
, aSize
, aStride
, aFormat
);
49 void gfxImageSurface::MakeInvalid() {
50 mSize
= IntSize(-1, -1);
55 void gfxImageSurface::InitWithData(unsigned char* aData
, const IntSize
& aSize
,
56 long aStride
, gfxImageFormat aFormat
) {
63 if (!Factory::CheckSurfaceSize(aSize
)) MakeInvalid();
65 cairo_format_t cformat
= GfxFormatToCairoFormat(mFormat
);
66 cairo_surface_t
* surface
= cairo_image_surface_create_for_data(
67 (unsigned char*)mData
, cformat
, mSize
.width
, mSize
.height
, mStride
);
69 // cairo_image_surface_create_for_data can return a 'null' surface
70 // in out of memory conditions. The gfxASurface::Init call checks
71 // the surface it receives to see if there is an error with the
72 // surface and handles it appropriately. That is why there is
77 static void* TryAllocAlignedBytes(size_t aSize
) {
78 // Use fallible allocators here
79 #if defined(HAVE_POSIX_MEMALIGN)
81 // Try to align for fast alpha recovery. This should only help
82 // cairo too, can't hurt.
83 return posix_memalign(&ptr
, 1 << gfxAlphaRecovery::GoodAlignmentLog2(), aSize
)
87 // Oh well, hope that luck is with us in the allocator
92 gfxImageSurface::gfxImageSurface(const IntSize
& size
, gfxImageFormat format
,
94 : mSize(size
), mData(nullptr), mFormat(format
) {
95 AllocateAndInit(0, 0, aClear
);
98 void gfxImageSurface::AllocateAndInit(long aStride
, int32_t aMinimalAllocation
,
100 // The callers should set mSize and mFormat.
105 mStride
= aStride
> 0 ? aStride
: ComputeStride();
106 if (aMinimalAllocation
< mSize
.height
* mStride
)
107 aMinimalAllocation
= mSize
.height
* mStride
;
109 if (!Factory::CheckSurfaceSize(mSize
)) MakeInvalid();
111 // if we have a zero-sized surface, just leave mData nullptr
112 if (mSize
.height
* mStride
> 0) {
113 // This can fail to allocate memory aligned as we requested,
114 // or it can fail to allocate any memory at all.
115 mData
= (unsigned char*)TryAllocAlignedBytes(aMinimalAllocation
);
117 if (aClear
) memset(mData
, 0, aMinimalAllocation
);
122 cairo_format_t cformat
= GfxFormatToCairoFormat(mFormat
);
123 cairo_surface_t
* surface
= cairo_image_surface_create_for_data(
124 (unsigned char*)mData
, cformat
, mSize
.width
, mSize
.height
, mStride
);
129 RecordMemoryUsed(mSize
.height
* ComputeStride() + sizeof(gfxImageSurface
));
133 gfxImageSurface::gfxImageSurface(const IntSize
& size
, gfxImageFormat format
,
134 long aStride
, int32_t aExtraBytes
, bool aClear
)
135 : mSize(size
), mData(nullptr), mFormat(format
) {
136 AllocateAndInit(aStride
, aExtraBytes
, aClear
);
139 gfxImageSurface::gfxImageSurface(cairo_surface_t
* csurf
) {
140 mSize
.width
= cairo_image_surface_get_width(csurf
);
141 mSize
.height
= cairo_image_surface_get_height(csurf
);
142 mData
= cairo_image_surface_get_data(csurf
);
143 mFormat
= CairoFormatToGfxFormat(cairo_image_surface_get_format(csurf
));
145 mStride
= cairo_image_surface_get_stride(csurf
);
150 gfxImageSurface::~gfxImageSurface() {
151 if (mOwnsData
) free(mData
);
155 long gfxImageSurface::ComputeStride(const IntSize
& aSize
,
156 gfxImageFormat aFormat
) {
159 if (aFormat
== SurfaceFormat::A8R8G8B8_UINT32
)
160 stride
= aSize
.width
* 4;
161 else if (aFormat
== SurfaceFormat::X8R8G8B8_UINT32
)
162 stride
= aSize
.width
* 4;
163 else if (aFormat
== SurfaceFormat::R5G6B5_UINT16
)
164 stride
= aSize
.width
* 2;
165 else if (aFormat
== SurfaceFormat::A8
)
166 stride
= aSize
.width
;
168 NS_WARNING("Unknown format specified to gfxImageSurface!");
169 stride
= aSize
.width
* 4;
172 stride
= ((stride
+ 3) / 4) * 4;
177 size_t gfxImageSurface::SizeOfExcludingThis(
178 mozilla::MallocSizeOf aMallocSizeOf
) const {
179 size_t n
= gfxASurface::SizeOfExcludingThis(aMallocSizeOf
);
181 n
+= aMallocSizeOf(mData
);
186 size_t gfxImageSurface::SizeOfIncludingThis(
187 mozilla::MallocSizeOf aMallocSizeOf
) const {
188 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf
);
191 bool gfxImageSurface::SizeOfIsMeasured() const { return true; }
193 // helper function for the CopyFrom methods
194 static void CopyForStride(unsigned char* aDest
, unsigned char* aSrc
,
195 const IntSize
& aSize
, long aDestStride
,
197 if (aDestStride
== aSrcStride
) {
198 memcpy(aDest
, aSrc
, aSrcStride
* aSize
.height
);
200 int lineSize
= std::min(aDestStride
, aSrcStride
);
201 for (int i
= 0; i
< aSize
.height
; i
++) {
202 unsigned char* src
= aSrc
+ aSrcStride
* i
;
203 unsigned char* dst
= aDest
+ aDestStride
* i
;
205 memcpy(dst
, src
, lineSize
);
210 // helper function for the CopyFrom methods
211 static bool FormatsAreCompatible(gfxImageFormat a1
, gfxImageFormat a2
) {
213 !(a1
== SurfaceFormat::A8R8G8B8_UINT32
&&
214 a2
== SurfaceFormat::X8R8G8B8_UINT32
) &&
215 !(a1
== SurfaceFormat::X8R8G8B8_UINT32
&&
216 a2
== SurfaceFormat::A8R8G8B8_UINT32
)) {
223 bool gfxImageSurface::CopyFrom(SourceSurface
* aSurface
) {
224 RefPtr
<DataSourceSurface
> data
= aSurface
->GetDataSurface();
230 IntSize
size(data
->GetSize().width
, data
->GetSize().height
);
235 if (!FormatsAreCompatible(SurfaceFormatToImageFormat(aSurface
->GetFormat()),
240 DataSourceSurface::ScopedMap
map(data
, DataSourceSurface::READ
);
241 CopyForStride(mData
, map
.GetData(), size
, mStride
, map
.GetStride());
246 bool gfxImageSurface::CopyFrom(gfxImageSurface
* other
) {
247 if (other
->mSize
!= mSize
) {
251 if (!FormatsAreCompatible(other
->mFormat
, mFormat
)) {
255 CopyForStride(mData
, other
->mData
, mSize
, mStride
, other
->mStride
);
260 bool gfxImageSurface::CopyTo(SourceSurface
* aSurface
) {
261 RefPtr
<DataSourceSurface
> data
= aSurface
->GetDataSurface();
267 IntSize
size(data
->GetSize().width
, data
->GetSize().height
);
272 if (!FormatsAreCompatible(SurfaceFormatToImageFormat(aSurface
->GetFormat()),
277 DataSourceSurface::ScopedMap
map(data
, DataSourceSurface::READ_WRITE
);
278 CopyForStride(map
.GetData(), mData
, size
, map
.GetStride(), mStride
);
283 already_AddRefed
<DataSourceSurface
>
284 gfxImageSurface::CopyToB8G8R8A8DataSourceSurface() {
285 RefPtr
<DataSourceSurface
> dataSurface
= Factory::CreateDataSourceSurface(
286 IntSize(GetSize().width
, GetSize().height
), SurfaceFormat::B8G8R8A8
);
290 return dataSurface
.forget();
293 already_AddRefed
<gfxSubimageSurface
> gfxImageSurface::GetSubimage(
294 const gfxRect
& aRect
) {
297 MOZ_ASSERT(gfxRect(0, 0, mSize
.width
, mSize
.height
).Contains(r
));
299 gfxImageFormat format
= Format();
301 unsigned char* subData
=
302 Data() + (Stride() * (int)r
.Y()) +
303 (int)r
.X() * gfxASurface::BytePerPixelFromFormat(Format());
305 if (format
== SurfaceFormat::A8R8G8B8_UINT32
&&
306 GetOpaqueRect().Contains(aRect
)) {
307 format
= SurfaceFormat::X8R8G8B8_UINT32
;
310 RefPtr
<gfxSubimageSurface
> image
= new gfxSubimageSurface(
311 this, subData
, IntSize((int)r
.Width(), (int)r
.Height()), format
);
313 return image
.forget();
316 gfxSubimageSurface::gfxSubimageSurface(gfxImageSurface
* aParent
,
317 unsigned char* aData
,
318 const IntSize
& aSize
,
319 gfxImageFormat aFormat
)
320 : gfxImageSurface(aData
, aSize
, aParent
->Stride(), aFormat
),
323 already_AddRefed
<gfxImageSurface
> gfxImageSurface::GetAsImageSurface() {
324 RefPtr
<gfxImageSurface
> surface
= this;
325 return surface
.forget();