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
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/
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
15 * The Original Code is Mozilla Foundation code.
17 * The Initial Developer of the Original Code is Mozilla Foundation.
18 * Portions created by the Initial Developer are Copyright (C) 2006
19 * the Initial Developer. All Rights Reserved.
22 * Stuart Parmenter <stuart@mozilla.com>
23 * Vladimir Vukicevic <vladimir@pobox.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #include "nsIMemoryReporter.h"
42 #include "gfxASurface.h"
44 #include "gfxImageSurface.h"
48 #ifdef CAIRO_HAS_WIN32_SURFACE
49 #include "gfxWindowsSurface.h"
51 #ifdef CAIRO_HAS_D2D_SURFACE
52 #include "gfxD2DSurface.h"
56 #include "gfxXlibSurface.h"
59 #ifdef CAIRO_HAS_QUARTZ_SURFACE
60 #include "gfxQuartzSurface.h"
61 #include "gfxQuartzImageSurface.h"
65 #include "gfxDirectFBSurface.h"
68 #if defined(CAIRO_HAS_QT_SURFACE) && defined(MOZ_WIDGET_QT)
69 #include "gfxQPainterSurface.h"
75 static cairo_user_data_key_t gfxasurface_pointer_key
;
77 // Surfaces use refcounting that's tied to the cairo surface refcnt, to avoid
78 // refcount mismatch issues.
80 gfxASurface::AddRef(void)
87 cairo_surface_reference(mSurface
);
90 return (nsrefcnt
) cairo_surface_get_reference_count(mSurface
);
92 // the surface isn't valid, but we still need to refcount
94 return ++mFloatingRefs
;
99 gfxASurface::Release(void)
102 NS_ASSERTION(mFloatingRefs
== 0, "gfxASurface::Release with floating refs still hanging around!");
104 // Note that there is a destructor set on user data for mSurface,
105 // which will delete this gfxASurface wrapper when the surface's refcount goes
107 nsrefcnt refcnt
= (nsrefcnt
) cairo_surface_get_reference_count(mSurface
);
108 cairo_surface_destroy(mSurface
);
110 // |this| may not be valid any more, don't use it!
114 if (--mFloatingRefs
== 0) {
119 return mFloatingRefs
;
124 gfxASurface::SurfaceDestroyFunc(void *data
) {
125 gfxASurface
*surf
= (gfxASurface
*) data
;
126 // fprintf (stderr, "Deleting wrapper for %p (wrapper: %p)\n", surf->mSurface, data);
131 gfxASurface::GetSurfaceWrapper(cairo_surface_t
*csurf
)
133 return (gfxASurface
*) cairo_surface_get_user_data(csurf
, &gfxasurface_pointer_key
);
137 gfxASurface::SetSurfaceWrapper(cairo_surface_t
*csurf
, gfxASurface
*asurf
)
139 cairo_surface_set_user_data(csurf
, &gfxasurface_pointer_key
, asurf
, SurfaceDestroyFunc
);
142 already_AddRefed
<gfxASurface
>
143 gfxASurface::Wrap (cairo_surface_t
*csurf
)
147 /* Do we already have a wrapper for this surface? */
148 result
= GetSurfaceWrapper(csurf
);
150 // fprintf(stderr, "Existing wrapper for %p -> %p\n", csurf, result);
155 /* No wrapper; figure out the surface type and create it */
156 cairo_surface_type_t stype
= cairo_surface_get_type(csurf
);
158 if (stype
== CAIRO_SURFACE_TYPE_IMAGE
) {
159 result
= new gfxImageSurface(csurf
);
161 #ifdef CAIRO_HAS_WIN32_SURFACE
162 else if (stype
== CAIRO_SURFACE_TYPE_WIN32
||
163 stype
== CAIRO_SURFACE_TYPE_WIN32_PRINTING
) {
164 result
= new gfxWindowsSurface(csurf
);
167 #ifdef CAIRO_HAS_D2D_SURFACE
168 else if (stype
== CAIRO_SURFACE_TYPE_D2D
) {
169 result
= new gfxD2DSurface(csurf
);
173 else if (stype
== CAIRO_SURFACE_TYPE_XLIB
) {
174 result
= new gfxXlibSurface(csurf
);
177 #ifdef CAIRO_HAS_QUARTZ_SURFACE
178 else if (stype
== CAIRO_SURFACE_TYPE_QUARTZ
) {
179 result
= new gfxQuartzSurface(csurf
);
181 else if (stype
== CAIRO_SURFACE_TYPE_QUARTZ_IMAGE
) {
182 result
= new gfxQuartzImageSurface(csurf
);
186 else if (stype
== CAIRO_SURFACE_TYPE_DIRECTFB
) {
187 result
= new gfxDirectFBSurface(csurf
);
190 #if defined(CAIRO_HAS_QT_SURFACE) && defined(MOZ_WIDGET_QT)
191 else if (stype
== CAIRO_SURFACE_TYPE_QT
) {
192 result
= new gfxQPainterSurface(csurf
);
196 result
= new gfxUnknownSurface(csurf
);
199 // fprintf(stderr, "New wrapper for %p -> %p\n", csurf, result);
206 gfxASurface::Init(cairo_surface_t
* surface
, PRBool existingSurface
)
208 if (cairo_surface_status(surface
)) {
209 // the surface has an error on it
210 mSurfaceValid
= PR_FALSE
;
211 cairo_surface_destroy(surface
);
215 SetSurfaceWrapper(surface
, this);
218 mSurfaceValid
= PR_TRUE
;
220 if (existingSurface
) {
224 if (cairo_surface_get_content(surface
) != CAIRO_CONTENT_COLOR
) {
225 cairo_surface_set_subpixel_antialiasing(surface
, CAIRO_SUBPIXEL_ANTIALIASING_DISABLED
);
230 gfxASurface::gfxSurfaceType
231 gfxASurface::GetType() const
234 return (gfxSurfaceType
)-1;
236 return (gfxSurfaceType
)cairo_surface_get_type(mSurface
);
239 gfxASurface::gfxContentType
240 gfxASurface::GetContentType() const
243 return (gfxContentType
)-1;
245 return (gfxContentType
)cairo_surface_get_content(mSurface
);
249 gfxASurface::SetDeviceOffset(const gfxPoint
& offset
)
251 cairo_surface_set_device_offset(mSurface
,
256 gfxASurface::GetDeviceOffset() const
259 cairo_surface_get_device_offset(mSurface
, &pt
.x
, &pt
.y
);
264 gfxASurface::Flush() const
266 cairo_surface_flush(mSurface
);
270 gfxASurface::MarkDirty()
272 cairo_surface_mark_dirty(mSurface
);
276 gfxASurface::MarkDirty(const gfxRect
& r
)
278 cairo_surface_mark_dirty_rectangle(mSurface
,
279 (int) r
.pos
.x
, (int) r
.pos
.y
,
280 (int) r
.size
.width
, (int) r
.size
.height
);
284 gfxASurface::SetData(const cairo_user_data_key_t
*key
,
286 thebes_destroy_func_t destroy
)
288 cairo_surface_set_user_data(mSurface
, key
, user_data
, destroy
);
292 gfxASurface::GetData(const cairo_user_data_key_t
*key
)
294 return cairo_surface_get_user_data(mSurface
, key
);
298 gfxASurface::Finish()
300 cairo_surface_finish(mSurface
);
303 already_AddRefed
<gfxASurface
>
304 gfxASurface::CreateSimilarSurface(gfxContentType aContent
,
305 const gfxIntSize
& aSize
)
307 if (!mSurface
|| !mSurfaceValid
) {
311 cairo_surface_t
*surface
=
312 cairo_surface_create_similar(mSurface
, cairo_content_t(aContent
),
313 aSize
.width
, aSize
.height
);
314 if (cairo_surface_status(surface
)) {
315 cairo_surface_destroy(surface
);
319 nsRefPtr
<gfxASurface
> result
= Wrap(surface
);
320 cairo_surface_destroy(surface
);
321 return result
.forget();
325 gfxASurface::CairoStatus()
330 return cairo_surface_status(mSurface
);
335 gfxASurface::CheckSurfaceSize(const gfxIntSize
& sz
, PRInt32 limit
)
337 if (sz
.width
< 0 || sz
.height
< 0) {
338 NS_WARNING("Surface width or height < 0!");
342 #if defined(XP_MACOSX)
343 // CoreGraphics is limited to images < 32K in *height*, so clamp all surfaces on the Mac to that height
344 if (sz
.height
> SHRT_MAX
) {
345 NS_WARNING("Surface size too large (would overflow)!");
350 // check to make sure we don't overflow a 32-bit
351 PRInt32 tmp
= sz
.width
* sz
.height
;
352 if (tmp
&& tmp
/ sz
.height
!= sz
.width
) {
353 NS_WARNING("Surface size too large (would overflow)!");
357 // always assume 4-byte stride
359 if (tmp
&& tmp
/ 4 != sz
.width
* sz
.height
) {
360 NS_WARNING("Surface size too large (would overflow)!");
364 // reject images with sides bigger than limit
366 (sz
.width
> limit
|| sz
.height
> limit
))
373 gfxASurface::BeginPrinting(const nsAString
& aTitle
, const nsAString
& aPrintToFileName
)
379 gfxASurface::EndPrinting()
385 gfxASurface::AbortPrinting()
391 gfxASurface::BeginPage()
397 gfxASurface::EndPage()
402 gfxASurface::gfxContentType
403 gfxASurface::ContentFromFormat(gfxImageFormat format
)
406 case ImageFormatARGB32
:
407 return CONTENT_COLOR_ALPHA
;
408 case ImageFormatRGB24
:
409 case ImageFormatRGB16_565
:
410 return CONTENT_COLOR
;
413 return CONTENT_ALPHA
;
415 case ImageFormatUnknown
:
417 return CONTENT_COLOR
;
421 gfxASurface::gfxImageFormat
422 gfxASurface::FormatFromContent(gfxASurface::gfxContentType type
)
425 case CONTENT_COLOR_ALPHA
:
426 return ImageFormatARGB32
;
428 return ImageFormatA8
;
431 return ImageFormatRGB24
;
436 gfxASurface::SetSubpixelAntialiasingEnabled(PRBool aEnabled
)
440 cairo_surface_set_subpixel_antialiasing(mSurface
,
441 aEnabled
? CAIRO_SUBPIXEL_ANTIALIASING_ENABLED
: CAIRO_SUBPIXEL_ANTIALIASING_DISABLED
);
445 gfxASurface::GetSubpixelAntialiasingEnabled()
449 return cairo_surface_get_subpixel_antialiasing(mSurface
) == CAIRO_SUBPIXEL_ANTIALIASING_ENABLED
;
453 gfxASurface::BytePerPixelFromFormat(gfxImageFormat format
)
456 case ImageFormatARGB32
:
457 case ImageFormatRGB24
:
459 case ImageFormatRGB16_565
:
464 NS_WARNING("Unknown byte per pixel value for Image format");
469 /** Memory reporting **/
471 static const char *sSurfaceNamesForSurfaceType
[] = {
478 "gfx/surface/quartz",
481 "gfx/surface/directfb",
484 "gfx/surface/win32printing",
485 "gfx/surface/quartzimage",
486 "gfx/surface/script",
487 "gfx/surface/qpainter",
488 "gfx/surface/recording",
498 PR_STATIC_ASSERT(NS_ARRAY_LENGTH(sSurfaceNamesForSurfaceType
) == gfxASurface::SurfaceTypeMax
);
499 #ifdef CAIRO_HAS_D2D_SURFACE
500 PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_D2D
) == PRUint32(gfxASurface::SurfaceTypeD2D
));
502 PR_STATIC_ASSERT(PRUint32(CAIRO_SURFACE_TYPE_SKIA
) == PRUint32(gfxASurface::SurfaceTypeSkia
));
505 SurfaceMemoryReporterPathForType(gfxASurface::gfxSurfaceType aType
)
508 aType
>= gfxASurface::SurfaceTypeMax
)
509 return "gfx/surface/unknown";
511 return sSurfaceNamesForSurfaceType
[aType
];
514 /* Surface size memory reporting */
515 static nsIMemoryReporter
*gSurfaceMemoryReporters
[gfxASurface::SurfaceTypeMax
] = { 0 };
516 static PRInt64 gSurfaceMemoryUsed
[gfxASurface::SurfaceTypeMax
] = { 0 };
518 class SurfaceMemoryReporter
:
519 public nsIMemoryReporter
522 SurfaceMemoryReporter(gfxASurface::gfxSurfaceType aType
)
528 NS_IMETHOD
GetPath(char **memoryPath
) {
529 *memoryPath
= strdup(SurfaceMemoryReporterPathForType(mType
));
533 NS_IMETHOD
GetDescription(char **desc
) {
534 *desc
= strdup("Memory used by gfx surface of given type.");
538 NS_IMETHOD
GetMemoryUsed(PRInt64
*memoryUsed
) {
539 *memoryUsed
= gSurfaceMemoryUsed
[mType
];
543 gfxASurface::gfxSurfaceType mType
;
546 NS_IMPL_ISUPPORTS1(SurfaceMemoryReporter
, nsIMemoryReporter
)
549 gfxASurface::RecordMemoryUsedForSurfaceType(gfxASurface::gfxSurfaceType aType
,
552 if (aType
< 0 || aType
>= SurfaceTypeMax
) {
553 NS_WARNING("Invalid type to RecordMemoryUsedForSurfaceType!");
557 if (gSurfaceMemoryReporters
[aType
] == 0) {
558 gSurfaceMemoryReporters
[aType
] = new SurfaceMemoryReporter(aType
);
559 NS_RegisterMemoryReporter(gSurfaceMemoryReporters
[aType
]);
562 gSurfaceMemoryUsed
[aType
] += aBytes
;
566 gfxASurface::RecordMemoryUsed(PRInt32 aBytes
)
568 RecordMemoryUsedForSurfaceType(GetType(), aBytes
);
569 mBytesRecorded
+= aBytes
;
573 gfxASurface::RecordMemoryFreed()
575 if (mBytesRecorded
) {
576 RecordMemoryUsedForSurfaceType(GetType(), -mBytesRecorded
);