a08b3fb13f50d15c50c48d8dbfcee211af631437
[framework/graphics/cairo.git] / src / skia / cairo-skia-context.cpp
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2002 University of Southern California
5  * Copyright © 2005 Red Hat, Inc.
6  * Copyright © 2010 Intel Corporation
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it either under the terms of the GNU Lesser General Public
10  * License version 2.1 as published by the Free Software Foundation
11  * (the "LGPL") or, at your option, under the terms of the Mozilla
12  * Public License Version 1.1 (the "MPL"). If you do not alter this
13  * notice, a recipient may use your version of this file under either
14  * the MPL or the LGPL.
15  *
16  * You should have received a copy of the LGPL along with this library
17  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  * You should have received a copy of the MPL along with this library
20  * in the file COPYING-MPL-1.1
21  *
22  * The contents of this file are subject to the Mozilla Public License
23  * Version 1.1 (the "License"); you may not use this file except in
24  * compliance with the License. You may obtain a copy of the License at
25  * http://www.mozilla.org/MPL/
26  *
27  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
28  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
29  * the specific language governing rights and limitations.
30  *
31  * The Original Code is the cairo graphics library.
32  *
33  * The Initial Developer of the Original Code is University of Southern
34  * California.
35  *
36  * Contributor(s):
37  *      Carl D. Worth <cworth@cworth.org>
38  *      Chris Wilson <chris@chris-wilson.co.uk>
39  */
40
41 #include "cairoint.h"
42
43 #include "cairo-private.h"
44 #include "cairo-error-private.h"
45 #include "cairo-arc-private.h"
46 #include "cairo-backend-private.h"
47 #include "cairo-default-context-private.h"
48 #include "cairo-freed-pool-private.h"
49 #include "cairo-gstate-private.h"
50 #include "cairo-image-surface-inline.h"
51 #include "cairo-path-private.h"
52 #include "cairo-pattern-private.h"
53 #include "cairo-skia-private.h"
54 #include "cairo-surface-backend-private.h"
55
56 #include <SkShader.h>
57 #include <SkColorShader.h>
58 #include <SkGradientShader.h>
59 #include <SkDashPathEffect.h>
60
61 #if !defined(INFINITY)
62 #define INFINITY HUGE_VAL
63 #endif
64
65 #if (CAIRO_FIXED_BITS == 32) && (CAIRO_FIXED_FRAC_BITS == 16) && defined(SK_SCALAR_IS_FIXED)
66 # define CAIRO_FIXED_TO_SK_SCALAR(x)  (x)
67 #elif defined(SK_SCALAR_IS_FIXED)
68 /* This can be done better, but this will do for now */
69 # define CAIRO_FIXED_TO_SK_SCALAR(x)  SkFloatToScalar(_cairo_fixed_to_double(x))
70 #else
71 # define CAIRO_FIXED_TO_SK_SCALAR(x)  SkFloatToScalar(_cairo_fixed_to_double(x))
72 #endif
73
74 #define UNSUPPORTED
75
76
77 static freed_pool_t context_pool;
78
79 static void
80 _cairo_skia_context_destroy (void *abstract_cr)
81 {
82     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
83
84     cr->path->reset ();
85     cr->paint->reset ();
86
87     delete cr->canvas;
88
89     cairo_surface_destroy (&cr->target->image.base);
90     cairo_surface_destroy (&cr->original->image.base);
91
92     if (cr->source != NULL) {
93         if (cr->source_image != NULL) {
94             _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra);
95             cr->source_image = NULL;
96         }
97         cairo_surface_destroy (cr->source);
98         cr->source = NULL;
99     }
100
101     _cairo_fini (&cr->base);
102
103     _freed_pool_put (&context_pool, cr);
104 }
105
106 static cairo_surface_t *
107 _cairo_skia_context_get_original_target (void *abstract_cr)
108 {
109     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
110
111     return &cr->original->image.base;
112 }
113
114 static cairo_surface_t *
115 _cairo_skia_context_get_current_target (void *abstract_cr)
116 {
117     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
118
119     return &cr->target->image.base;
120 }
121
122 static cairo_status_t
123 _cairo_skia_context_save (void *abstract_cr)
124 {
125     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
126
127     cr->canvas->save ();
128     return CAIRO_STATUS_SUCCESS;
129 }
130
131 static cairo_status_t
132 _cairo_skia_context_restore (void *abstract_cr)
133 {
134     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
135
136     cr->canvas->restore ();
137     return CAIRO_STATUS_SUCCESS;
138 }
139
140 static cairo_status_t
141 _cairo_skia_context_push_group (void *abstract_cr, cairo_content_t content)
142 {
143     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
144     cairo_surface_t *group_surface;
145     cairo_status_t status;
146     int width, height;
147
148     //clip = _cairo_gstate_get_clip (cr->gstate);
149     width = cr->target->image.width;
150     height = cr->target->image.height;
151     group_surface = cr->target->image.base.backend->create_similar (&cr->target->image.base,
152                                                                     content, width, height);
153
154 #if 0
155     /* Set device offsets on the new surface so that logically it appears at
156      * the same location on the parent surface -- when we pop_group this,
157      * the source pattern will get fixed up for the appropriate target surface
158      * device offsets, so we want to set our own surface offsets from /that/,
159      * and not from the device origin. */
160     cairo_surface_set_device_offset (group_surface,
161                                      parent_surface->device_transform.x0 - extents.x,
162                                      parent_surface->device_transform.y0 - extents.y);
163
164     /* If we have a current path, we need to adjust it to compensate for
165      * the device offset just applied. */
166     _cairo_path_fixed_transform (cr->path,
167                                  &group_surface->device_transform);
168 #endif
169
170     status = _cairo_skia_context_save (cr);
171     if (unlikely (status)) {
172         cairo_surface_destroy (group_surface);
173         return status;
174     }
175
176     cairo_surface_destroy (&cr->target->image.base);
177     cr->target = (cairo_skia_surface_t *) group_surface;
178
179     return CAIRO_STATUS_SUCCESS;
180 }
181
182 static cairo_pattern_t *
183 _cairo_skia_context_pop_group (void *abstract_cr)
184 {
185     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
186     cairo_surface_t *group_surface;
187     cairo_pattern_t *group_pattern;
188     cairo_status_t status;
189
190     group_surface = cairo_surface_reference (&cr->target->image.base);
191
192     status = _cairo_skia_context_restore (cr);
193     if (unlikely (status)) {
194         group_pattern = _cairo_pattern_create_in_error (status);
195         goto done;
196     }
197
198     group_pattern = cairo_pattern_create_for_surface (group_surface);
199     status = group_pattern->status;
200     if (unlikely (status))
201         goto done;
202
203 #if 0
204     _cairo_gstate_get_matrix (cr->gstate, &group_matrix);
205     /* Transform by group_matrix centered around device_transform so that when
206      * we call _cairo_gstate_copy_transformed_pattern the result is a pattern
207      * with a matrix equivalent to the device_transform of group_surface. */
208     if (_cairo_surface_has_device_transform (group_surface)) {
209         cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform);
210         _cairo_pattern_transform (group_pattern, &group_matrix);
211         _cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse);
212     } else {
213         cairo_pattern_set_matrix (group_pattern, &group_matrix);
214     }
215
216     /* If we have a current path, we need to adjust it to compensate for
217      * the device offset just removed. */
218     _cairo_path_fixed_transform (cr->path,
219                                  &group_surface->device_transform_inverse);
220 #endif
221
222 done:
223     cairo_surface_destroy (group_surface);
224
225     return group_pattern;
226 }
227
228 static inline cairo_surface_t *
229 surface_from_pattern (const cairo_pattern_t *pattern)
230 {
231     return (reinterpret_cast <const cairo_surface_pattern_t *> (pattern))->surface;
232 }
233
234 static inline bool
235 surface_to_sk_bitmap (cairo_surface_t *surface, SkBitmap& bitmap)
236 {
237     cairo_image_surface_t *img = (cairo_image_surface_t *) surface;
238     SkBitmap::Config config;
239     bool opaque;
240
241     if (unlikely (! format_to_sk_config (img->format, config, opaque)))
242         return false;
243
244     bitmap.reset ();
245     bitmap.setConfig (config, img->width, img->height, img->stride);
246     bitmap.setIsOpaque (opaque);
247     bitmap.setPixels (img->data);
248
249     return true;
250 }
251
252 static inline SkMatrix
253 matrix_to_sk (const cairo_matrix_t& mat)
254 {
255     SkMatrix skm;
256
257     skm.reset ();
258     skm.set (SkMatrix::kMScaleX, SkFloatToScalar (mat.xx));
259     skm.set (SkMatrix::kMSkewX,  SkFloatToScalar (mat.xy));
260     skm.set (SkMatrix::kMTransX, SkFloatToScalar (mat.x0));
261     skm.set (SkMatrix::kMSkewY,  SkFloatToScalar (mat.yx));
262     skm.set (SkMatrix::kMScaleY, SkFloatToScalar (mat.yy));
263     skm.set (SkMatrix::kMTransY, SkFloatToScalar (mat.y0));
264
265     /*
266     skm[6] = SkFloatToScalar (0.0);
267     skm[7] = SkFloatToScalar (0.0);
268     skm[8] = SkFloatToScalar (1.0); -- this isn't right, it wants a magic value in there that it'll set itself.  It wants Sk_Fract1 (2.30), not Sk_Scalar1
269     */
270
271     return skm;
272 }
273
274 static inline SkMatrix
275 matrix_inverse_to_sk (const cairo_matrix_t& mat)
276 {
277     cairo_matrix_t inv = mat;
278     cairo_status_t status = cairo_matrix_invert (&inv);
279     assert (status == CAIRO_STATUS_SUCCESS);
280     return matrix_to_sk (inv);
281 }
282
283 static SkShader::TileMode
284 extend_to_sk (cairo_extend_t extend)
285 {
286     static const SkShader::TileMode modeMap[] = {
287         SkShader::kClamp_TileMode,  // NONE behaves like PAD, because noone wants NONE
288         SkShader::kRepeat_TileMode,
289         SkShader::kMirror_TileMode,
290         SkShader::kClamp_TileMode
291     };
292
293     return modeMap[extend];
294 }
295
296 static inline SkColor
297 color_to_sk (const cairo_color_t& c)
298 {
299     /* Need unpremultiplied 1-byte values */
300     return SkColorSetARGB ((U8CPU) (c.alpha * 255),
301                            (U8CPU) (c.red * 255),
302                            (U8CPU) (c.green * 255),
303                            (U8CPU) (c.blue * 255));
304 }
305
306 static inline SkColor
307 color_stop_to_sk (const cairo_color_stop_t& c)
308 {
309     /* Need unpremultiplied 1-byte values */
310     return SkColorSetARGB ((U8CPU) (c.alpha * 255),
311                            (U8CPU) (c.red * 255),
312                            (U8CPU) (c.green * 255),
313                            (U8CPU) (c.blue * 255));
314 }
315
316 static SkShader*
317 source_to_sk_shader (cairo_skia_context_t *cr,
318                      const cairo_pattern_t *pattern)
319 {
320     SkShader *shader = NULL;
321
322     if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) {
323         cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern;
324         return new SkColorShader (color_to_sk (solid->color));
325     } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
326         cairo_surface_t *surface = surface_from_pattern (pattern);
327
328         cr->source = cairo_surface_reference (surface);
329
330         if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
331             cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;
332
333             shader = SkShader::CreateBitmapShader (*esurf->bitmap,
334                                                    extend_to_sk (pattern->extend),
335                                                    extend_to_sk (pattern->extend));
336         } else {
337             SkBitmap bitmap;
338
339             if (! _cairo_surface_is_image (surface)) {
340                 cairo_status_t status;
341
342                 status = _cairo_surface_acquire_source_image (surface,
343                                                               &cr->source_image,
344                                                               &cr->source_extra);
345                 if (status)
346                     return NULL;
347
348                 surface = &cr->source_image->base;
349             }
350
351             if (unlikely (! surface_to_sk_bitmap (surface, bitmap)))
352                 return NULL;
353
354             shader = SkShader::CreateBitmapShader (bitmap,
355                                                    extend_to_sk (pattern->extend),
356                                                    extend_to_sk (pattern->extend));
357         }
358     } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR
359                /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */)
360     {
361         cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern;
362         SkColor colors_stack[10];
363         SkScalar pos_stack[10];
364         SkColor *colors = colors_stack;
365         SkScalar *pos = pos_stack;
366
367         if (gradient->n_stops > 10) {
368             colors = new SkColor[gradient->n_stops];
369             pos = new SkScalar[gradient->n_stops];
370         }
371
372         for (unsigned int i = 0; i < gradient->n_stops; i++) {
373             pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset);
374             colors[i] = color_stop_to_sk (gradient->stops[i].color);
375         }
376
377         if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) {
378             cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient;
379             SkPoint points[2];
380
381             points[0].set (SkFloatToScalar (linear->pd1.x),
382                            SkFloatToScalar (linear->pd1.y));
383             points[1].set (SkFloatToScalar (linear->pd2.x),
384                            SkFloatToScalar (linear->pd2.y));
385             shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops,
386                                                      extend_to_sk (pattern->extend));
387         } else {
388             // XXX todo -- implement real radial shaders in Skia
389         }
390
391         if (gradient->n_stops > 10) {
392             delete [] colors;
393             delete [] pos;
394         }
395     }
396
397     if (shader && ! _cairo_matrix_is_identity (&pattern->matrix))
398         shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix));
399
400     return shader;
401 }
402
403 static inline bool
404 pattern_filter_to_sk (const cairo_pattern_t *pattern)
405 {
406     switch (pattern->filter) {
407     case CAIRO_FILTER_GOOD:
408     case CAIRO_FILTER_BEST:
409     case CAIRO_FILTER_BILINEAR:
410     case CAIRO_FILTER_GAUSSIAN:
411         return true;
412     default:
413     case CAIRO_FILTER_FAST:
414     case CAIRO_FILTER_NEAREST:
415         return false;
416     }
417 }
418
419 static inline bool
420 pattern_to_sk_color (const cairo_pattern_t *pattern, SkColor& color)
421 {
422     if (pattern->type != CAIRO_PATTERN_TYPE_SOLID)
423         return false;
424
425     color = color_to_sk (((cairo_solid_pattern_t *) pattern)->color);
426     return true;
427 }
428
429 static cairo_status_t
430 _cairo_skia_context_set_source (void *abstract_cr,
431                                 cairo_pattern_t *source)
432 {
433     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
434     SkColor color;
435
436     if (cr->source != NULL) {
437         if (cr->source_image != NULL) {
438             _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra);
439             cr->source_image = NULL;
440         }
441         cairo_surface_destroy (cr->source);
442         cr->source = NULL;
443     }
444
445     if (pattern_to_sk_color (source, color)) {
446         cr->paint->setColor (color);
447     } else {
448         SkShader *shader = source_to_sk_shader (cr, source);
449         if (shader == NULL) {
450             UNSUPPORTED;
451             return CAIRO_STATUS_SUCCESS;
452         }
453
454         cr->paint->setShader (shader);
455         shader->unref ();
456
457         cr->paint->setFilterBitmap (pattern_filter_to_sk (source));
458     }
459
460     /* XXX change notification */
461     return CAIRO_STATUS_SUCCESS;
462 }
463
464 static cairo_status_t
465 _cairo_skia_context_set_source_rgba (void *abstract_cr, double red, double green, double blue, double alpha)
466 {
467     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
468
469     /* Need unpremultiplied 1-byte values */
470     cr->paint->setARGB ((U8CPU) (alpha * 255),
471                         (U8CPU) (red * 255),
472                         (U8CPU) (green * 255),
473                         (U8CPU) (blue * 255));
474     return CAIRO_STATUS_SUCCESS;
475 }
476
477 static cairo_status_t
478 _cairo_skia_context_set_source_surface (void *abstract_cr,
479                                         cairo_surface_t *surface,
480                                         double     x,
481                                         double     y)
482 {
483     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
484     cairo_pattern_t *pattern;
485     cairo_matrix_t matrix;
486     cairo_status_t status;
487
488     if (surface->type == CAIRO_SURFACE_TYPE_SKIA) {
489         cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface;
490         SkShader *shader;
491
492         shader = SkShader::CreateBitmapShader (*esurf->bitmap,
493                                                SkShader::kClamp_TileMode, /* XXX */
494                                                SkShader::kClamp_TileMode);
495
496         cr->paint->setShader (shader);
497         shader->unref ();
498
499         cr->paint->setFilterBitmap (true);
500
501         return CAIRO_STATUS_SUCCESS;
502     }
503
504     pattern = cairo_pattern_create_for_surface (surface);
505     if (unlikely (pattern->status))
506         return pattern->status;
507
508     cairo_matrix_init_translate (&matrix, -x, -y);
509     cairo_pattern_set_matrix (pattern, &matrix);
510
511     status = _cairo_skia_context_set_source (cr, pattern);
512     cairo_pattern_destroy (pattern);
513
514     return status;
515 }
516
517 static cairo_pattern_t *
518 _cairo_skia_context_get_source (void *abstract_cr)
519 {
520     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
521
522     UNSUPPORTED;
523     return NULL;
524 }
525
526 static cairo_status_t
527 _cairo_skia_context_set_tolerance (void *abstract_cr,
528                                    double tolerance)
529 {
530     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
531
532     /* XXX ignored */
533     return CAIRO_STATUS_SUCCESS;
534 }
535
536 static inline SkXfermode::Mode
537 operator_to_sk (cairo_operator_t op)
538 {
539     static const SkXfermode::Mode modeMap[] = {
540         SkXfermode::kClear_Mode,
541
542         SkXfermode::kSrc_Mode,
543         SkXfermode::kSrcOver_Mode,
544         SkXfermode::kSrcIn_Mode,
545         SkXfermode::kSrcOut_Mode,
546         SkXfermode::kSrcATop_Mode,
547
548         SkXfermode::kDst_Mode,
549         SkXfermode::kDstOver_Mode,
550         SkXfermode::kDstIn_Mode,
551         SkXfermode::kDstOut_Mode,
552         SkXfermode::kDstATop_Mode,
553
554         SkXfermode::kXor_Mode,
555         SkXfermode::kPlus_Mode, // XXX Add?
556         SkXfermode::kPlus_Mode, // XXX SATURATE
557
558         SkXfermode::kPlus_Mode,
559         SkXfermode::kMultiply_Mode,
560         SkXfermode::kScreen_Mode,
561         SkXfermode::kOverlay_Mode,
562         SkXfermode::kDarken_Mode,
563         SkXfermode::kLighten_Mode,
564         SkXfermode::kColorDodge_Mode,
565         SkXfermode::kColorBurn_Mode,
566         SkXfermode::kHardLight_Mode,
567         SkXfermode::kSoftLight_Mode,
568         SkXfermode::kDifference_Mode,
569         SkXfermode::kExclusion_Mode,
570
571         SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_HUE
572         SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_SATURATION,
573         SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_COLOR,
574         SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_LUMINOSITY
575     };
576
577     return modeMap[op];
578 }
579
580 static cairo_status_t
581 _cairo_skia_context_set_operator (void *abstract_cr, cairo_operator_t op)
582 {
583     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
584
585     cr->paint->setXfermodeMode (operator_to_sk (op));
586     return CAIRO_STATUS_SUCCESS;
587 }
588
589 static cairo_status_t
590 _cairo_skia_context_set_opacity (void *abstract_cr, double opacity)
591 {
592     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
593
594     /* XXX */
595     return CAIRO_STATUS_SUCCESS;
596 }
597
598 static cairo_status_t
599 _cairo_skia_context_set_antialias (void *abstract_cr, cairo_antialias_t antialias)
600 {
601     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
602
603     cr->paint->setAntiAlias (antialias != CAIRO_ANTIALIAS_NONE);
604     return CAIRO_STATUS_SUCCESS;
605 }
606
607 static cairo_status_t
608 _cairo_skia_context_set_fill_rule (void *abstract_cr,
609                                    cairo_fill_rule_t fill_rule)
610 {
611     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
612
613     cr->path->setFillType (fill_rule == CAIRO_FILL_RULE_WINDING ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType);
614     return CAIRO_STATUS_SUCCESS;
615 }
616
617 static cairo_status_t
618 _cairo_skia_context_set_line_width (void *abstract_cr,
619                                     double line_width)
620 {
621     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
622
623     cr->paint->setStrokeWidth (SkFloatToScalar (line_width));
624     return CAIRO_STATUS_SUCCESS;
625 }
626
627 static cairo_status_t
628 _cairo_skia_context_set_line_cap (void *abstract_cr,
629                                   cairo_line_cap_t line_cap)
630 {
631     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
632     static const SkPaint::Cap map[] = {
633         SkPaint::kButt_Cap,
634         SkPaint::kRound_Cap,
635         SkPaint::kSquare_Cap
636     };
637     cr->paint->setStrokeCap (map[line_cap]);
638     return CAIRO_STATUS_SUCCESS;
639 }
640
641 static cairo_status_t
642 _cairo_skia_context_set_line_join (void *abstract_cr,
643                                    cairo_line_join_t line_join)
644 {
645     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
646     static const SkPaint::Join map[] = {
647         SkPaint::kMiter_Join,
648         SkPaint::kRound_Join,
649         SkPaint::kBevel_Join
650     };
651     cr->paint->setStrokeJoin (map[line_join]);
652     return CAIRO_STATUS_SUCCESS;
653 }
654
655 static cairo_status_t
656 _cairo_skia_context_set_dash (void *abstract_cr,
657                               const double *dashes,
658                               int             num_dashes,
659                               double          offset)
660 {
661     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
662     SkScalar intervals_static[20];
663     SkScalar *intervals = intervals_static;
664
665     if (num_dashes == 0) {
666         cr->paint->setPathEffect (NULL);
667         return CAIRO_STATUS_SUCCESS;
668     }
669
670     int loop = 0;
671     if ((num_dashes & 1) != 0) {
672         loop = 1;
673         num_dashes <<= 1;
674     }
675
676     if (num_dashes > 20)
677         intervals = new SkScalar[num_dashes];
678
679     int i = 0;
680     do {
681         for (int j = 0; i < num_dashes; j++)
682             intervals[i++] = SkFloatToScalar (dashes[j]);
683     } while (loop--);
684
685     SkDashPathEffect *dash = new SkDashPathEffect (intervals, num_dashes, SkFloatToScalar (offset));
686
687     cr->paint->setPathEffect (dash);
688     dash->unref ();
689
690     return CAIRO_STATUS_SUCCESS;
691 }
692
693 static cairo_status_t
694 _cairo_skia_context_set_miter_limit (void *abstract_cr, double limit)
695 {
696     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
697
698     cr->paint->setStrokeMiter (SkFloatToScalar (limit));
699     return CAIRO_STATUS_SUCCESS;
700 }
701
702 static cairo_antialias_t
703 _cairo_skia_context_get_antialias (void *abstract_cr)
704 {
705     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
706
707     return cr->paint->isAntiAlias () ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE;
708 }
709
710 static void
711 _cairo_skia_context_get_dash (void *abstract_cr,
712                               double *dashes,
713                               int *num_dashes,
714                               double *offset)
715 {
716     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
717
718     *num_dashes = 0;
719     /* XXX */
720 }
721
722 static cairo_fill_rule_t
723 _cairo_skia_context_get_fill_rule (void *abstract_cr)
724 {
725     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
726     SkPath::FillType ft;
727
728     ft = cr->path->getFillType ();
729     if (ft == SkPath::kWinding_FillType)
730         return CAIRO_FILL_RULE_WINDING;
731     if (ft == SkPath::kEvenOdd_FillType)
732         return CAIRO_FILL_RULE_EVEN_ODD;;
733
734     UNSUPPORTED;
735     return CAIRO_FILL_RULE_WINDING;
736 }
737
738 static double
739 _cairo_skia_context_get_line_width (void *abstract_cr)
740 {
741     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
742
743     return /* ScalarToFloat */ cr->paint->getStrokeWidth ();
744 }
745
746 static cairo_line_cap_t
747 _cairo_skia_context_get_line_cap (void *abstract_cr)
748 {
749     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
750     static const cairo_line_cap_t map[] = {
751         CAIRO_LINE_CAP_BUTT,
752         CAIRO_LINE_CAP_ROUND,
753         CAIRO_LINE_CAP_SQUARE
754     };
755     return map[cr->paint->getStrokeCap ()];
756 }
757
758 static cairo_line_join_t
759 _cairo_skia_context_get_line_join (void *abstract_cr)
760 {
761     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
762     static const cairo_line_join_t map[] = {
763         CAIRO_LINE_JOIN_MITER,
764         CAIRO_LINE_JOIN_ROUND,
765         CAIRO_LINE_JOIN_BEVEL
766     };
767     return map[cr->paint->getStrokeJoin ()];
768 }
769
770 static double
771 _cairo_skia_context_get_miter_limit (void *abstract_cr)
772 {
773     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
774
775     return /* SkScalarToFloat */ cr->paint->getStrokeMiter ();
776 }
777
778 static cairo_operator_t
779 _cairo_skia_context_get_operator (void *abstract_cr)
780 {
781     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
782
783     UNSUPPORTED;
784     //cr->paint->getXfermode ();
785     return CAIRO_OPERATOR_OVER;
786 }
787
788 static double
789 _cairo_skia_context_get_opacity (void *abstract_cr)
790 {
791     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
792
793     UNSUPPORTED;
794     return 1.;
795 }
796
797 static double
798 _cairo_skia_context_get_tolerance (void *abstract_cr)
799 {
800     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
801
802     /* XXX */
803     return CAIRO_GSTATE_TOLERANCE_DEFAULT;
804 }
805
806
807 /* Current tranformation matrix */
808
809 static cairo_status_t
810 _cairo_skia_context_translate (void *abstract_cr,
811                                double tx,
812                                double ty)
813 {
814     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
815
816     cairo_matrix_translate (&cr->matrix, tx, ty);
817     return CAIRO_STATUS_SUCCESS;
818 }
819
820 static cairo_status_t
821 _cairo_skia_context_scale (void *abstract_cr,
822                            double sx,
823                               double sy)
824 {
825     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
826
827     cairo_matrix_scale (&cr->matrix, sx, sy);
828     return CAIRO_STATUS_SUCCESS;
829 }
830
831 static cairo_status_t
832 _cairo_skia_context_rotate (void *abstract_cr,
833                             double theta)
834 {
835     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
836
837     cairo_matrix_rotate (&cr->matrix, theta);
838     return CAIRO_STATUS_SUCCESS;
839 }
840
841 static cairo_status_t
842 _cairo_skia_context_transform (void *abstract_cr,
843                                const cairo_matrix_t *matrix)
844 {
845     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
846
847     cairo_matrix_multiply (&cr->matrix, &cr->matrix, matrix);
848     return CAIRO_STATUS_SUCCESS;
849 }
850
851 static cairo_status_t
852 _cairo_skia_context_set_matrix (void *abstract_cr,
853                                 const cairo_matrix_t *matrix)
854 {
855     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
856
857     cr->matrix = *matrix;
858     return CAIRO_STATUS_SUCCESS;
859 }
860
861 static cairo_status_t
862 _cairo_skia_context_set_identity_matrix (void *abstract_cr)
863 {
864     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
865
866     cairo_matrix_init_identity (&cr->matrix);
867     return CAIRO_STATUS_SUCCESS;
868 }
869
870 static void
871 _cairo_skia_context_get_matrix (void *abstract_cr,
872                                 cairo_matrix_t *matrix)
873 {
874     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
875
876     *matrix = cr->matrix;
877 }
878
879 static void
880 _cairo_skia_context_user_to_device (void *abstract_cr,
881                                     double *x,
882                                     double *y)
883 {
884     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
885
886     cairo_matrix_transform_point (&cr->matrix, x, y);
887 }
888
889 static void
890 _cairo_skia_context_user_to_device_distance (void *abstract_cr,
891                                              double *dx,
892                                              double *dy)
893 {
894     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
895
896     cairo_matrix_transform_distance (&cr->matrix, dx, dy);
897 }
898
899 static void
900 _cairo_skia_context_device_to_user (void *abstract_cr,
901                                     double *x,
902                                     double *y)
903 {
904     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
905     cairo_matrix_t inverse;
906     cairo_status_t status;
907
908     inverse = cr->matrix;
909     status = cairo_matrix_invert (&inverse);
910     assert (CAIRO_STATUS_SUCCESS == status);
911
912     cairo_matrix_transform_point (&inverse, x, y);
913 }
914
915 static void
916 _cairo_skia_context_device_to_user_distance (void *abstract_cr,
917                                              double *dx,
918                                              double *dy)
919 {
920     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
921     cairo_matrix_t inverse;
922     cairo_status_t status;
923
924     inverse = cr->matrix;
925     status = cairo_matrix_invert (&inverse);
926     assert (CAIRO_STATUS_SUCCESS == status);
927
928     cairo_matrix_transform_distance (&inverse, dx, dy);
929 }
930
931 /* Path constructor */
932
933 static cairo_status_t
934 _cairo_skia_context_new_path (void *abstract_cr)
935 {
936     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
937
938     cr->path->reset ();
939     return CAIRO_STATUS_SUCCESS;
940 }
941
942 static cairo_status_t
943 _cairo_skia_context_new_sub_path (void *abstract_cr)
944 {
945     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
946
947     cr->path->rMoveTo (0, 0); /* XXX */
948     return CAIRO_STATUS_SUCCESS;
949 }
950
951 static void
952 user_to_device_point (cairo_skia_context_t *cr, double *x, double *y)
953 {
954     cairo_matrix_transform_point (&cr->matrix, x, y);
955     cairo_matrix_transform_point (&cr->target->image.base.device_transform, x, y);
956 }
957
958 static void
959 user_to_device_distance (cairo_skia_context_t *cr, double *dx, double *dy)
960 {
961     cairo_matrix_transform_distance (&cr->matrix, dx, dy);
962     cairo_matrix_transform_distance (&cr->target->image.base.device_transform, dx, dy);
963 }
964
965 static cairo_status_t
966 _cairo_skia_context_move_to (void *abstract_cr, double x, double y)
967 {
968     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
969
970     user_to_device_point (cr, &x, &y);
971     cr->path->moveTo (SkFloatToScalar (x), SkFloatToScalar (y));
972     return CAIRO_STATUS_SUCCESS;
973 }
974
975 static cairo_status_t
976 _cairo_skia_context_line_to (void *abstract_cr, double x, double y)
977 {
978     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
979
980     user_to_device_point (cr, &x, &y);
981     cr->path->lineTo (SkFloatToScalar (x), SkFloatToScalar (y));
982     return CAIRO_STATUS_SUCCESS;
983 }
984
985 static cairo_status_t
986 _cairo_skia_context_curve_to (void *abstract_cr,
987                               double x1, double y1,
988                               double x2, double y2,
989                               double x3, double y3)
990 {
991     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
992
993     user_to_device_point (cr, &x1, &y1);
994     user_to_device_point (cr, &x2, &y2);
995     user_to_device_point (cr, &x3, &y3);
996     cr->path->cubicTo (SkFloatToScalar (x1), SkFloatToScalar (y1),
997                        SkFloatToScalar (x2), SkFloatToScalar (y2),
998                        SkFloatToScalar (x3), SkFloatToScalar (y3));
999     return CAIRO_STATUS_SUCCESS;
1000 }
1001
1002 static cairo_status_t
1003 _cairo_skia_context_arc_to (void *abstract_cr,
1004                             double x1, double y1,
1005                             double x2, double y2,
1006                             double radius)
1007 {
1008     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1009
1010 #if 0
1011     user_to_device_point (cr, &x1, &y1);
1012     user_to_device_point (cr, &x2, &y2);
1013     user_to_device_distance (cr, &radius, &radius);
1014 #endif
1015
1016     cr->path->arcTo (SkFloatToScalar (x1), SkFloatToScalar (y1),
1017                      SkFloatToScalar (x2), SkFloatToScalar (y2),
1018                      SkFloatToScalar (radius));
1019     return CAIRO_STATUS_SUCCESS;
1020 }
1021
1022 static cairo_status_t
1023 _cairo_skia_context_rel_move_to (void *abstract_cr, double dx, double dy)
1024 {
1025     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1026
1027     user_to_device_distance (cr, &dx, &dy);
1028     cr->path->rMoveTo (SkFloatToScalar (dx), SkFloatToScalar (dy));
1029     return CAIRO_STATUS_SUCCESS;
1030 }
1031
1032 static cairo_status_t
1033 _cairo_skia_context_rel_line_to (void *abstract_cr, double dx, double dy)
1034 {
1035     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1036
1037     user_to_device_distance (cr, &dx, &dy);
1038     cr->path->rLineTo (SkFloatToScalar (dx), SkFloatToScalar (dy));
1039     return CAIRO_STATUS_SUCCESS;
1040 }
1041
1042 static cairo_status_t
1043 _cairo_skia_context_rel_curve_to (void *abstract_cr,
1044                                   double dx1, double dy1,
1045                                   double dx2, double dy2,
1046                                   double dx3, double dy3)
1047 {
1048     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1049
1050     user_to_device_distance (cr, &dx1, &dy1);
1051     user_to_device_distance (cr, &dx2, &dy2);
1052     user_to_device_distance (cr, &dx3, &dy3);
1053     cr->path->rCubicTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1),
1054                         SkFloatToScalar (dx2), SkFloatToScalar (dy2),
1055                         SkFloatToScalar (dx3), SkFloatToScalar (dy3));
1056     return CAIRO_STATUS_SUCCESS;
1057 }
1058
1059 static cairo_status_t
1060 _cairo_skia_context_rel_arc_to (void *abstract_cr,
1061                                 double dx1, double dy1,
1062                                 double dx2, double dy2,
1063                                 double radius)
1064 {
1065     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1066
1067 #if 0
1068     user_to_device_point (cr, &x1, &y1);
1069     user_to_device_point (cr, &x2, &y2);
1070     user_to_device_distance (cr, &radius, &radius);
1071 #endif
1072
1073     cr->path->arcTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1),
1074                      SkFloatToScalar (dx2), SkFloatToScalar (dy2),
1075                      SkFloatToScalar (radius));
1076     return CAIRO_STATUS_SUCCESS;
1077 }
1078
1079 static cairo_status_t
1080 _cairo_skia_context_close_path (void *abstract_cr)
1081 {
1082     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1083
1084     cr->path->close ();
1085     return CAIRO_STATUS_SUCCESS;
1086 }
1087
1088 static cairo_status_t
1089 _cairo_skia_context_rectangle (void *abstract_cr,
1090                                double x, double y,
1091                                double width, double height)
1092 {
1093     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1094     double x1, y1, x2, y2;
1095
1096     /* XXX assume no rotation! */
1097     x1 = x, y1 = y;
1098     user_to_device_point (cr, &x1, &y1);
1099
1100     x2 = x + width, y2 = y + height;
1101     user_to_device_point (cr, &x2, &y2);
1102
1103     cr->path->addRect (SkFloatToScalar (x1), SkFloatToScalar (y1),
1104                        SkFloatToScalar (x2), SkFloatToScalar (y2));
1105     return CAIRO_STATUS_SUCCESS;
1106 }
1107
1108 static cairo_status_t
1109 _cairo_skia_context_arc (void *abstract_cr,
1110                          double xc, double yc, double radius,
1111                          double angle1, double angle2,
1112                          cairo_bool_t forward)
1113 {
1114     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1115     cairo_status_t status;
1116
1117     /* XXX cr->path->arc() */
1118
1119     /* Do nothing, successfully, if radius is <= 0 */
1120     if (radius <= 0.0) {
1121         status = _cairo_skia_context_line_to (cr, xc, yc);
1122         if (unlikely (status))
1123             return status;
1124
1125         status = _cairo_skia_context_line_to (cr, xc, yc);
1126         if (unlikely (status))
1127             return status;
1128
1129         return CAIRO_STATUS_SUCCESS;
1130     }
1131
1132     status = _cairo_skia_context_line_to (cr,
1133                                           xc + radius * cos (angle1),
1134                                           yc + radius * sin (angle1));
1135
1136     if (unlikely (status))
1137         return status;
1138
1139     if (forward)
1140         _cairo_arc_path (&cr->base, xc, yc, radius, angle1, angle2);
1141     else
1142         _cairo_arc_path_negative (&cr->base, xc, yc, radius, angle1, angle2);
1143
1144     return CAIRO_STATUS_SUCCESS;
1145 }
1146
1147 static void
1148 _cairo_skia_context_path_extents (void *abstract_cr,
1149                                   double *x1,
1150                                   double *y1,
1151                                   double *x2,
1152                                   double *y2)
1153 {
1154     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1155     SkRect rect;
1156
1157     rect = cr->path->getBounds ();
1158
1159     UNSUPPORTED;
1160     /* XXX transform SkScalar rect to user */
1161 }
1162
1163 static cairo_bool_t
1164 _cairo_skia_context_has_current_point (void *abstract_cr)
1165 {
1166     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1167
1168     return TRUE;
1169 }
1170
1171 static cairo_bool_t
1172 _cairo_skia_context_get_current_point (void *abstract_cr,
1173                                        double *x,
1174                                        double *y)
1175 {
1176     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1177     SkPoint pt;
1178
1179     cr->path->getLastPt (&pt);
1180     //*x = SkScalarToFloat (pt.x);
1181     //*y = SkScalarToFloat (pt.y);
1182     //_cairo_gstate_backend_to_user (cr->gstate, x, y);
1183
1184     return TRUE;
1185 }
1186
1187 static cairo_path_t *
1188 _cairo_skia_context_copy_path (void *abstract_cr)
1189 {
1190     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1191
1192     /* XXX iterate */
1193     UNSUPPORTED;
1194     return NULL;
1195 }
1196
1197 static cairo_path_t *
1198 _cairo_skia_context_copy_path_flat (void *abstract_cr)
1199 {
1200     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1201
1202     /* XXX iterate and decompose */
1203     UNSUPPORTED;
1204     return NULL;
1205 }
1206
1207 static cairo_status_t
1208 _cairo_skia_context_append_path (void *abstract_cr,
1209                                  const cairo_path_t *path)
1210 {
1211     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1212
1213    // return _cairo_path_append_to_context (path, cr);
1214     return CAIRO_STATUS_SUCCESS;
1215 }
1216
1217 static cairo_status_t
1218 _cairo_skia_stroke_to_path (void *abstract_cr)
1219 {
1220     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1221
1222     cr->paint->setStyle (SkPaint::kStroke_Style);
1223     cr->paint->getFillPath (*cr->path, cr->path);
1224     return CAIRO_STATUS_SUCCESS;
1225 }
1226
1227
1228 static cairo_status_t
1229 _cairo_skia_context_paint (void *abstract_cr)
1230 {
1231     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1232
1233 #if 0
1234     if (cr->source != NULL) {
1235         SkBitmap bitmap;
1236         SkMatrix bitmapMatrix;
1237
1238         if (cr->source->type == CAIRO_SURFACE_TYPE_SKIA) {
1239             cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) cr->source->type;
1240
1241             bitmap = *esurf->bitmap;
1242         } else {
1243             surface_to_sk_bitmap (&cr->source_image->base, bitmap);
1244         }
1245
1246         // XXX pattern->matrix, pattern->filter, pattern->extend
1247         cr->canvas->drawBitmapMatrix (bitmap, bitmapMatrix, cr->paint);
1248     } else {
1249         cr->canvas->drawPaint (*cr->paint);
1250     }
1251 #else
1252     cr->canvas->drawPaint (*cr->paint);
1253 #endif
1254     return CAIRO_STATUS_SUCCESS;
1255 }
1256
1257 static cairo_status_t
1258 _cairo_skia_context_paint_with_alpha (void *abstract_cr,
1259                                       double alpha)
1260 {
1261     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1262     cairo_status_t status;
1263
1264     if (CAIRO_ALPHA_IS_OPAQUE (alpha))
1265         return _cairo_skia_context_paint (cr);
1266
1267     cr->paint->setAlpha(SkScalarRound(255*alpha));
1268     status = _cairo_skia_context_paint (cr);
1269     cr->paint->setAlpha(255);
1270
1271     return status;
1272 }
1273
1274 static cairo_status_t
1275 _cairo_skia_context_mask (void *abstract_cr,
1276                           cairo_pattern_t *mask)
1277 {
1278     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1279
1280     /* XXX */
1281     //UNSUPPORTED;
1282     return CAIRO_STATUS_SUCCESS;
1283 }
1284
1285 static cairo_status_t
1286 _cairo_skia_context_stroke_preserve (void *abstract_cr)
1287 {
1288     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1289
1290     cr->paint->setStyle (SkPaint::kStroke_Style);
1291
1292     /* XXX pen transformation? */
1293     //assert (_cairo_matrix_is_identity (&cr->matrix));
1294     cr->canvas->drawPath (*cr->path, *cr->paint);
1295     return CAIRO_STATUS_SUCCESS;
1296 }
1297
1298 static cairo_status_t
1299 _cairo_skia_context_stroke (void *abstract_cr)
1300 {
1301     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1302     cairo_status_t status;
1303
1304     status = _cairo_skia_context_stroke_preserve (cr);
1305     if (unlikely (status))
1306         return status;
1307
1308     return _cairo_skia_context_new_path (cr);
1309 }
1310
1311 static cairo_status_t
1312 _cairo_skia_context_in_stroke (void *abstract_cr,
1313                                double x, double y,
1314                                cairo_bool_t *inside)
1315 {
1316     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1317
1318     UNSUPPORTED;
1319     return CAIRO_STATUS_SUCCESS;
1320 }
1321
1322 static cairo_status_t
1323 _cairo_skia_context_stroke_extents (void *abstract_cr,
1324                                     double *x1, double *y1, double *x2, double *y2)
1325 {
1326     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1327
1328     UNSUPPORTED;
1329     return CAIRO_STATUS_SUCCESS;
1330 }
1331
1332 static cairo_status_t
1333 _cairo_skia_context_fill_preserve (void *abstract_cr)
1334 {
1335     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1336
1337     cr->paint->setStyle (SkPaint::kFill_Style);
1338     cr->canvas->drawPath (*cr->path, *cr->paint);
1339     return CAIRO_STATUS_SUCCESS;
1340 }
1341
1342 static cairo_status_t
1343 _cairo_skia_context_fill (void *abstract_cr)
1344 {
1345     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1346     cairo_status_t status;
1347
1348     status = _cairo_skia_context_fill_preserve (cr);
1349     if (unlikely (status))
1350         return status;
1351
1352     return _cairo_skia_context_new_path (cr);
1353 }
1354
1355 static cairo_status_t
1356 _cairo_skia_context_in_fill (void *abstract_cr,
1357                                 double x, double y,
1358                                 cairo_bool_t *inside)
1359 {
1360     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1361
1362     UNSUPPORTED;
1363     return CAIRO_STATUS_SUCCESS;
1364 }
1365
1366 static cairo_status_t
1367 _cairo_skia_context_fill_extents (void *abstract_cr,
1368                                      double *x1, double *y1, double *x2, double *y2)
1369 {
1370     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1371
1372     UNSUPPORTED;
1373     return CAIRO_STATUS_SUCCESS;
1374 }
1375
1376 static cairo_status_t
1377 _cairo_skia_context_clip_preserve (void *abstract_cr)
1378 {
1379     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1380
1381     cr->canvas->clipPath (*cr->path);
1382     return CAIRO_STATUS_SUCCESS;
1383 }
1384
1385 static cairo_status_t
1386 _cairo_skia_context_clip (void *abstract_cr)
1387 {
1388     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1389     cairo_status_t status;
1390
1391     status = _cairo_skia_context_clip_preserve (cr);
1392     if (unlikely (status))
1393         return status;
1394
1395     return _cairo_skia_context_new_path (cr);
1396 }
1397
1398 static cairo_status_t
1399 _cairo_skia_context_in_clip (void *abstract_cr,
1400                              double x, double y,
1401                              cairo_bool_t *inside)
1402 {
1403     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1404
1405     return CAIRO_STATUS_SUCCESS;
1406 }
1407
1408 static cairo_status_t
1409 _cairo_skia_context_reset_clip (void *abstract_cr)
1410 {
1411     cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1412     SkRegion rgn(SkIRect::MakeWH (cr->target->bitmap->width (),
1413                                   cr->target->bitmap->height ()));
1414
1415     cr->canvas->setClipRegion(rgn);
1416     return CAIRO_STATUS_SUCCESS;
1417 }
1418
1419 static cairo_status_t
1420 _cairo_skia_context_clip_extents (void *abstract_cr,
1421                                   double *x1, double *y1,
1422                                   double *x2, double *y2)
1423 {
1424     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1425
1426     UNSUPPORTED;
1427     return CAIRO_STATUS_SUCCESS;
1428 }
1429
1430 static cairo_rectangle_list_t *
1431 _cairo_skia_context_copy_clip_rectangle_list (void *abstract_cr)
1432 {
1433     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1434
1435     UNSUPPORTED;
1436     return NULL;
1437 }
1438
1439 static cairo_status_t
1440 _cairo_skia_context_copy_page (void *abstract_cr)
1441 {
1442     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1443
1444     UNSUPPORTED;
1445     return CAIRO_STATUS_SUCCESS;
1446 }
1447
1448 static cairo_status_t
1449 _cairo_skia_context_show_page (void *abstract_cr)
1450 {
1451     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1452     UNSUPPORTED;
1453     return CAIRO_STATUS_SUCCESS;
1454 }
1455
1456 static cairo_status_t
1457 _cairo_skia_context_set_font_face (void *abstract_cr,
1458                                    cairo_font_face_t *font_face)
1459 {
1460    // cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1461
1462     //return _cairo_gstate_set_font_face (cr->gstate, font_face);
1463     return CAIRO_STATUS_SUCCESS;
1464 }
1465
1466 static cairo_font_face_t *
1467 _cairo_skia_context_get_font_face (void *abstract_cr)
1468 {
1469     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1470
1471     UNSUPPORTED;
1472     return NULL;
1473 }
1474
1475 static cairo_status_t
1476 _cairo_skia_context_font_extents (void *abstract_cr,
1477                                   cairo_font_extents_t *extents)
1478 {
1479     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1480
1481     UNSUPPORTED;
1482     return CAIRO_STATUS_SUCCESS;
1483 }
1484
1485 static cairo_status_t
1486 _cairo_skia_context_set_font_size (void *abstract_cr,
1487                                    double size)
1488 {
1489     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1490
1491     UNSUPPORTED;
1492     return CAIRO_STATUS_SUCCESS;
1493 }
1494
1495 static cairo_status_t
1496 _cairo_skia_context_set_font_matrix (void *abstract_cr,
1497                                      const cairo_matrix_t *matrix)
1498 {
1499     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1500
1501     UNSUPPORTED;
1502     return CAIRO_STATUS_SUCCESS;
1503 }
1504
1505 static void
1506 _cairo_skia_context_get_font_matrix (void *abstract_cr,
1507                                      cairo_matrix_t *matrix)
1508 {
1509     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1510
1511     UNSUPPORTED;
1512 }
1513
1514 static cairo_status_t
1515 _cairo_skia_context_set_font_options (void *abstract_cr,
1516                                       const cairo_font_options_t *options)
1517 {
1518     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1519
1520     UNSUPPORTED;
1521     return CAIRO_STATUS_SUCCESS;
1522 }
1523
1524 static void
1525 _cairo_skia_context_get_font_options (void *abstract_cr,
1526                                       cairo_font_options_t *options)
1527 {
1528     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1529
1530     UNSUPPORTED;
1531 }
1532
1533 static cairo_status_t
1534 _cairo_skia_context_set_scaled_font (void *abstract_cr,
1535                                         cairo_scaled_font_t *scaled_font)
1536 {
1537     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1538
1539     UNSUPPORTED;
1540     return CAIRO_STATUS_SUCCESS;
1541 }
1542
1543 static cairo_scaled_font_t *
1544 _cairo_skia_context_get_scaled_font (void *abstract_cr)
1545 {
1546     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1547
1548     UNSUPPORTED;
1549     return _cairo_scaled_font_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);
1550 }
1551
1552 static cairo_status_t
1553 _cairo_skia_context_glyphs (void *abstract_cr,
1554                             const cairo_glyph_t *glyphs,
1555                             int num_glyphs,
1556                             cairo_glyph_text_info_t *info)
1557 {
1558     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1559
1560     /* XXX */
1561     //UNSUPPORTED;
1562     return CAIRO_STATUS_SUCCESS;
1563 }
1564
1565 static cairo_status_t
1566 _cairo_skia_context_glyph_path (void *abstract_cr,
1567                                 const cairo_glyph_t *glyphs,
1568                                 int num_glyphs)
1569 {
1570     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1571
1572     UNSUPPORTED;
1573     return CAIRO_STATUS_SUCCESS;
1574 }
1575
1576 static cairo_status_t
1577 _cairo_skia_context_glyph_extents (void                *abstract_cr,
1578                                    const cairo_glyph_t    *glyphs,
1579                                    int                    num_glyphs,
1580                                    cairo_text_extents_t   *extents)
1581 {
1582     //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr;
1583
1584     UNSUPPORTED;
1585     return CAIRO_STATUS_SUCCESS;
1586 }
1587
1588 static const cairo_backend_t _cairo_skia_context_backend = {
1589     CAIRO_TYPE_SKIA,
1590     _cairo_skia_context_destroy,
1591
1592     _cairo_skia_context_get_original_target,
1593     _cairo_skia_context_get_current_target,
1594
1595     _cairo_skia_context_save,
1596     _cairo_skia_context_restore,
1597
1598     _cairo_skia_context_push_group,
1599     _cairo_skia_context_pop_group,
1600
1601     _cairo_skia_context_set_source_rgba,
1602     _cairo_skia_context_set_source_surface,
1603     _cairo_skia_context_set_source,
1604     _cairo_skia_context_get_source,
1605
1606     _cairo_skia_context_set_antialias,
1607     _cairo_skia_context_set_dash,
1608     _cairo_skia_context_set_fill_rule,
1609     _cairo_skia_context_set_line_cap,
1610     _cairo_skia_context_set_line_join,
1611     _cairo_skia_context_set_line_width,
1612     _cairo_skia_context_set_miter_limit,
1613     _cairo_skia_context_set_opacity,
1614     _cairo_skia_context_set_operator,
1615     _cairo_skia_context_set_tolerance,
1616     _cairo_skia_context_get_antialias,
1617     _cairo_skia_context_get_dash,
1618     _cairo_skia_context_get_fill_rule,
1619     _cairo_skia_context_get_line_cap,
1620     _cairo_skia_context_get_line_join,
1621     _cairo_skia_context_get_line_width,
1622     _cairo_skia_context_get_miter_limit,
1623     _cairo_skia_context_get_opacity,
1624     _cairo_skia_context_get_operator,
1625     _cairo_skia_context_get_tolerance,
1626
1627     _cairo_skia_context_translate,
1628     _cairo_skia_context_scale,
1629     _cairo_skia_context_rotate,
1630     _cairo_skia_context_transform,
1631     _cairo_skia_context_set_matrix,
1632     _cairo_skia_context_set_identity_matrix,
1633     _cairo_skia_context_get_matrix,
1634     _cairo_skia_context_user_to_device,
1635     _cairo_skia_context_user_to_device_distance,
1636     _cairo_skia_context_device_to_user,
1637     _cairo_skia_context_device_to_user_distance,
1638
1639     _cairo_skia_context_new_path,
1640     _cairo_skia_context_new_sub_path,
1641     _cairo_skia_context_move_to,
1642     _cairo_skia_context_rel_move_to,
1643     _cairo_skia_context_line_to,
1644     _cairo_skia_context_rel_line_to,
1645     _cairo_skia_context_curve_to,
1646     _cairo_skia_context_rel_curve_to,
1647     _cairo_skia_context_arc_to,
1648     _cairo_skia_context_rel_arc_to,
1649     _cairo_skia_context_close_path,
1650     _cairo_skia_context_arc,
1651     _cairo_skia_context_rectangle,
1652     _cairo_skia_context_path_extents,
1653     _cairo_skia_context_has_current_point,
1654     _cairo_skia_context_get_current_point,
1655     _cairo_skia_context_copy_path,
1656     _cairo_skia_context_copy_path_flat,
1657     _cairo_skia_context_append_path,
1658
1659     _cairo_skia_stroke_to_path,
1660
1661     _cairo_skia_context_clip,
1662     _cairo_skia_context_clip_preserve,
1663     _cairo_skia_context_in_clip,
1664     _cairo_skia_context_clip_extents,
1665     _cairo_skia_context_reset_clip,
1666     _cairo_skia_context_copy_clip_rectangle_list,
1667
1668     _cairo_skia_context_paint,
1669     _cairo_skia_context_paint_with_alpha,
1670     _cairo_skia_context_mask,
1671
1672     _cairo_skia_context_stroke,
1673     _cairo_skia_context_stroke_preserve,
1674     _cairo_skia_context_in_stroke,
1675     _cairo_skia_context_stroke_extents,
1676
1677     _cairo_skia_context_fill,
1678     _cairo_skia_context_fill_preserve,
1679     _cairo_skia_context_in_fill,
1680     _cairo_skia_context_fill_extents,
1681
1682     _cairo_skia_context_set_font_face,
1683     _cairo_skia_context_get_font_face,
1684     _cairo_skia_context_set_font_size,
1685     _cairo_skia_context_set_font_matrix,
1686     _cairo_skia_context_get_font_matrix,
1687     _cairo_skia_context_set_font_options,
1688     _cairo_skia_context_get_font_options,
1689     _cairo_skia_context_set_scaled_font,
1690     _cairo_skia_context_get_scaled_font,
1691     _cairo_skia_context_font_extents,
1692
1693     _cairo_skia_context_glyphs,
1694     _cairo_skia_context_glyph_path,
1695     _cairo_skia_context_glyph_extents,
1696
1697     _cairo_skia_context_copy_page,
1698     _cairo_skia_context_show_page,
1699 };
1700
1701 cairo_t *
1702 _cairo_skia_context_create (void *target)
1703 {
1704     cairo_skia_surface_t *surface = (cairo_skia_surface_t *) target;
1705     cairo_skia_context_t *cr;
1706
1707     cr = (cairo_skia_context_t *) _freed_pool_get (&context_pool);
1708     if (unlikely (cr == NULL)) {
1709             cr = new cairo_skia_context_t;
1710             if (unlikely (cr == NULL))
1711                 return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
1712
1713             cr->path = new SkPath;
1714             cr->paint = new SkPaint;
1715     }
1716
1717     _cairo_init (&cr->base, &_cairo_skia_context_backend);
1718
1719     cr->source = NULL;
1720     cr->source_image = NULL;
1721
1722     cr->paint->setStrokeWidth (SkFloatToScalar (2.0));
1723
1724     cr->target = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target);
1725     cr->original = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target);
1726     cr->canvas = new SkCanvas (*surface->bitmap);
1727     cr->canvas->save ();
1728
1729     cairo_matrix_init_identity (&cr->matrix);
1730
1731     return &cr->base;
1732 }
1733
1734 #if 0
1735 void
1736 _cairo_skia_context_set_SkPaint (cairo_t *cr, SkPaint paint)
1737 {
1738     *cr->paint = paint;
1739 }
1740
1741 void
1742 _cairo_skia_context_set_SkPath (cairo_t *cr, SkPath path)
1743 {
1744     *cr->path = path;
1745 }
1746 #endif