/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ /* cairo - a vector graphics library with display and print output * * Copyright © 2002 University of Southern California * Copyright © 2005 Red Hat, Inc. * Copyright © 2010 Intel Corporation * * This library is free software; you can redistribute it and/or * modify it either under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation * (the "LGPL") or, at your option, under the terms of the Mozilla * Public License Version 1.1 (the "MPL"). If you do not alter this * notice, a recipient may use your version of this file under either * the MPL or the LGPL. * * You should have received a copy of the LGPL along with this library * in the file COPYING-LGPL-2.1; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * You should have received a copy of the MPL along with this library * in the file COPYING-MPL-1.1 * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in * compliance with the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY * OF ANY KIND, either express or implied. See the LGPL or the MPL for * the specific language governing rights and limitations. * * The Original Code is the cairo graphics library. * * The Initial Developer of the Original Code is University of Southern * California. * * Contributor(s): * Carl D. Worth * Chris Wilson */ #include "cairoint.h" #include "cairo-private.h" #include "cairo-error-private.h" #include "cairo-arc-private.h" #include "cairo-backend-private.h" #include "cairo-default-context-private.h" #include "cairo-freed-pool-private.h" #include "cairo-gstate-private.h" #include "cairo-image-surface-inline.h" #include "cairo-path-private.h" #include "cairo-pattern-private.h" #include "cairo-skia-private.h" #include "cairo-surface-backend-private.h" #include #include #include #include #if !defined(INFINITY) #define INFINITY HUGE_VAL #endif #if (CAIRO_FIXED_BITS == 32) && (CAIRO_FIXED_FRAC_BITS == 16) && defined(SK_SCALAR_IS_FIXED) # define CAIRO_FIXED_TO_SK_SCALAR(x) (x) #elif defined(SK_SCALAR_IS_FIXED) /* This can be done better, but this will do for now */ # define CAIRO_FIXED_TO_SK_SCALAR(x) SkFloatToScalar(_cairo_fixed_to_double(x)) #else # define CAIRO_FIXED_TO_SK_SCALAR(x) SkFloatToScalar(_cairo_fixed_to_double(x)) #endif #define UNSUPPORTED static freed_pool_t context_pool; static void _cairo_skia_context_destroy (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->path->reset (); cr->paint->reset (); delete cr->canvas; cairo_surface_destroy (&cr->target->image.base); cairo_surface_destroy (&cr->original->image.base); if (cr->source != NULL) { if (cr->source_image != NULL) { _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra); cr->source_image = NULL; } cairo_surface_destroy (cr->source); cr->source = NULL; } _cairo_fini (&cr->base); _freed_pool_put (&context_pool, cr); } static cairo_surface_t * _cairo_skia_context_get_original_target (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return &cr->original->image.base; } static cairo_surface_t * _cairo_skia_context_get_current_target (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return &cr->target->image.base; } static cairo_status_t _cairo_skia_context_save (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->canvas->save (); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_restore (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->canvas->restore (); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_push_group (void *abstract_cr, cairo_content_t content) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_surface_t *group_surface; cairo_status_t status; int width, height; //clip = _cairo_gstate_get_clip (cr->gstate); width = cr->target->image.width; height = cr->target->image.height; group_surface = cr->target->image.base.backend->create_similar (&cr->target->image.base, content, width, height); #if 0 /* Set device offsets on the new surface so that logically it appears at * the same location on the parent surface -- when we pop_group this, * the source pattern will get fixed up for the appropriate target surface * device offsets, so we want to set our own surface offsets from /that/, * and not from the device origin. */ cairo_surface_set_device_offset (group_surface, parent_surface->device_transform.x0 - extents.x, parent_surface->device_transform.y0 - extents.y); /* If we have a current path, we need to adjust it to compensate for * the device offset just applied. */ _cairo_path_fixed_transform (cr->path, &group_surface->device_transform); #endif status = _cairo_skia_context_save (cr); if (unlikely (status)) { cairo_surface_destroy (group_surface); return status; } cairo_surface_destroy (&cr->target->image.base); cr->target = (cairo_skia_surface_t *) group_surface; return CAIRO_STATUS_SUCCESS; } static cairo_pattern_t * _cairo_skia_context_pop_group (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_surface_t *group_surface; cairo_pattern_t *group_pattern; cairo_status_t status; group_surface = cairo_surface_reference (&cr->target->image.base); status = _cairo_skia_context_restore (cr); if (unlikely (status)) { group_pattern = _cairo_pattern_create_in_error (status); goto done; } group_pattern = cairo_pattern_create_for_surface (group_surface); status = group_pattern->status; if (unlikely (status)) goto done; #if 0 _cairo_gstate_get_matrix (cr->gstate, &group_matrix); /* Transform by group_matrix centered around device_transform so that when * we call _cairo_gstate_copy_transformed_pattern the result is a pattern * with a matrix equivalent to the device_transform of group_surface. */ if (_cairo_surface_has_device_transform (group_surface)) { cairo_pattern_set_matrix (group_pattern, &group_surface->device_transform); _cairo_pattern_transform (group_pattern, &group_matrix); _cairo_pattern_transform (group_pattern, &group_surface->device_transform_inverse); } else { cairo_pattern_set_matrix (group_pattern, &group_matrix); } /* If we have a current path, we need to adjust it to compensate for * the device offset just removed. */ _cairo_path_fixed_transform (cr->path, &group_surface->device_transform_inverse); #endif done: cairo_surface_destroy (group_surface); return group_pattern; } static inline cairo_surface_t * surface_from_pattern (const cairo_pattern_t *pattern) { return (reinterpret_cast (pattern))->surface; } static inline bool surface_to_sk_bitmap (cairo_surface_t *surface, SkBitmap& bitmap) { cairo_image_surface_t *img = (cairo_image_surface_t *) surface; SkBitmap::Config config; bool opaque; if (unlikely (! format_to_sk_config (img->format, config, opaque))) return false; bitmap.reset (); bitmap.setConfig (config, img->width, img->height, img->stride); bitmap.setIsOpaque (opaque); bitmap.setPixels (img->data); return true; } static inline SkMatrix matrix_to_sk (const cairo_matrix_t& mat) { SkMatrix skm; skm.reset (); skm.set (SkMatrix::kMScaleX, SkFloatToScalar (mat.xx)); skm.set (SkMatrix::kMSkewX, SkFloatToScalar (mat.xy)); skm.set (SkMatrix::kMTransX, SkFloatToScalar (mat.x0)); skm.set (SkMatrix::kMSkewY, SkFloatToScalar (mat.yx)); skm.set (SkMatrix::kMScaleY, SkFloatToScalar (mat.yy)); skm.set (SkMatrix::kMTransY, SkFloatToScalar (mat.y0)); /* skm[6] = SkFloatToScalar (0.0); skm[7] = SkFloatToScalar (0.0); 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 */ return skm; } static inline SkMatrix matrix_inverse_to_sk (const cairo_matrix_t& mat) { cairo_matrix_t inv = mat; cairo_status_t status = cairo_matrix_invert (&inv); assert (status == CAIRO_STATUS_SUCCESS); return matrix_to_sk (inv); } static SkShader::TileMode extend_to_sk (cairo_extend_t extend) { static const SkShader::TileMode modeMap[] = { SkShader::kClamp_TileMode, // NONE behaves like PAD, because noone wants NONE SkShader::kRepeat_TileMode, SkShader::kMirror_TileMode, SkShader::kClamp_TileMode }; return modeMap[extend]; } static inline SkColor color_to_sk (const cairo_color_t& c) { /* Need unpremultiplied 1-byte values */ return SkColorSetARGB ((U8CPU) (c.alpha * 255), (U8CPU) (c.red * 255), (U8CPU) (c.green * 255), (U8CPU) (c.blue * 255)); } static inline SkColor color_stop_to_sk (const cairo_color_stop_t& c) { /* Need unpremultiplied 1-byte values */ return SkColorSetARGB ((U8CPU) (c.alpha * 255), (U8CPU) (c.red * 255), (U8CPU) (c.green * 255), (U8CPU) (c.blue * 255)); } static SkShader* source_to_sk_shader (cairo_skia_context_t *cr, const cairo_pattern_t *pattern) { SkShader *shader = NULL; if (pattern->type == CAIRO_PATTERN_TYPE_SOLID) { cairo_solid_pattern_t *solid = (cairo_solid_pattern_t *) pattern; return new SkColorShader (color_to_sk (solid->color)); } else if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) { cairo_surface_t *surface = surface_from_pattern (pattern); cr->source = cairo_surface_reference (surface); if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; shader = SkShader::CreateBitmapShader (*esurf->bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } else { SkBitmap bitmap; if (! _cairo_surface_is_image (surface)) { cairo_status_t status; status = _cairo_surface_acquire_source_image (surface, &cr->source_image, &cr->source_extra); if (status) return NULL; surface = &cr->source_image->base; } if (unlikely (! surface_to_sk_bitmap (surface, bitmap))) return NULL; shader = SkShader::CreateBitmapShader (bitmap, extend_to_sk (pattern->extend), extend_to_sk (pattern->extend)); } } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */) { cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; SkColor colors_stack[10]; SkScalar pos_stack[10]; SkColor *colors = colors_stack; SkScalar *pos = pos_stack; if (gradient->n_stops > 10) { colors = new SkColor[gradient->n_stops]; pos = new SkScalar[gradient->n_stops]; } for (unsigned int i = 0; i < gradient->n_stops; i++) { pos[i] = CAIRO_FIXED_TO_SK_SCALAR (gradient->stops[i].offset); colors[i] = color_stop_to_sk (gradient->stops[i].color); } if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; SkPoint points[2]; points[0].set (SkFloatToScalar (linear->pd1.x), SkFloatToScalar (linear->pd1.y)); points[1].set (SkFloatToScalar (linear->pd2.x), SkFloatToScalar (linear->pd2.y)); shader = SkGradientShader::CreateLinear (points, colors, pos, gradient->n_stops, extend_to_sk (pattern->extend)); } else { // XXX todo -- implement real radial shaders in Skia } if (gradient->n_stops > 10) { delete [] colors; delete [] pos; } } if (shader && ! _cairo_matrix_is_identity (&pattern->matrix)) shader->setLocalMatrix (matrix_inverse_to_sk (pattern->matrix)); return shader; } static inline bool pattern_filter_to_sk (const cairo_pattern_t *pattern) { switch (pattern->filter) { case CAIRO_FILTER_GOOD: case CAIRO_FILTER_BEST: case CAIRO_FILTER_BILINEAR: case CAIRO_FILTER_GAUSSIAN: return true; default: case CAIRO_FILTER_FAST: case CAIRO_FILTER_NEAREST: return false; } } static inline bool pattern_to_sk_color (const cairo_pattern_t *pattern, SkColor& color) { if (pattern->type != CAIRO_PATTERN_TYPE_SOLID) return false; color = color_to_sk (((cairo_solid_pattern_t *) pattern)->color); return true; } static cairo_status_t _cairo_skia_context_set_source (void *abstract_cr, cairo_pattern_t *source) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkColor color; if (cr->source != NULL) { if (cr->source_image != NULL) { _cairo_surface_release_source_image (cr->source, cr->source_image, cr->source_extra); cr->source_image = NULL; } cairo_surface_destroy (cr->source); cr->source = NULL; } if (pattern_to_sk_color (source, color)) { cr->paint->setColor (color); } else { SkShader *shader = source_to_sk_shader (cr, source); if (shader == NULL) { UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } cr->paint->setShader (shader); shader->unref (); cr->paint->setFilterBitmap (pattern_filter_to_sk (source)); } /* XXX change notification */ return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_source_rgba (void *abstract_cr, double red, double green, double blue, double alpha) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* Need unpremultiplied 1-byte values */ cr->paint->setARGB ((U8CPU) (alpha * 255), (U8CPU) (red * 255), (U8CPU) (green * 255), (U8CPU) (blue * 255)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_source_surface (void *abstract_cr, cairo_surface_t *surface, double x, double y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_pattern_t *pattern; cairo_matrix_t matrix; cairo_status_t status; if (surface->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; SkShader *shader; shader = SkShader::CreateBitmapShader (*esurf->bitmap, SkShader::kClamp_TileMode, /* XXX */ SkShader::kClamp_TileMode); cr->paint->setShader (shader); shader->unref (); cr->paint->setFilterBitmap (true); return CAIRO_STATUS_SUCCESS; } pattern = cairo_pattern_create_for_surface (surface); if (unlikely (pattern->status)) return pattern->status; cairo_matrix_init_translate (&matrix, -x, -y); cairo_pattern_set_matrix (pattern, &matrix); status = _cairo_skia_context_set_source (cr, pattern); cairo_pattern_destroy (pattern); return status; } static cairo_pattern_t * _cairo_skia_context_get_source (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return NULL; } static cairo_status_t _cairo_skia_context_set_tolerance (void *abstract_cr, double tolerance) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX ignored */ return CAIRO_STATUS_SUCCESS; } static inline SkXfermode::Mode operator_to_sk (cairo_operator_t op) { static const SkXfermode::Mode modeMap[] = { SkXfermode::kClear_Mode, SkXfermode::kSrc_Mode, SkXfermode::kSrcOver_Mode, SkXfermode::kSrcIn_Mode, SkXfermode::kSrcOut_Mode, SkXfermode::kSrcATop_Mode, SkXfermode::kDst_Mode, SkXfermode::kDstOver_Mode, SkXfermode::kDstIn_Mode, SkXfermode::kDstOut_Mode, SkXfermode::kDstATop_Mode, SkXfermode::kXor_Mode, SkXfermode::kPlus_Mode, // XXX Add? SkXfermode::kPlus_Mode, // XXX SATURATE SkXfermode::kPlus_Mode, SkXfermode::kMultiply_Mode, SkXfermode::kScreen_Mode, SkXfermode::kOverlay_Mode, SkXfermode::kDarken_Mode, SkXfermode::kLighten_Mode, SkXfermode::kColorDodge_Mode, SkXfermode::kColorBurn_Mode, SkXfermode::kHardLight_Mode, SkXfermode::kSoftLight_Mode, SkXfermode::kDifference_Mode, SkXfermode::kExclusion_Mode, SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_HUE SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_SATURATION, SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_COLOR, SkXfermode::kSrcOver_Mode, // XXX: CAIRO_OPERATOR_HSL_LUMINOSITY }; return modeMap[op]; } static cairo_status_t _cairo_skia_context_set_operator (void *abstract_cr, cairo_operator_t op) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setXfermodeMode (operator_to_sk (op)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_opacity (void *abstract_cr, double opacity) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX */ return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_antialias (void *abstract_cr, cairo_antialias_t antialias) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setAntiAlias (antialias != CAIRO_ANTIALIAS_NONE); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_fill_rule (void *abstract_cr, cairo_fill_rule_t fill_rule) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->path->setFillType (fill_rule == CAIRO_FILL_RULE_WINDING ? SkPath::kWinding_FillType : SkPath::kEvenOdd_FillType); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_line_width (void *abstract_cr, double line_width) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStrokeWidth (SkFloatToScalar (line_width)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_line_cap (void *abstract_cr, cairo_line_cap_t line_cap) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; static const SkPaint::Cap map[] = { SkPaint::kButt_Cap, SkPaint::kRound_Cap, SkPaint::kSquare_Cap }; cr->paint->setStrokeCap (map[line_cap]); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_line_join (void *abstract_cr, cairo_line_join_t line_join) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; static const SkPaint::Join map[] = { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join }; cr->paint->setStrokeJoin (map[line_join]); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_dash (void *abstract_cr, const double *dashes, int num_dashes, double offset) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkScalar intervals_static[20]; SkScalar *intervals = intervals_static; if (num_dashes == 0) { cr->paint->setPathEffect (NULL); return CAIRO_STATUS_SUCCESS; } int loop = 0; if ((num_dashes & 1) != 0) { loop = 1; num_dashes <<= 1; } if (num_dashes > 20) intervals = new SkScalar[num_dashes]; int i = 0; do { for (int j = 0; i < num_dashes; j++) intervals[i++] = SkFloatToScalar (dashes[j]); } while (loop--); SkDashPathEffect *dash = new SkDashPathEffect (intervals, num_dashes, SkFloatToScalar (offset)); cr->paint->setPathEffect (dash); dash->unref (); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_miter_limit (void *abstract_cr, double limit) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStrokeMiter (SkFloatToScalar (limit)); return CAIRO_STATUS_SUCCESS; } static cairo_antialias_t _cairo_skia_context_get_antialias (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return cr->paint->isAntiAlias () ? CAIRO_ANTIALIAS_DEFAULT : CAIRO_ANTIALIAS_NONE; } static void _cairo_skia_context_get_dash (void *abstract_cr, double *dashes, int *num_dashes, double *offset) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; *num_dashes = 0; /* XXX */ } static cairo_fill_rule_t _cairo_skia_context_get_fill_rule (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkPath::FillType ft; ft = cr->path->getFillType (); if (ft == SkPath::kWinding_FillType) return CAIRO_FILL_RULE_WINDING; if (ft == SkPath::kEvenOdd_FillType) return CAIRO_FILL_RULE_EVEN_ODD;; UNSUPPORTED; return CAIRO_FILL_RULE_WINDING; } static double _cairo_skia_context_get_line_width (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return /* ScalarToFloat */ cr->paint->getStrokeWidth (); } static cairo_line_cap_t _cairo_skia_context_get_line_cap (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; static const cairo_line_cap_t map[] = { CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_ROUND, CAIRO_LINE_CAP_SQUARE }; return map[cr->paint->getStrokeCap ()]; } static cairo_line_join_t _cairo_skia_context_get_line_join (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; static const cairo_line_join_t map[] = { CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_ROUND, CAIRO_LINE_JOIN_BEVEL }; return map[cr->paint->getStrokeJoin ()]; } static double _cairo_skia_context_get_miter_limit (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return /* SkScalarToFloat */ cr->paint->getStrokeMiter (); } static cairo_operator_t _cairo_skia_context_get_operator (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; //cr->paint->getXfermode (); return CAIRO_OPERATOR_OVER; } static double _cairo_skia_context_get_opacity (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return 1.; } static double _cairo_skia_context_get_tolerance (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX */ return CAIRO_GSTATE_TOLERANCE_DEFAULT; } /* Current tranformation matrix */ static cairo_status_t _cairo_skia_context_translate (void *abstract_cr, double tx, double ty) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_translate (&cr->matrix, tx, ty); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_scale (void *abstract_cr, double sx, double sy) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_scale (&cr->matrix, sx, sy); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rotate (void *abstract_cr, double theta) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_rotate (&cr->matrix, theta); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_transform (void *abstract_cr, const cairo_matrix_t *matrix) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_multiply (&cr->matrix, &cr->matrix, matrix); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_matrix (void *abstract_cr, const cairo_matrix_t *matrix) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->matrix = *matrix; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_identity_matrix (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_init_identity (&cr->matrix); return CAIRO_STATUS_SUCCESS; } static void _cairo_skia_context_get_matrix (void *abstract_cr, cairo_matrix_t *matrix) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; *matrix = cr->matrix; } static void _cairo_skia_context_user_to_device (void *abstract_cr, double *x, double *y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_transform_point (&cr->matrix, x, y); } static void _cairo_skia_context_user_to_device_distance (void *abstract_cr, double *dx, double *dy) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_transform_distance (&cr->matrix, dx, dy); } static void _cairo_skia_context_device_to_user (void *abstract_cr, double *x, double *y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_t inverse; cairo_status_t status; inverse = cr->matrix; status = cairo_matrix_invert (&inverse); assert (CAIRO_STATUS_SUCCESS == status); cairo_matrix_transform_point (&inverse, x, y); } static void _cairo_skia_context_device_to_user_distance (void *abstract_cr, double *dx, double *dy) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_matrix_t inverse; cairo_status_t status; inverse = cr->matrix; status = cairo_matrix_invert (&inverse); assert (CAIRO_STATUS_SUCCESS == status); cairo_matrix_transform_distance (&inverse, dx, dy); } /* Path constructor */ static cairo_status_t _cairo_skia_context_new_path (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->path->reset (); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_new_sub_path (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->path->rMoveTo (0, 0); /* XXX */ return CAIRO_STATUS_SUCCESS; } static void user_to_device_point (cairo_skia_context_t *cr, double *x, double *y) { cairo_matrix_transform_point (&cr->matrix, x, y); cairo_matrix_transform_point (&cr->target->image.base.device_transform, x, y); } static void user_to_device_distance (cairo_skia_context_t *cr, double *dx, double *dy) { cairo_matrix_transform_distance (&cr->matrix, dx, dy); cairo_matrix_transform_distance (&cr->target->image.base.device_transform, dx, dy); } static cairo_status_t _cairo_skia_context_move_to (void *abstract_cr, double x, double y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_point (cr, &x, &y); cr->path->moveTo (SkFloatToScalar (x), SkFloatToScalar (y)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_line_to (void *abstract_cr, double x, double y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_point (cr, &x, &y); cr->path->lineTo (SkFloatToScalar (x), SkFloatToScalar (y)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_curve_to (void *abstract_cr, double x1, double y1, double x2, double y2, double x3, double y3) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_point (cr, &x1, &y1); user_to_device_point (cr, &x2, &y2); user_to_device_point (cr, &x3, &y3); cr->path->cubicTo (SkFloatToScalar (x1), SkFloatToScalar (y1), SkFloatToScalar (x2), SkFloatToScalar (y2), SkFloatToScalar (x3), SkFloatToScalar (y3)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_arc_to (void *abstract_cr, double x1, double y1, double x2, double y2, double radius) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; #if 0 user_to_device_point (cr, &x1, &y1); user_to_device_point (cr, &x2, &y2); user_to_device_distance (cr, &radius, &radius); #endif cr->path->arcTo (SkFloatToScalar (x1), SkFloatToScalar (y1), SkFloatToScalar (x2), SkFloatToScalar (y2), SkFloatToScalar (radius)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rel_move_to (void *abstract_cr, double dx, double dy) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_distance (cr, &dx, &dy); cr->path->rMoveTo (SkFloatToScalar (dx), SkFloatToScalar (dy)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rel_line_to (void *abstract_cr, double dx, double dy) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_distance (cr, &dx, &dy); cr->path->rLineTo (SkFloatToScalar (dx), SkFloatToScalar (dy)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rel_curve_to (void *abstract_cr, double dx1, double dy1, double dx2, double dy2, double dx3, double dy3) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; user_to_device_distance (cr, &dx1, &dy1); user_to_device_distance (cr, &dx2, &dy2); user_to_device_distance (cr, &dx3, &dy3); cr->path->rCubicTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1), SkFloatToScalar (dx2), SkFloatToScalar (dy2), SkFloatToScalar (dx3), SkFloatToScalar (dy3)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rel_arc_to (void *abstract_cr, double dx1, double dy1, double dx2, double dy2, double radius) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; #if 0 user_to_device_point (cr, &x1, &y1); user_to_device_point (cr, &x2, &y2); user_to_device_distance (cr, &radius, &radius); #endif cr->path->arcTo (SkFloatToScalar (dx1), SkFloatToScalar (dy1), SkFloatToScalar (dx2), SkFloatToScalar (dy2), SkFloatToScalar (radius)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_close_path (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->path->close (); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_rectangle (void *abstract_cr, double x, double y, double width, double height) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; double x1, y1, x2, y2; /* XXX assume no rotation! */ x1 = x, y1 = y; user_to_device_point (cr, &x1, &y1); x2 = x + width, y2 = y + height; user_to_device_point (cr, &x2, &y2); cr->path->addRect (SkFloatToScalar (x1), SkFloatToScalar (y1), SkFloatToScalar (x2), SkFloatToScalar (y2)); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_arc (void *abstract_cr, double xc, double yc, double radius, double angle1, double angle2, cairo_bool_t forward) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_status_t status; /* XXX cr->path->arc() */ /* Do nothing, successfully, if radius is <= 0 */ if (radius <= 0.0) { status = _cairo_skia_context_line_to (cr, xc, yc); if (unlikely (status)) return status; status = _cairo_skia_context_line_to (cr, xc, yc); if (unlikely (status)) return status; return CAIRO_STATUS_SUCCESS; } status = _cairo_skia_context_line_to (cr, xc + radius * cos (angle1), yc + radius * sin (angle1)); if (unlikely (status)) return status; if (forward) _cairo_arc_path (&cr->base, xc, yc, radius, angle1, angle2); else _cairo_arc_path_negative (&cr->base, xc, yc, radius, angle1, angle2); return CAIRO_STATUS_SUCCESS; } static void _cairo_skia_context_path_extents (void *abstract_cr, double *x1, double *y1, double *x2, double *y2) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkRect rect; rect = cr->path->getBounds (); UNSUPPORTED; /* XXX transform SkScalar rect to user */ } static cairo_bool_t _cairo_skia_context_has_current_point (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return TRUE; } static cairo_bool_t _cairo_skia_context_get_current_point (void *abstract_cr, double *x, double *y) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkPoint pt; cr->path->getLastPt (&pt); //*x = SkScalarToFloat (pt.x); //*y = SkScalarToFloat (pt.y); //_cairo_gstate_backend_to_user (cr->gstate, x, y); return TRUE; } static cairo_path_t * _cairo_skia_context_copy_path (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX iterate */ UNSUPPORTED; return NULL; } static cairo_path_t * _cairo_skia_context_copy_path_flat (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX iterate and decompose */ UNSUPPORTED; return NULL; } static cairo_status_t _cairo_skia_context_append_path (void *abstract_cr, const cairo_path_t *path) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; // return _cairo_path_append_to_context (path, cr); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_stroke_to_path (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStyle (SkPaint::kStroke_Style); cr->paint->getFillPath (*cr->path, cr->path); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_paint (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; #if 0 if (cr->source != NULL) { SkBitmap bitmap; SkMatrix bitmapMatrix; if (cr->source->type == CAIRO_SURFACE_TYPE_SKIA) { cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) cr->source->type; bitmap = *esurf->bitmap; } else { surface_to_sk_bitmap (&cr->source_image->base, bitmap); } // XXX pattern->matrix, pattern->filter, pattern->extend cr->canvas->drawBitmapMatrix (bitmap, bitmapMatrix, cr->paint); } else { cr->canvas->drawPaint (*cr->paint); } #else cr->canvas->drawPaint (*cr->paint); #endif return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_paint_with_alpha (void *abstract_cr, double alpha) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_status_t status; if (CAIRO_ALPHA_IS_OPAQUE (alpha)) return _cairo_skia_context_paint (cr); cr->paint->setAlpha(SkScalarRound(255*alpha)); status = _cairo_skia_context_paint (cr); cr->paint->setAlpha(255); return status; } static cairo_status_t _cairo_skia_context_mask (void *abstract_cr, cairo_pattern_t *mask) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX */ //UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_stroke_preserve (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStyle (SkPaint::kStroke_Style); /* XXX pen transformation? */ //assert (_cairo_matrix_is_identity (&cr->matrix)); cr->canvas->drawPath (*cr->path, *cr->paint); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_stroke (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_status_t status; status = _cairo_skia_context_stroke_preserve (cr); if (unlikely (status)) return status; return _cairo_skia_context_new_path (cr); } static cairo_status_t _cairo_skia_context_in_stroke (void *abstract_cr, double x, double y, cairo_bool_t *inside) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_stroke_extents (void *abstract_cr, double *x1, double *y1, double *x2, double *y2) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_fill_preserve (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->paint->setStyle (SkPaint::kFill_Style); cr->canvas->drawPath (*cr->path, *cr->paint); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_fill (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_status_t status; status = _cairo_skia_context_fill_preserve (cr); if (unlikely (status)) return status; return _cairo_skia_context_new_path (cr); } static cairo_status_t _cairo_skia_context_in_fill (void *abstract_cr, double x, double y, cairo_bool_t *inside) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_fill_extents (void *abstract_cr, double *x1, double *y1, double *x2, double *y2) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_clip_preserve (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cr->canvas->clipPath (*cr->path); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_clip (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; cairo_status_t status; status = _cairo_skia_context_clip_preserve (cr); if (unlikely (status)) return status; return _cairo_skia_context_new_path (cr); } static cairo_status_t _cairo_skia_context_in_clip (void *abstract_cr, double x, double y, cairo_bool_t *inside) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_reset_clip (void *abstract_cr) { cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; SkRegion rgn(SkIRect::MakeWH (cr->target->bitmap->width (), cr->target->bitmap->height ())); cr->canvas->setClipRegion(rgn); return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_clip_extents (void *abstract_cr, double *x1, double *y1, double *x2, double *y2) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_rectangle_list_t * _cairo_skia_context_copy_clip_rectangle_list (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return NULL; } static cairo_status_t _cairo_skia_context_copy_page (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_show_page (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_font_face (void *abstract_cr, cairo_font_face_t *font_face) { // cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; //return _cairo_gstate_set_font_face (cr->gstate, font_face); return CAIRO_STATUS_SUCCESS; } static cairo_font_face_t * _cairo_skia_context_get_font_face (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return NULL; } static cairo_status_t _cairo_skia_context_font_extents (void *abstract_cr, cairo_font_extents_t *extents) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_font_size (void *abstract_cr, double size) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_set_font_matrix (void *abstract_cr, const cairo_matrix_t *matrix) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static void _cairo_skia_context_get_font_matrix (void *abstract_cr, cairo_matrix_t *matrix) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; } static cairo_status_t _cairo_skia_context_set_font_options (void *abstract_cr, const cairo_font_options_t *options) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static void _cairo_skia_context_get_font_options (void *abstract_cr, cairo_font_options_t *options) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; } static cairo_status_t _cairo_skia_context_set_scaled_font (void *abstract_cr, cairo_scaled_font_t *scaled_font) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_scaled_font_t * _cairo_skia_context_get_scaled_font (void *abstract_cr) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return _cairo_scaled_font_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); } static cairo_status_t _cairo_skia_context_glyphs (void *abstract_cr, const cairo_glyph_t *glyphs, int num_glyphs, cairo_glyph_text_info_t *info) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; /* XXX */ //UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_glyph_path (void *abstract_cr, const cairo_glyph_t *glyphs, int num_glyphs) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static cairo_status_t _cairo_skia_context_glyph_extents (void *abstract_cr, const cairo_glyph_t *glyphs, int num_glyphs, cairo_text_extents_t *extents) { //cairo_skia_context_t *cr = (cairo_skia_context_t *) abstract_cr; UNSUPPORTED; return CAIRO_STATUS_SUCCESS; } static const cairo_backend_t _cairo_skia_context_backend = { CAIRO_TYPE_SKIA, _cairo_skia_context_destroy, _cairo_skia_context_get_original_target, _cairo_skia_context_get_current_target, _cairo_skia_context_save, _cairo_skia_context_restore, _cairo_skia_context_push_group, _cairo_skia_context_pop_group, _cairo_skia_context_set_source_rgba, _cairo_skia_context_set_source_surface, _cairo_skia_context_set_source, _cairo_skia_context_get_source, _cairo_skia_context_set_antialias, _cairo_skia_context_set_dash, _cairo_skia_context_set_fill_rule, _cairo_skia_context_set_line_cap, _cairo_skia_context_set_line_join, _cairo_skia_context_set_line_width, _cairo_skia_context_set_miter_limit, _cairo_skia_context_set_opacity, _cairo_skia_context_set_operator, _cairo_skia_context_set_tolerance, _cairo_skia_context_get_antialias, _cairo_skia_context_get_dash, _cairo_skia_context_get_fill_rule, _cairo_skia_context_get_line_cap, _cairo_skia_context_get_line_join, _cairo_skia_context_get_line_width, _cairo_skia_context_get_miter_limit, _cairo_skia_context_get_opacity, _cairo_skia_context_get_operator, _cairo_skia_context_get_tolerance, _cairo_skia_context_translate, _cairo_skia_context_scale, _cairo_skia_context_rotate, _cairo_skia_context_transform, _cairo_skia_context_set_matrix, _cairo_skia_context_set_identity_matrix, _cairo_skia_context_get_matrix, _cairo_skia_context_user_to_device, _cairo_skia_context_user_to_device_distance, _cairo_skia_context_device_to_user, _cairo_skia_context_device_to_user_distance, _cairo_skia_context_user_to_device, /* XXX backend */ _cairo_skia_context_user_to_device_distance, /* XXX backend */ _cairo_skia_context_device_to_user, /* XXX backend */ _cairo_skia_context_device_to_user_distance, /* XXX backend */ _cairo_skia_context_new_path, _cairo_skia_context_new_sub_path, _cairo_skia_context_move_to, _cairo_skia_context_rel_move_to, _cairo_skia_context_line_to, _cairo_skia_context_rel_line_to, _cairo_skia_context_curve_to, _cairo_skia_context_rel_curve_to, _cairo_skia_context_arc_to, _cairo_skia_context_rel_arc_to, _cairo_skia_context_close_path, _cairo_skia_context_arc, _cairo_skia_context_rectangle, _cairo_skia_context_path_extents, _cairo_skia_context_has_current_point, _cairo_skia_context_get_current_point, _cairo_skia_context_copy_path, _cairo_skia_context_copy_path_flat, _cairo_skia_context_append_path, _cairo_skia_stroke_to_path, _cairo_skia_context_clip, _cairo_skia_context_clip_preserve, _cairo_skia_context_in_clip, _cairo_skia_context_clip_extents, _cairo_skia_context_reset_clip, _cairo_skia_context_copy_clip_rectangle_list, _cairo_skia_context_paint, _cairo_skia_context_paint_with_alpha, _cairo_skia_context_mask, _cairo_skia_context_stroke, _cairo_skia_context_stroke_preserve, _cairo_skia_context_in_stroke, _cairo_skia_context_stroke_extents, _cairo_skia_context_fill, _cairo_skia_context_fill_preserve, _cairo_skia_context_in_fill, _cairo_skia_context_fill_extents, _cairo_skia_context_set_font_face, _cairo_skia_context_get_font_face, _cairo_skia_context_set_font_size, _cairo_skia_context_set_font_matrix, _cairo_skia_context_get_font_matrix, _cairo_skia_context_set_font_options, _cairo_skia_context_get_font_options, _cairo_skia_context_set_scaled_font, _cairo_skia_context_get_scaled_font, _cairo_skia_context_font_extents, _cairo_skia_context_glyphs, _cairo_skia_context_glyph_path, _cairo_skia_context_glyph_extents, _cairo_skia_context_copy_page, _cairo_skia_context_show_page, }; cairo_t * _cairo_skia_context_create (void *target) { cairo_skia_surface_t *surface = (cairo_skia_surface_t *) target; cairo_skia_context_t *cr; cr = (cairo_skia_context_t *) _freed_pool_get (&context_pool); if (unlikely (cr == NULL)) { cr = new cairo_skia_context_t; if (unlikely (cr == NULL)) return _cairo_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); cr->path = new SkPath; cr->paint = new SkPaint; } _cairo_init (&cr->base, &_cairo_skia_context_backend); cr->source = NULL; cr->source_image = NULL; cr->paint->setStrokeWidth (SkFloatToScalar (2.0)); cr->target = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target); cr->original = (cairo_skia_surface_t *) cairo_surface_reference ((cairo_surface_t *) target); cr->canvas = new SkCanvas (*surface->bitmap); cr->canvas->save (); cairo_matrix_init_identity (&cr->matrix); return &cr->base; } #if 0 void _cairo_skia_context_set_SkPaint (cairo_t *cr, SkPaint paint) { *cr->paint = paint; } void _cairo_skia_context_set_SkPath (cairo_t *cr, SkPath path) { *cr->path = path; } #endif