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); }
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; }
/*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); }
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); }
static void gf_add_n_bezier(GF_Path *gp, GF_Point2D *newpts, u32 nbPoints) { Double mu; u32 numPoints, i; GF_Point2D end; numPoints = (u32) FIX2INT(GF_2D_DEFAULT_RES * gp->fineness); mu = 0.0; if (numPoints) mu = 1/(Double)numPoints; for (i=1; i<numPoints; i++) { NBezier(newpts, nbPoints - 1, i*mu, &end); gf_path_add_line_to(gp, end.x, end.y); } gf_path_add_line_to(gp, newpts[nbPoints-1].x, newpts[nbPoints-1].y); }
static GF_Err svg_rect_add_arc(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed cx, Fixed cy, Fixed rx, Fixed ry) { Fixed angle, start_angle, end_angle, sweep, _vx, _vy, start_x, start_y; s32 i, num_steps; if (!gp->n_points) return GF_BAD_PARAM; start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; //start angle and end angle start_angle = gf_atan2(start_y-cy, start_x-cx); end_angle = gf_atan2(end_y-cy, end_x-cx); sweep = end_angle - start_angle; if (sweep<0) sweep += 2*GF_PI; num_steps = 16; for (i=1; i<=num_steps; i++) { angle = start_angle + sweep*i/num_steps; _vx = cx + gf_mulfix(rx, gf_cos(angle)); _vy = cy + gf_mulfix(ry, gf_sin(angle)); gf_path_add_line_to(gp, _vx, _vy); } return GF_OK; }
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); }
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); } }
static int ft_line_to(const FT_Vector *to, void *user) { ft_outliner *ftol = (ft_outliner *)user; if ( (ftol->last_x == to->x) && (ftol->last_y == to->y)) { gf_path_close(ftol->path); } else { gf_path_add_line_to(ftol->path, INT2FIX(to->x), INT2FIX(to->y) ); } return 0; }
GF_EXPORT GF_Err gf_path_add_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed fa_x, Fixed fa_y, Fixed fb_x, Fixed fb_y, Bool cw) { GF_Matrix2D mat, inv; Fixed angle, start_angle, end_angle, sweep, axis_w, axis_h, tmp, cx, cy, _vx, _vy, start_x, start_y; s32 i, num_steps; if (!gp->n_points) return GF_BAD_PARAM; start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; cx = (fb_x + fa_x)/2; cy = (fb_y + fa_y)/2; angle = gf_atan2(fb_y-fa_y, fb_x-fa_x); gf_mx2d_init(mat); gf_mx2d_add_rotation(&mat, 0, 0, angle); gf_mx2d_add_translation(&mat, cx, cy); gf_mx2d_copy(inv, mat); gf_mx2d_inverse(&inv); gf_mx2d_apply_coords(&inv, &start_x, &start_y); gf_mx2d_apply_coords(&inv, &end_x, &end_y); gf_mx2d_apply_coords(&inv, &fa_x, &fa_y); gf_mx2d_apply_coords(&inv, &fb_x, &fb_y); //start angle and end angle start_angle = gf_atan2(start_y, start_x); end_angle = gf_atan2(end_y, end_x); tmp = gf_mulfix((start_x - fa_x), (start_x - fa_x)) + gf_mulfix((start_y - fa_y), (start_y - fa_y)); axis_w = gf_sqrt(tmp); tmp = gf_mulfix((start_x - fb_x) , (start_x - fb_x)) + gf_mulfix((start_y - fb_y), (start_y - fb_y)); axis_w += gf_sqrt(tmp); axis_w /= 2; axis_h = gf_sqrt(gf_mulfix(axis_w, axis_w) - gf_mulfix(fa_x,fa_x)); sweep = end_angle - start_angle; if (cw) { if (sweep>0) sweep -= 2*GF_PI; } else { if (sweep<0) sweep += 2*GF_PI; } num_steps = GF_2D_DEFAULT_RES/2; for (i=1; i<=num_steps; i++) { angle = start_angle + sweep*i/num_steps; _vx = gf_mulfix(axis_w, gf_cos(angle)); _vy = gf_mulfix(axis_h, gf_sin(angle)); /*re-invert*/ gf_mx2d_apply_coords(&mat, &_vx, &_vy); gf_path_add_line_to(gp, _vx, _vy); } return GF_OK; }
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 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; }
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); } }
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_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_EXPORT GF_Err gf_path_close(GF_Path *gp) { Fixed diff; GF_Point2D start, end; if (!gp || !gp->n_contours) return GF_BAD_PARAM; if (gp->n_contours<=1) start = gp->points[0]; else start = gp->points[gp->contours[gp->n_contours-2] + 1]; end = gp->points[gp->n_points-1]; end.x -= start.x; end.y -= start.y; diff = gf_mulfix(end.x, end.x) + gf_mulfix(end.y, end.y); if (ABS(diff) > FIX_ONE/1000) { GF_Err e = gf_path_add_line_to(gp, start.x, start.y); if (e) return e; } gp->tags[gp->n_points-1] = GF_PATH_CLOSE; return GF_OK; }
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); }
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; }
/*flattening algo taken from libart but passed to sqrt tests for line distance to avoid 16.16 fixed overflow*/ static GF_Err gf_subdivide_cubic(GF_Path *gp, Fixed x0, Fixed y0, Fixed x1, Fixed y1, Fixed x2, Fixed y2, Fixed x3, Fixed y3, Fixed fineness) { GF_Point2D pt; Fixed x3_0, y3_0, z3_0, z1_0, z1_dot, z2_dot, z1_perp, z2_perp; Fixed max_perp; Fixed x_m, y_m, xa1, ya1, xa2, ya2, xb1, yb1, xb2, yb2; GF_Err e; pt.x = x3_0 = x3 - x0; pt.y = y3_0 = y3 - y0; /*z3_0 is dist z0-z3*/ z3_0 = gf_v2d_len(&pt); pt.x = x1 - x0; pt.y = y1 - y0; z1_0 = gf_v2d_len(&pt); if ((z3_0*100 < FIX_ONE) && (z1_0*100 < FIX_ONE)) goto nosubdivide; /* perp is distance from line, multiplied by dist z0-z3 */ max_perp = gf_mulfix(fineness, z3_0); z1_perp = gf_mulfix((y1 - y0), x3_0) - gf_mulfix((x1 - x0), y3_0); if (ABS(z1_perp) > max_perp) goto subdivide; z2_perp = gf_mulfix((y3 - y2), x3_0) - gf_mulfix((x3 - x2), y3_0); if (ABS(z2_perp) > max_perp) goto subdivide; z1_dot = gf_mulfix((x1 - x0), x3_0) + gf_mulfix((y1 - y0), y3_0); if ((z1_dot < 0) && (ABS(z1_dot) > max_perp)) goto subdivide; z2_dot = gf_mulfix((x3 - x2), x3_0) + gf_mulfix((y3 - y2), y3_0); if ((z2_dot < 0) && (ABS(z2_dot) > max_perp)) goto subdivide; if (gf_divfix(z1_dot + z1_dot, z3_0) > z3_0) goto subdivide; if (gf_divfix(z2_dot + z2_dot, z3_0) > z3_0) goto subdivide; nosubdivide: /* don't subdivide */ return gf_path_add_line_to(gp, x3, y3); subdivide: xa1 = (x0 + x1) / 2; ya1 = (y0 + y1) / 2; xa2 = (x0 + 2 * x1 + x2) / 4; ya2 = (y0 + 2 * y1 + y2) / 4; xb1 = (x1 + 2 * x2 + x3) / 4; yb1 = (y1 + 2 * y2 + y3) / 4; xb2 = (x2 + x3) / 2; yb2 = (y2 + y3) / 2; x_m = (xa2 + xb1) / 2; y_m = (ya2 + yb1) / 2; /*safeguard for numerical stability*/ if ( (ABS(x_m-x0) < FIX_EPSILON) && (ABS(y_m-y0) < FIX_EPSILON)) return gf_path_add_line_to(gp, x3, y3); if ( (ABS(x3-x_m) < FIX_EPSILON) && (ABS(y3-y_m) < FIX_EPSILON)) return gf_path_add_line_to(gp, x3, y3); e = gf_subdivide_cubic(gp, x0, y0, xa1, ya1, xa2, ya2, x_m, y_m, fineness); if (e) return e; return gf_subdivide_cubic(gp, x_m, y_m, xb1, yb1, xb2, yb2, x3, y3, fineness); }
GF_EXPORT GF_Err gf_path_add_svg_arc_to(GF_Path *gp, Fixed end_x, Fixed end_y, Fixed r_x, Fixed r_y, Fixed x_axis_rotation, Bool large_arc_flag, Bool sweep_flag) { Fixed start_x, start_y; Fixed xmid,ymid; Fixed xmidp,ymidp; Fixed xmidpsq,ymidpsq; Fixed phi, cos_phi, sin_phi; Fixed c_x, c_y; Fixed cxp, cyp; Fixed scale; Fixed rxsq, rysq; Fixed start_angle, sweep_angle; Fixed radius_scale; Fixed vx, vy, normv; Fixed ux, uy, normu; Fixed sign; u32 i, num_steps; if (!gp->n_points) return GF_BAD_PARAM; if (!r_x || !r_y) { gf_path_add_line_to(gp, end_x, end_y); return GF_OK; } if (r_x < 0) r_x = -r_x; if (r_y < 0) r_y = -r_y; start_x = gp->points[gp->n_points-1].x; start_y = gp->points[gp->n_points-1].y; phi = gf_mulfix(gf_divfix(x_axis_rotation, 180), GF_PI); cos_phi = gf_cos(phi); sin_phi = gf_sin(phi); xmid = (start_x - end_x)/2; ymid = (start_y - end_y)/2; if (!xmid && !ymid) { gf_path_add_line_to(gp, end_x, end_y); return GF_OK; } xmidp = gf_mulfix(cos_phi, xmid) + gf_mulfix(sin_phi, ymid); ymidp = gf_mulfix(-sin_phi, xmid) + gf_mulfix(cos_phi, ymid); xmidpsq = gf_mulfix(xmidp, xmidp); ymidpsq = gf_mulfix(ymidp, ymidp); rxsq = gf_mulfix(r_x, r_x); rysq = gf_mulfix(r_y, r_y); assert(rxsq && rxsq); radius_scale = gf_divfix(xmidpsq, rxsq) + gf_divfix(ymidpsq, rysq); if (radius_scale > FIX_ONE) { r_x = gf_mulfix(gf_sqrt(radius_scale), r_x); r_y = gf_mulfix(gf_sqrt(radius_scale), r_y); rxsq = gf_mulfix(r_x, r_x); rysq = gf_mulfix(r_y, r_y); } #if 0 /* Old code with overflow problems in fixed point, sign was sometimes negative (cf tango SVG icons appointment-new.svg)*/ sign = gf_mulfix(rxsq,ymidpsq) + gf_mulfix(rysq, xmidpsq); scale = FIX_ONE; /*FIXME - what if scale is 0 ??*/ if (sign) scale = gf_divfix( (gf_mulfix(rxsq,rysq) - gf_mulfix(rxsq, ymidpsq) - gf_mulfix(rysq,xmidpsq)), sign ); #else /* New code: the sign variable computation is split into simpler cases and the expression is divided by rxsq to reduce the range */ if ((rxsq == 0 || ymidpsq ==0) && (rysq == 0 || xmidpsq == 0)) { scale = FIX_ONE; } else if (rxsq == 0 || ymidpsq ==0) { scale = gf_divfix(rxsq,xmidpsq) - FIX_ONE; } else if (rysq == 0 || xmidpsq == 0) { scale = gf_divfix(rysq,ymidpsq) - FIX_ONE; } else { Fixed tmp; tmp = gf_mulfix(gf_divfix(rysq, rxsq), xmidpsq); sign = ymidpsq + tmp; scale = gf_divfix((rysq - ymidpsq - tmp),sign); } #endif /* precision problem may lead to negative value around zero, we need to take care of it before sqrt */ scale = gf_sqrt(ABS(scale)); cxp = gf_mulfix(scale, gf_divfix(gf_mulfix(r_x, ymidp),r_y)); cyp = gf_mulfix(scale, -gf_divfix(gf_mulfix(r_y, xmidp),r_x)); cxp = (large_arc_flag == sweep_flag ? - cxp : cxp); cyp = (large_arc_flag == sweep_flag ? - cyp : cyp); c_x = gf_mulfix(cos_phi, cxp) - gf_mulfix(sin_phi, cyp) + (start_x + end_x)/2; c_y = gf_mulfix(sin_phi, cxp) + gf_mulfix(cos_phi, cyp) + (start_y + end_y)/2; ux = FIX_ONE; uy = 0; normu = FIX_ONE; vx = gf_divfix(xmidp-cxp,r_x); vy = gf_divfix(ymidp-cyp,r_y); normv = gf_sqrt(gf_mulfix(vx, vx) + gf_mulfix(vy,vy)); sign = vy; start_angle = gf_acos(gf_divfix(vx,normv)); start_angle = (sign > 0 ? start_angle: -start_angle); ux = vx; uy = vy; normu = normv; vx = gf_divfix(-xmidp-cxp,r_x); vy = gf_divfix(-ymidp-cyp,r_y); normu = gf_sqrt(gf_mulfix(ux, ux) + gf_mulfix(uy,uy)); sign = gf_mulfix(ux, vy) - gf_mulfix(uy, vx); sweep_angle = gf_divfix( gf_mulfix(ux,vx) + gf_mulfix(uy, vy), gf_mulfix(normu, normv) ); /*numerical stability safety*/ sweep_angle = MAX(-FIX_ONE, MIN(sweep_angle, FIX_ONE)); sweep_angle = gf_acos(sweep_angle); sweep_angle = (sign > 0 ? sweep_angle: -sweep_angle); if (sweep_flag == 0) { if (sweep_angle > 0) sweep_angle -= GF_2PI; } else { if (sweep_angle < 0) sweep_angle += GF_2PI; } num_steps = GF_2D_DEFAULT_RES/2; for (i=1; i<=num_steps; i++) { Fixed _vx, _vy; Fixed _vxp, _vyp; Fixed angle = start_angle + sweep_angle*i/num_steps; _vx = gf_mulfix(r_x, gf_cos(angle)); _vy = gf_mulfix(r_y, gf_sin(angle)); _vxp = gf_mulfix(cos_phi, _vx) - gf_mulfix(sin_phi, _vy) + c_x; _vyp = gf_mulfix(sin_phi, _vx) + gf_mulfix(cos_phi, _vy) + c_y; gf_path_add_line_to(gp, _vxp, _vyp); } return GF_OK; }
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); }
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 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; }
GF_EXPORT GF_Err gf_path_add_line_to_vec(GF_Path *gp, GF_Point2D *pt) { return gf_path_add_line_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); }
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); }
/* 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 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); } }