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 Mozilla Corporation code.
16 : *
17 : * The Initial Developer of the Original Code is Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2007
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : * Stuart Parmenter <stuart@mozilla.com>
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 "gfxTypes.h"
39 : #include "gfxPattern.h"
40 : #include "gfxASurface.h"
41 : #include "gfxPlatform.h"
42 :
43 : #include "cairo.h"
44 :
45 : #include <vector>
46 :
47 : using namespace mozilla::gfx;
48 :
49 0 : gfxPattern::gfxPattern(cairo_pattern_t *aPattern)
50 0 : : mGfxPattern(NULL)
51 : {
52 0 : mPattern = cairo_pattern_reference(aPattern);
53 0 : }
54 :
55 0 : gfxPattern::gfxPattern(const gfxRGBA& aColor)
56 0 : : mGfxPattern(NULL)
57 : {
58 0 : mPattern = cairo_pattern_create_rgba(aColor.r, aColor.g, aColor.b, aColor.a);
59 0 : }
60 :
61 : // from another surface
62 19 : gfxPattern::gfxPattern(gfxASurface *surface)
63 19 : : mGfxPattern(NULL)
64 : {
65 19 : mPattern = cairo_pattern_create_for_surface(surface->CairoSurface());
66 19 : }
67 :
68 : // linear
69 0 : gfxPattern::gfxPattern(gfxFloat x0, gfxFloat y0, gfxFloat x1, gfxFloat y1)
70 0 : : mGfxPattern(NULL)
71 : {
72 0 : mPattern = cairo_pattern_create_linear(x0, y0, x1, y1);
73 0 : }
74 :
75 : // radial
76 0 : gfxPattern::gfxPattern(gfxFloat cx0, gfxFloat cy0, gfxFloat radius0,
77 : gfxFloat cx1, gfxFloat cy1, gfxFloat radius1)
78 0 : : mGfxPattern(NULL)
79 : {
80 : mPattern = cairo_pattern_create_radial(cx0, cy0, radius0,
81 0 : cx1, cy1, radius1);
82 0 : }
83 :
84 : // Azure
85 0 : gfxPattern::gfxPattern(SourceSurface *aSurface, const Matrix &aTransform)
86 : : mPattern(NULL)
87 : , mGfxPattern(NULL)
88 : , mSourceSurface(aSurface)
89 0 : , mTransform(aTransform)
90 : {
91 0 : }
92 :
93 57 : gfxPattern::~gfxPattern()
94 : {
95 19 : cairo_pattern_destroy(mPattern);
96 :
97 19 : if (mGfxPattern) {
98 0 : mGfxPattern->~Pattern();
99 : }
100 76 : }
101 :
102 : cairo_pattern_t *
103 19 : gfxPattern::CairoPattern()
104 : {
105 19 : return mPattern;
106 : }
107 :
108 : void
109 0 : gfxPattern::AddColorStop(gfxFloat offset, const gfxRGBA& c)
110 : {
111 0 : if (mPattern) {
112 0 : mStops = NULL;
113 0 : if (gfxPlatform::GetCMSMode() == eCMSMode_All) {
114 0 : gfxRGBA cms;
115 0 : gfxPlatform::TransformPixel(c, cms, gfxPlatform::GetCMSRGBTransform());
116 :
117 : // Use the original alpha to avoid unnecessary float->byte->float
118 : // conversion errors
119 : cairo_pattern_add_color_stop_rgba(mPattern, offset,
120 0 : cms.r, cms.g, cms.b, c.a);
121 : }
122 : else
123 0 : cairo_pattern_add_color_stop_rgba(mPattern, offset, c.r, c.g, c.b, c.a);
124 : }
125 0 : }
126 :
127 : void
128 0 : gfxPattern::SetMatrix(const gfxMatrix& matrix)
129 : {
130 0 : if (mPattern) {
131 0 : cairo_matrix_t mat = *reinterpret_cast<const cairo_matrix_t*>(&matrix);
132 0 : cairo_pattern_set_matrix(mPattern, &mat);
133 : } else {
134 0 : mTransform = ToMatrix(matrix);
135 : }
136 0 : }
137 :
138 : gfxMatrix
139 0 : gfxPattern::GetMatrix() const
140 : {
141 0 : if (mPattern) {
142 : cairo_matrix_t mat;
143 0 : cairo_pattern_get_matrix(mPattern, &mat);
144 0 : return gfxMatrix(*reinterpret_cast<gfxMatrix*>(&mat));
145 : } else {
146 0 : return ThebesMatrix(mTransform);
147 : }
148 : }
149 :
150 : Pattern*
151 0 : gfxPattern::GetPattern(mozilla::gfx::DrawTarget *aTarget)
152 : {
153 0 : if (!mPattern) {
154 0 : mGfxPattern = new (mSurfacePattern.addr())
155 0 : SurfacePattern(mSourceSurface, EXTEND_CLAMP, mTransform);
156 0 : return mGfxPattern;
157 : }
158 :
159 0 : GraphicsExtend extend = (GraphicsExtend)cairo_pattern_get_extend(mPattern);
160 :
161 0 : switch (cairo_pattern_get_type(mPattern)) {
162 : case CAIRO_PATTERN_TYPE_SURFACE:
163 : {
164 0 : GraphicsFilter filter = (GraphicsFilter)cairo_pattern_get_filter(mPattern);
165 : cairo_matrix_t mat;
166 0 : cairo_pattern_get_matrix(mPattern, &mat);
167 0 : gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
168 :
169 0 : cairo_surface_t *surf = NULL;
170 0 : cairo_pattern_get_surface(mPattern, &surf);
171 :
172 0 : if (!mSourceSurface) {
173 0 : nsRefPtr<gfxASurface> gfxSurf = gfxASurface::Wrap(surf);
174 : mSourceSurface =
175 0 : gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTarget, gfxSurf);
176 : }
177 :
178 0 : if (mSourceSurface) {
179 0 : Matrix newMat = ToMatrix(matrix);
180 0 : newMat.Invert();
181 : double x, y;
182 0 : cairo_surface_get_device_offset(surf, &x, &y);
183 0 : newMat.Translate(-x, -y);
184 0 : mGfxPattern = new (mSurfacePattern.addr())
185 0 : SurfacePattern(mSourceSurface, ToExtendMode(extend), newMat, ToFilter(filter));
186 0 : return mGfxPattern;
187 : }
188 0 : break;
189 : }
190 : case CAIRO_PATTERN_TYPE_LINEAR:
191 : {
192 : double x1, y1, x2, y2;
193 0 : cairo_pattern_get_linear_points(mPattern, &x1, &y1, &x2, &y2);
194 0 : if (!mStops) {
195 0 : int count = 0;
196 0 : cairo_pattern_get_color_stop_count(mPattern, &count);
197 :
198 0 : std::vector<GradientStop> stops;
199 :
200 0 : for (int i = 0; i < count; i++) {
201 0 : GradientStop stop;
202 : double r, g, b, a, offset;
203 0 : cairo_pattern_get_color_stop_rgba(mPattern, i, &offset, &r, &g, &b, &a);
204 :
205 0 : stop.offset = offset;
206 0 : stop.color = Color(Float(r), Float(g), Float(b), Float(a));
207 0 : stops.push_back(stop);
208 : }
209 :
210 0 : mStops = aTarget->CreateGradientStops(&stops.front(), count, ToExtendMode(extend));
211 : }
212 :
213 0 : if (mStops) {
214 : cairo_matrix_t mat;
215 0 : cairo_pattern_get_matrix(mPattern, &mat);
216 0 : gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
217 :
218 0 : Matrix newMat = ToMatrix(matrix);
219 0 : newMat.Invert();
220 :
221 0 : mGfxPattern = new (mLinearGradientPattern.addr())
222 0 : LinearGradientPattern(Point(x1, y1), Point(x2, y2), mStops, newMat);
223 :
224 0 : return mGfxPattern;
225 : }
226 0 : break;
227 : }
228 : case CAIRO_PATTERN_TYPE_RADIAL:
229 : {
230 0 : if (!mStops) {
231 0 : int count = 0;
232 0 : cairo_pattern_get_color_stop_count(mPattern, &count);
233 :
234 0 : std::vector<GradientStop> stops;
235 :
236 0 : for (int i = 0; i < count; i++) {
237 0 : GradientStop stop;
238 : double r, g, b, a, offset;
239 0 : cairo_pattern_get_color_stop_rgba(mPattern, i, &offset, &r, &g, &b, &a);
240 :
241 0 : stop.offset = offset;
242 0 : stop.color = Color(Float(r), Float(g), Float(b), Float(a));
243 0 : stops.push_back(stop);
244 : }
245 :
246 0 : mStops = aTarget->CreateGradientStops(&stops.front(), count, ToExtendMode(extend));
247 : }
248 :
249 0 : if (mStops) {
250 : cairo_matrix_t mat;
251 0 : cairo_pattern_get_matrix(mPattern, &mat);
252 0 : gfxMatrix matrix(*reinterpret_cast<gfxMatrix*>(&mat));
253 :
254 0 : Matrix newMat = ToMatrix(matrix);
255 0 : newMat.Invert();
256 :
257 : double x1, y1, x2, y2, r1, r2;
258 0 : cairo_pattern_get_radial_circles(mPattern, &x1, &y1, &r1, &x2, &y2, &r2);
259 0 : mGfxPattern = new (mRadialGradientPattern.addr())
260 0 : RadialGradientPattern(Point(x1, y1), Point(x2, y2), r1, r2, mStops, newMat);
261 :
262 0 : return mGfxPattern;
263 : }
264 0 : break;
265 : }
266 : default:
267 : /* Reassure the compiler we are handling all the enum values. */
268 0 : break;
269 : }
270 :
271 0 : new (mColorPattern.addr()) ColorPattern(Color(0, 0, 0, 0));
272 0 : return mColorPattern.addr();
273 : }
274 :
275 : void
276 0 : gfxPattern::SetExtend(GraphicsExtend extend)
277 : {
278 0 : if (mPattern) {
279 0 : mStops = NULL;
280 0 : if (extend == EXTEND_PAD_EDGE) {
281 0 : if (cairo_pattern_get_type(mPattern) == CAIRO_PATTERN_TYPE_SURFACE) {
282 0 : cairo_surface_t *surf = NULL;
283 :
284 0 : cairo_pattern_get_surface (mPattern, &surf);
285 0 : if (surf) {
286 0 : switch (cairo_surface_get_type(surf)) {
287 : case CAIRO_SURFACE_TYPE_WIN32_PRINTING:
288 : case CAIRO_SURFACE_TYPE_QUARTZ:
289 0 : extend = EXTEND_NONE;
290 0 : break;
291 :
292 : case CAIRO_SURFACE_TYPE_WIN32:
293 : case CAIRO_SURFACE_TYPE_XLIB:
294 : default:
295 0 : extend = EXTEND_PAD;
296 0 : break;
297 : }
298 : }
299 : }
300 :
301 : // if something went wrong, or not a surface pattern, use PAD
302 0 : if (extend == EXTEND_PAD_EDGE)
303 0 : extend = EXTEND_PAD;
304 : }
305 :
306 0 : cairo_pattern_set_extend(mPattern, (cairo_extend_t)extend);
307 : } else {
308 : // This is always a surface pattern and will default to EXTEND_PAD
309 : // for EXTEND_PAD_EDGE.
310 0 : mExtend = ToExtendMode(extend);
311 : }
312 0 : }
313 :
314 : bool
315 0 : gfxPattern::IsOpaque()
316 : {
317 0 : if (mPattern) {
318 0 : switch (cairo_pattern_get_type(mPattern)) {
319 : case CAIRO_PATTERN_TYPE_SURFACE:
320 : {
321 0 : cairo_surface_t *surf = NULL;
322 0 : cairo_pattern_get_surface(mPattern, &surf);
323 :
324 0 : if (cairo_surface_get_content(surf) == CAIRO_CONTENT_COLOR) {
325 0 : return true;
326 : }
327 : }
328 : default:
329 0 : return false;
330 : }
331 : }
332 :
333 0 : if (mSourceSurface->GetFormat() == FORMAT_B8G8R8X8) {
334 0 : return true;
335 : }
336 0 : return false;
337 : }
338 :
339 : gfxPattern::GraphicsExtend
340 0 : gfxPattern::Extend() const
341 : {
342 0 : if (mPattern) {
343 0 : return (GraphicsExtend)cairo_pattern_get_extend(mPattern);
344 : } else {
345 0 : return ThebesExtend(mExtend);
346 : }
347 : }
348 :
349 : void
350 0 : gfxPattern::SetFilter(GraphicsFilter filter)
351 : {
352 0 : if (mPattern) {
353 0 : cairo_pattern_set_filter(mPattern, (cairo_filter_t)filter);
354 : } else {
355 0 : mFilter = ToFilter(filter);
356 : }
357 0 : }
358 :
359 : gfxPattern::GraphicsFilter
360 0 : gfxPattern::Filter() const
361 : {
362 0 : if (mPattern) {
363 0 : return (GraphicsFilter)cairo_pattern_get_filter(mPattern);
364 : } else {
365 0 : return ThebesFilter(mFilter);
366 : }
367 : }
368 :
369 : bool
370 0 : gfxPattern::GetSolidColor(gfxRGBA& aColor)
371 : {
372 : return cairo_pattern_get_rgba(mPattern,
373 : &aColor.r,
374 : &aColor.g,
375 : &aColor.b,
376 0 : &aColor.a) == CAIRO_STATUS_SUCCESS;
377 : }
378 :
379 : already_AddRefed<gfxASurface>
380 0 : gfxPattern::GetSurface()
381 : {
382 0 : if (mPattern) {
383 0 : cairo_surface_t *surf = nsnull;
384 :
385 0 : if (cairo_pattern_get_surface (mPattern, &surf) != CAIRO_STATUS_SUCCESS)
386 0 : return nsnull;
387 :
388 0 : return gfxASurface::Wrap(surf);
389 : } else {
390 : // We should never be trying to get the surface off an Azure gfx Pattern.
391 0 : NS_ERROR("Attempt to get surface off an Azure gfxPattern!");
392 0 : return NULL;
393 : }
394 : }
395 :
396 : gfxPattern::GraphicsPatternType
397 0 : gfxPattern::GetType() const
398 : {
399 0 : if (mPattern) {
400 0 : return (GraphicsPatternType) cairo_pattern_get_type(mPattern);
401 : } else {
402 : // We should never be trying to get the type off an Azure gfx Pattern.
403 0 : MOZ_ASSERT(0);
404 0 : return PATTERN_SURFACE;
405 : }
406 : }
407 :
408 : int
409 0 : gfxPattern::CairoStatus()
410 : {
411 0 : if (mPattern) {
412 0 : return cairo_pattern_status(mPattern);
413 : } else {
414 : // An Azure pattern as this point is never in error status.
415 0 : return CAIRO_STATUS_SUCCESS;
416 : }
417 : }
|