commit 634065859e15e0adff831a50ada5ae51dd09925c Author: Vladimir Vukicevic Date: Sat Oct 25 15:34:23 2008 -0700 Add Skia backend. diff --git a/boilerplate/Makefile.sources b/boilerplate/Makefile.sources index 92de9d2..b98ff82 100644 --- a/boilerplate/Makefile.sources +++ b/boilerplate/Makefile.sources @@ -51,3 +51,6 @@ cairo_boilerplate_xcb_sources = cairo-boilerplate-xcb.c cairo_boilerplate_xlib_headers = cairo-boilerplate-xlib.h cairo_boilerplate_xlib_private = cairo-boilerplate-xlib-private.h cairo_boilerplate_xlib_sources = cairo-boilerplate-xlib.c + +cairo_boilerplate_skia_private = cairo-boilerplate-skia-private.h +cairo_boilerplate_skia_sources = cairo-boilerplate-skia.c diff --git a/boilerplate/cairo-boilerplate-skia-private.h b/boilerplate/cairo-boilerplate-skia-private.h new file mode 100644 index 0000000..058d34d --- /dev/null +++ b/boilerplate/cairo-boilerplate-skia-private.h @@ -0,0 +1,23 @@ + +#ifndef _CAIRO_BOILERPLATE_SKIA_PRIVATE_H_ +#define _CAIRO_BOILERPLATE_SKIA_PRIVATE_H_ + +cairo_surface_t * +_cairo_boilerplate_skia_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure); + +cairo_surface_t * +_cairo_boilerplate_skia_get_image_surface (cairo_surface_t *src, + int page, + int width, + int height); + +#endif /* _CAIRO_BOILERPLATE_SKIA_PRIVATE_H_ */ + diff --git a/boilerplate/cairo-boilerplate-skia.c b/boilerplate/cairo-boilerplate-skia.c new file mode 100644 index 0000000..f295901 --- /dev/null +++ b/boilerplate/cairo-boilerplate-skia.c @@ -0,0 +1,46 @@ + +#include + +#include "cairo-boilerplate.h" +#include "cairo-boilerplate-skia-private.h" + +#include + +cairo_surface_t * +_cairo_boilerplate_skia_create_surface (const char *name, + cairo_content_t content, + int width, + int height, + int max_width, + int max_height, + cairo_boilerplate_mode_t mode, + int id, + void **closure) +{ + cairo_format_t format; + + *closure = NULL; + + if (content == CAIRO_CONTENT_COLOR_ALPHA) { + format = CAIRO_FORMAT_ARGB32; + } else if (content == CAIRO_CONTENT_COLOR) { + format = CAIRO_FORMAT_RGB24; + } else { + assert (0); /* not reached */ + return NULL; + } + + return cairo_skia_surface_create (format, width, height); +} + +cairo_surface_t * +_cairo_boilerplate_skia_get_image_surface (cairo_surface_t *src, + int page, + int width, + int height) +{ + if (page != 0) + return cairo_boilerplate_surface_create_in_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH); + + return cairo_skia_surface_get_image (src); +} diff --git a/boilerplate/cairo-boilerplate.c b/boilerplate/cairo-boilerplate.c index 34b9133..c739494 100644 --- a/boilerplate/cairo-boilerplate.c +++ b/boilerplate/cairo-boilerplate.c @@ -62,6 +62,9 @@ #if CAIRO_HAS_XLIB_SURFACE #include "cairo-boilerplate-xlib-private.h" #endif +#if CAIRO_HAS_SKIA_SURFACE +#include "cairo-boilerplate-skia-private.h" +#endif #include #include @@ -278,6 +281,16 @@ static cairo_boilerplate_target_t targets[] = NULL, _cairo_boilerplate_get_image_surface, cairo_surface_write_to_png }, + { "skia", NULL, CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR_ALPHA, 0, + _cairo_boilerplate_skia_create_surface, NULL, + NULL, + _cairo_boilerplate_skia_get_image_surface, + cairo_surface_write_to_png }, + { "skia", NULL, CAIRO_SURFACE_TYPE_IMAGE, CAIRO_CONTENT_COLOR, 0, + _cairo_boilerplate_skia_create_surface, NULL, + NULL, + _cairo_boilerplate_skia_get_image_surface, + cairo_surface_write_to_png }, #ifdef CAIRO_HAS_TEST_SURFACES { "test-fallback", NULL, CAIRO_INTERNAL_SURFACE_TYPE_TEST_FALLBACK, CAIRO_CONTENT_COLOR_ALPHA, 0, diff --git a/configure.ac b/configure.ac index cbde1b8..56e3518 100644 --- a/configure.ac +++ b/configure.ac @@ -127,6 +127,13 @@ AM_CONDITIONAL(CAIRO_CAN_TEST_WIN32_PRINTING_SURFACE, test "x$test_win32_printin dnl =========================================================================== +CAIRO_ENABLE_SURFACE_BACKEND(skia, Skia, no, [ + skia_CFLAGS="-I/Users/vladimir/proj/skia/include -I/Users/vladimir/proj/skia/include/corecg" + skia_LIBS="/Users/vladimir/proj/skia/build/Release/libskia.a" +]) + +dnl =========================================================================== + CAIRO_ENABLE_SURFACE_BACKEND(os2, OS/2, no, [ case "$host" in *-*-os2*) diff --git a/perf/cairo-perf-diff-files.c b/perf/cairo-perf-diff-files.c index 9b9f5f9..e032c17 100644 --- a/perf/cairo-perf-diff-files.c +++ b/perf/cairo-perf-diff-files.c @@ -448,8 +448,13 @@ main (int argc, const char *argv[]) reports = xmalloc (args.num_filenames * sizeof (cairo_perf_report_t)); - for (i = 0; i < args.num_filenames; i++ ) - cairo_perf_report_load (&reports[i], args.filenames[i]); + if (args.num_filenames == 2) { + cairo_perf_report_load (&reports[0], args.filenames[0], getenv("PERF_A")); + cairo_perf_report_load (&reports[1], args.filenames[1], getenv("PERF_B")); + } else { + for (i = 0; i < args.num_filenames; i++ ) + cairo_perf_report_load (&reports[i], args.filenames[i], NULL); + } cairo_perf_reports_compare (reports, args.num_filenames, &args.options); diff --git a/perf/cairo-perf-report.c b/perf/cairo-perf-report.c index 79e2f92..400d6d1 100644 --- a/perf/cairo-perf-report.c +++ b/perf/cairo-perf-report.c @@ -384,7 +384,8 @@ cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report) void cairo_perf_report_load (cairo_perf_report_t *report, - const char *filename) + const char *filename, + const char *limit_backend) { FILE *file; test_report_status_t status; @@ -433,8 +434,17 @@ cairo_perf_report_load (cairo_perf_report_t *report, if (status == TEST_REPORT_STATUS_ERROR) fprintf (stderr, "Ignoring unrecognized line %d of %s:\n%s", line_number, filename, line); - if (status == TEST_REPORT_STATUS_SUCCESS) - report->tests_count++; + if (status == TEST_REPORT_STATUS_SUCCESS) { + if (limit_backend && + (strcmp(report->tests[report->tests_count].backend, limit_backend) == 0)) + { + //free(report->tests[report->tests_count].backend); + report->tests[report->tests_count].backend = strdup("cairo"); + report->tests_count++; + } else if (!limit_backend) { + report->tests_count++; + } + } /* Do nothing on TEST_REPORT_STATUS_COMMENT */ } diff --git a/perf/cairo-perf.c b/perf/cairo-perf.c index a6d59a5..1b75ae7 100644 --- a/perf/cairo-perf.c +++ b/perf/cairo-perf.c @@ -131,10 +131,13 @@ cairo_perf_has_similar (cairo_perf_t *perf) cairo_surface_t *target = cairo_get_target (perf->cr); /* exclude the image backend */ - if (cairo_surface_get_type (target) == CAIRO_SURFACE_TYPE_IMAGE) - return FALSE; - - return TRUE; + switch (cairo_surface_get_type (target)) { + case CAIRO_SURFACE_TYPE_IMAGE: + case CAIRO_SURFACE_TYPE_SKIA: + return FALSE; + default: + return TRUE; + } } void diff --git a/perf/cairo-perf.h b/perf/cairo-perf.h index 0cedb69..81236e3 100644 --- a/perf/cairo-perf.h +++ b/perf/cairo-perf.h @@ -144,7 +144,8 @@ typedef enum { void cairo_perf_report_load (cairo_perf_report_t *report, - const char *filename); + const char *filename, + const char *limit_backend); void cairo_perf_report_sort_and_compute_stats (cairo_perf_report_t *report); diff --git a/perf/composite-checker.c b/perf/composite-checker.c index 69f48a0..3a479df 100644 --- a/perf/composite-checker.c +++ b/perf/composite-checker.c @@ -87,6 +87,20 @@ composite_checker (cairo_perf_t *perf, image = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, PAT_SIZE, PAT_SIZE); + if (0) { + cairo_t *cc = cairo_create(image); + cairo_set_source_rgb(cc, 0, 0, 0); + cairo_paint(cc); + + cairo_set_source_rgb(cc, 1, 1, 1); + cairo_new_path(cc); + cairo_rectangle(cc, 0, 0, PAT_SIZE/2, PAT_SIZE/2); + cairo_rectangle(cc, PAT_SIZE/2, PAT_SIZE/2, PAT_SIZE/2, PAT_SIZE/2); + cairo_fill(cc); + + cairo_destroy(cc); + } + checkerboard = cairo_pattern_create_for_surface (image); cairo_pattern_set_filter (checkerboard, CAIRO_FILTER_NEAREST); cairo_pattern_set_extend (checkerboard, CAIRO_EXTEND_REPEAT); diff --git a/perf/paint.c b/perf/paint.c index 6f75016..0b886d5 100644 --- a/perf/paint.c +++ b/perf/paint.c @@ -34,6 +34,15 @@ do_paint (cairo_t *cr, int width, int height) cairo_perf_timer_stop (); + if (1) { + static int k = 0; + char buf[256]; + + sprintf(buf, "s%d.png", k++); + cairo_surface_write_to_png (cairo_get_target(cr), buf); + fprintf (stderr, "wrote %s\n", buf); + } + return cairo_perf_timer_elapsed (); } diff --git a/src/Makefile.sources b/src/Makefile.sources index 842aec2..8713906 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -242,3 +242,6 @@ cairo_glitz_sources = cairo-glitz-surface.c cairo_directfb_headers = cairo-directfb.h cairo_directfb_sources = cairo-directfb-surface.c + +cairo_skia_headers = cairo-skia.h +cairo_skia_sources = cairo-skia-surface.cpp diff --git a/src/cairo-skia-surface.cpp b/src/cairo-skia-surface.cpp new file mode 100644 index 0000000..1f02e77 --- /dev/null +++ b/src/cairo-skia-surface.cpp @@ -0,0 +1,1167 @@ +/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mozilla 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 Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#include "cairoint.h" + +#include "cairo-skia.h" + +#include +#include +#include +#include + +#include +#include + +#include + +#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 + +#ifndef CAIRO_INT_STATUS_SUCCESS +# define CAIRO_INT_STATUS_SUCCESS ((cairo_int_status_t) CAIRO_STATUS_SUCCESS) +#endif + +//#define CAIRO_MAYBE_UNSUPPORTED CAIRO_INT_STATUS_SUCCESS +#define CAIRO_MAYBE_UNSUPPORTED CAIRO_INT_STATUS_UNSUPPORTED +//#define CAIRO_MAYBE_UNSUPPORTED do_unsupported() + +static unsigned long num_skia_surfaces = 0; + +static cairo_int_status_t do_unsupported() { + printf ("unsupported!\n"); + return CAIRO_INT_STATUS_SUCCESS; +} + +typedef struct cairo_skia_surface { + cairo_surface_t base; + + SkBitmap *bitmap; + SkCanvas *canvas; + + /* this will go away eventually; convenient place to hold an image surface wrapper */ + cairo_image_surface_t *image_surface; +} cairo_skia_surface_t; + +static cairo_skia_surface_t * +_cairo_skia_surface_create_internal (SkBitmap::Config config, + bool opaque, + unsigned char *data, + int width, + int height, + int stride); + +static cairo_status_t +_cairo_skia_surface_clone_similar (void *asurface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out); + +/* + * conversion methods + */ + +/* + * format conversion + */ +static inline bool +format_to_sk_config (cairo_format_t format, + SkBitmap::Config& config, + bool& opaque) +{ + opaque = false; + + switch (format) { + case CAIRO_FORMAT_ARGB32: + config = SkBitmap::kARGB_8888_Config; + break; + case CAIRO_FORMAT_RGB24: + config = SkBitmap::kARGB_8888_Config; + opaque = true; + break; + case CAIRO_FORMAT_A8: + config = SkBitmap::kA8_Config; + break; + case CAIRO_FORMAT_A1: + config = SkBitmap::kA1_Config; + break; + default: + return false; + } + + return true; +} + +static inline cairo_format_t +sk_config_to_format (SkBitmap::Config config, + bool opaque) +{ + switch (config) { + case SkBitmap::kARGB_8888_Config: + if (opaque) + return CAIRO_FORMAT_RGB24; + return CAIRO_FORMAT_ARGB32; + + case SkBitmap::kA8_Config: + return CAIRO_FORMAT_A8; + + case SkBitmap::kA1_Config: + return CAIRO_FORMAT_A1; + } + + return (cairo_format_t) -1; +} + +/* + * image surface wrappig + */ +static inline bool +image_surface_to_sk_bitmap (cairo_image_surface_t *img, + SkBitmap& bitmap) +{ + SkBitmap::Config config; + bool opaque; + + if (!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; +} + +/* + * operator conversion + */ + +static inline SkPorterDuff::Mode +operator_to_sk(cairo_operator_t op) +{ + static const SkPorterDuff::Mode modeMap[] = { + SkPorterDuff::kClear_Mode, + + SkPorterDuff::kSrc_Mode, + SkPorterDuff::kSrcOver_Mode, + SkPorterDuff::kSrcIn_Mode, + SkPorterDuff::kSrcOut_Mode, + SkPorterDuff::kSrcATop_Mode, + + SkPorterDuff::kDst_Mode, + SkPorterDuff::kDstOver_Mode, + SkPorterDuff::kDstIn_Mode, + SkPorterDuff::kDstOut_Mode, + SkPorterDuff::kDstATop_Mode, + + SkPorterDuff::kXor_Mode, + SkPorterDuff::kLighten_Mode, // XXX ADD + SkPorterDuff::kDarken_Mode // XXX SATURATE + }; + + return modeMap[op]; +} + +/* + * tiling mode conversion + */ +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]; +} + +/* + * color conversion + */ +static inline SkColor +color_to_sk(const cairo_color_t& c) +{ + return SkColorSetARGB + (_cairo_fixed_integer_part(_cairo_fixed_from_double(c.alpha * 255.0)), + _cairo_fixed_integer_part(_cairo_fixed_from_double(c.red * 255.0)), + _cairo_fixed_integer_part(_cairo_fixed_from_double(c.green * 255.0)), + _cairo_fixed_integer_part(_cairo_fixed_from_double(c.blue * 255.0))); +} + +/* + * matrix conversion + */ +static inline SkMatrix +matrix_to_sk(const cairo_matrix_t& mat) +{ + SkMatrix skm; + + skm.reset(); + skm.set(0, SkFloatToScalar(mat.xx)); + skm.set(1, SkFloatToScalar(mat.xy)); + skm.set(2, SkFloatToScalar(mat.x0)); + skm.set(3, SkFloatToScalar(mat.yx)); + skm.set(4, SkFloatToScalar(mat.yy)); + skm.set(5, 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; +} + +/* + * pattern conversion + */ +static inline SkShader* +pattern_to_sk(cairo_skia_surface_t *dst, 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_pattern_t *spat = (cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = (cairo_surface_t *) spat->surface; + + if (cairo_surface_get_type (surface) == 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 if (cairo_surface_get_type (surface) == CAIRO_SURFACE_TYPE_IMAGE) { + SkBitmap bitmap; + if (!image_surface_to_sk_bitmap((cairo_image_surface_t *) surface, bitmap)) + return NULL; + shader = SkShader::CreateBitmapShader(bitmap, + extend_to_sk(pattern->extend), + extend_to_sk(pattern->extend)); + } else { + cairo_rectangle_int_t extents; + + if (_cairo_surface_get_extents(surface, &extents)) + return NULL; + + cairo_skia_surface_t *clone; + + // XXX this can be optimized; we could easily avoid cloning the entire + // surface + int dontcare; + if (_cairo_skia_surface_clone_similar(dst, surface, + extents.x, extents.y, + extents.width, extents.height, + &dontcare, &dontcare, + (cairo_surface_t **) &clone)) + return NULL; + + shader = SkShader::CreateBitmapShader(*clone->bitmap, + extend_to_sk(pattern->extend), + extend_to_sk(pattern->extend)); + + // I -think- this is safe + cairo_surface_destroy ((cairo_surface_t *) clone); + } + } else if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR + /* || pattern->type == CAIRO_PATTERN_TYPE_RADIAL */) + { + cairo_gradient_pattern_t *gradient = (cairo_gradient_pattern_t *) pattern; + + if (gradient->n_stops == 0) + return NULL; + if (gradient->n_stops == 1) + return new SkColorShader(color_to_sk(gradient->stops[0].color)); + + SkPoint points[2]; + + 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_to_sk(gradient->stops[i].color); + } + + if (pattern->type == CAIRO_PATTERN_TYPE_LINEAR) { + cairo_linear_pattern_t *linear = (cairo_linear_pattern_t *) gradient; + points[0].set(CAIRO_FIXED_TO_SK_SCALAR(linear->p1.x), + CAIRO_FIXED_TO_SK_SCALAR(linear->p1.y)); + points[1].set(CAIRO_FIXED_TO_SK_SCALAR(linear->p2.x), + CAIRO_FIXED_TO_SK_SCALAR(linear->p2.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)) + { + cairo_matrix_t cm = pattern->matrix; + cairo_matrix_invert(&cm); + SkMatrix m = matrix_to_sk(cm); + shader->setLocalMatrix(m); + } + + return shader; +} + +static inline bool +pattern_filter_to_sk(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; + } + + return false; +} + +static inline bool +pattern_to_sk_color(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; +} + +/* + * path conversion + */ + +struct CairoPathConverter { + CairoPathConverter (cairo_path_fixed_t *path, + cairo_matrix_t *mat = NULL) + : matrix (mat), isFirst(TRUE) + { + _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + doMoveTo, doLineTo, doCurveTo, doClosePath, + this); + } + + CairoPathConverter (cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + cairo_matrix_t *mat = NULL) + : matrix (mat), isFirst(TRUE) + { + _cairo_path_fixed_interpret (path, + CAIRO_DIRECTION_FORWARD, + doMoveTo, doLineTo, doCurveTo, doClosePath, + this); + + if (fill_rule == CAIRO_FILL_RULE_EVEN_ODD) + skPath.setFillType(SkPath::kEvenOdd_FillType); + else + skPath.setFillType(SkPath::kWinding_FillType); + } + + static cairo_status_t doMoveTo (void *closure, cairo_point_t *point) { + CairoPathConverter *cpc = static_cast(closure); + if (cpc->matrix) { + double x = _cairo_fixed_to_double(point->x); + double y = _cairo_fixed_to_double(point->y); + cairo_matrix_transform_point(cpc->matrix, &x, &y); + cpc->skPath.moveTo(SkFloatToScalar(x), SkFloatToScalar(y)); + } else { + cpc->skPath.moveTo(CAIRO_FIXED_TO_SK_SCALAR(point->x), + CAIRO_FIXED_TO_SK_SCALAR(point->y)); + } + cpc->isFirst = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + static cairo_status_t doLineTo (void *closure, cairo_point_t *point) { + CairoPathConverter *cpc = static_cast(closure); + if (cpc->isFirst) + return doMoveTo(closure, point); + + if (cpc->matrix) { + double x = _cairo_fixed_to_double(point->x); + double y = _cairo_fixed_to_double(point->y); + cairo_matrix_transform_point(cpc->matrix, &x, &y); + cpc->skPath.lineTo(SkFloatToScalar(x), SkFloatToScalar(y)); + } else { + cpc->skPath.lineTo(CAIRO_FIXED_TO_SK_SCALAR(point->x), + CAIRO_FIXED_TO_SK_SCALAR(point->y)); + } + cpc->isFirst = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + static cairo_status_t doCurveTo (void *closure, + cairo_point_t *p0, + cairo_point_t *p1, + cairo_point_t *p2) + { + CairoPathConverter *cpc = static_cast(closure); + if (cpc->isFirst) + doMoveTo(closure, p0); + + if (cpc->matrix) { + double x0 = _cairo_fixed_to_double(p0->x); + double y0 = _cairo_fixed_to_double(p0->y); + double x1 = _cairo_fixed_to_double(p1->x); + double y1 = _cairo_fixed_to_double(p1->y); + double x2 = _cairo_fixed_to_double(p2->x); + double y2 = _cairo_fixed_to_double(p2->y); + cairo_matrix_transform_point(cpc->matrix, &x0, &y0); + cairo_matrix_transform_point(cpc->matrix, &x1, &y1); + cairo_matrix_transform_point(cpc->matrix, &x2, &y2); + + cpc->skPath.cubicTo(SkFloatToScalar(x0), + SkFloatToScalar(y0), + SkFloatToScalar(x1), + SkFloatToScalar(y1), + SkFloatToScalar(x2), + SkFloatToScalar(y2)); + } else { + cpc->skPath.cubicTo(CAIRO_FIXED_TO_SK_SCALAR(p0->x), + CAIRO_FIXED_TO_SK_SCALAR(p0->y), + CAIRO_FIXED_TO_SK_SCALAR(p1->x), + CAIRO_FIXED_TO_SK_SCALAR(p1->y), + CAIRO_FIXED_TO_SK_SCALAR(p2->x), + CAIRO_FIXED_TO_SK_SCALAR(p2->y)); + } + cpc->isFirst = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + static cairo_status_t doClosePath (void *closure) + { + CairoPathConverter *cpc = static_cast(closure); + cpc->skPath.close(); + cpc->isFirst = FALSE; + return CAIRO_STATUS_SUCCESS; + } + + cairo_matrix_t *matrix; + SkPath skPath; +private: + cairo_bool_t isFirst : 1; +}; + +/* + * cairo surface methods + */ + +static cairo_surface_t * +_cairo_skia_surface_create_similar (void *asurface, + cairo_content_t content, + int width, + int height) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + cairo_skia_surface_t *new_surf = + _cairo_skia_surface_create_internal (surface->bitmap->config(), + surface->bitmap->isOpaque(), + NULL, + width, + height, + 0); + + return (cairo_surface_t *) new_surf; +} + +static cairo_status_t +_cairo_skia_surface_finish (void *asurface) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + cairo_surface_destroy ((cairo_surface_t*) surface->image_surface); + + delete surface->canvas; + delete surface->bitmap; + + surface->image_surface = NULL; + surface->canvas = NULL; + surface->bitmap = NULL; + + num_skia_surfaces--; + //fprintf (stderr, "--- free skia surface: %p (%d now)\n", surface, num_skia_surfaces); + + return CAIRO_STATUS_SUCCESS; +} + +static cairo_status_t +_cairo_skia_surface_acquire_source_image (void *asurface, + cairo_image_surface_t **image_out, + void **image_extra) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + *image_out = surface->image_surface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_skia_surface_release_source_image (void *asurface, + cairo_image_surface_t *image, + void *image_extra) +{ + //cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; +} + +static cairo_status_t +_cairo_skia_surface_acquire_dest_image (void *asurface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t **image_out, + cairo_rectangle_int_t *image_rect, + void **image_extra) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + image_rect->x = 0; + image_rect->y = 0; + image_rect->width = surface->bitmap->width(); + image_rect->height = surface->bitmap->height(); + + *image_out = surface->image_surface; + *image_extra = NULL; + + return CAIRO_STATUS_SUCCESS; +} + +static void +_cairo_skia_surface_release_dest_image (void *asurface, + cairo_rectangle_int_t *interest_rect, + cairo_image_surface_t *image, + cairo_rectangle_int_t *image_rect, + void *image_extra) +{ + //cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; +} + +cairo_status_t +_cairo_skia_surface_clone_similar (void *asurface, + cairo_surface_t *src, + int src_x, + int src_y, + int width, + int height, + int *clone_offset_x, + int *clone_offset_y, + cairo_surface_t **clone_out) +{ + cairo_status_t status; + + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + cairo_image_surface_t *image_surface = NULL; + void *image_extra; + + status = _cairo_surface_acquire_source_image(src, + &image_surface, + &image_extra); + if (status) + return status; + + cairo_skia_surface_t *dst = + _cairo_skia_surface_create_internal (surface->bitmap->config(), + surface->bitmap->isOpaque(), + NULL, + width, + height, + 0); + if (!dst) { + status = CAIRO_STATUS_NO_MEMORY; + goto bail; + } + + cairo_t *cr = cairo_create ((cairo_surface_t*)dst); + cairo_set_source_surface (cr, (cairo_surface_t *) image_surface, -src_x, -src_y); + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (cr); + cairo_destroy (cr); + + *clone_offset_x = src_x; + *clone_offset_y = src_y; + + *clone_out = (cairo_surface_t *) dst; + + bail: + if (image_surface) + _cairo_surface_release_source_image (src, image_surface, image_extra); + + return status; +} + +static cairo_int_status_t +_cairo_skia_surface_intersect_clip_path (void *asurface, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + if (path == NULL) { + /* XXX TODO: teach Skia how to reset the clip path */ + surface->canvas->restore(); + surface->canvas->save(); + } else { + CairoPathConverter cpc(path, fill_rule); + surface->canvas->clipPath(cpc.skPath); + } + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_skia_surface_get_extents (void *asurface, + cairo_rectangle_int_t *extents) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + extents->x = 0; + extents->y = 0; + extents->width = surface->bitmap->width(); + extents->height = surface->bitmap->height(); + + return CAIRO_INT_STATUS_SUCCESS; +} + +/* + * Core drawing operations + */ + +static SkBitmap * +pattern_to_sk_bitmap (cairo_skia_surface_t *dst, + cairo_pattern_t *pattern, + SkMatrix *matrix) +{ + if (pattern->type != CAIRO_PATTERN_TYPE_SURFACE) + return NULL; + + if (pattern->extend != CAIRO_EXTEND_NONE) + return NULL; + + cairo_surface_pattern_t *spat = (cairo_surface_pattern_t *) pattern; + cairo_surface_t *surface = (cairo_surface_t *) spat->surface; + SkBitmap *bitmap; + + if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_SKIA) { + bitmap = new SkBitmap(*((cairo_skia_surface_t*)surface)->bitmap); + } else if (cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE) { + bitmap = new SkBitmap; + if (!image_surface_to_sk_bitmap((cairo_image_surface_t *) surface, *bitmap)) + return NULL; + } else { + cairo_rectangle_int_t extents; + + if (_cairo_surface_get_extents(surface, &extents) != CAIRO_INT_STATUS_SUCCESS) + return NULL; + + cairo_skia_surface_t *clone; + int dontcare; + if (_cairo_skia_surface_clone_similar(dst, surface, + extents.x, extents.y, + extents.width, extents.height, + &dontcare, &dontcare, + (cairo_surface_t **) &clone)) + return NULL; + + bitmap = new SkBitmap(*clone->bitmap); + cairo_surface_destroy((cairo_surface_t*)clone); + } + + *matrix = matrix_to_sk (pattern->matrix); + return bitmap; +} + +static cairo_int_status_t +_cairo_skia_surface_paint (void *asurface, + cairo_operator_t op, + cairo_pattern_t *source) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + SkColor color; + + if (pattern_to_sk_color(source, color)) { + surface->canvas->drawColor(color, operator_to_sk(op)); + return CAIRO_INT_STATUS_SUCCESS; + } + + SkMatrix bitmapMatrix; + SkBitmap *bitmap = pattern_to_sk_bitmap(surface, source, &bitmapMatrix); + SkShader *shader = NULL; + if (!bitmap) + shader = pattern_to_sk(surface, source); + + if (!bitmap && !shader) + return CAIRO_MAYBE_UNSUPPORTED; + + SkPaint paint; + paint.setFilterBitmap(pattern_filter_to_sk(source)); + paint.setPorterDuffXfermode(operator_to_sk(op)); + + if (shader) { + paint.setShader(shader); + surface->canvas->drawPaint(paint); + } else { + surface->canvas->drawBitmapMatrix(*bitmap, bitmapMatrix, &paint); + } + + if (bitmap) + delete bitmap; + if (shader) + shader->unref(); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_skia_surface_mask (void *asurface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_pattern_t *mask) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + if (mask->type == CAIRO_PATTERN_TYPE_SOLID && + op == CAIRO_OPERATOR_OVER) + { + cairo_solid_pattern_t *solidmask = (cairo_solid_pattern_t *) mask; + + surface->canvas->saveLayerAlpha(NULL, U8CPU(solidmask->color.alpha * 255)); + cairo_int_status_t status = _cairo_skia_surface_paint (asurface, op, source); + surface->canvas->restore(); + return status; + } + + return CAIRO_MAYBE_UNSUPPORTED; +} + +static cairo_int_status_t +_cairo_skia_surface_stroke (void *asurface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_stroke_style_t *style, + cairo_matrix_t *ctm, + cairo_matrix_t *ctm_inverse, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + SkPaint paint; + paint.setStyle(SkPaint::kStroke_Style); + + SkColor color; + if (pattern_to_sk_color(source, color)) { + paint.setColor(color); + } else { + SkShader *shader = pattern_to_sk(surface, source); + if (shader == NULL) + return CAIRO_MAYBE_UNSUPPORTED; + + paint.setShader(shader); + shader->unref(); + + paint.setFilterBitmap(pattern_filter_to_sk(source)); + } + + paint.setPorterDuffXfermode(operator_to_sk(op)); + if (antialias == CAIRO_ANTIALIAS_NONE) + paint.setAntiAlias(false); + else + paint.setAntiAlias(true); + + /* Convert the various stroke rendering bits */ + paint.setStrokeWidth (SkFloatToScalar(style->line_width)); + paint.setStrokeMiter (SkFloatToScalar(style->miter_limit)); + + static const SkPaint::Cap capMap[] = { + SkPaint::kButt_Cap, + SkPaint::kRound_Cap, + SkPaint::kSquare_Cap + }; + paint.setStrokeCap(capMap[style->line_cap]); + + static const SkPaint::Join joinMap[] = { + SkPaint::kMiter_Join, + SkPaint::kRound_Join, + SkPaint::kBevel_Join + }; + paint.setStrokeJoin(joinMap[style->line_join]); + + /* If we have a dash pattern, we need to + * create a SkDashPathEffect and set it on the Paint. + */ + if (style->dash != NULL) { + SkScalar intervals_static[20]; + SkScalar *intervals = intervals_static; + + int loop = 0; + unsigned int dash_count = style->num_dashes; + if ((dash_count & 1) != 0) { + loop = 1; + dash_count <<= 1; + } + + if (dash_count > 20) + intervals = new SkScalar[dash_count]; + + unsigned int i = 0; + do { + for (unsigned int j = 0; i < style->num_dashes; j++) + intervals[i++] = SkFloatToScalar(style->dash[j]); + } while (loop--); + + SkDashPathEffect *dash = new SkDashPathEffect(intervals, + dash_count, + SkFloatToScalar(style->dash_offset)); + + paint.setPathEffect(dash); + dash->unref(); + } + + CairoPathConverter cpc(path, ctm_inverse); + surface->canvas->save(SkCanvas::kMatrix_SaveFlag); + SkMatrix m = matrix_to_sk(*ctm); + surface->canvas->concat(m); + surface->canvas->drawPath(cpc.skPath, paint); + surface->canvas->restore(); + + return CAIRO_INT_STATUS_SUCCESS; +} + +static cairo_int_status_t +_cairo_skia_surface_fill (void *asurface, + cairo_operator_t op, + cairo_pattern_t *source, + cairo_path_fixed_t *path, + cairo_fill_rule_t fill_rule, + double tolerance, + cairo_antialias_t antialias) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *)asurface; + + SkPaint paint; + paint.setStyle(SkPaint::kFill_Style); + + SkColor color; + if (pattern_to_sk_color(source, color)) { + paint.setColor(color); + } else { + SkShader *shader = pattern_to_sk(surface, source); + if (shader == NULL) + return CAIRO_MAYBE_UNSUPPORTED; + + paint.setShader(shader); + shader->unref(); + + paint.setFilterBitmap(pattern_filter_to_sk(source)); + } + + paint.setPorterDuffXfermode(operator_to_sk(op)); + if (antialias == CAIRO_ANTIALIAS_NONE) + paint.setAntiAlias(false); + else + paint.setAntiAlias(true); + + CairoPathConverter cpc(path, fill_rule); + + surface->canvas->drawPath(cpc.skPath, paint); + + return CAIRO_INT_STATUS_SUCCESS; +} + + +static const struct _cairo_surface_backend +cairo_skia_surface_backend = { + CAIRO_SURFACE_TYPE_SKIA, + _cairo_skia_surface_create_similar, + _cairo_skia_surface_finish, + _cairo_skia_surface_acquire_source_image, + _cairo_skia_surface_release_source_image, + _cairo_skia_surface_acquire_dest_image, + _cairo_skia_surface_release_dest_image, + _cairo_skia_surface_clone_similar, + NULL, /* composite */ + NULL, /* fill_rectangles */ + NULL, /* composite_trapezoids */ + NULL, /* copy_page */ + NULL, /* show_page */ + NULL, /* set_clip_region */ + _cairo_skia_surface_intersect_clip_path, + _cairo_skia_surface_get_extents, + NULL, /* old_show_glyphs */ + NULL, /* get_font_options */ + NULL, /* flush */ + NULL, /* mark_dirty_rectangle */ + NULL, /* scaled_font_fini */ + NULL, /* scaled_glyph_fini */ + + _cairo_skia_surface_paint, + _cairo_skia_surface_mask, + _cairo_skia_surface_stroke, + _cairo_skia_surface_fill, + NULL, /* show_glyphs */ + + NULL, /* snapshot */ + NULL, /* is_similar */ + NULL, /* reset */ +}; + +/* + * Surface constructors + */ + +cairo_skia_surface_t * +_cairo_skia_surface_create_internal (SkBitmap::Config config, + bool opaque, + unsigned char *data, + int width, + int height, + int stride) +{ + cairo_skia_surface_t *surface = (cairo_skia_surface_t *) malloc (sizeof (cairo_skia_surface_t)); + if (!surface) + return NULL; + + memset (surface, 0, sizeof(cairo_skia_surface_t)); + + _cairo_surface_init(&surface->base, &cairo_skia_surface_backend, + _cairo_content_from_format(sk_config_to_format(config, opaque))); + + surface->bitmap = new SkBitmap; + if (data == NULL) { + surface->bitmap->setConfig (config, width, height); + surface->bitmap->setIsOpaque (opaque); + surface->bitmap->allocPixels (); + } else { + surface->bitmap->setConfig (config, width, height, stride); + surface->bitmap->setIsOpaque (opaque); + surface->bitmap->setPixels (data); + } + + surface->canvas = new SkCanvas(*surface->bitmap); + //surface->canvas->translate(SkIntToScalar(0), SkIntToScalar(height)); + //surface->canvas->scale(SkIntToScalar(1), SkIntToScalar(-1)); + surface->canvas->save(); + + surface->image_surface = (cairo_image_surface_t *) + cairo_image_surface_create_for_data ((unsigned char *) surface->bitmap->getPixels(), + sk_config_to_format(config, opaque), + surface->bitmap->width(), + surface->bitmap->height(), + surface->bitmap->rowBytes()); + + num_skia_surfaces++; + //fprintf (stderr, "+++ alloc skia surface: %p (%d now)\n", surface, num_skia_surfaces); + + return surface; +} + +cairo_surface_t * +cairo_skia_surface_create (cairo_format_t format, + int width, + int height) +{ + cairo_skia_surface_t *surface; + + SkBitmap::Config config; + bool opaque; + + if (!CAIRO_FORMAT_VALID (format) || + !format_to_sk_config (format, config, opaque)) + { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + surface = _cairo_skia_surface_create_internal (config, opaque, + NULL, + width, height, 0); + + if (!surface) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + return (cairo_surface_t *) surface; +} + +cairo_surface_t * +cairo_skia_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride) +{ + cairo_skia_surface_t *surface; + + SkBitmap::Config config; + bool opaque; + + if (!CAIRO_FORMAT_VALID (format) || + !format_to_sk_config (format, config, opaque)) + { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_INVALID_FORMAT)); + } + + surface = _cairo_skia_surface_create_internal (config, opaque, + data, + width, height, stride); + + if (!surface) { + return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); + } + + return (cairo_surface_t *) surface; +} + +unsigned char * +cairo_skia_surface_get_data (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return NULL; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return (unsigned char *) esurf->bitmap->getPixels(); +} + +cairo_format_t +cairo_skia_surface_get_format (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return (cairo_format_t) -1; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return sk_config_to_format(esurf->bitmap->config(), + esurf->bitmap->isOpaque()); +} + +int +cairo_skia_surface_get_width (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return -1; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return esurf->bitmap->width(); +} + +int +cairo_skia_surface_get_height (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return -1; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return esurf->bitmap->height(); +} + +int +cairo_skia_surface_get_stride (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return -1; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return esurf->bitmap->rowBytes(); +} + +cairo_surface_t * +cairo_skia_surface_get_image (cairo_surface_t *surface) +{ + if (cairo_surface_get_type(surface) != CAIRO_SURFACE_TYPE_SKIA) + return NULL; + + cairo_skia_surface_t *esurf = (cairo_skia_surface_t *) surface; + return (cairo_surface_t *) esurf->image_surface; +} + +/*** + +Todo: + +*** Skia: + +- mask() + +*** Sk: + +High: +- antialiased clipping? + +Medium: +- implement clip path reset (to avoid restore/save) +- implement complex radial patterns (2 centers and 2 radii) + +Low: +- implement EXTEND_NONE + +***/ diff --git a/src/cairo-skia.h b/src/cairo-skia.h new file mode 100644 index 0000000..17468cb --- /dev/null +++ b/src/cairo-skia.h @@ -0,0 +1,73 @@ +/* cairo - a vector graphics library with display and print output + * + * Copyright © 2007 Mozilla 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 Mozilla Corporation. + * + * Contributor(s): + * Vladimir Vukicevic + */ + +#ifndef CAIRO_SKIA_H +#define CAIRO_SKIA_H + +CAIRO_BEGIN_DECLS + +cairo_public cairo_surface_t * +cairo_skia_surface_create (cairo_format_t format, + int width, + int height); + +cairo_public cairo_surface_t * +cairo_skia_surface_create_for_data (unsigned char *data, + cairo_format_t format, + int width, + int height, + int stride); + +cairo_public unsigned char * +cairo_skia_surface_get_data (cairo_surface_t *surface); + +cairo_public cairo_format_t +cairo_skia_surface_get_format (cairo_surface_t *surface); + +cairo_public int +cairo_skia_surface_get_width (cairo_surface_t *surface); + +cairo_public int +cairo_skia_surface_get_height (cairo_surface_t *surface); + +cairo_public int +cairo_skia_surface_get_stride (cairo_surface_t *surface); + +cairo_public cairo_surface_t * +cairo_skia_surface_get_image (cairo_surface_t *surface); + +CAIRO_END_DECLS + +#endif /* CAIRO_SKIA_H */ diff --git a/src/cairo.h b/src/cairo.h index cf4bc05..003d1ad 100644 --- a/src/cairo.h +++ b/src/cairo.h @@ -1913,7 +1913,8 @@ typedef enum _cairo_surface_type { CAIRO_SURFACE_TYPE_SVG, CAIRO_SURFACE_TYPE_OS2, CAIRO_SURFACE_TYPE_WIN32_PRINTING, - CAIRO_SURFACE_TYPE_QUARTZ_IMAGE + CAIRO_SURFACE_TYPE_QUARTZ_IMAGE, + CAIRO_SURFACE_TYPE_SKIA } cairo_surface_type_t; cairo_public cairo_surface_type_t