static void svg_sani_render_path(GF_Node *node, void *rs, Bool is_destroy) { SVG_SANI_pathElement *path = (SVG_SANI_pathElement *)node; Drawable *cs = (Drawable *)gf_node_get_private(node); RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) { svg_sani_destroy_path(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, eff); if (gf_node_dirty_get(node) & GF_SG_SVG_GEOMETRY_DIRTY) { #if USE_GF_PATH cs->path = &path->d; #else drawable_reset_path(cs); gf_svg_path_build(cs->path, path->d.commands, path->d.points); #endif if (path->fill_rule==GF_PATH_FILL_ZERO_NONZERO) cs->path->flags |= GF_PATH_FILL_ZERO_NONZERO; gf_node_dirty_clear(node, GF_SG_SVG_GEOMETRY_DIRTY); cs->flags |= DRAWABLE_HAS_CHANGED; } svg_sani_DrawablePostRender(cs, (SVG_SANI_TransformableElement *)path, eff, 0, (path->pathLength.type==SVG_NUMBER_VALUE) ? path->pathLength.value : 0); }
void compositor_extrude_text(GF_Node *node, GF_TraverseState *tr_state, GF_Mesh *mesh, MFVec3f *thespine, Fixed creaseAngle, Bool begin_cap, Bool end_cap, MFRotation *spine_ori, MFVec2f *spine_scale, Bool txAlongSpine) { u32 i, count; Fixed min_cx, min_cy, width_cx, width_cy; TextStack *st = (TextStack *) gf_node_get_private(node); /*rebuild text node*/ if (gf_node_dirty_get(node)) { ParentNode2D *parent = tr_state->parent; tr_state->parent = NULL; text_clean_paths(tr_state->visual->compositor, st); drawable_reset_path(st->graph); gf_node_dirty_clear(node, 0); build_text(st, (M_Text *)node, tr_state); tr_state->parent = parent; } min_cx = st->bounds.x; min_cy = st->bounds.y - st->bounds.height; width_cx = st->bounds.width; width_cy = st->bounds.height; mesh_reset(mesh); count = gf_list_count(st->spans); for (i=0; i<count; i++) { GF_TextSpan *span = (GF_TextSpan *)gf_list_get(st->spans, i); GF_Path *span_path = gf_font_span_create_path(span); mesh_extrude_path_ext(mesh, span_path, thespine, creaseAngle, min_cx, min_cy, width_cx, width_cy, begin_cap, end_cap, spine_ori, spine_scale, txAlongSpine); gf_path_del(span_path); } mesh_update_bounds(mesh); gf_mesh_build_aabbtree(mesh); }
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 RenderCurve2D(SFNode *node, void *rs) { DrawableContext *ctx; M_Curve2D *c2D = (M_Curve2D *)node; Drawable *cs = Node_GetPrivate(node); RenderEffect2D *eff = rs; if (!c2D->point) return; if (Node_GetDirty(node)) { drawable_reset_path(cs); cs->path->resolution = eff->surface->render->compositor->base_curve_resolution; cs->path->fineness = c2D->fineness; if (eff->surface->render->compositor->high_speed) cs->path->fineness /= 2; build_curve2D(cs, c2D); Node_ClearDirty(node); cs->node_changed = 1; } ctx = drawable_init_context(cs, eff); if (!ctx) return; drawctx_store_original_bounds(ctx); drawable_finalize_render(ctx, eff); }
static void RenderRectangle(SFNode *node, void *reff) { DrawableContext *ctx; Drawable *rs = Node_GetPrivate(node); RenderEffect2D *eff = reff; if (Node_GetDirty(node)) { drawable_reset_path(rs); m4_path_add_rectangle(rs->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y); Node_ClearDirty(node); rs->node_changed = 1; } ctx = drawable_init_context(rs, eff); if (!ctx) return; ctx->transparent = 0; /*if not filled, transparent*/ if (!ctx->aspect.filled) { ctx->transparent = 1; } /*if alpha, transparent*/ else if (M4C_A(ctx->aspect.fill_color) != 0xFF) { ctx->transparent = 1; } /*if rotated, transparent (doesn't fill bounds)*/ else if (ctx->transform.m[1] || ctx->transform.m[3]) { ctx->transparent = 1; } else if (!eff->color_mat.identity) ctx->transparent = 1; drawctx_store_original_bounds(ctx); drawable_finalize_render(ctx, eff); }
static void svg_ellipse_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { drawable_reset_path(stack); gf_path_add_ellipse(stack->path, (atts->cx ? atts->cx->value : 0), (atts->cy ? atts->cy->value : 0), (atts->rx ? 2*atts->rx->value : 0), (atts->ry ? 2*atts->ry->value : 0)); }
static void ellipse_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { drawable_reset_path(stack); gf_path_add_ellipse(stack->path, 0, 0, ((M_Ellipse *) node)->radius.x*2, ((M_Ellipse *) node)->radius.y*2); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
static void svg_path_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { #if USE_GF_PATH drawable_reset_path_outline(stack); stack->path = atts->d; #else drawable_reset_path(stack); gf_svg_path_build(stack->path, atts->d->commands, atts->d->points); #endif }
static void circle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { Fixed a = ((M_Circle *) node)->radius * 2; drawable_reset_path(stack); gf_path_add_ellipse(stack->path, 0, 0, a, a); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
static void rectangle_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { /*if modified update node - we don't update for other traversing mode in order not to mess up the dirty rect tracking (otherwise we would miss geometry changes with same bounds)*/ if (gf_node_dirty_get(node)) { drawable_reset_path(stack); gf_path_add_rect_center(stack->path, 0, 0, ((M_Rectangle *) node)->size.x, ((M_Rectangle *) node)->size.y); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
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); } }
void text_clean_paths(GF_Compositor *compositor, TextStack *stack) { GF_TextSpan *span; /*delete all path objects*/ while (gf_list_count(stack->spans)) { span = (GF_TextSpan*) gf_list_get(stack->spans, 0); gf_list_rem(stack->spans, 0); gf_font_manager_delete_span(compositor->font_manager, span); } stack->bounds.width = stack->bounds.height = 0; drawable_reset_path(stack->graph); }
static void disk2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { Fixed a = ((X_Disk2D *) node)->outerRadius * 2; drawable_reset_path(stack); gf_path_add_ellipse(stack->path, 0, 0, a, a); a = ((X_Disk2D *) node)->innerRadius * 2; if (a) gf_path_add_ellipse(stack->path, 0, 0, a, a); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
static void arc2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { if (gf_node_dirty_get(node)) { drawable_reset_path(stack); if (gf_node_get_tag(node)==TAG_X3D_Arc2D) { X_Arc2D *a = (X_Arc2D *) node; gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, 0); } else { X_ArcClose2D *a = (X_ArcClose2D *) node; gf_path_add_arc(stack->path, a->radius, a->startAngle, a->endAngle, !stricmp(a->closureType.buffer, "PIE") ? 2 : 1); } gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); } }
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 RenderEllipse(SFNode *node, void *rs) { DrawableContext *ctx; Drawable *cs = Node_GetPrivate(node); RenderEffect2D *eff = rs; if (Node_GetDirty(node)) { drawable_reset_path(cs); m4_path_add_ellipse(cs->path, ((M_Ellipse *) node)->radius.x, ((M_Ellipse *) node)->radius.y); Node_ClearDirty(node); cs->node_changed = 1; } ctx = drawable_init_context(cs, eff); if (!ctx) return; drawctx_store_original_bounds(ctx); drawable_finalize_render(ctx, eff); }
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 void ifs2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { u32 i; SFVec2f *pts; u32 ci_count, c_count; Bool started; M_IndexedFaceSet2D *ifs2D; M_Coordinate2D *coord; if (! gf_node_dirty_get(node)) return; ifs2D = (M_IndexedFaceSet2D *)node; coord = (M_Coordinate2D *)ifs2D->coord; drawable_reset_path(stack); gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); c_count = coord->point.count; ci_count = ifs2D->coordIndex.count; pts = coord->point.vals; if (ci_count > 0) { started = 0; for (i=0; i < ci_count; i++) { if (ifs2D->coordIndex.vals[i] == -1) { gf_path_close(stack->path); started = 0; } else if (!started) { started = 1; gf_path_add_move_to_vec(stack->path, &pts[ifs2D->coordIndex.vals[i]]); } else { gf_path_add_line_to_vec(stack->path, &pts[ifs2D->coordIndex.vals[i]]); } } if (started) gf_path_close(stack->path); } else if (c_count) { gf_path_add_move_to_vec(stack->path, &pts[0]); for (i=1; i < c_count; i++) { gf_path_add_line_to_vec(stack->path, &pts[i]); } gf_path_close(stack->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); } }
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); }
static void pointset2d_check_changes(GF_Node *node, Drawable *stack, GF_TraverseState *tr_state) { u32 i; Fixed w, h; M_Coordinate2D *coord; if (!gf_node_dirty_get(node)) return; coord = (M_Coordinate2D *) ((M_PointSet2D *)node)->coord; drawable_reset_path(stack); get_point_size(&tr_state->transform, &w, &h); /*for PS2D don't add to avoid too much antialiasing, just try to fill the given pixel*/ for (i=0; i < coord->point.count; i++) gf_path_add_rect(stack->path, coord->point.vals[i].x, coord->point.vals[i].y, w, h); stack->path->flags |= GF_PATH_FILL_ZERO_NONZERO; gf_node_dirty_clear(node, 0); drawable_mark_modified(stack, tr_state); }
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 Bitmap_BuildGraph(BitmapStack *st, DrawableContext *ctx, RenderEffect2D *eff) { M_Bitmap *bmp = (M_Bitmap *)st->graph->owner; M4Matrix2D mat; Float w , h; w = ctx->h_texture->active_window.width; h = ctx->h_texture->active_window.height; /*get size with scale*/ drawable_reset_path(st->graph); /*reverse meterMetrics conversion*/ mx2d_init(mat); if (!eff->is_pixel_metrics) mx2d_add_scale(&mat, eff->min_hsize, eff->min_hsize); mx2d_inverse(&mat); /*the spec says STRICTLY positive or -1, but some content use 0...*/ mx2d_add_scale(&mat, (bmp->scale.x>=0) ? bmp->scale.x : 1, (bmp->scale.y>=0) ? bmp->scale.y : 1); mx2d_apply_coords(&mat, &w, &h); m4_path_add_rectangle(st->graph->path, 0, 0, w, h); m4_rect_center(&ctx->original, w, h); }
static void RenderILS2D(SFNode *node, void *rs) { DrawableContext *ctx; M_IndexedLineSet2D *ils2D = (M_IndexedLineSet2D *)node; Drawable *cs = Node_GetPrivate(node); RenderEffect2D *eff = rs; if (!ils2D->coord) return; if (Node_GetDirty(node)) { drawable_reset_path(cs); build_graph(cs, ils2D); Node_ClearDirty(node); cs->node_changed = 1; } ctx = drawable_init_context(cs, eff); if (!ctx) return; /*ILS2D are NEVER filled*/ ctx->aspect.filled = 0; drawctx_store_original_bounds(ctx); drawable_finalize_render(ctx, eff); }
static void RenderPointSet2D(SFNode *node, void *rs) { DrawableContext *ctx; M_PointSet2D *ps2D = (M_PointSet2D *)node; Drawable *cs = Node_GetPrivate(node); RenderEffect2D *eff = rs; if (!ps2D->coord) return; if (Node_GetDirty(node)) { drawable_reset_path(cs); build_graph(cs, &eff->transform, ps2D); Node_ClearDirty(node); cs->node_changed = 1; } ctx = drawable_init_context(cs, eff); if (!ctx) return; ctx->aspect.filled = 1; ctx->aspect.has_line = 0; drawctx_store_original_bounds(ctx); drawable_finalize_render(ctx, eff); }
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_traverse_text(GF_Node *node, void *rs, Bool is_destroy) { SVGPropertiesPointers backup_props; u32 backup_flags; GF_Matrix2D backup_matrix; GF_Matrix mx3d; GF_ChildNodeItem *child; DrawableContext *ctx; SVG_TextStack *st = (SVG_TextStack *)gf_node_get_private(node); GF_TraverseState *tr_state = (GF_TraverseState *)rs; SVG_Element *text = (SVG_Element *)node; SVGAllAttributes atts; u32 i,imax; Fixed * lw; if (is_destroy) { drawable_del(st->drawable); svg_reset_text_stack(st); gf_list_del(st->spans); gf_free(st); return; } if (tr_state->traversing_mode==TRAVERSE_DRAW_2D) { svg_text_draw_2d(st, tr_state); return; } else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) { tr_state->text_parent = node; gf_font_spans_get_selection(node, st->spans, tr_state); /*and browse children*/ child = ((GF_ParentNode *) text)->children; while (child) { switch (gf_node_get_tag(child->node)) { case TAG_SVG_tspan: gf_node_traverse(child->node, tr_state); break; } child = child->next; } tr_state->text_parent = NULL; return; } gf_svg_flatten_attributes(text, &atts); if (!compositor_svg_traverse_base(node, &atts, tr_state, &backup_props, &backup_flags)) return; tr_state->in_svg_text++; tr_state->text_parent = node; if (tr_state->traversing_mode==TRAVERSE_PICK) { compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d); if (*tr_state->svg_props->pointer_events!=SVG_POINTEREVENTS_NONE) gf_font_spans_pick(node, st->spans, tr_state, &st->bounds, 1, st->drawable); /*and browse children*/ child = ((GF_ParentNode *) text)->children; while (child) { switch (gf_node_get_tag(child->node)) { case TAG_SVG_tspan: gf_node_traverse(child->node, tr_state); break; } child = child->next; } memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d); tr_state->svg_flags = backup_flags; tr_state->text_parent = NULL; tr_state->in_svg_text--; return; } else if (tr_state->traversing_mode==TRAVERSE_GET_TEXT) { gf_font_spans_get_selection(node, st->spans, tr_state); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; tr_state->text_parent = NULL; tr_state->in_svg_text--; return; } compositor_svg_apply_local_transformation(tr_state, &atts, &backup_matrix, &mx3d); if ( (st->prev_size != tr_state->svg_props->font_size->value) || (st->prev_flags != *tr_state->svg_props->font_style) || (st->prev_anchor != *tr_state->svg_props->text_anchor) || (gf_node_dirty_get(node) & (GF_SG_SVG_GEOMETRY_DIRTY | GF_SG_CHILD_DIRTY) ) || tr_state->visual->compositor->reset_fonts ) { u32 mode; child = ((GF_ParentNode *) text)->children; svg_reset_text_stack(st); tr_state->text_end_x = 0; tr_state->text_end_y = 0; /*init the xml:space algo*/ tr_state->last_char_type = 0; /*initialize x and y counters - stored at the traverse level for handling tspan & co*/ if (atts.text_x) tr_state->count_x = gf_list_count(*atts.text_x); else tr_state->count_x=0; if (atts.text_y) tr_state->count_y = gf_list_count(*atts.text_y); else tr_state->count_y=0; if (atts.text_rotate) tr_state->count_rotate = gf_list_count(*atts.text_rotate); else tr_state->count_rotate=0; /*horizontal justifiers container*/ tr_state->x_anchors = gf_list_new(); /*compute length of all text blocks*/ while (child) { svg_compute_text_width(child->node, &atts, tr_state); child=child->next; } /*apply justification of all blocks*/ imax=gf_list_count(tr_state->x_anchors); for (i=0; i<imax; i++) { lw=gf_list_get(tr_state->x_anchors, i); svg_apply_text_anchor(tr_state, lw); } /*re-initialize x and y counters for final compute*/ if (atts.text_x) tr_state->count_x = gf_list_count(*atts.text_x); else tr_state->count_x=0; if (atts.text_y) tr_state->count_y = gf_list_count(*atts.text_y); else tr_state->count_y=0; if (atts.text_rotate) tr_state->count_rotate = gf_list_count(*atts.text_rotate); else tr_state->count_rotate=0; tr_state->idx_rotate = 0; tr_state->chunk_index = 0; /*initialize current text position*/ if (!tr_state->text_end_x) { SVG_Coordinate *xc = (atts.text_x ? (SVG_Coordinate *) gf_list_get(*atts.text_x, 0) : NULL); tr_state->text_end_x = (xc ? xc->value : 0); } if (!tr_state->text_end_y) { SVG_Coordinate *yc = (atts.text_y ? (SVG_Coordinate *) gf_list_get(*atts.text_y, 0) : NULL); tr_state->text_end_y = (yc ? yc->value : 0); } /*pass x and y to children*/ tr_state->text_x = atts.text_x; tr_state->text_y = atts.text_y; tr_state->text_rotate = atts.text_rotate; drawable_reset_path(st->drawable); /*switch to bounds mode, and recompute children*/ mode = tr_state->traversing_mode; tr_state->traversing_mode = TRAVERSE_GET_BOUNDS; tr_state->last_char_type = 0; child = ((GF_ParentNode *) text)->children; while (child) { svg_traverse_text_block(child->node, &atts, tr_state, st->spans); child = child->next; } tr_state->traversing_mode = mode; gf_node_dirty_clear(node, 0); drawable_mark_modified(st->drawable, tr_state); st->prev_size = tr_state->svg_props->font_size->value; st->prev_flags = *tr_state->svg_props->font_style; st->prev_anchor = *tr_state->svg_props->text_anchor; while (gf_list_count(tr_state->x_anchors)) { Fixed *f = gf_list_last(tr_state->x_anchors); gf_list_rem_last(tr_state->x_anchors); gf_free(f); } gf_list_del(tr_state->x_anchors); tr_state->x_anchors = NULL; svg_update_bounds(st); } if (tr_state->traversing_mode == TRAVERSE_GET_BOUNDS) { if (!compositor_svg_is_display_off(tr_state->svg_props)) tr_state->bounds = st->bounds; } else if ((tr_state->traversing_mode == TRAVERSE_SORT) && !compositor_svg_is_display_off(tr_state->svg_props) && (*(tr_state->svg_props->visibility) != SVG_VISIBILITY_HIDDEN) ) { ctx = drawable_init_context_svg(st->drawable, tr_state); if (ctx) svg_finalize_sort(ctx, st, tr_state); /*and browse children*/ child = ((GF_ParentNode *) text)->children; while (child) { switch (gf_node_get_tag(child->node)) { case TAG_SVG_tspan: gf_node_traverse(child->node, tr_state); break; case TAG_SVG_switch: gf_node_traverse(child->node, tr_state); break; } child = child->next; } } tr_state->in_svg_text--; tr_state->text_parent = NULL; compositor_svg_restore_parent_transformation(tr_state, &backup_matrix, &mx3d); memcpy(tr_state->svg_props, &backup_props, sizeof(SVGPropertiesPointers)); tr_state->svg_flags = backup_flags; }
static void svg_circle_rebuild(GF_Node *node, Drawable *stack, SVGAllAttributes *atts) { Fixed r = 2*(atts->r ? atts->r->value : 0); drawable_reset_path(stack); gf_path_add_ellipse(stack->path, (atts->cx ? atts->cx->value : 0), (atts->cy ? atts->cy->value : 0), r, r); }
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)); }
static void DrawBitmap(DrawableContext *ctx) { u8 alpha; Render2D *sr; Bool use_hw, has_scale; M_Bitmap *bmp = (M_Bitmap *) ctx->node->owner; BitmapStack *st = (BitmapStack *) Node_GetPrivate(ctx->node->owner); sr = ctx->surface->render; /*bitmaps are NEVER rotated (forbidden in spec). In case a rotation was done we still display (reset the skew components)*/ ctx->transform.m[1] = ctx->transform.m[3] = 0; has_scale = 0; if (bmp->scale.x>0 && bmp->scale.x!=1) has_scale = 1; if (bmp->scale.y>0 && bmp->scale.y!=1) has_scale = 1; use_hw = 1; alpha = M4C_A(ctx->aspect.fill_color); /*check if driver can handle alpha blit*/ if (alpha!=255) { use_hw = sr->compositor->video_out->bHasAlpha; if (has_scale) use_hw = sr->compositor->video_out->bHasAlphaStretch; } /*for MatteTexture*/ if (!ctx->cmat.identity || ctx->h_texture->has_cmat) use_hw = 0; /*to do - materialKey*/ /*this is not a native texture, use graphics*/ if (!ctx->h_texture->data) { use_hw = 0; } else { if (!ctx->surface->SupportsFormat || !ctx->surface->DrawBitmap ) use_hw = 0; /*format not supported directly, try with brush*/ else if (!ctx->surface->SupportsFormat(ctx->surface, ctx->h_texture->pixelformat) ) use_hw = 0; } /*no HW, fall back to the graphics driver*/ if (!use_hw) { drawable_reset_path(st->graph); m4_path_add_rectangle(st->graph->path, 0, 0, ctx->original.width, ctx->original.height); ctx->no_antialias = 1; VS2D_TexturePath(ctx->surface, st->graph->path, ctx); return; } /*direct rendering, render without clippers */ if (ctx->surface->render->top_effect->trav_flags & TF_RENDER_DIRECT) { ctx->surface->DrawBitmap(ctx->surface, ctx->h_texture, &ctx->clip, &ctx->unclip); } /*render bitmap for all dirty rects*/ else { u32 i; M4IRect clip; for (i=0; i<ctx->surface->to_redraw.count; i++) { /*there's an opaque region above, don't draw*/ if (ctx->surface->draw_node_index<ctx->surface->to_redraw.opaque_node_index[i]) continue; clip = ctx->clip; m4_irect_intersect(&clip, &ctx->surface->to_redraw.list[i]); if (clip.width && clip.height) { ctx->surface->DrawBitmap(ctx->surface, ctx->h_texture, &clip, &ctx->unclip); } } } }