Mercurial > MadButterfly
changeset 482:d38aca825822 Android_Skia
Import more functions for Skia graphic engine.
author | Thinker K.F. Li <thinker@branda.to> |
---|---|
date | Sun, 15 Nov 2009 16:23:21 +0800 |
parents | 273307d061b7 |
children | d984a6672be7 |
files | include/mb_graph_engine_skia.h src/graph_engine_skia.cpp |
diffstat | 2 files changed, 736 insertions(+), 63 deletions(-) [+] |
line wrap: on
line diff
--- a/include/mb_graph_engine_skia.h Sun Nov 15 16:21:09 2009 +0800 +++ b/include/mb_graph_engine_skia.h Sun Nov 15 16:23:21 2009 +0800 @@ -2,6 +2,7 @@ #define __MB_GE_SKIA_H_ #include <stdio.h> +#include "mb_basic_types.h" #include "mb_img_ldr.h" /*! \defgroup mb_ge_skia MadButterfly Graphic Engine with Skia @@ -11,8 +12,6 @@ #define MBE_OPERATOR_SOURCE 1 #define MBE_STATUS_SUCCESS 0 -typedef float co_aix; - struct _mbe_text_extents_t { co_aix x_bearing; co_aix y_bearing; @@ -34,20 +33,20 @@ typedef struct _mbe_pattern_t mbe_pattern_t; typedef struct _mbe_t mbe_t; -extern void mbe_pattern_add_color_stop_rgba(mbe_pattern_t *ptn, - co_aix offset, - co_aix r, co_aix g, co_aix b, - co_aix a); extern mbe_pattern_t *mbe_pattern_create_for_surface(mbe_surface_t *surface); extern mbe_pattern_t *mbe_pattern_create_radial(co_aix cx0, co_aix cy0, co_aix radius0, co_aix cx1, co_aix cy1, - co_aix radius1); + co_aix radius1, + grad_stop_t *stops, + int stop_cnt); extern mbe_pattern_t *mbe_pattern_create_linear(co_aix x0, co_aix y0, - co_aix x1, co_aix y1); + co_aix x1, co_aix y1, + grad_stop_t *stops, + int stop_cnt); extern void mbe_pattern_set_matrix(mbe_pattern_t *ptn, const co_aix matrix[6]); -extern void mbe_pattern_destroy(mbe_pattern_t *canvas); +extern void mbe_pattern_destroy(mbe_pattern_t *ptn); extern int mbe_image_surface_get_stride(mbe_surface_t *surface); extern int mbe_image_surface_get_height(mbe_surface_t *surface);
--- a/src/graph_engine_skia.cpp Sun Nov 15 16:21:09 2009 +0800 +++ b/src/graph_engine_skia.cpp Sun Nov 15 16:23:21 2009 +0800 @@ -1,7 +1,45 @@ +/*! \page ge_layer Graphic Engine Layer + * + * Graphic Engine Layer is an abstract of graphic engine; likes Cairo + * and Skia. It provides portability for the rest of MadButterfly. + * + * The basic stratage of interface of graphic engine layer is defined + * according purpose of MadButterfly. For example, MadButterfly wants + * a function that can clear a canvas, we define a clear function. + * Never define a indirectly way to finish the function. Never define + * a way to finish the function for the reason that some engine + * require you to finish the task in that procedure. It avoids + * binding graphic engine layer with any behavior of a graphic engine, + * and provides more compatible with other engines, to define + * interface of graphic engine layer according purpose of + * MadButterfly. + * + * \section ge_mem Graphic Engine Layer Memory Management + * + * MadButterfly is responsible for management of objects and memory + * blocks returned by graphic engine layer, even for graphic engines + * that have management model. MadButterfly supposes memory blocks + * only be released when they are no more used. MadBufferfly is + * responsible for release them. So, even a graphic engine has + * reference count with objects, MadButterfly still keep a reference + * for every object returned by the engine until no one will use it. + * + * \section ge_transform Transformation of Coordination System + * + * Points of pathes are transformed when it is added to the canvas + * with the transformation matrix at the time. So, changes of + * transformation matrix of an canvas will not affect points that had + * been added. It only affects points been added when the matrix is + * setted. + */ #include <stdio.h> #include <SkCanvas.h> #include <SkBitmap.h> #include <SkShader.h> +#include <SkDevice.h> +#include <SkGradientShader.h> +#include <SkXfermode.h> +#include <SkColorFilter.h> #define C_START extern "C" { #define C_END } @@ -10,6 +48,21 @@ #include "mb_graph_engine_skia.h" #include "mb_shapes.h" +#include "mb_img_ldr.h" + +/*! \brief Source pattern + * + * For Skia, source pattern is SkShader with some decoration. Since + * SkShade will repeative tiling or extenting edge color, it can not + * stop tiling and extenting for fixed size bitmap. So, we need to + * translate mbe_paint() into a drawing of a rectangle. + */ +struct _mbe_pattern_t { + SkShader *shader; + int w, h; + int has_size; + co_aix matrix[6]; +}; struct _mbe_scaled_font_t { struct _mb_font_face_t *face; @@ -17,46 +70,409 @@ co_aix ctm[6]; }; struct _mbe_font_face_t {}; +/*! \brief MadButterfly Graphic Engine Context. + * + * A context comprises source pattern, target surface, path, + * line-width, and transform matrix. + */ struct _mbe_t { SkCanvas *canvas; - SkShader *shader; - int shader_owned; + SkPath *path, *subpath; + SkPaint *paint; + SkRegion *saved_region; + + struct _mbe_states_t *states; +}; + +struct _mbe_states_t { + mbe_pattern_t *ptn; + int ptn_owned; + co_aix line_width; + co_aix matrix[6]; + struct _mbe_states_t *next; }; #ifndef ASSERT #define ASSERT(x) #endif -void mbe_pattern_add_color_stop_rgba(mbe_pattern_t *ptn, - co_aix offset, - co_aix r, co_aix g, co_aix b, - co_aix a) {} -mbe_pattern_t *mbe_pattern_create_for_surface(mbe_surface_t *surface) {} -mbe_pattern_t *mbe_pattern_create_radial(co_aix cx0, co_aix cy0, - co_aix radius0, - co_aix cx1, co_aix cy1, - co_aix radius1) {} -mbe_pattern_t *mbe_pattern_create_linear(co_aix x0, co_aix y0, - co_aix x1, co_aix y1) {} -void mbe_pattern_set_matrix(mbe_pattern_t *ptn, - const co_aix matrix[6]) {} -void mbe_pattern_destroy(mbe_pattern_t *canvas) {} +#define PI 3.1415926535897931 + +#define CO_AIX_2_SKSCALAR(a) ((a) * 65536) +#define SKSCALAR_2_CO_AIX(a) ((co_aix)(a) / 65536) +#define MB_MATRIX_2_SKMATRIX(sk, mb) { \ + (sk).setScaleX(CO_AIX_2_SKSCALAR((mb)[0])); \ + (sk).setSkewX(CO_AIX_2_SKSCALAR((mb)[1])); \ + (sk).setTranslateX(CO_AIX_2_SKSCALAR((mb)[2])); \ + (sk).setSkewY(CO_AIX_2_SKSCALAR((mb)[3])); \ + (sk).setScaleY(CO_AIX_2_SKSCALAR((mb)[4])); \ + (sk).setTranslateY(CO_AIX_2_SKSCALAR((mb)[5])); \ + } +#define SKMATRIX_2_MB_MATRIX(mb, sk) { \ + (mb)[0] = SKSCALAR_2_CO_AIX((sk).getScaleX()); \ + (mb)[1] = SKSCALAR_2_CO_AIX((sk).getSkewX()); \ + (mb)[2] = SKSCALAR_2_CO_AIX((sk).getTranslateX()); \ + (mb)[3] = SKSCALAR_2_CO_AIX((sk).getSkewY()); \ + (mb)[4] = SKSCALAR_2_CO_AIX((sk).getScaleY()); \ + (mb)[5] = SKSCALAR_2_CO_AIX((sk).getTranslateY()); \ + } +#define MBSTOP_2_SKCOLOR(c) \ + ((((int)((c)->a * 255)) << 24) | \ + (((int)((c)->r * 255)) << 16) | \ + (((int)((c)->g * 255)) << 8) | \ + (((int)((c)->b * 255)))) + +static const co_aix id_matrix[6] = { 1, 0, 0, 0, 1, 0 }; + +static void +_prepare_sized_pattern(mbe_t *mbe, mbe_pattern_t *ptn) { + SkCanvas *canvas = mbe->canvas; + SkPath path; + co_aix x, y; + co_aix reverse[6]; + + *mbe->saved_region = canvas->getTotalClip(); + + compute_reverse(ptn->matrix, reverse); + x = 0; y = 0; + matrix_trans_pos(reverse, &x, &y); + path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y)); + x = 0; y = ptn->h; + matrix_trans_pos(reverse, &x, &y); + path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y)); + x = ptn->w; y = ptn->h; + matrix_trans_pos(reverse, &x, &y); + path.moveTo(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y)); + path.close(); + + canvas->clipPath(path, SkRegion::kIntersect_Op); +} + +static void +_finish_sized_pattern(mbe_t *mbe) { + SkCanvas *canvas = mbe->canvas; + + canvas->setClipRegion(*mbe->saved_region); +} + +static void +_canvas_device_region(SkCanvas *canvas, SkRegion *region) { + SkDevice *device; + int w, h; + + device = canvas->getDevice(); + w = device->width(); + h = device->height(); + region->setRect(0, 0, w, h); +} + +static void +_update_path(mbe_t *mbe) { + SkPath *path = mbe->path; + SkPath *subpath = mbe->subpath; + SkMatrix canvas_matrix; + SkPoint point; + + MB_MATRIX_2_SKMATRIX(canvas_matrix, mbe->states->matrix); + path->addPath(*subpath, canvas_matrix); + + subpath->getLastPt(&point); + subpath->rewind(); + subpath->moveTo(point); +} + +/* + * When a function want to use the paint associated with a canvas to + * draw, it should call _prepare_paint() can make the paint ready. + * And, call _finish_paint() when the paint is no more used. + */ +static void +_prepare_paint(mbe_t *mbe, SkPaint::Style style) { + SkPaint *paint = mbe->paint; + mbe_pattern_t *ptn = mbe->states->ptn; + SkShader *shader = ptn->shader; + co_aix matrix[6]; + SkMatrix skmatrix; + + paint->setStyle(style); + + /* Local matrix of SkShader is a mapping from source pattern to + * user space. Unlikely, for Cairo is a mapping from user space + * to source pattern. + */ + matrix_mul(mbe->states->matrix, ptn->matrix, matrix); + MB_MATRIX_2_SKMATRIX(skmatrix, matrix); + shader->setLocalMatrix(skmatrix); + paint->setShader(shader); + + if(style == SkPaint::kStroke_Style) + paint->setStrokeWidth(CO_AIX_2_SKSCALAR(mbe->states->line_width)); + + if(ptn->has_size) + _prepare_sized_pattern(mbe, ptn); +} + +static void +_finish_paint(mbe_t *mbe) { + mbe_pattern_t *ptn = mbe->states->ptn; + + mbe->paint->reset(); + if(ptn->has_size) + _finish_sized_pattern(mbe); +} + +mbe_pattern_t *mbe_pattern_create_for_surface(mbe_surface_t *surface) { + mbe_pattern_t *ptn; + SkBitmap *bitmap = (SkBitmap *)surface; -int mbe_image_surface_get_stride(mbe_surface_t *surface) {} -int mbe_image_surface_get_height(mbe_surface_t *surface) {} -int mbe_image_surface_get_width(mbe_surface_t *surface) {} -unsigned char *mbe_image_surface_get_data(mbe_surface_t *surface) {} + ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t)); + ptn->shader = SkShader::CreateBitmapShader(*bitmap, + SkShader::kClamp_TileMode, + SkShader::kClamp_TileMode); + if(ptn->shader == NULL) { + free(ptn); + return NULL; + } + + ptn->has_size = 1; + ptn->w = bitmap->width(); + ptn->h = bitmap->height(); + + memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6); + + return ptn; +} + +mbe_pattern_t * +mbe_pattern_create_radial(co_aix cx0, co_aix cy0, co_aix radius0, + co_aix cx1, co_aix cy1, co_aix radius1, + grad_stop_t *stops, int stop_cnt) { + mbe_pattern_t *ptn; + SkColor *colors; + SkScalar *poses; + grad_stop_t *stop; + SkPoint center; + int i; + + ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t)); + colors = new SkColor[stop_cnt]; + poses = new SkScalar[stop_cnt]; + if(ptn == NULL || colors == NULL || poses == NULL) + goto fail; + + center.set(CO_AIX_2_SKSCALAR(cx1), CO_AIX_2_SKSCALAR(cy1)); + + stop = stops; + for(i = 0; i < stop_cnt; i++) { + colors[i] = MBSTOP_2_SKCOLOR(stop); + poses[i] = CO_AIX_2_SKSCALAR(stop->offset); + } + + /* + * cx0, cy0 and radius0 is not used. Since Skia is still not + * support two circles radial. And, SVG 1.2 is also not support + * two circles. + */ + ptn->shader = + SkGradientShader::CreateRadial(center, CO_AIX_2_SKSCALAR(radius1), + colors, poses, stop_cnt, + SkShader::kClamp_TileMode); + if(ptn->shader == NULL) + goto fail; + + memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6); + + delete colors; + delete poses; + return ptn; + + fail: + if(ptn) free(ptn); + if(colors) delete colors; + if(poses) delete poses; + return NULL; +} + +mbe_pattern_t * +mbe_pattern_create_linear(co_aix x0, co_aix y0, + co_aix x1, co_aix y1, + grad_stop_t *stops, int stop_cnt) { + mbe_pattern_t *ptn; + SkColor *colors; + SkScalar *poses; + grad_stop_t *stop; + SkPoint points[2]; + int i; + + ptn = (mbe_pattern_t *)malloc(sizeof(mbe_pattern_t)); + colors = new SkColor[stop_cnt]; + poses = new SkScalar[stop_cnt]; + if(ptn == NULL || colors == NULL || poses == NULL) + goto fail; + + points[0].set(CO_AIX_2_SKSCALAR(x0), CO_AIX_2_SKSCALAR(y0)); + points[1].set(CO_AIX_2_SKSCALAR(x1), CO_AIX_2_SKSCALAR(y1)); + + stop = stops; + for(i = 0; i < stop_cnt; i++) { + colors[i] = MBSTOP_2_SKCOLOR(stop); + poses[i] = CO_AIX_2_SKSCALAR(stop->offset); + } + + /* + * cx0, cy0 and radius0 is not used. Since Skia is still not + * support two circles radial. And, SVG 1.2 is also not support + * two circles. + */ + ptn->shader = + SkGradientShader::CreateLinear(points, colors, poses, stop_cnt, + SkShader::kClamp_TileMode); + if(ptn->shader == NULL) + goto fail; + + memcpy(ptn->matrix, id_matrix, sizeof(co_aix) * 6); + + delete colors; + delete poses; + return ptn; + + fail: + if(ptn) free(ptn); + if(colors) delete colors; + if(poses) delete poses; + return NULL; +} + +void mbe_pattern_set_matrix(mbe_pattern_t *ptn, const co_aix matrix[6]) { + SkMatrix skmatrix; + + MB_MATRIX_2_SKMATRIX(skmatrix, matrix); + + ptn->shader->setLocalMatrix(skmatrix); +} + +void mbe_pattern_destroy(mbe_pattern_t *ptn) { + if(ptn->shader) + delete ptn->shader; + free(ptn); +} + +int mbe_image_surface_get_stride(mbe_surface_t *surface) { + return ((SkBitmap *)surface)->rowBytes(); +} + +int mbe_image_surface_get_height(mbe_surface_t *surface) { + return ((SkBitmap *)surface)->height(); +} + +int mbe_image_surface_get_width(mbe_surface_t *surface) { + return ((SkBitmap *)surface)->width(); +} + +unsigned char *mbe_image_surface_get_data(mbe_surface_t *surface) { + return (unsigned char *)((SkBitmap *)surface)->getPixels(); +} + mbe_surface_t *mbe_image_surface_create_from_png(const char *filename) {} + mbe_surface_t * mbe_image_surface_create_for_data(unsigned char *data, mb_img_fmt_t fmt, int width, int height, - int stride) {} -mb_img_fmt_t mbe_image_surface_get_format(mbe_surface_t *surface) {} + int stride) { + SkBitmap *bitmap; + SkBitmap::Config cfg; + + switch(fmt) { + case MB_IFMT_ARGB32: + cfg = SkBitmap::kARGB_8888_Config; break; + + case MB_IFMT_A8: + cfg = SkBitmap::kA8_Config; break; + + case MB_IFMT_A1: + cfg = SkBitmap::kA1_Config; break; + + case MB_IFMT_RGB16_565: + cfg = SkBitmap::kRGB_565_Config; break; + + case MB_IFMT_RGB24: + default: + return NULL; + } + + bitmap = new SkBitmap(); + if(bitmap == NULL) + return NULL; + + bitmap->setConfig(cfg, width, height, stride); + bitmap->setPixels(data); + + return (mbe_surface_t *)bitmap; +} + +mb_img_fmt_t mbe_image_surface_get_format(mbe_surface_t *surface) { + SkBitmap *bitmap = (SkBitmap *)surface; + mb_img_fmt_t fmt; + SkBitmap::Config cfg; + + cfg = bitmap->getConfig(); + switch(cfg) { + case SkBitmap::kARGB_8888_Config: + fmt = MB_IFMT_ARGB32; break; + + case SkBitmap::kA8_Config: + fmt = MB_IFMT_A8; break; + + case SkBitmap::kA1_Config: + fmt = MB_IFMT_A1; break; + + case SkBitmap::kRGB_565_Config: + fmt = MB_IFMT_RGB16_565; break; + + default: + fmt = MB_IFMT_DUMMY; + } + + return fmt; +} + mbe_surface_t * -mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height) {} +mbe_image_surface_create(mb_img_fmt_t fmt, int width, int height) { + SkBitmap *bitmap; + SkBitmap::Config cfg; -mbe_scaled_font_t *mbe_scaled_font_reference(mbe_scaled_font_t *scaled) {} + switch(fmt) { + case MB_IFMT_ARGB32: + cfg = SkBitmap::kARGB_8888_Config; break; + + case MB_IFMT_A8: + cfg = SkBitmap::kA8_Config; break; + + case MB_IFMT_A1: + cfg = SkBitmap::kA1_Config; break; + + case MB_IFMT_RGB16_565: + cfg = SkBitmap::kRGB_565_Config; break; + + case MB_IFMT_RGB24: + default: + return NULL; + } + + bitmap = new SkBitmap(); + if(bitmap == NULL) + return NULL; + + bitmap->setConfig(cfg, width, height); + bitmap->allocPixels(); + + return (mbe_surface_t *)bitmap; +} + +mbe_scaled_font_t *mbe_scaled_font_reference(mbe_scaled_font_t *scaled) { +} + void mbe_scaled_font_destroy(mbe_scaled_font_t *scaled) {} mbe_font_face_t *mbe_font_face_reference(mbe_font_face_t *face) {} mbe_scaled_font_t * @@ -68,75 +484,333 @@ mbe_text_extents_t *extents) {} void mbe_font_face_destroy(mbe_font_face_t *face) {} -void mbe_paint_with_alpha(mbe_t *canvas, co_aix alpha) {} + +void mbe_paint_with_alpha(mbe_t *canvas, co_aix alpha) { + SkPaint *paint = canvas->paint; + SkColorFilter *filter; + SkColor color; + + color = ((uint32_t)(alpha * 255)) << 24; + filter = + SkColorFilter::CreatePorterDuffFilter(color, + SkPorterDuff::kSrcOver_Mode); + mbe_paint(canvas); + +} + void mbe_surface_destroy(mbe_surface_t *surface) {} void mbe_set_source_rgba(mbe_t *canvas, co_aix r, co_aix g, co_aix b, co_aix a) {} void mbe_set_scaled_font(mbe_t *canvas, const mbe_scaled_font_t *scaled) {} void mbe_set_source_rgb(mbe_t *canvas, co_aix r, co_aix g, co_aix b) {} -void mbe_set_line_width(mbe_t *canvas, co_aix width) {} + +void mbe_set_line_width(mbe_t *canvas, co_aix width) { + canvas->states->line_width = width; +} + mbe_font_face_t *mbe_get_font_face(mbe_t *canvas) {} -void mbe_fill_preserve(mbe_t *canvas) {} -void mbe_set_source(mbe_t *canvas, mbe_pattern_t *source) {} -void mbe_reset_clip(mbe_t *canvas) {} -mbe_surface_t *mbe_get_target(mbe_t *canvas) {} -void mbe_close_path(mbe_t *canvas) {} + +void mbe_fill_preserve(mbe_t *canvas) { + mbe_pattern_t *ptn = canvas->states->ptn; + SkPaint *paint = canvas->paint; + SkPath *path = canvas->path; + SkRegion *saved_clip = NULL; + co_aix x, y; + + ASSERT(paint); + ASSERT(ptn); + ASSERT(path); + + if(!canvas->subpath->isEmpty()) + _update_path(canvas); + + _prepare_paint(canvas, SkPaint::kFill_Style); + + canvas->canvas->drawPath(*path, *paint); + + _finish_paint(canvas); +} + +void mbe_set_source(mbe_t *canvas, mbe_pattern_t *source) { + canvas->states->ptn = source; +} + +void mbe_reset_clip(mbe_t *canvas) { + SkRegion clip; + + _canvas_device_region(canvas->canvas, &clip); + canvas->canvas->setClipRegion(clip); +} + +mbe_surface_t *mbe_get_target(mbe_t *canvas) { + return (mbe_surface_t *)&canvas->canvas->getDevice()->accessBitmap(false); +} + +void mbe_close_path(mbe_t *canvas) { + canvas->subpath->close(); +} + void mbe_text_path(mbe_t *canvas, const char *txt) {} + void mbe_rectangle(mbe_t *canvas, co_aix x, co_aix y, - co_aix width, co_aix height) {} -int mbe_in_stroke(mbe_t *canvas, co_aix x, co_aix y) {} -void mbe_new_path(mbe_t *canvas) {} + co_aix width, co_aix height) { + SkPath *subpath = canvas->subpath; + + subpath->addRect(CO_AIX_2_SKSCALAR(x), CO_AIX_2_SKSCALAR(y), + CO_AIX_2_SKSCALAR(x + width), + CO_AIX_2_SKSCALAR(y + height)); +} + +int mbe_in_stroke(mbe_t *canvas, co_aix x, co_aix y) { + return 0; +} + +void mbe_new_path(mbe_t *canvas) { + canvas->subpath->reset(); +} + void mbe_curve_to(mbe_t *canvas, co_aix x1, co_aix y1, co_aix x2, co_aix y2, - co_aix x3, co_aix y3) {} -void mbe_restore(mbe_t *canvas) {} -void mbe_move_to(mbe_t *canvas, co_aix x, co_aix y) {} -void mbe_line_to(mbe_t *canvas, co_aix x, co_aix y) {} -int mbe_in_fill(mbe_t *canvas, co_aix x, co_aix y) {} -void mbe_stroke(mbe_t *canvas) {} + co_aix x3, co_aix y3) { + SkPath *subpath = canvas->subpath; + + subpath->cubicTo(CO_AIX_2_SKSCALAR(x1), CO_AIX_2_SKSCALAR(y1), + CO_AIX_2_SKSCALAR(x2), CO_AIX_2_SKSCALAR(y2), + CO_AIX_2_SKSCALAR(x3), CO_AIX_2_SKSCALAR(y3)); +} + +void mbe_restore(mbe_t *canvas) { + struct _mbe_states_t *states; + + _update_path(canvas); + + states = canvas->states; + ASSERT(states->next); + canvas->states = states->next; + free(states); +} + +void mbe_move_to(mbe_t *canvas, co_aix x, co_aix y) { + canvas->subpath->moveTo(CO_AIX_2_SKSCALAR(x), + CO_AIX_2_SKSCALAR(y)); +} + +void mbe_line_to(mbe_t *canvas, co_aix x, co_aix y) { + canvas->subpath->lineTo(CO_AIX_2_SKSCALAR(x), + CO_AIX_2_SKSCALAR(y)); +} + +int mbe_in_fill(mbe_t *canvas, co_aix x, co_aix y) { + SkRegion region, dev_region; + bool in_fill; + + if(!canvas->subpath->isEmpty()) + _update_path(canvas); + + _canvas_device_region(canvas->canvas, &dev_region); + region.setPath(*canvas->path, dev_region); + + in_fill = region.contains(x, y); + + return in_fill; +} + +void mbe_stroke(mbe_t *canvas) { + SkPath *path = canvas->path; + SkPaint *paint = canvas->paint; + + ASSERT(ptn); + ASSERT(path); + ASSERT(paint); + + if(!canvas->subpath->isEmpty()) + _update_path(canvas); + + _prepare_paint(canvas, SkPaint::kStroke_Style); + + canvas->canvas->drawPath(*path, *paint); + + _finish_paint(canvas); + + path->reset(); +} mbe_t *mbe_create(mbe_surface_t *target) { mbe_t *mbe; + struct _mbe_states_t *states; SkBitmap *bitmap = (SkBitmap *)target; mbe = (mbe_t *)malloc(sizeof(mbe_t)); if(mbe == NULL) return NULL; - mbe->canvas = new SkCanvas(*bitmap); - if(mbe->canvas == NULL) { + mbe->states = (struct _mbe_states_t *) + malloc(sizeof(struct _mbe_states_t)); + states = mbe->states; + if(states == NULL) { free(mbe); return NULL; } - mbe->shader = NULL; - mbe->shader_owned = 0; + mbe->canvas = new SkCanvas(*bitmap); + mbe->path = new SkPath(); + mbe->subpath = new SkPath(); + mbe->saved_region = new SkRegion(); + mbe->paint = new SkPaint(); + states->ptn = NULL; + states->ptn_owned = 0; + states->line_width = 0; + states->next = NULL; + + if(mbe->canvas == NULL || mbe->path == NULL || + mbe->subpath == NULL || mbe->paint == NULL || + mbe->saved_region == NULL) + goto fail; + memcpy(states->matrix, id_matrix, sizeof(co_aix) * 6); + return mbe; + + fail: + if(mbe->canvas) delete mbe->canvas; + if(mbe->path) delete mbe->path; + if(mbe->subpath) delete mbe->subpath; + if(mbe->paint) delete mbe->paint; + if(mbe->saved_region) delete mbe->saved_region; + free(states); + free(mbe); + + return NULL; } void mbe_destroy(mbe_t *canvas) { + struct _mbe_states_t *states; + delete canvas->canvas; - if(canvas->shader && canvas->shader_owned) - delete canvas->shader; + delete canvas->path; + delete canvas->subpath; + delete canvas->paint; + delete canvas->saved_region; + while(canvas->states) { + states = canvas->states; + canvas->states = states->next; + + if(states->ptn && states->ptn_owned) + mbe_pattern_destroy(states->ptn); + free(states); + } free(canvas); } -void mbe_paint(mbe_t *canvas) {} -void mbe_save(mbe_t *canvas) {} -void mbe_fill(mbe_t *canvas) {} -void mbe_clip(mbe_t *canvas) {} +void mbe_paint(mbe_t *canvas) { + SkPaint *paint = canvas->paint; + + ASSERT(paint); + + _prepare_paint(canvas, SkPaint::kFill_Style); + + canvas->canvas->drawPaint(*paint); + + _finish_paint(canvas); +} + +void mbe_save(mbe_t *canvas) { + struct _mbe_states_t *states; + + states = (struct _mbe_states_t *)malloc(sizeof(struct _mbe_states_t)); + ASSERT(states); + + memcpy(states, canvas->states, sizeof(struct _mbe_states_t)); + states->next = canvas->states; + canvas->states = states; +} + +void mbe_fill(mbe_t *canvas) { + mbe_fill_preserve(canvas); + canvas->path->reset(); +} + +void mbe_clip(mbe_t *canvas) { + if(!canvas->subpath->isEmpty()) + _update_path(canvas); + + canvas->canvas->clipPath(*canvas->path, SkRegion::kIntersect_Op); + canvas->path->reset(); +} mbe_font_face_t * mbe_query_font_face(const char *family, int slant, int weight) {} void mbe_free_font_face(mbe_font_face_t *face) {} -void mbe_clear(mbe_t *canvas) {} -void mbe_copy_source(mbe_t *canvas) {} -void mbe_transform(mbe_t *mbe, co_aix matrix[6]) {} +void mbe_clear(mbe_t *canvas) { + SkColor color = 0; + + canvas->canvas->drawColor(color, SkPorterDuff::kClear_Mode); +} + +void mbe_copy_source(mbe_t *canvas) { + SkPaint *paint = canvas->paint; + SkXfermode *mode; + + _prepare_paint(canvas, SkPaint::kFill_Style); + mode = SkPorterDuff::CreateXfermode(SkPorterDuff::kSrc_Mode); + paint->setXfermode(mode); + mode->unref(); + + canvas->canvas->drawPaint(*paint); + + _finish_paint(canvas); +} + +void mbe_transform(mbe_t *mbe, co_aix matrix[6]) { + _update_path(mbe); + + matrix_mul(matrix, mbe->states->matrix, mbe->states->matrix); +} + void mbe_arc(mbe_t *mbe, co_aix x, co_aix y, co_aix radius, - co_aix angle_start, co_aix angle_stop) {} + co_aix angle_start, co_aix angle_stop) { + SkPoint point; + SkPath *subpath = mbe->subpath; + SkRect rect; + SkScalar x0, y0; + SkScalar ang_start, ang_stop; + SkScalar sweep; + SkScalar r; /* radius */ + + subpath->getLastPt(&point); + x0 = point.fX; + y0 = point.fX; + r = CO_AIX_2_SKSCALAR(radius); + ang_start = CO_AIX_2_SKSCALAR(angle_start * 180 / PI); + ang_stop = CO_AIX_2_SKSCALAR(angle_stop * 180 / PI); + + /* Skia can only draw an arc in clockwise directly. We negative + * start and stop point to draw the arc in the mirror along x-axis + * in a sub-path. Then, the sub-path are reflected along x-axis, + * again. We get a right path, and add it to the path of mbe_t. + */ + if(ang_start > ang_stop) { + SkPath tmppath; + SkMatrix matrix; + co_aix reflect[6] = { 1, 0, 0, + 0, -1, 0}; + + rect.set(-r, -r, r, r); + sweep = ang_start - ang_stop; + tmppath.arcTo(rect, -ang_start, sweep, false); + + reflect[2] = x; + reflect[5] = y; + MB_MATRIX_2_SKMATRIX(matrix, reflect); + subpath->addPath(tmppath, matrix); + } else { + rect.set(x0 - r, y0 - r, x0 + r, y0 + r); + sweep = ang_stop - ang_start; + subpath->arcTo(rect, ang_start, sweep, false); + } +} C_END