1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "SourceSurfaceCairo.h"
8 #include "DrawTargetCairo.h"
9 #include "HelpersCairo.h"
10 #include "DataSourceSurfaceWrapper.h"
11 
12 #include "cairo.h"
13 
14 namespace mozilla {
15 namespace gfx {
16 
CairoFormatToSurfaceFormat(cairo_format_t format)17 static SurfaceFormat CairoFormatToSurfaceFormat(cairo_format_t format) {
18   switch (format) {
19     case CAIRO_FORMAT_ARGB32:
20       return SurfaceFormat::B8G8R8A8;
21     case CAIRO_FORMAT_RGB24:
22       return SurfaceFormat::B8G8R8X8;
23     case CAIRO_FORMAT_RGB16_565:
24       return SurfaceFormat::R5G6B5_UINT16;
25     case CAIRO_FORMAT_A8:
26       return SurfaceFormat::A8;
27     default:
28       return SurfaceFormat::B8G8R8A8;
29   }
30 }
31 
SourceSurfaceCairo(cairo_surface_t * aSurface,const IntSize & aSize,const SurfaceFormat & aFormat,DrawTargetCairo * aDrawTarget)32 SourceSurfaceCairo::SourceSurfaceCairo(
33     cairo_surface_t* aSurface, const IntSize& aSize,
34     const SurfaceFormat& aFormat, DrawTargetCairo* aDrawTarget /* = nullptr */)
35     : mSize(aSize),
36       mFormat(aFormat),
37       mSurface(aSurface),
38       mDrawTarget(aDrawTarget) {
39   cairo_surface_reference(mSurface);
40 }
41 
~SourceSurfaceCairo()42 SourceSurfaceCairo::~SourceSurfaceCairo() { cairo_surface_destroy(mSurface); }
43 
GetSize() const44 IntSize SourceSurfaceCairo::GetSize() const { return mSize; }
45 
GetFormat() const46 SurfaceFormat SourceSurfaceCairo::GetFormat() const { return mFormat; }
47 
GetDataSurface()48 already_AddRefed<DataSourceSurface> SourceSurfaceCairo::GetDataSurface() {
49   RefPtr<DataSourceSurface> dataSurf;
50 
51   if (cairo_surface_get_type(mSurface) == CAIRO_SURFACE_TYPE_IMAGE) {
52     dataSurf = new DataSourceSurfaceCairo(mSurface);
53   } else {
54     cairo_surface_t* imageSurf = cairo_image_surface_create(
55         GfxFormatToCairoFormat(mFormat), mSize.width, mSize.height);
56 
57     // Fill the new image surface with the contents of our surface.
58     cairo_t* ctx = cairo_create(imageSurf);
59     cairo_set_source_surface(ctx, mSurface, 0, 0);
60     cairo_paint(ctx);
61     cairo_destroy(ctx);
62 
63     dataSurf = new DataSourceSurfaceCairo(imageSurf);
64     cairo_surface_destroy(imageSurf);
65   }
66 
67   // We also need to make sure that the returned surface has
68   // surface->GetType() == SurfaceType::DATA.
69   return MakeAndAddRef<DataSourceSurfaceWrapper>(dataSurf);
70 }
71 
GetSurface() const72 cairo_surface_t* SourceSurfaceCairo::GetSurface() const { return mSurface; }
73 
DrawTargetWillChange()74 void SourceSurfaceCairo::DrawTargetWillChange() {
75   if (mDrawTarget) {
76     mDrawTarget = nullptr;
77 
78     // We're about to lose our version of the surface, so make a copy of it.
79     cairo_surface_t* surface = cairo_surface_create_similar(
80         mSurface, GfxFormatToCairoContent(mFormat), mSize.width, mSize.height);
81     cairo_t* ctx = cairo_create(surface);
82     cairo_pattern_t* pat = cairo_pattern_create_for_surface(mSurface);
83     cairo_set_source(ctx, pat);
84     cairo_paint(ctx);
85     cairo_destroy(ctx);
86     cairo_pattern_destroy(pat);
87 
88     // Swap in this new surface.
89     cairo_surface_destroy(mSurface);
90     mSurface = surface;
91   }
92 }
93 
DataSourceSurfaceCairo(cairo_surface_t * imageSurf)94 DataSourceSurfaceCairo::DataSourceSurfaceCairo(cairo_surface_t* imageSurf)
95     : mImageSurface(imageSurf) {
96   cairo_surface_reference(mImageSurface);
97 }
98 
~DataSourceSurfaceCairo()99 DataSourceSurfaceCairo::~DataSourceSurfaceCairo() {
100   cairo_surface_destroy(mImageSurface);
101 }
102 
GetData()103 unsigned char* DataSourceSurfaceCairo::GetData() {
104   return cairo_image_surface_get_data(mImageSurface);
105 }
106 
Stride()107 int32_t DataSourceSurfaceCairo::Stride() {
108   return cairo_image_surface_get_stride(mImageSurface);
109 }
110 
GetSize() const111 IntSize DataSourceSurfaceCairo::GetSize() const {
112   IntSize size;
113   size.width = cairo_image_surface_get_width(mImageSurface);
114   size.height = cairo_image_surface_get_height(mImageSurface);
115 
116   return size;
117 }
118 
GetFormat() const119 SurfaceFormat DataSourceSurfaceCairo::GetFormat() const {
120   return CairoFormatToSurfaceFormat(
121       cairo_image_surface_get_format(mImageSurface));
122 }
123 
GetSurface() const124 cairo_surface_t* DataSourceSurfaceCairo::GetSurface() const {
125   return mImageSurface;
126 }
127 
128 }  // namespace gfx
129 }  // namespace mozilla
130