static void svg_rect_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { Fixed rx = (atts->rx ? atts->rx->value : 0); Fixed ry = (atts->ry ? atts->ry->value : 0); Fixed x = (atts->x ? atts->x->value : 0); Fixed y = (atts->y ? atts->y->value : 0); Fixed width = (atts->width ? atts->width->value : 0); Fixed height = (atts->height ? atts->height->value : 0); drawable_reset_path(stack); if (!width || !height) return; /*we follow SVG 1.1 and not 1.2 !!*/ if (rx || ry) { Fixed cx, cy; if (rx >= width/2) rx = width/2; if (ry >= height/2) ry = height/2; if (rx == 0) rx = ry; if (ry == 0) ry = rx; gf_path_add_move_to(stack->path, x+rx, y); if (width-rx!=rx) gf_path_add_line_to(stack->path, x+width-rx, y); cx = x+width-rx; cy = y+ry; svg_rect_add_arc(stack->path, x+width, y+ry, cx, cy, rx, ry); if (height-ry!=ry) gf_path_add_line_to(stack->path, x+width, y+height-ry); cx = x+width-rx; cy = y+height-ry; svg_rect_add_arc(stack->path, x+width-rx, y+height, cx, cy, rx, ry); if (width-rx!=rx) gf_path_add_line_to(stack->path, x+rx, y+height); cx = x+rx; cy = y+height-ry; svg_rect_add_arc(stack->path, x, y+height-ry, cx, cy, rx, ry); if (height-ry!=ry) gf_path_add_line_to(stack->path, x, y+ry); cx = x+rx; cy = y+ry; svg_rect_add_arc(stack->path, x+rx, y, cx, cy, rx, ry); gf_path_close(stack->path); } else { gf_path_add_move_to(stack->path, x, y); gf_path_add_line_to(stack->path, x+width, y); gf_path_add_line_to(stack->path, x+width, y+height); gf_path_add_line_to(stack->path, x, y+height); gf_path_close(stack->path); } }
static void svg_sani_render_line(GF_Node *node, void *rs, Bool is_destroy) { SVG_SANI_lineElement *line = (SVG_SANI_lineElement *)node; Drawable *cs = (Drawable *)gf_node_get_private(node); RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { DestroyDrawableNode(node); return; } if (eff->traversing_mode==TRAVERSE_DRAW) { drawable_draw(eff); return; } else if (eff->traversing_mode==TRAVERSE_PICK) { drawable_pick(eff); return; } svg_sani_render_base(node, (RenderEffect2D *)rs); if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) { drawable_reset_path(cs); gf_path_add_move_to(cs->path, line->x1.value, line->y1.value); gf_path_add_line_to(cs->path, line->x2.value, line->y2.value); gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY); cs->flags |= DRAWABLE_HAS_CHANGED; } svg_sani_DrawablePostRender(cs, (SVG_SANI_TransformableElement *)line, (RenderEffect2D *)rs, 0, 0); }
int ft_move_to(FTCST FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; gf_path_add_move_to(ftol->path, INT2FIX(to->x), INT2FIX(to->y) ); ftol->last_x = (s32) to->x; ftol->last_y = (s32) to->y; return 0; }
static int ft_move_to(const FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; gf_path_add_move_to(ftol->path, INT2FIX(to->x), INT2FIX(to->y) ); ftol->last_x = to->x; ftol->last_y = to->y; return 0; }
void visual_2d_fill_irect(GF_VisualManager *visual, GF_IRect *rc, u32 fill, u32 strike) { GF_Path *path; GF_Path *outline; GF_PenSettings pen; GF_Raster2D *raster = visual->compositor->rasterizer; #ifdef SKIP_DRAW return; #endif if (!rc) return; if (!visual->is_attached) return; if (!fill && !strike ) return; /*no aa*/ visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1); raster->surface_set_matrix(visual->raster_surface, NULL); raster->surface_set_raster_level(visual->raster_surface, GF_RASTER_HIGH_SPEED); raster->surface_set_matrix(visual->raster_surface, NULL); path = gf_path_new(); gf_path_add_move_to(path, INT2FIX(rc->x-1), INT2FIX(rc->y+2-rc->height)); gf_path_add_line_to(path, INT2FIX(rc->x+rc->width-2), INT2FIX(rc->y+2-rc->height)); gf_path_add_line_to(path, INT2FIX(rc->x+rc->width), INT2FIX(rc->y)); gf_path_add_line_to(path, INT2FIX(rc->x), INT2FIX(rc->y)); gf_path_close(path); if (fill) { raster->surface_set_path(visual->raster_surface, path); raster->stencil_set_brush_color(visual->raster_brush, fill); raster->surface_set_clipper(visual->raster_surface, rc); raster->surface_fill(visual->raster_surface, visual->raster_brush); raster->surface_set_path(visual->raster_surface, NULL); } if (strike) { memset(&pen, 0, sizeof(GF_PenSettings)); pen.width = 2; pen.align = GF_PATH_LINE_INSIDE; pen.join = GF_LINE_JOIN_BEVEL; outline = gf_path_get_outline(path, pen); outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO; raster->surface_set_path(visual->raster_surface, outline); raster->stencil_set_brush_color(visual->raster_brush, strike); raster->surface_set_clipper(visual->raster_surface, rc); raster->surface_fill(visual->raster_surface, visual->raster_brush); raster->surface_set_path(visual->raster_surface, NULL); gf_path_del(outline); } gf_path_del(path); }
static void svg_polyline_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { u32 i, nbPoints; drawable_reset_path(stack); if (atts->points) nbPoints = gf_list_count(*atts->points); else nbPoints = 0; if (nbPoints) { SVG_Point *p = (SVG_Point *)gf_list_get(*atts->points, 0); gf_path_add_move_to(stack->path, p->x, p->y); for (i = 1; i < nbPoints; i++) { p = (SVG_Point *)gf_list_get(*atts->points, i); gf_path_add_line_to(stack->path, p->x, p->y); } } else { gf_path_add_move_to(stack->path, 0, 0); } }
GF_FontManager *gf_font_manager_new(GF_User *user) { char *def_font = "SERIF"; u32 i, count; GF_FontManager *font_mgr; GF_FontReader *ifce; const char *opt; ifce = NULL; opt = gf_cfg_get_key(user->config, "FontEngine", "FontReader"); if (opt) { ifce = (GF_FontReader *) gf_modules_load_interface_by_name(user->modules, opt, GF_FONT_READER_INTERFACE); if (ifce && ifce->init_font_engine(ifce) != GF_OK) { gf_modules_close_interface((GF_BaseInterface *)ifce); ifce = NULL; } } if (!ifce) { count = gf_modules_get_count(user->modules); for (i=0; i<count; i++) { ifce = (GF_FontReader *) gf_modules_load_interface(user->modules, i, GF_FONT_READER_INTERFACE); if (!ifce) continue; if (ifce->init_font_engine(ifce) != GF_OK) { gf_modules_close_interface((GF_BaseInterface *)ifce); ifce = NULL; continue; } gf_cfg_set_key(user->config, "FontEngine", "FontReader", ifce->module_name); break; } } GF_SAFEALLOC(font_mgr, GF_FontManager); font_mgr->reader = ifce; font_mgr->id_buffer_size = 20; font_mgr->id_buffer = gf_malloc(sizeof(u32)*font_mgr->id_buffer_size); gf_font_manager_set_font(font_mgr, &def_font, 1, 0); font_mgr->default_font = font_mgr->font; font_mgr->line_path= gf_path_new(); gf_path_add_move_to(font_mgr->line_path, -FIX_ONE/2, FIX_ONE/2); gf_path_add_line_to(font_mgr->line_path, FIX_ONE/2, FIX_ONE/2); gf_path_add_line_to(font_mgr->line_path, FIX_ONE/2, -FIX_ONE/2); gf_path_add_line_to(font_mgr->line_path, -FIX_ONE/2, -FIX_ONE/2); gf_path_close(font_mgr->line_path); opt = gf_cfg_get_key(user->config, "FontEngine", "WaitForFontLoad"); if (!opt) gf_cfg_set_key(user->config, "FontEngine", "WaitForFontLoad", "no"); if (opt && !strcmp(opt, "yes")) font_mgr->wait_font_load = 1; return font_mgr; }
static void svg_sani_render_polygon(GF_Node *node, void *rs, Bool is_destroy) { SVG_SANI_polygonElement *polygon = (SVG_SANI_polygonElement *)node; Drawable *cs = (Drawable *)gf_node_get_private(node); RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { DestroyDrawableNode(node); return; } if (eff->traversing_mode==TRAVERSE_DRAW) { drawable_draw(eff); return; } else if (eff->traversing_mode==TRAVERSE_PICK) { drawable_pick(eff); return; } svg_sani_render_base(node, (RenderEffect2D *)rs); if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) { u32 i; u32 nbPoints = gf_list_count(polygon->points); drawable_reset_path(cs); if (nbPoints) { SVG_Point *p = (SVG_Point *)gf_list_get(polygon->points, 0); gf_path_add_move_to(cs->path, p->x, p->y); for (i = 1; i < nbPoints; i++) { p = (SVG_Point *)gf_list_get(polygon->points, i); gf_path_add_line_to(cs->path, p->x, p->y); } gf_path_close(cs->path); } else { gf_path_add_move_to(cs->path, 0, 0); } gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY); cs->flags |= DRAWABLE_HAS_CHANGED; } svg_sani_DrawablePostRender(cs, (SVG_SANI_TransformableElement *)polygon, (RenderEffect2D *)rs, 0, 0); }
/*adds rectangle centered on cx, cy*/ GF_EXPORT GF_Err gf_path_add_rect_center(GF_Path *gp, Fixed cx, Fixed cy, Fixed w, Fixed h) { GF_Err e = gf_path_add_move_to(gp, cx - w/2, cy - h/2); if (e) return e; e = gf_path_add_line_to(gp, cx + w/2, cy - h/2); if (e) return e; e = gf_path_add_line_to(gp, cx + w/2, cy + h/2); if (e) return e; e = gf_path_add_line_to(gp, cx - w/2, cy + h/2); if (e) return e; return gf_path_close(gp); }
static void ils2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { u32 i; Bool started; SFVec2f *pts; M_IndexedLineSet2D *ils2D; M_Coordinate2D *coord; if (! gf_node_dirty_get(node)) return; drawable_reset_path(stack); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); ils2D = (M_IndexedLineSet2D *)node; coord = (M_Coordinate2D *)ils2D->coord; pts = coord->point.vals; if (ils2D->coordIndex.count > 0) { started = 0; for (i=0; i < ils2D->coordIndex.count; i++) { /*NO close on ILS2D*/ if (ils2D->coordIndex.vals[i] == -1) { started = 0; } else if (!started) { started = 1; gf_path_add_move_to(stack->path, pts[ils2D->coordIndex.vals[i]].x, pts[ils2D->coordIndex.vals[i]].y); } else { gf_path_add_line_to(stack->path, pts[ils2D->coordIndex.vals[i]].x, pts[ils2D->coordIndex.vals[i]].y); } } } else if (coord->point.count) { gf_path_add_move_to(stack->path, pts[0].x, pts[0].y); for (i=1; i < coord->point.count; i++) { gf_path_add_line_to(stack->path, pts[i].x, pts[i].y); } } stack->path->flags |= GF_PATH_FILL_ZERO_NONZERO; }
GF_EXPORT GF_Err gf_path_add_rect(GF_Path *gp, Fixed ox, Fixed oy, Fixed w, Fixed h) { GF_Err e = gf_path_add_move_to(gp, ox, oy); if (e) return e; e = gf_path_add_line_to(gp, ox + w, oy); if (e) return e; e = gf_path_add_line_to(gp, ox+w, oy-h); if (e) return e; e = gf_path_add_line_to(gp, ox, oy-h); if (e) return e; return gf_path_close(gp); }
GF_EXPORT GF_Err gf_path_add_arc(GF_Path *gp, Fixed radius, Fixed start_angle, Fixed end_angle, u32 close_type) { GF_Err e; Fixed _vx, _vy, step, cur; s32 i, do_run; step = (end_angle - start_angle) / (GF_2D_DEFAULT_RES); radius *= 2; /*pie*/ i=0; if (close_type==2) { gf_path_add_move_to(gp, 0, 0); i=1; } do_run = 1; cur=start_angle; while (do_run) { if (cur>=end_angle) { do_run = 0; cur = end_angle; } _vx = gf_mulfix(radius, gf_cos(cur)); _vy = gf_mulfix(radius, gf_sin(cur)); if (!i) { e = gf_path_add_move_to(gp, _vx, _vy); i = 1; } else { e = gf_path_add_line_to(gp, _vx, _vy); } if (e) return e; cur+=step; } if (close_type) e = gf_path_close(gp); return e; }
static void polyline2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { u32 i; X_Polyline2D *a = (X_Polyline2D *) node; drawable_reset_path(stack); for (i=0; i<a->lineSegments.count; i++) { if (i) { gf_path_add_line_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y); } else { gf_path_add_move_to(stack->path, a->lineSegments.vals[i].x, a->lineSegments.vals[i].y); } } gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
static void triangleset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { u32 i, count; X_TriangleSet2D *p = (X_TriangleSet2D *)node; drawable_reset_path(stack); count = p->vertices.count; while (count%3) count--; for (i=0; i<count; i+=3) { gf_path_add_move_to(stack->path, p->vertices.vals[i].x, p->vertices.vals[i].y); gf_path_add_line_to(stack->path, p->vertices.vals[i+1].x, p->vertices.vals[i+1].y); gf_path_add_line_to(stack->path, p->vertices.vals[i+2].x, p->vertices.vals[i+2].y); gf_path_close(stack->path); } gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
GF_EXPORT GF_Err gf_path_add_ellipse(GF_Path *gp, Fixed cx, Fixed cy, Fixed a_axis, Fixed b_axis) { GF_Err e; Fixed _vx, _vy, cur; u32 i; a_axis /= 2; b_axis /= 2; e = gf_path_add_move_to(gp, cx+a_axis, cy); if (e) return e; for (i=1; i<GF_2D_DEFAULT_RES; i++) { cur = GF_2PI*i/GF_2D_DEFAULT_RES; _vx = gf_mulfix(a_axis, gf_cos(cur) ); _vy = gf_mulfix(b_axis, gf_sin(cur) ); e = gf_path_add_line_to(gp, _vx + cx, _vy + cy); if (e) return e; } return gf_path_close(gp); }
static void svg_line_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { drawable_reset_path(stack); gf_path_add_move_to(stack->path, (atts->x1 ? atts->x1->value : 0), (atts->y1 ? atts->y1->value : 0)); gf_path_add_line_to(stack->path, (atts->x2 ? atts->x2->value : 0), (atts->y2 ? atts->y2->value : 0)); }
void visual_2d_fill_rect(GF_VisualManager *visual, DrawableContext *ctx, GF_Rect *_rc, u32 color, u32 strike_color, GF_TraverseState *tr_state) { GF_Path *path; GF_Rect *rc; GF_Raster2D *raster = visual->compositor->rasterizer; #ifdef SKIP_DRAW return; #endif if (! visual->CheckAttached(visual) ) return; if (!color && !strike_color) return; if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) { if (visual->compositor->draw_bvol) draw_clipper(visual, ctx); return; } /*no aa*/ visual_2d_set_options(visual->compositor, visual->raster_surface, 0, 1); if (_rc) { rc = _rc; raster->surface_set_matrix(visual->raster_surface, &ctx->transform); } else { rc = &ctx->bi->unclip; raster->surface_set_matrix(visual->raster_surface, NULL); } path = gf_path_new(); gf_path_add_move_to(path, rc->x, rc->y-rc->height); gf_path_add_line_to(path, rc->x+rc->width, rc->y-rc->height); gf_path_add_line_to(path, rc->x+rc->width, rc->y); gf_path_add_line_to(path, rc->x, rc->y); gf_path_close(path); if (color) { /*push path*/ raster->surface_set_path(visual->raster_surface, path); raster->stencil_set_brush_color(visual->raster_brush, color); visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); } if (strike_color) { GF_Path *outline; GF_PenSettings pen; memset(&pen, 0, sizeof(GF_PenSettings)); pen.width = 1; pen.join = GF_LINE_JOIN_BEVEL; pen.dash = GF_DASH_STYLE_DOT; raster->stencil_set_brush_color(visual->raster_brush, strike_color); outline = gf_path_get_outline(path, pen); outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO; raster->surface_set_path(visual->raster_surface, outline); visual_2d_fill_path(visual, ctx, visual->raster_brush, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); gf_path_del(outline); } gf_path_del(path); }
static void ILS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { GF_Path *path; SFVec2f *pts; SFColor col; Fixed alpha; u32 i, count, col_ind, ind, end_at; u32 linear[2], *colors; SFVec2f start, end; u32 j, num_col; GF_STENCIL grad; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ils2D->coord; M_Color *color = (M_Color *) ils2D->color; end.x = end.y = 0; if (!coord->point.count) return; if (! ils2D->color) { /*no texturing*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; pts = coord->point.vals; if (!ils2D->colorPerVertex || (color->color.count<2) ) { count = 0; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; ind = ils2D->coordIndex.count ? ils2D->coordIndex.vals[0] : 0; i=1; path = gf_path_new(); gf_path_add_move_to(path, pts[ind].x, pts[ind].y); for (; i<=end_at; i++) { if ((i==end_at) || (ils2D->coordIndex.count && ils2D->coordIndex.vals[i] == -1)) { /*draw current*/ col_ind = (ils2D->colorIndex.count && (ils2D->colorIndex.vals[count]>=0) ) ? (u32) ils2D->colorIndex.vals[count] : count; if (col_ind>=color->color.count) col_ind=color->color.count-1; col = color->color.vals[col_ind]; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); i++; if (i>=end_at) break; gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_move_to(path, pts[ind].x, pts[ind].y); if (ils2D->coordIndex.count) count++; continue; } else { ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0) ) ? (u32) ils2D->coordIndex.vals[i] : i; gf_path_add_line_to(path, pts[ind].x, pts[ind].y); } } gf_path_del(path); return; } raster = NULL; end_at = ils2D->coordIndex.count; if (!end_at) end_at = coord->point.count; count = 0; col_ind = 0; ind = 0; i=0; path = gf_path_new(); while (1) { gf_path_reset(path); ind = (ils2D->coordIndex.count && (ils2D->coordIndex.vals[i]>=0)) ? (u32) ils2D->coordIndex.vals[i] : i; start = pts[ind]; num_col = 1; i++; gf_path_add_move_to(path, start.x, start.y); if (ils2D->coordIndex.count) { while (ils2D->coordIndex.vals[i] != -1) { end = pts[ils2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; if (i >= ils2D->coordIndex.count) break; } } else { while (i<end_at) { end = pts[i]; gf_path_add_line_to(path, end.x, end.y); i++; num_col++; } } raster = tr_state->visual->compositor->rasterizer; /*use linear gradient*/ if (num_col==2) { Fixed pos[2]; grad = raster->stencil_new(raster, GF_STENCIL_LINEAR_GRADIENT); if (ils2D->colorIndex.count) { col = color->color.vals[ils2D->colorIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->colorIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind]]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[ils2D->coordIndex.vals[col_ind+1]]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { col = color->color.vals[col_ind]; linear[0] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col = color->color.vals[col_ind+1]; linear[1] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } pos[0] = 0; pos[1] = FIX_ONE; raster->stencil_set_linear_gradient(grad, start.x, start.y, end.x, end.y); raster->stencil_set_gradient_interpolation(grad, pos, linear, 2); } else { grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); if (grad) { raster->stencil_set_vertex_path(grad, path); colors = (u32*)gf_malloc(sizeof(u32) * num_col); for (j=0; j<num_col; j++) { if (ils2D->colorIndex.count>0) { col = color->color.vals[ils2D->colorIndex.vals[col_ind+j]]; } else if (ils2D->coordIndex.count) { col = color->color.vals[ils2D->coordIndex.vals[col_ind+j]]; } else { col = color->color.vals[col_ind+j]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); } } raster->stencil_set_matrix(grad, &ctx->transform); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, grad, tr_state); if (grad) raster->stencil_delete(grad); i ++; col_ind += num_col + 1; if (i >= ils2D->coordIndex.count) break; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }
GF_EXPORT GF_Err gf_path_add_move_to_vec(GF_Path *gp, GF_Point2D *pt) { return gf_path_add_move_to(gp, pt->x, pt->y); }
void curve2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state, MFInt32 *idx) { M_Curve2D *c2D; SFVec2f orig, ct_orig, ct_end, end; u32 cur_index, i, remain, type_count, pt_count; SFVec2f *pts; M_Coordinate2D *coord; c2D = (M_Curve2D *)node; coord = (M_Coordinate2D *)c2D->point; drawable_reset_path(stack); if (!coord) return; stack->path->fineness = c2D->fineness; if (tr_state->visual->compositor->high_speed) stack->path->fineness /= 2; pts = coord->point.vals; if (!pts) return; cur_index = c2D->type.count ? 1 : 0; /*if the first type is a moveTo skip initial moveTo*/ i=0; if (cur_index) { while (c2D->type.vals[i]==0) i++; } ct_orig = orig = pts[ GET_IDX(i) ]; gf_path_add_move_to(stack->path, orig.x, orig.y); pt_count = coord->point.count; type_count = c2D->type.count; for (; i<type_count; i++) { switch (c2D->type.vals[i]) { /*moveTo, 1 point*/ case 0: CHECK_VALID_C2D(0); orig = pts[ GET_IDX(cur_index) ]; if (i) gf_path_add_move_to(stack->path, orig.x, orig.y); cur_index += 1; break; /*lineTo, 1 point*/ case 1: CHECK_VALID_C2D(0); end = pts[ GET_IDX(cur_index) ]; gf_path_add_line_to(stack->path, end.x, end.y); orig = end; cur_index += 1; break; /*curveTo, 3 points*/ case 2: CHECK_VALID_C2D(2); ct_orig = pts[ GET_IDX(cur_index) ]; ct_end = pts[ GET_IDX(cur_index+1) ]; end = pts[ GET_IDX(cur_index+2) ]; gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); cur_index += 3; ct_orig = ct_end; orig = end; break; /*nextCurveTo, 2 points (cf spec)*/ case 3: CHECK_VALID_C2D(1); ct_orig.x = 2*orig.x - ct_orig.x; ct_orig.y = 2*orig.y - ct_orig.y; ct_end = pts[ GET_IDX(cur_index) ]; end = pts[ GET_IDX(cur_index+1) ]; gf_path_add_cubic_to(stack->path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); cur_index += 2; ct_orig = ct_end; orig = end; break; /*all XCurve2D specific*/ /*CW and CCW ArcTo*/ case 4: case 5: CHECK_VALID_C2D(2); ct_orig = pts[ GET_IDX(cur_index) ]; ct_end = pts[ GET_IDX(cur_index+1) ]; end = pts[ GET_IDX(cur_index+2) ]; gf_path_add_arc_to(stack->path, end.x, end.y, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, (c2D->type.vals[i]==5) ? 1 : 0); cur_index += 3; ct_orig = ct_end; orig = end; break; /*ClosePath*/ case 6: gf_path_close(stack->path); break; /*quadratic CurveTo, 2 points*/ case 7: CHECK_VALID_C2D(1); ct_end = pts[ GET_IDX(cur_index) ]; end = pts[ GET_IDX(cur_index+1) ]; gf_path_add_quadratic_to(stack->path, ct_end.x, ct_end.y, end.x, end.y); cur_index += 2; ct_orig = ct_end; orig = end; break; } } /*what's left is an N-bezier spline*/ if (!idx && (pt_count > cur_index) ) { /*first moveto*/ if (!cur_index) cur_index++; remain = pt_count - cur_index; if (remain>1) gf_path_add_bezier(stack->path, &pts[cur_index], remain); } gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); }
void VS2D_FillRect(VisualSurface2D *surf, DrawableContext *ctx, GF_Rect *_rc, u32 color, u32 strike_color) { GF_Path *path; GF_Rect *rc; GF_Raster2D *r2d = surf->render->compositor->r2d; #ifdef SKIP_DRAW return; #endif if (!surf->the_surface) return; if (!color && !strike_color) return; if ((ctx->flags & CTX_PATH_FILLED) && (ctx->flags & CTX_PATH_STROKE) ) { if (surf->render->compositor->draw_bvol) draw_clipper(surf, ctx); return; } /*no aa*/ VS2D_SetOptions(surf->render, surf->the_surface, 0, 1); if (_rc) { rc = _rc; r2d->surface_set_matrix(surf->the_surface, &ctx->transform); } else { rc = &ctx->bi->unclip; r2d->surface_set_matrix(surf->the_surface, NULL); } path = gf_path_new(); gf_path_add_move_to(path, rc->x, rc->y-rc->height); gf_path_add_line_to(path, rc->x+rc->width, rc->y-rc->height); gf_path_add_line_to(path, rc->x+rc->width, rc->y); gf_path_add_line_to(path, rc->x, rc->y); gf_path_close(path); if (color) { /*push path*/ r2d->surface_set_path(surf->the_surface, path); r2d->stencil_set_brush_color(surf->the_brush, color); VS2D_DoFill(surf, ctx, surf->the_brush); r2d->surface_set_path(surf->the_surface, NULL); } if (strike_color) { GF_Path *outline; GF_PenSettings pen; memset(&pen, 0, sizeof(GF_PenSettings)); pen.width = 1; pen.join = GF_LINE_JOIN_BEVEL; pen.dash = GF_DASH_STYLE_DOT; r2d->stencil_set_brush_color(surf->the_brush, strike_color); outline = gf_path_get_outline(path, pen); outline->flags &= ~GF_PATH_FILL_ZERO_NONZERO; r2d->surface_set_path(surf->the_surface, outline); VS2D_DoFill(surf, ctx, surf->the_brush); r2d->surface_set_path(surf->the_surface, NULL); gf_path_del(outline); } gf_path_del(path); }
static void build_shape(FSStack *st, GF_Node *node) { GF_FieldInfo field; MFVec2f *coords; MFInt32 *com, *widthIndex, *lineIndex, *fillIndex, *coordIndex; MFFloat *widths; MFColor *colors; u32 wi, li, fi, ci, command, i, has_ci; FSItem *fill_item, *line_item; Fixed w; SFVec2f cur, pt, ct1={0,0}, ct2, *pts; GF_Rect rc; u32 line_col, fill_col; Bool need_line, need_fill; /*get all fields*/ gf_node_get_field(node, 0, &field); coords = field.far_ptr; gf_node_get_field(node, 1, &field); com = field.far_ptr; gf_node_get_field(node, 2, &field); widths = field.far_ptr; gf_node_get_field(node, 3, &field); colors = field.far_ptr; gf_node_get_field(node, 4, &field); widthIndex = field.far_ptr; gf_node_get_field(node, 5, &field); lineIndex = field.far_ptr; gf_node_get_field(node, 6, &field); fillIndex = field.far_ptr; gf_node_get_field(node, 7, &field); coordIndex = field.far_ptr; wi = li = fi = ci = 0; w = 0; st->max_width = 0; cur.x = cur.y = 0; fill_item = line_item = NULL; need_line = need_fill = 0; cur.x = cur.y = 0; has_ci = coordIndex->count ? 1 : 0; pts = coords->vals; line_col = fill_col = 0; /*implicit commands: 0 1 2 3*/ /* if (widthIndex->count) { w = (widthIndex->vals[wi]==-1) ? 0 : widths->vals[widthIndex->vals[wi]]; if (!w) { need_line = 0; line_item = NULL; } else { need_line = 1; if (st->max_width<w) st->max_width = w; } wi++; } if (lineIndex->count) { if (w) { line_col = SFCOL_MAKE_ARGB(colors->vals[lineIndex->vals[li]]); need_line = 1; } li++; } if (fillIndex->count) { if (fillIndex->vals[fi]==-1) { fill_col = 0; fill_item = NULL; } else { fill_col = SFCOL_MAKE_ARGB(colors->vals[fillIndex->vals[fi]]); need_fill = 1; } fi++; } if (!coordIndex->count) return; cur = coords->vals[coordIndex->vals[ci]]; ci++; */ for (command=0; command<com->count; command++) { switch (com->vals[command]) { /*set line width*/ case 0: if (wi >= widthIndex->count) return; w = (widthIndex->vals[wi]==-1) ? 0 : widths->vals[widthIndex->vals[wi]]; if (!w) line_item = NULL; else { need_line = 1; if (st->max_width<w) st->max_width = w; } wi++; break; /*set line color*/ case 1: if (li > lineIndex->count) return; if (w) { line_col = SFCOL_MAKE_ARGB(colors->vals[lineIndex->vals[li]]); need_line = 1; } li++; break; /*set fill color*/ case 2: if (fi >= fillIndex->count) return; if (fillIndex->vals[fi]==-1) { fill_col = 0; fill_item = NULL; } else { fill_col = SFCOL_MAKE_ARGB(colors->vals[fillIndex->vals[fi]]); need_fill = 1; } fi++; break; /*moveTo*/ case 3: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); need_line = 0; } if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_move_to(fill_item->path, pt.x, pt.y); if (line_item) gf_path_add_move_to(line_item->path, pt.x, pt.y); ct1 = pt; cur = pt; ci++; break; /*lineTo*/ case 4: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_line_to(fill_item->path, pt.x, pt.y); if (line_item) gf_path_add_line_to(line_item->path, pt.x, pt.y); cur = pt; ci++; break; /*cubic curveTo*/ case 5: if ((has_ci && ci + 2 >= coordIndex->count) || (!has_ci && ci + 2>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { ct1 = pts[coordIndex->vals[ci]]; ct2 = pts[coordIndex->vals[ci+1]]; pt = pts[coordIndex->vals[ci+2]]; } else { ct1 = pts[ci]; ct2 = pts[ci+1]; pt = pts[ci+2]; } if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); ct1 = ct2; cur = pt; ci += 3; break; /*cubic nextCurveTo*/ case 6: if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } ct1.x = 2*cur.x - ct1.x; ct1.y = 2*cur.y - ct1.y; if (has_ci) { ct2 = pts[coordIndex->vals[ci]]; pt = pts[coordIndex->vals[ci+1]]; } else { ct2 = pts[ci]; pt = pts[ci+1]; } if (fill_item) gf_path_add_cubic_to(fill_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); if (line_item) gf_path_add_cubic_to(line_item->path, ct1.x, ct1.y, ct2.x, ct2.y, pt.x, pt.y); ct1 = ct2; cur = pt; ci += 2; break; /*quadratic CurveTo*/ case 7: if ((has_ci && ci + 1 >= coordIndex->count) || (!has_ci && ci + 1>= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } if (has_ci) { ct1 = pts[coordIndex->vals[ci]]; pt = pts[coordIndex->vals[ci+1]]; } else { ct1 = pts[ci]; pt = pts[ci+1]; } if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y); if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y); cur = pt; ci += 2; break; /*quadratic nextCurveTo*/ case 8: if ((has_ci && ci >= coordIndex->count) || (!has_ci && ci >= coords->count) ) return; if (need_fill) { fill_item = new_fs_item(st, 0, fill_col, 0); gf_path_add_move_to(fill_item->path, cur.x, cur.y); need_fill = 0; } if (need_line) { line_item = new_fs_item(st, line_col, 0, w); gf_path_add_move_to(line_item->path, cur.x, cur.y); need_line = 0; } ct1.x = 2*cur.x - ct1.x; ct1.y = 2*cur.y - ct1.y; if (has_ci) { pt = pts[coordIndex->vals[ci]]; } else { pt = pts[ci]; } if (fill_item) gf_path_add_quadratic_to(fill_item->path, ct1.x, ct1.y, pt.x, pt.y); if (line_item) gf_path_add_quadratic_to(line_item->path, ct1.x, ct1.y, pt.x, pt.y); cur = pt; ci += 2; break; /*close*/ case 9: if (fill_item) gf_path_close(fill_item->path); if (line_item) gf_path_close(line_item->path); break; } } /*compute bounds*/ st->bounds.width = st->bounds.height = 0; for (i=0; i<gf_list_count(st->items); i++) { line_item = gf_list_get(st->items, i); gf_path_get_bounds(line_item->path, &rc); gf_rect_union(&st->bounds, &rc); } }
static void svg_sani_render_rect(GF_Node *node, void *rs, Bool is_destroy) { Drawable *cs = (Drawable *)gf_node_get_private(node); SVG_SANI_rectElement *rect = (SVG_SANI_rectElement *)node; RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { DestroyDrawableNode(node); return; } if (eff->traversing_mode==TRAVERSE_DRAW) { drawable_draw(eff); return; } else if (eff->traversing_mode==TRAVERSE_PICK) { drawable_pick(eff); return; } svg_sani_render_base(node, (RenderEffect2D *)rs); /* 3) for a leaf node Recreates the path (i.e the shape) only if the node is dirty (has changed compared to the previous rendering phase) */ if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) { Fixed rx = rect->rx.value; Fixed ry = rect->ry.value; Fixed x = rect->x.value; Fixed y = rect->y.value; Fixed width = rect->width.value; Fixed height = rect->height.value; //fprintf(stdout, "Rebuilding rect %8x\n",rect); drawable_reset_path(cs); if (rx || ry) { if (rx >= width/2) rx = width/2; if (ry >= height/2) ry = height/2; if (rx == 0) rx = ry; if (ry == 0) ry = rx; gf_path_add_move_to(cs->path, x+rx, y); gf_path_add_line_to(cs->path, x+width-rx, y); gf_path_add_quadratic_to(cs->path, x+width, y, x+width, y+ry); gf_path_add_line_to(cs->path, x+width, y+height-ry); gf_path_add_quadratic_to(cs->path, x+width, y+height, x+width-rx, y+height); gf_path_add_line_to(cs->path, x+rx, y+height); gf_path_add_quadratic_to(cs->path, x, y+height, x, y+height-ry); gf_path_add_line_to(cs->path, x, y+ry); gf_path_add_quadratic_to(cs->path, x, y, x+rx, y); gf_path_close(cs->path); } else { gf_path_add_move_to(cs->path, x, y); gf_path_add_line_to(cs->path, x+width, y); gf_path_add_line_to(cs->path, x+width, y+height); gf_path_add_line_to(cs->path, x, y+height); gf_path_close(cs->path); } gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY); cs->flags |= DRAWABLE_HAS_CHANGED; } svg_sani_DrawablePostRender(cs, (SVG_SANI_TransformableElement *)rect, (RenderEffect2D *)rs, 1, 0); }
static GF_Glyph *gdip_load_glyph(GF_FontReader *dr, u32 glyph_name) { GF_Rect bounds; GF_Glyph *glyph; GpPath *path_tmp; GpStringFormat *fmt; GpMatrix *mat; Float est_advance_h; unsigned short str[4]; int i; FontPriv *ctx = (FontPriv *)dr->udta; if (!ctx->font) return NULL; RectF rc; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipCreateStringFormat(StringFormatFlagsNoWrap | StringFormatFlagsNoFitBlackBox | StringFormatFlagsMeasureTrailingSpaces, LANG_NEUTRAL, &fmt); GdipSetStringFormatAlign(fmt, StringAlignmentNear); GdipCreatePath(FillModeAlternate, &path_tmp); if (glyph_name==0x20) { est_advance_h = ctx->whitespace_width; } else { /*to compute first glyph alignment (say 'x', we figure out its bounding full box by using the '_' char as wrapper (eg, "_x_") then the bounding box starting from xMin of the glyph ('x_'). The difference between both will give us a good approx of the glyph alignment*/ str[0] = glyph_name; str[1] = (unsigned short) '_'; str[2] = (unsigned short) 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); est_advance_h = rc.Width - ctx->underscore_width; } GdipResetPath(path_tmp); str[0] = glyph_name; str[1] = (unsigned short) 0; rc.X = rc.Y = 0; rc.Width = rc.Height = 0; GdipAddPathString(path_tmp, (const WCHAR *)str, -1, ctx->font, ctx->font_style, ctx->em_size, &rc, fmt); GdipGetPathWorldBounds(path_tmp, &rc, NULL, NULL); /*flip so that we are in a font coordinate system - also move back the glyph to x=0 and y=baseline, GdiPlus doesn't do so*/ GdipCreateMatrix(&mat); GdipTranslateMatrix(mat, - rc.X, -ctx->ascent, MatrixOrderAppend); GdipScaleMatrix(mat, 1, -1, MatrixOrderAppend); GdipTransformPath(path_tmp, mat); GdipDeleteMatrix(mat); /*start enum*/ s32 count; GdipGetPointCount(path_tmp, &count); GpPointF *pts = new GpPointF[count]; BYTE *types = new BYTE[count]; GdipGetPathTypes(path_tmp, types, count); GdipGetPathPoints(path_tmp, pts, count); GF_SAFEALLOC(glyph, GF_Glyph); GF_SAFEALLOC(glyph->path, GF_Path); for (i=0; i<count; ) { BOOL closed = 0; s32 sub_type; sub_type = types[i] & PathPointTypePathTypeMask; if (sub_type == PathPointTypeStart) { gf_path_add_move_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); i++; } else if (sub_type == PathPointTypeLine) { gf_path_add_line_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y)); if (types[i] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i++; } else if (sub_type == PathPointTypeBezier) { assert(i+2<=count); gf_path_add_cubic_to(glyph->path, FLT2FIX(pts[i].X), FLT2FIX(pts[i].Y), FLT2FIX(pts[i+1].X), FLT2FIX(pts[i+1].Y), FLT2FIX(pts[i+2].X), FLT2FIX(pts[i+2].Y)); if (types[i+2] & PathPointTypeCloseSubpath) gf_path_close(glyph->path); i += 3; } else { assert(0); break; } } delete [] pts; delete [] types; GdipDeleteStringFormat(fmt); GdipDeletePath(path_tmp); glyph->ID = glyph_name; glyph->utf_name = glyph_name; glyph->vert_advance = (s32) (ctx->ascent-ctx->descent); glyph->horiz_advance = (s32) est_advance_h; gf_path_get_bounds(glyph->path, &bounds); glyph->width = FIX2INT(bounds.width); glyph->height = FIX2INT(bounds.height); return glyph; }
/* TODO: update for elliptical arcs */ GF_EXPORT void gf_svg_path_build(GF_Path *path, GF_List *commands, GF_List *points) { u32 i, j, command_count; SVG_Point orig, ct_orig, ct_end, end, *tmp; command_count = gf_list_count(commands); orig.x = orig.y = ct_orig.x = ct_orig.y = 0; for (i=0, j=0; i<command_count; i++) { u8 *command = (u8 *)gf_list_get(commands, i); switch (*command) { case SVG_PATHCOMMAND_M: /* Move To */ tmp = (SVG_Point*)gf_list_get(points, j); orig = *tmp; gf_path_add_move_to(path, orig.x, orig.y); j++; /*provision for nextCurveTo when no curve is specified: "If there is no previous command or if the previous command was not an C, c, S or s, assume the first control point is coincident with the current point. */ ct_orig = orig; break; case SVG_PATHCOMMAND_L: /* Line To */ tmp = (SVG_Point*)gf_list_get(points, j); end = *tmp; gf_path_add_line_to(path, end.x, end.y); j++; orig = end; /*cf above*/ ct_orig = orig; break; case SVG_PATHCOMMAND_C: /* Curve To */ tmp = (SVG_Point*)gf_list_get(points, j); ct_orig = *tmp; tmp = (SVG_Point*)gf_list_get(points, j+1); ct_end = *tmp; tmp = (SVG_Point*)gf_list_get(points, j+2); end = *tmp; gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); ct_orig = ct_end; orig = end; j+=3; break; case SVG_PATHCOMMAND_S: /* Next Curve To */ ct_orig.x = 2*orig.x - ct_orig.x; ct_orig.y = 2*orig.y - ct_orig.y; tmp = (SVG_Point*)gf_list_get(points, j); ct_end = *tmp; tmp = (SVG_Point*)gf_list_get(points, j+1); end = *tmp; gf_path_add_cubic_to(path, ct_orig.x, ct_orig.y, ct_end.x, ct_end.y, end.x, end.y); ct_orig = ct_end; orig = end; j+=2; break; case SVG_PATHCOMMAND_Q: /* Quadratic Curve To */ tmp = (SVG_Point*)gf_list_get(points, j); ct_orig = *tmp; tmp = (SVG_Point*)gf_list_get(points, j+1); end = *tmp; gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y); orig = end; j+=2; break; case SVG_PATHCOMMAND_T: /* Next Quadratic Curve To */ ct_orig.x = 2*orig.x - ct_orig.x; ct_orig.y = 2*orig.y - ct_orig.y; tmp = (SVG_Point*)gf_list_get(points, j); end = *tmp; gf_path_add_quadratic_to(path, ct_orig.x, ct_orig.y, end.x, end.y); orig = end; j++; break; case SVG_PATHCOMMAND_Z: /* Close */ gf_path_close(path); break; } } }
static void IFS2D_Draw(GF_Node *node, GF_TraverseState *tr_state) { u32 i, count, ci_count; u32 j, ind_col, num_col; SFVec2f center, end; SFColor col_cen; GF_STENCIL grad; u32 *colors; GF_Path *path; SFVec2f start; SFVec2f *pts; SFColor col; Fixed alpha; GF_Raster2D *raster; DrawableContext *ctx = tr_state->ctx; M_IndexedFaceSet2D *ifs2D = (M_IndexedFaceSet2D *)node; M_Coordinate2D *coord = (M_Coordinate2D*) ifs2D->coord; M_Color *color = (M_Color *) ifs2D->color; col.red = col.green = col.blue = 0; /*simple case, no color specified*/ if (!ifs2D->color) { visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } /*if default face use first color*/ ci_count = ifs2D->coordIndex.count; pts = coord->point.vals; if (ci_count == 0) { col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[0]] : color->color.vals[0]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha || !ctx->aspect.pen_props.width) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } /*we have color per faces so we need N path :(*/ if (! ifs2D->colorPerVertex) { path = gf_path_new(); count = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_move_to(path, start.x, start.y); i++; while (ifs2D->coordIndex.vals[i] != -1) { start = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, start.x, start.y); i++; if (i >= ci_count) break; } /*close in ALL cases because even if the start/end points are the same the line join needs to be present*/ gf_path_close(path); col = (ifs2D->colorIndex.count > 0) ? color->color.vals[ifs2D->colorIndex.vals[count]] : color->color.vals[count]; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color)) / 255; if (!alpha) { alpha = INT2FIX(GF_COL_A(ctx->aspect.line_color)) / 255; ctx->aspect.line_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } else { ctx->aspect.fill_color = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); } visual_2d_texture_path(tr_state->visual, path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, path, ctx, NULL, NULL, tr_state); count++; i++; if (i >= ci_count) break; ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); return; } /*final case, color per vertex means gradient fill/strike*/ raster = tr_state->visual->compositor->rasterizer; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); /*not supported, fill default*/ if (!grad) { visual_2d_texture_path(tr_state->visual, ctx->drawable->path, ctx, tr_state); visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, NULL, NULL, tr_state); return; } path = gf_path_new(); ind_col = 0; i = 0; while (1) { gf_path_reset(path); start = pts[ifs2D->coordIndex.vals[i]]; center = start; gf_path_add_move_to(path, start.x, start.y); num_col = 1; i+=1; while (ifs2D->coordIndex.vals[i] != -1) { end = pts[ifs2D->coordIndex.vals[i]]; gf_path_add_line_to(path, end.x, end.y); i++; center.x += end.x; center.y += end.y; num_col ++; if (i >= ci_count) break; } gf_path_close(path); num_col++; alpha = INT2FIX(GF_COL_A(ctx->aspect.fill_color) ) / 255; colors = (u32*)gf_malloc(sizeof(u32) * num_col); col_cen.blue = col_cen.red = col_cen.green = 0; for (j=0; j<num_col-1; j++) { if (ifs2D->colorIndex.count > ind_col + j) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col + j]]; } else if (ci_count > ind_col + j) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col + j]]; } colors[j] = GF_COL_ARGB_FIXED(alpha, col.red, col.green, col.blue); col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; } colors[num_col-1] = colors[0]; if (ifs2D->colorIndex.count > ind_col) { col = color->color.vals[ifs2D->colorIndex.vals[ind_col]]; } else if (ci_count > ind_col) { col = color->color.vals[ifs2D->coordIndex.vals[ind_col]]; } col_cen.blue += col.blue; col_cen.green += col.green; col_cen.red += col.red; raster->stencil_set_vertex_path(grad, path); raster->stencil_set_vertex_colors(grad, colors, num_col); gf_free(colors); col_cen.blue /= num_col; col_cen.green /= num_col; col_cen.red /= num_col; center.x /= num_col; center.y /= num_col; raster->stencil_set_vertex_center(grad, center.x, center.y, GF_COL_ARGB_FIXED(alpha, col_cen.red, col_cen.green, col_cen.blue) ); raster->stencil_set_matrix(grad, &ctx->transform); /*draw*/ visual_2d_draw_path(tr_state->visual, ctx->drawable->path, ctx, grad, grad, tr_state); raster->stencil_delete(grad); //goto next point i++; ind_col += num_col + 1; if (i >= ci_count) break; grad = raster->stencil_new(raster, GF_STENCIL_VERTEX_GRADIENT); ctx->flags &= ~CTX_PATH_FILLED; ctx->flags &= ~CTX_PATH_STROKE; } gf_path_del(path); }