1 : /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
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) 2011
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either the GNU General Public License Version 2 or later (the "GPL"), or
25 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "DrawTargetCairo.h"
38 :
39 : #include "SourceSurfaceCairo.h"
40 : #include "PathCairo.h"
41 : #include "HelpersCairo.h"
42 : #include "ScaledFontBase.h"
43 :
44 : #include "cairo.h"
45 :
46 : #include "Blur.h"
47 :
48 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
49 : #include "cairo-quartz.h"
50 : #include <ApplicationServices/ApplicationServices.h>
51 : #endif
52 :
53 : #ifdef CAIRO_HAS_XLIB_SURFACE
54 : #include "cairo-xlib.h"
55 : #endif
56 :
57 : #include <algorithm>
58 :
59 : namespace mozilla {
60 : namespace gfx {
61 :
62 : namespace {
63 :
64 : // An RAII class to prepare to draw a context and optional path. Saves and
65 : // restores the context on construction/destruction.
66 : class AutoPrepareForDrawing
67 : {
68 : public:
69 0 : AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx)
70 0 : : mCtx(ctx)
71 : {
72 0 : dt->PrepareForDrawing(ctx);
73 0 : cairo_save(mCtx);
74 0 : }
75 :
76 0 : AutoPrepareForDrawing(DrawTargetCairo* dt, cairo_t* ctx, const Path* path)
77 0 : : mCtx(ctx)
78 : {
79 0 : dt->PrepareForDrawing(ctx, path);
80 0 : cairo_save(mCtx);
81 0 : }
82 :
83 0 : ~AutoPrepareForDrawing() { cairo_restore(mCtx); }
84 :
85 : private:
86 : cairo_t* mCtx;
87 : };
88 :
89 : } // end anonymous namespace
90 :
91 : static bool
92 0 : GetCairoSurfaceSize(cairo_surface_t* surface, IntSize& size)
93 : {
94 0 : switch (cairo_surface_get_type(surface))
95 : {
96 : case CAIRO_SURFACE_TYPE_IMAGE:
97 : {
98 0 : size.width = cairo_image_surface_get_width(surface);
99 0 : size.height = cairo_image_surface_get_height(surface);
100 0 : return true;
101 : }
102 :
103 : #ifdef CAIRO_HAS_XLIB_SURFACE
104 : case CAIRO_SURFACE_TYPE_XLIB:
105 : {
106 0 : size.width = cairo_xlib_surface_get_width(surface);
107 0 : size.height = cairo_xlib_surface_get_height(surface);
108 0 : return true;
109 : }
110 : #endif
111 :
112 : #ifdef CAIRO_HAS_QUARTZ_SURFACE
113 : case CAIRO_SURFACE_TYPE_QUARTZ:
114 : {
115 : CGContextRef cgc = cairo_quartz_surface_get_cg_context(surface);
116 :
117 : // It's valid to call these CGBitmapContext functions on non-bitmap
118 : // contexts; they'll just return 0 in that case.
119 : size.width = CGBitmapContextGetWidth(cgc);
120 : size.height = CGBitmapContextGetWidth(cgc);
121 : return true;
122 : }
123 : #endif
124 :
125 : default:
126 0 : return false;
127 : }
128 : }
129 :
130 : static bool
131 0 : PatternIsCompatible(const Pattern& aPattern)
132 : {
133 0 : switch (aPattern.GetType())
134 : {
135 : case PATTERN_LINEAR_GRADIENT:
136 : {
137 0 : const LinearGradientPattern& pattern = static_cast<const LinearGradientPattern&>(aPattern);
138 0 : return pattern.mStops->GetBackendType() == BACKEND_CAIRO;
139 : }
140 : case PATTERN_RADIAL_GRADIENT:
141 : {
142 0 : const RadialGradientPattern& pattern = static_cast<const RadialGradientPattern&>(aPattern);
143 0 : return pattern.mStops->GetBackendType() == BACKEND_CAIRO;
144 : }
145 : default:
146 0 : return true;
147 : }
148 : }
149 :
150 : // Never returns NULL. As such, you must always pass in Cairo-compatible
151 : // patterns, most notably gradients with a GradientStopCairo.
152 : // The pattern returned must have cairo_pattern_destroy() called on it by the
153 : // caller.
154 : // As the cairo_pattern_t returned may depend on the Pattern passed in, the
155 : // lifetime of the cairo_pattern_t returned must not exceed the lifetime of the
156 : // Pattern passed in.
157 : static cairo_pattern_t*
158 0 : GfxPatternToCairoPattern(const Pattern& aPattern, Float aAlpha)
159 : {
160 : cairo_pattern_t* pat;
161 :
162 0 : switch (aPattern.GetType())
163 : {
164 : case PATTERN_COLOR:
165 : {
166 0 : Color color = static_cast<const ColorPattern&>(aPattern).mColor;
167 0 : pat = cairo_pattern_create_rgba(color.r, color.g, color.b, color.a * aAlpha);
168 0 : break;
169 : }
170 :
171 : case PATTERN_SURFACE:
172 : {
173 0 : const SurfacePattern& pattern = static_cast<const SurfacePattern&>(aPattern);
174 : cairo_surface_t* surf;
175 :
176 : // After this block, |surf| always has an extra cairo reference to be
177 : // destroyed. This makes creating new surfaces or reusing old ones more
178 : // uniform.
179 0 : if (pattern.mSurface->GetType() == SURFACE_CAIRO) {
180 0 : const SourceSurfaceCairo* source = static_cast<const SourceSurfaceCairo*>(pattern.mSurface.get());
181 0 : surf = source->GetSurface();
182 0 : cairo_surface_reference(surf);
183 0 : } else if (pattern.mSurface->GetType() == SURFACE_CAIRO_IMAGE) {
184 : const DataSourceSurfaceCairo* source =
185 0 : static_cast<const DataSourceSurfaceCairo*>(pattern.mSurface.get());
186 0 : surf = source->GetSurface();
187 0 : cairo_surface_reference(surf);
188 : } else {
189 0 : RefPtr<DataSourceSurface> source = pattern.mSurface->GetDataSurface();
190 0 : surf = cairo_image_surface_create_for_data(source->GetData(),
191 0 : GfxFormatToCairoFormat(source->GetFormat()),
192 0 : source->GetSize().width,
193 0 : source->GetSize().height,
194 0 : source->Stride());
195 : }
196 :
197 0 : pat = cairo_pattern_create_for_surface(surf);
198 0 : cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(pattern.mFilter));
199 0 : cairo_pattern_set_extend(pat, GfxExtendToCairoExtend(pattern.mExtendMode));
200 :
201 0 : cairo_surface_destroy(surf);
202 :
203 0 : break;
204 : }
205 : case PATTERN_LINEAR_GRADIENT:
206 : {
207 0 : const LinearGradientPattern& pattern = static_cast<const LinearGradientPattern&>(aPattern);
208 :
209 : pat = cairo_pattern_create_linear(pattern.mBegin.x, pattern.mBegin.y,
210 0 : pattern.mEnd.x, pattern.mEnd.y);
211 :
212 0 : MOZ_ASSERT(pattern.mStops->GetBackendType() == BACKEND_CAIRO);
213 : const std::vector<GradientStop>& stops =
214 0 : static_cast<GradientStopsCairo*>(pattern.mStops.get())->GetStops();
215 0 : for (size_t i = 0; i < stops.size(); ++i) {
216 0 : const GradientStop& stop = stops[i];
217 : cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r,
218 : stop.color.g, stop.color.b,
219 0 : stop.color.a);
220 : }
221 :
222 0 : break;
223 : }
224 : case PATTERN_RADIAL_GRADIENT:
225 : {
226 0 : const RadialGradientPattern& pattern = static_cast<const RadialGradientPattern&>(aPattern);
227 :
228 : pat = cairo_pattern_create_radial(pattern.mCenter1.x, pattern.mCenter1.y, pattern.mRadius1,
229 0 : pattern.mCenter2.x, pattern.mCenter2.y, pattern.mRadius2);
230 :
231 : const std::vector<GradientStop>& stops =
232 0 : static_cast<GradientStopsCairo*>(pattern.mStops.get())->GetStops();
233 0 : for (size_t i = 0; i < stops.size(); ++i) {
234 0 : const GradientStop& stop = stops[i];
235 : cairo_pattern_add_color_stop_rgba(pat, stop.offset, stop.color.r,
236 : stop.color.g, stop.color.b,
237 0 : stop.color.a);
238 : }
239 :
240 0 : break;
241 : }
242 : default:
243 : {
244 : // We should support all pattern types!
245 0 : MOZ_ASSERT(false);
246 : }
247 : }
248 :
249 0 : return pat;
250 : }
251 :
252 : static bool
253 0 : NeedIntermediateSurface(const Pattern& aPattern, const DrawOptions& aOptions)
254 : {
255 : // We pre-multiply colours' alpha by the global alpha, so we don't need to
256 : // use an intermediate surface for them.
257 0 : if (aPattern.GetType() == PATTERN_COLOR)
258 0 : return false;
259 :
260 0 : if (aOptions.mAlpha == 1.0)
261 0 : return false;
262 :
263 0 : return true;
264 : }
265 :
266 0 : DrawTargetCairo::DrawTargetCairo()
267 0 : : mContext(NULL)
268 : {
269 0 : }
270 :
271 0 : DrawTargetCairo::~DrawTargetCairo()
272 : {
273 0 : MarkSnapshotsIndependent();
274 0 : if (mPathObserver) {
275 0 : mPathObserver->ForgetDrawTarget();
276 : }
277 0 : cairo_destroy(mContext);
278 0 : }
279 :
280 : IntSize
281 0 : DrawTargetCairo::GetSize()
282 : {
283 0 : return IntSize();
284 : }
285 :
286 : TemporaryRef<SourceSurface>
287 0 : DrawTargetCairo::Snapshot()
288 : {
289 0 : cairo_surface_t* csurf = cairo_get_target(mContext);
290 0 : IntSize size;
291 0 : if (GetCairoSurfaceSize(csurf, size)) {
292 0 : cairo_content_t content = cairo_surface_get_content(csurf);
293 : RefPtr<SourceSurfaceCairo> surf = new SourceSurfaceCairo(csurf, size,
294 0 : CairoContentToGfxFormat(content),
295 0 : this);
296 0 : AppendSnapshot(surf);
297 0 : return surf;
298 : }
299 :
300 0 : return NULL;
301 : }
302 :
303 : void
304 0 : DrawTargetCairo::Flush()
305 : {
306 0 : cairo_surface_t* surf = cairo_get_target(mContext);
307 0 : cairo_surface_flush(surf);
308 0 : }
309 :
310 : void
311 0 : DrawTargetCairo::PrepareForDrawing(cairo_t* aContext, const Path* aPath /* = NULL */)
312 : {
313 0 : WillChange(aPath);
314 0 : }
315 :
316 : void
317 0 : DrawTargetCairo::DrawSurface(SourceSurface *aSurface,
318 : const Rect &aDest,
319 : const Rect &aSource,
320 : const DrawSurfaceOptions &aSurfOptions,
321 : const DrawOptions &aOptions)
322 : {
323 0 : AutoPrepareForDrawing prep(this, mContext);
324 :
325 0 : float sx = aSource.Width() / aDest.Width();
326 0 : float sy = aSource.Height() / aDest.Height();
327 :
328 : cairo_matrix_t src_mat;
329 0 : cairo_matrix_init_scale(&src_mat, sx, sy);
330 0 : cairo_matrix_translate(&src_mat, aSource.X(), aSource.Y());
331 :
332 0 : cairo_surface_t* surf = NULL;
333 0 : if (aSurface->GetType() == SURFACE_CAIRO) {
334 0 : surf = static_cast<SourceSurfaceCairo*>(aSurface)->GetSurface();
335 : }
336 :
337 0 : cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
338 0 : cairo_pattern_set_matrix(pat, &src_mat);
339 0 : cairo_pattern_set_filter(pat, GfxFilterToCairoFilter(aSurfOptions.mFilter));
340 :
341 0 : cairo_save(mContext);
342 :
343 0 : cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
344 :
345 0 : cairo_translate(mContext, aDest.X(), aDest.Y());
346 :
347 0 : cairo_set_source(mContext, pat);
348 :
349 0 : cairo_new_path(mContext);
350 0 : cairo_rectangle(mContext, 0, 0, aDest.Width(), aDest.Height());
351 0 : cairo_clip(mContext);
352 0 : cairo_paint_with_alpha(mContext, aOptions.mAlpha);
353 :
354 0 : cairo_restore(mContext);
355 :
356 0 : cairo_pattern_destroy(pat);
357 0 : }
358 :
359 : void
360 0 : DrawTargetCairo::DrawSurfaceWithShadow(SourceSurface *aSurface,
361 : const Point &aDest,
362 : const Color &aColor,
363 : const Point &aOffset,
364 : Float aSigma,
365 : CompositionOp aOperator)
366 : {
367 0 : WillChange();
368 :
369 0 : if (aSurface->GetType() != SURFACE_CAIRO) {
370 0 : return;
371 : }
372 :
373 0 : SourceSurfaceCairo* source = static_cast<SourceSurfaceCairo*>(aSurface);
374 :
375 0 : Float width = aSurface->GetSize().width;
376 0 : Float height = aSurface->GetSize().height;
377 0 : Rect extents(0, 0, width, height);
378 :
379 : AlphaBoxBlur blur(extents, IntSize(0, 0),
380 0 : AlphaBoxBlur::CalculateBlurRadius(Point(aSigma, aSigma)),
381 0 : NULL, NULL);
382 0 : if (!blur.GetData()) {
383 : return;
384 : }
385 :
386 0 : IntSize blursize = blur.GetSize();
387 :
388 : cairo_surface_t* blursurf = cairo_image_surface_create_for_data(blur.GetData(),
389 : CAIRO_FORMAT_A8,
390 : blursize.width,
391 : blursize.height,
392 0 : blur.GetStride());
393 :
394 : // Draw the source surface into the surface we're going to blur.
395 0 : cairo_surface_t* surf = source->GetSurface();
396 0 : cairo_pattern_t* pat = cairo_pattern_create_for_surface(surf);
397 :
398 0 : cairo_t* ctx = cairo_create(blursurf);
399 :
400 0 : cairo_set_source(ctx, pat);
401 :
402 0 : IntRect blurrect = blur.GetRect();
403 0 : cairo_new_path(ctx);
404 0 : cairo_rectangle(ctx, blurrect.x, blurrect.y, blurrect.width, blurrect.height);
405 0 : cairo_clip(ctx);
406 0 : cairo_paint(ctx);
407 :
408 0 : cairo_destroy(ctx);
409 :
410 : // Blur the result, then use that blurred result as a mask to draw the shadow
411 : // colour to the surface.
412 0 : blur.Blur();
413 :
414 0 : cairo_save(mContext);
415 :
416 0 : cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
417 0 : cairo_set_source_rgba(mContext, aColor.r, aColor.g, aColor.b, aColor.a);
418 :
419 0 : cairo_identity_matrix(mContext);
420 0 : cairo_translate(mContext, aDest.x, aDest.y);
421 :
422 0 : cairo_mask_surface(mContext, blursurf, aOffset.x, aOffset.y);
423 :
424 : // Now that the shadow has been drawn, we can draw the surface on top.
425 :
426 0 : cairo_set_operator(mContext, GfxOpToCairoOp(aOperator));
427 :
428 0 : cairo_set_source(mContext, pat);
429 :
430 0 : cairo_new_path(mContext);
431 0 : cairo_rectangle(mContext, 0, 0, width, height);
432 0 : cairo_clip(mContext);
433 :
434 0 : cairo_paint(mContext);
435 :
436 0 : cairo_restore(mContext);
437 :
438 0 : cairo_pattern_destroy(pat);
439 : }
440 :
441 : void
442 0 : DrawTargetCairo::DrawPattern(const Pattern& aPattern,
443 : const StrokeOptions& aStrokeOptions,
444 : const DrawOptions& aOptions,
445 : DrawPatternType aDrawType)
446 : {
447 0 : if (!PatternIsCompatible(aPattern)) {
448 0 : return;
449 : }
450 :
451 0 : cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha);
452 0 : cairo_set_source(mContext, pat);
453 :
454 0 : if (NeedIntermediateSurface(aPattern, aOptions)) {
455 0 : cairo_push_group_with_content(mContext, CAIRO_CONTENT_COLOR_ALPHA);
456 :
457 : // Don't want operators to be applied twice
458 0 : cairo_set_operator(mContext, CAIRO_OPERATOR_OVER);
459 :
460 0 : if (aDrawType == DRAW_STROKE) {
461 0 : SetCairoStrokeOptions(mContext, aStrokeOptions);
462 0 : cairo_stroke_preserve(mContext);
463 : } else {
464 0 : cairo_fill_preserve(mContext);
465 : }
466 :
467 0 : cairo_pop_group_to_source(mContext);
468 :
469 : // Now draw the content using the desired operator
470 0 : cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
471 0 : cairo_paint_with_alpha(mContext, aOptions.mAlpha);
472 : } else {
473 0 : cairo_set_operator(mContext, GfxOpToCairoOp(aOptions.mCompositionOp));
474 :
475 0 : if (aDrawType == DRAW_STROKE) {
476 0 : SetCairoStrokeOptions(mContext, aStrokeOptions);
477 0 : cairo_stroke_preserve(mContext);
478 : } else {
479 0 : cairo_fill_preserve(mContext);
480 : }
481 : }
482 :
483 0 : cairo_pattern_destroy(pat);
484 : }
485 :
486 : void
487 0 : DrawTargetCairo::FillRect(const Rect &aRect,
488 : const Pattern &aPattern,
489 : const DrawOptions &aOptions)
490 : {
491 0 : AutoPrepareForDrawing prep(this, mContext);
492 :
493 0 : cairo_new_path(mContext);
494 0 : cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height());
495 :
496 0 : DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
497 0 : }
498 :
499 : void
500 0 : DrawTargetCairo::CopySurface(SourceSurface *aSurface,
501 : const IntRect &aSourceRect,
502 : const IntPoint &aDestination)
503 : {
504 0 : AutoPrepareForDrawing prep(this, mContext);
505 0 : }
506 :
507 : void
508 0 : DrawTargetCairo::ClearRect(const Rect& aRect)
509 : {
510 0 : AutoPrepareForDrawing prep(this, mContext);
511 :
512 0 : cairo_save(mContext);
513 :
514 0 : cairo_new_path(mContext);
515 0 : cairo_set_operator(mContext, CAIRO_OPERATOR_CLEAR);
516 0 : cairo_rectangle(mContext, aRect.X(), aRect.Y(),
517 0 : aRect.Width(), aRect.Height());
518 0 : cairo_fill(mContext);
519 :
520 0 : cairo_restore(mContext);
521 0 : }
522 :
523 : void
524 0 : DrawTargetCairo::StrokeRect(const Rect &aRect,
525 : const Pattern &aPattern,
526 : const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
527 : const DrawOptions &aOptions /* = DrawOptions() */)
528 : {
529 0 : AutoPrepareForDrawing prep(this, mContext);
530 :
531 0 : cairo_new_path(mContext);
532 0 : cairo_rectangle(mContext, aRect.x, aRect.y, aRect.Width(), aRect.Height());
533 :
534 0 : DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE);
535 0 : }
536 :
537 : void
538 0 : DrawTargetCairo::StrokeLine(const Point &aStart,
539 : const Point &aEnd,
540 : const Pattern &aPattern,
541 : const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
542 : const DrawOptions &aOptions /* = DrawOptions() */)
543 : {
544 0 : AutoPrepareForDrawing prep(this, mContext);
545 :
546 0 : cairo_new_path(mContext);
547 0 : cairo_move_to(mContext, aStart.x, aStart.y);
548 0 : cairo_line_to(mContext, aEnd.x, aEnd.y);
549 :
550 0 : DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE);
551 0 : }
552 :
553 : void
554 0 : DrawTargetCairo::Stroke(const Path *aPath,
555 : const Pattern &aPattern,
556 : const StrokeOptions &aStrokeOptions /* = StrokeOptions() */,
557 : const DrawOptions &aOptions /* = DrawOptions() */)
558 : {
559 0 : AutoPrepareForDrawing prep(this, mContext, aPath);
560 :
561 0 : if (aPath->GetBackendType() != BACKEND_CAIRO)
562 : return;
563 :
564 0 : PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
565 0 : path->CopyPathTo(mContext, this);
566 :
567 0 : DrawPattern(aPattern, aStrokeOptions, aOptions, DRAW_STROKE);
568 : }
569 :
570 : void
571 0 : DrawTargetCairo::Fill(const Path *aPath,
572 : const Pattern &aPattern,
573 : const DrawOptions &aOptions /* = DrawOptions() */)
574 : {
575 0 : AutoPrepareForDrawing prep(this, mContext, aPath);
576 :
577 0 : if (aPath->GetBackendType() != BACKEND_CAIRO)
578 : return;
579 :
580 0 : PathCairo* path = const_cast<PathCairo*>(static_cast<const PathCairo*>(aPath));
581 0 : path->CopyPathTo(mContext, this);
582 :
583 0 : DrawPattern(aPattern, StrokeOptions(), aOptions, DRAW_FILL);
584 : }
585 :
586 : void
587 0 : DrawTargetCairo::FillGlyphs(ScaledFont *aFont,
588 : const GlyphBuffer &aBuffer,
589 : const Pattern &aPattern,
590 : const DrawOptions &aOptions)
591 : {
592 0 : AutoPrepareForDrawing prep(this, mContext);
593 :
594 0 : ScaledFontBase* scaledFont = static_cast<ScaledFontBase*>(aFont);
595 0 : cairo_set_scaled_font(mContext, scaledFont->GetCairoScaledFont());
596 :
597 0 : cairo_pattern_t* pat = GfxPatternToCairoPattern(aPattern, aOptions.mAlpha);
598 0 : cairo_set_source(mContext, pat);
599 0 : cairo_pattern_destroy(pat);
600 :
601 : // Convert our GlyphBuffer into an array of Cairo glyphs.
602 0 : std::vector<cairo_glyph_t> glyphs(aBuffer.mNumGlyphs);
603 0 : for (uint32_t i = 0; i < aBuffer.mNumGlyphs; ++i) {
604 0 : glyphs[i].index = aBuffer.mGlyphs[i].mIndex;
605 0 : glyphs[i].x = aBuffer.mGlyphs[i].mPosition.x;
606 0 : glyphs[i].y = aBuffer.mGlyphs[i].mPosition.y;
607 : }
608 :
609 0 : cairo_show_glyphs(mContext, &glyphs[0], aBuffer.mNumGlyphs);
610 0 : }
611 :
612 : void
613 0 : DrawTargetCairo::Mask(const Pattern &aSource,
614 : const Pattern &aMask,
615 : const DrawOptions &aOptions /* = DrawOptions() */)
616 : {
617 0 : AutoPrepareForDrawing prep(this, mContext);
618 0 : }
619 :
620 : void
621 0 : DrawTargetCairo::PushClip(const Path *aPath)
622 : {
623 0 : }
624 :
625 : void
626 0 : DrawTargetCairo::PushClipRect(const Rect& aRect)
627 : {
628 0 : }
629 :
630 : void
631 0 : DrawTargetCairo::PopClip()
632 : {
633 0 : }
634 :
635 : TemporaryRef<PathBuilder>
636 0 : DrawTargetCairo::CreatePathBuilder(FillRule aFillRule /* = FILL_WINDING */) const
637 : {
638 : RefPtr<PathBuilderCairo> builder = new PathBuilderCairo(mContext,
639 : const_cast<DrawTargetCairo*>(this),
640 0 : aFillRule);
641 :
642 : // Creating a PathBuilder implicitly resets our mPathObserver, as it calls
643 : // SetPathObserver() on us. Since this guarantees our old path is saved off,
644 : // it's safe to reset the path here.
645 0 : cairo_new_path(mContext);
646 :
647 0 : return builder;
648 : }
649 :
650 : TemporaryRef<GradientStops>
651 0 : DrawTargetCairo::CreateGradientStops(GradientStop *aStops, uint32_t aNumStops, ExtendMode aExtendMode) const
652 : {
653 0 : RefPtr<GradientStopsCairo> stops = new GradientStopsCairo(aStops, aNumStops);
654 0 : return stops;
655 : }
656 :
657 : TemporaryRef<SourceSurface>
658 0 : DrawTargetCairo::CreateSourceSurfaceFromData(unsigned char *aData,
659 : const IntSize &aSize,
660 : int32_t aStride,
661 : SurfaceFormat aFormat) const
662 : {
663 : cairo_surface_t* surf = cairo_image_surface_create_for_data(aData,
664 : GfxFormatToCairoFormat(aFormat),
665 : aSize.width,
666 : aSize.height,
667 0 : aStride);
668 0 : RefPtr<SourceSurfaceCairo> source_surf = new SourceSurfaceCairo(surf, aSize, aFormat);
669 0 : cairo_surface_destroy(surf);
670 0 : return source_surf;
671 : }
672 :
673 : TemporaryRef<SourceSurface>
674 0 : DrawTargetCairo::OptimizeSourceSurface(SourceSurface *aSurface) const
675 : {
676 0 : return aSurface;
677 : }
678 :
679 : TemporaryRef<SourceSurface>
680 0 : DrawTargetCairo::CreateSourceSurfaceFromNativeSurface(const NativeSurface &aSurface) const
681 : {
682 0 : if (aSurface.mType == NATIVE_SURFACE_CAIRO_SURFACE) {
683 0 : IntSize size;
684 0 : cairo_surface_t* surf = static_cast<cairo_surface_t*>(aSurface.mSurface);
685 0 : if (GetCairoSurfaceSize(surf, size)) {
686 : RefPtr<SourceSurfaceCairo> source =
687 0 : new SourceSurfaceCairo(surf, size, aSurface.mFormat);
688 0 : return source;
689 : }
690 : }
691 :
692 0 : return NULL;
693 : }
694 :
695 : TemporaryRef<DrawTarget>
696 0 : DrawTargetCairo::CreateSimilarDrawTarget(const IntSize &aSize, SurfaceFormat aFormat) const
697 : {
698 : cairo_surface_t* similar = cairo_surface_create_similar(cairo_get_target(mContext),
699 : GfxFormatToCairoContent(aFormat),
700 0 : aSize.width, aSize.height);
701 :
702 0 : if (!cairo_surface_status(similar)) {
703 0 : RefPtr<DrawTargetCairo> target = new DrawTargetCairo();
704 0 : target->Init(similar);
705 0 : return target;
706 : }
707 :
708 0 : return NULL;
709 : }
710 :
711 : bool
712 0 : DrawTargetCairo::Init(cairo_surface_t* aSurface)
713 : {
714 0 : mContext = cairo_create(aSurface);
715 :
716 0 : return true;
717 : }
718 :
719 : void *
720 0 : DrawTargetCairo::GetNativeSurface(NativeSurfaceType aType)
721 : {
722 0 : if (aType == NATIVE_SURFACE_CAIRO_SURFACE) {
723 0 : return cairo_get_target(mContext);
724 : }
725 :
726 0 : return NULL;
727 : }
728 :
729 : void
730 0 : DrawTargetCairo::MarkSnapshotsIndependent()
731 : {
732 : // Make a copy of the vector, since MarkIndependent implicitly modifies mSnapshots.
733 0 : std::vector<SourceSurfaceCairo*> snapshots = mSnapshots;
734 0 : for (std::vector<SourceSurfaceCairo*>::iterator iter = snapshots.begin();
735 0 : iter != snapshots.end();
736 : ++iter) {
737 0 : (*iter)->MarkIndependent();
738 : }
739 0 : }
740 :
741 : void
742 0 : DrawTargetCairo::AppendSnapshot(SourceSurfaceCairo* aSnapshot)
743 : {
744 0 : mSnapshots.push_back(aSnapshot);
745 0 : }
746 :
747 : void
748 0 : DrawTargetCairo::RemoveSnapshot(SourceSurfaceCairo* aSnapshot)
749 : {
750 0 : std::vector<SourceSurfaceCairo*>::iterator iter = std::find(mSnapshots.begin(),
751 0 : mSnapshots.end(),
752 0 : aSnapshot);
753 0 : if (iter != mSnapshots.end()) {
754 0 : mSnapshots.erase(iter);
755 : }
756 0 : }
757 :
758 : void
759 0 : DrawTargetCairo::WillChange(const Path* aPath /* = NULL */)
760 : {
761 0 : if (!mSnapshots.empty()) {
762 0 : for (std::vector<SourceSurfaceCairo*>::iterator iter = mSnapshots.begin();
763 0 : iter != mSnapshots.end(); ++iter) {
764 0 : (*iter)->DrawTargetWillChange();
765 : }
766 : // All snapshots will now have copied data.
767 0 : mSnapshots.clear();
768 : }
769 :
770 0 : if (aPath && mPathObserver && !mPathObserver->ContainsPath(aPath)) {
771 0 : mPathObserver->PathWillChange();
772 0 : mPathObserver = NULL;
773 : }
774 0 : }
775 :
776 : void
777 0 : DrawTargetCairo::SetPathObserver(CairoPathContext* aPathObserver)
778 : {
779 0 : if (mPathObserver && mPathObserver != aPathObserver) {
780 0 : mPathObserver->PathWillChange();
781 : }
782 0 : mPathObserver = aPathObserver;
783 0 : }
784 :
785 : void
786 0 : DrawTargetCairo::SetTransform(const Matrix& aTransform)
787 : {
788 : // We're about to logically change our transformation. Our current path will
789 : // need to change, because Cairo stores paths in device space.
790 0 : if (mPathObserver) {
791 0 : mPathObserver->MatrixWillChange(aTransform);
792 : }
793 :
794 0 : mTransform = aTransform;
795 :
796 : cairo_matrix_t mat;
797 0 : GfxMatrixToCairoMatrix(mTransform, mat);
798 0 : cairo_set_matrix(mContext, &mat);
799 0 : }
800 :
801 : }
802 : }
|