cairo/src/skia/cairo-skia-context.cpp
Chris Wilson af9fbd176b Introduce a new compositor architecture
Having spent the last dev cycle looking at how we could specialize the
compositors for various backends, we once again look for the
commonalities in order to reduce the duplication. In part this is
motivated by the idea that spans is a good interface for both the
existent GL backend and pixman, and so they deserve a dedicated
compositor. xcb/xlib target an identical rendering system and so they
should be using the same compositor, and it should be possible to run
that same compositor locally against pixman to generate reference tests.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>

P.S. This brings massive upheaval (read breakage) I've tried delaying in
order to fix as many things as possible but now this one patch does far,
far, far too much. Apologies in advance for breaking your favourite
backend, but trust me in that the end result will be much better. :)
2011-09-12 08:29:48 +01:00

1741 lines
46 KiB
C++

/* -*- 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 <cworth@cworth.org>
* Chris Wilson <chris@chris-wilson.co.uk>
*/
#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-path-private.h"
#include "cairo-pattern-private.h"
#include "cairo-skia-private.h"
#include "cairo-surface-backend-private.h"
#include <SkShader.h>
#include <SkColorShader.h>
#include <SkGradientShader.h>
#include <SkDashPathEffect.h>
#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 <const cairo_surface_pattern_t *> (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;
if (CAIRO_ALPHA_IS_OPAQUE (alpha))
return _cairo_skia_context_paint (cr);
/*XXX */
return _cairo_skia_context_paint (cr);
}
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_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