static void RenderLayer2D(GF_Node *node, void *rs, Bool is_destroy) { u32 i; GF_List *prevback, *prevviews; GF_Rect clip; M_Viewport *vp; ChildGroup2D *cg; GF_Matrix2D gf_mx2d_bck; GroupingNode2D *parent_bck; DrawableContext *back_ctx; Bool bool_bck; DrawableContext *ctx; M_Background2D *back; M_Layer2D *l = (M_Layer2D *)node; Layer2DStack *l2D = (Layer2DStack *) gf_node_get_private(node); RenderEffect2D *eff; if (is_destroy) { DeleteGroupingNode2D((GroupingNode2D *)l2D); gf_list_del(l2D->backs); gf_list_del(l2D->views); free(l2D); return; } eff = (RenderEffect2D *) rs; gf_mx2d_copy(gf_mx2d_bck, eff->transform); parent_bck = eff->parent; eff->parent = (GroupingNode2D *) l2D; gf_mx2d_init(eff->transform); bool_bck = eff->draw_background; prevback = eff->back_stack; prevviews = eff->view_stack; eff->back_stack = l2D->backs; eff->view_stack = l2D->views; if (l2D->first) { /*render on back first to register with stack*/ if (l->background) { eff->draw_background = 0; gf_node_render((GF_Node*) l->background, eff); group2d_reset_children((GroupingNode2D*) l2D); eff->draw_background = 1; } vp = (M_Viewport*)l->viewport; if (vp) { gf_list_add(l2D->views, vp); if (!vp->isBound) { vp->isBound = 1; gf_node_event_out_str((GF_Node*)vp, "isBound"); } } } back = NULL; if (gf_list_count(l2D->backs) ) { back = (M_Background2D*)gf_list_get(l2D->backs, 0); if (!back->isBound) back = NULL; } vp = NULL; if (gf_list_count(l2D->views)) { vp = (M_Viewport*)gf_list_get(l2D->views, 0); if (!vp->isBound) vp = NULL; } if (!eff->is_pixel_metrics) gf_mx2d_add_scale(&eff->transform, eff->min_hsize, eff->min_hsize); l2D->clip = R2D_ClipperToPixelMetrics(eff, l->size); /*apply viewport*/ if (vp) { clip = l2D->clip; vp_setup((GF_Node *) vp, eff, &clip); } back_ctx = NULL; if (back) { /*setup back size and render*/ group2d_start_child((GroupingNode2D *)l2D); eff->draw_background = 1; ctx = b2D_GetContext(back, l2D->backs); ctx->bi->unclip = l2D->clip; ctx->bi->clip = gf_rect_pixelize(&ctx->bi->unclip); gf_mx2d_init(ctx->transform); gf_node_render((GF_Node *) back, eff); eff->draw_background = 0; /*we need a trick since we're not using a dedicated surface for layer rendering, we emulate the back context: remove previous context and insert fake one*/ if (!(eff->trav_flags & TF_RENDER_DIRECT) && (gf_list_count(l2D->groups)==1)) { ChildGroup2D *cg = (ChildGroup2D *)gf_list_get(l2D->groups, 0); back_ctx = VS2D_GetDrawableContext(eff->surface); gf_list_rem(cg->contexts, 0); gf_list_add(cg->contexts, back_ctx); back_ctx->h_texture = ctx->h_texture; back_ctx->flags = ctx->flags; back_ctx->flags &= ~CTX_IS_TRANSPARENT; back_ctx->flags |= CTX_IS_BACKGROUND; back_ctx->aspect = ctx->aspect; back_ctx->drawable = ctx->drawable; drawable_check_bounds(back_ctx, eff->surface); back_ctx->bi->clip = ctx->bi->clip; back_ctx->bi->unclip = ctx->bi->unclip; } group2d_end_child((GroupingNode2D *)l2D); } group2d_traverse((GroupingNode2D *)l2D, l->children, eff); /*restore effect*/ eff->draw_background = bool_bck; gf_mx2d_copy(eff->transform, gf_mx2d_bck); eff->parent = parent_bck; eff->back_stack = prevback; eff->view_stack = prevviews; /*check bindables*/ if (l2D->first) { Bool redraw = 0; l2D->first = 0; if (!back && gf_list_count(l2D->backs)) redraw = 1; if (!vp && gf_list_count(l2D->views) ) redraw = 1; /*we missed background or viewport (was not declared as bound during traversal, and is bound now)*/ if (redraw) { group2d_reset_children((GroupingNode2D*)l2D); gf_sr_invalidate(l2D->compositor, NULL); return; } } i=0; while ((cg = (ChildGroup2D *)gf_list_enum(l2D->groups, &i))) { child2d_render_done(cg, eff, &l2D->clip); } group2d_reset_children((GroupingNode2D*)l2D); group2d_force_bounds(eff->parent, &l2D->clip); }
static void RenderPathLayout(SFNode *node, void *rs) { u32 i, count, minor, major, int_bck; Float length, offset, length_after_point; Bool res; ChildGroup2D *cg; M4Matrix2D mat; GroupingNode2D *parent_bck; PathLayoutStack *gr = (PathLayoutStack *) Node_GetPrivate(node); M_PathLayout *pl = (M_PathLayout *)node; RenderEffect2D *eff = (RenderEffect2D *) rs; if (!pl->geometry) return; /*only low-level primitives allowed*/ switch (Node_GetTag((SFNode *) pl->geometry)) { case TAG_MPEG4_Rectangle: return; case TAG_MPEG4_Circle: return; case TAG_MPEG4_Ellipse: return; } /*store effect*/ mx2d_copy(mat, eff->transform); parent_bck = eff->parent; mx2d_init(eff->transform); eff->parent = NULL; /*check geom changes*/ if ((pl->geometry != gr->last_geom) || Node_GetDirty(pl->geometry)) { if (gr->iter) m4_path_delete_iterator(gr->iter); gr->iter = NULL; int_bck = eff->trav_flags; eff->trav_flags |= TF_SWITCHED_OFF; Node_Render(pl->geometry, eff); eff->trav_flags = int_bck; gr->last_geom = pl->geometry; } if (!gr->iter) { /*get the drawable*/ Drawable *dr = (Drawable *) Node_GetPrivate( (SFNode *) pl->geometry); /*init iteration*/ if (!dr || !dr->path) return; gr->iter = m4_path_new_iterator(dr->path); if (!gr->iter) return; } eff->parent = (GroupingNode2D*)gr; int_bck = eff->text_split_mode; eff->text_split_mode = 2; group2d_traverse((GroupingNode2D*)gr, pl->children, eff); eff->text_split_mode = int_bck; /*restore effect*/ mx2d_copy(eff->transform, mat); eff->parent = parent_bck; count = ChainGetCount(gr->groups); length = gr->iter->length; offset = length * pl->pathOffset; major = pl->alignment.count ? pl->alignment.vals[0] : 0; minor = (pl->alignment.count==2) ? pl->alignment.vals[1] : 0; if (pl->wrapMode==1) { while (offset<0) offset += length; } for (i=0; i<count; i++) { cg = ChainGetEntry(gr->groups, i); if (cg->original.width>length) break; /*first set our center and baseline*/ mx2d_init(mat); /*major align*/ switch (major) { case 2: if (cg->is_text_group) mx2d_add_translation(&mat, -1*cg->original.x - cg->original.width, 0); else mx2d_add_translation(&mat, -1 * cg->original.width/2, 0); length_after_point = 0; break; case 1: length_after_point = cg->original.width/2; if (cg->is_text_group) mx2d_add_translation(&mat, -1*cg->original.x - cg->original.width / 2, 0); break; default: case 0: if (cg->is_text_group) mx2d_add_translation(&mat, cg->original.x, 0); else mx2d_add_translation(&mat, cg->original.width/2, 0); length_after_point = cg->original.width; break; } /*if wrapping and out of path, restart*/ if ((pl->wrapMode==1) && (offset+length_after_point>=length)) { offset += length_after_point; offset -= length; i--; continue; } /*if not wrapping and not yet in path skip */ if (!pl->wrapMode && (offset+length_after_point < 0)) { child2d_render_done_complex(cg, (RenderEffect2D *)rs, NULL); goto next; } /*minor justify*/ switch (minor) { /*top alignment*/ case 3: if (cg->is_text_group) mx2d_add_translation(&mat, 0, -1 * cg->ascent); else mx2d_add_translation(&mat, 0, -1 * cg->original.height / 2); break; /*baseline*/ case 1: /*move to bottom align if not text*/ if (!cg->is_text_group) mx2d_add_translation(&mat, 0, cg->original.height / 2); break; /*middle*/ case 2: /*if text use (asc+desc) /2 as line height since glyph height differ*/ if (cg->is_text_group) mx2d_add_translation(&mat, 0, cg->descent - (cg->ascent + cg->descent) / 2); break; /*bottomline alignment*/ case 0: default: if (cg->is_text_group) mx2d_add_translation(&mat, 0, cg->descent); else mx2d_add_translation(&mat, 0, cg->original.height / 2); break; } res = m4_pathiterator_get_transform_at_offset(gr->iter, offset, (Bool) (pl->wrapMode==2), &mat, 1, length_after_point); if (!res) break; child2d_render_done_complex(cg, (RenderEffect2D *)rs, &mat); next: if (i+1<count) { ChildGroup2D *cg_next = ChainGetEntry(gr->groups, i+1); /*update offset according to major alignment */ switch (major) { case 2: if (cg_next->is_text_group) offset += pl->spacing * cg_next->original.x; offset += pl->spacing * cg_next->original.width; break; case 1: if (cg->is_text_group) offset += pl->spacing * cg->original.x / 2; offset += pl->spacing * cg->original.width / 2; offset += cg_next->original.width / 2; break; default: case 0: if (cg->is_text_group) offset += pl->spacing * cg->original.x; offset += pl->spacing * cg->original.width; break; } } /*wrap*/ if ((pl->wrapMode==1) && (offset>=length)) offset-=length; } /*undrawn nodes*/ for (;i<count; i++) { cg = ChainGetEntry(gr->groups, i); child2d_render_done_complex(cg, (RenderEffect2D *)rs, NULL); } group2d_reset_children((GroupingNode2D *) gr); }