static void svg_font_on_load(GF_Node *handler, GF_DOM_Event *event, GF_Node *observer) { GF_Compositor *compositor; GF_Font *font; assert(event->currentTarget->ptr_type==GF_DOM_EVENT_NODE); assert(gf_node_get_tag((GF_Node*)event->currentTarget->ptr)==TAG_SVG_font); font = gf_node_get_private((GF_Node*)event->currentTarget->ptr); font->not_loaded = 0; compositor = (GF_Compositor *)gf_node_get_private((GF_Node *)handler); /*brute-force signaling that all fonts have changed and texts must be recomputed*/ compositor->reset_fonts = 1; gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); compositor->fonts_pending--; }
void compositor_svg_video_modified(GF_Compositor *compositor, GF_Node *node) { /*if href has been modified, stop the video (and associated audio if any) right away - we cannot wait for next traversal to process this as the video could be in a hidden subtree not traversed*/ if (gf_node_dirty_get(node) & GF_SG_SVG_XLINK_HREF_DIRTY) { SVG_video_stack *st = (SVG_video_stack *)gf_node_get_private(node); /*WARNING - stack may be NULL at this point when inserting the video from script*/ if (st && st->txh.is_open) { if (st->audio) { svg_audio_smil_evaluate_ex(NULL, 0, SMIL_TIMING_EVAL_REMOVE, st->audio, st->txh.owner); gf_node_unregister(st->audio, NULL); st->audio = NULL; } /*reset cached URL to avoid reopening the resource in the smil timing callback*/ gf_sg_vrml_mf_reset(&st->txurl, GF_SG_VRML_MFURL); gf_sc_texture_stop(&st->txh); } } gf_node_dirty_set(node, 0, GF_FALSE); /*and force a redraw of next frame*/ gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); }
void svg_traverse_domtext(GF_Node *node, SVGAllAttributes *atts, GF_TraverseState *tr_state, GF_List *spans, GF_Node *anchor_node) { GF_DOMText *dom_text = (GF_DOMText *)node; Fixed x, y; u32 i; Fixed x_anchor, *ptr; GF_Font *font; Fixed block_width; GF_FontManager *fm; GF_TextSpan *span; if (!dom_text->textContent) return; if (tr_state->in_svg_text_area) { svg_traverse_dom_text_area(node, atts, tr_state, spans); return; } fm = tr_state->visual->compositor->font_manager; if (!fm) return; font = svg_set_font(tr_state, fm); if (!font) return; if (font->not_loaded) { tr_state->visual->compositor->reset_fonts = GF_TRUE; tr_state->visual->compositor->skip_flush = 1; gf_sc_next_frame_state(tr_state->visual->compositor, GF_SC_DRAW_FRAME); return; } span = svg_get_text_span(fm, font, tr_state->svg_props->font_size->value, (tr_state->count_x>1), (tr_state->count_y>1), tr_state->count_rotate, atts, dom_text->textContent, atts->xml_lang ? *atts->xml_lang : NULL, tr_state); if (!span) return; i=0; /* if character position is given in (x, y) attributes, use it. Otherwise add text at tr_state->text_end_x. */ while ((i<span->nb_glyphs) && ( (tr_state->count_x>1) || (tr_state->count_y>1) ) ) { //get x and y positions if (tr_state->count_x==0) { x = tr_state->text_end_x; } else { SVG_Coordinate *xc = (SVG_Coordinate *) gf_list_get(*tr_state->text_x, tr_state->chunk_index); x = xc->value; (tr_state->count_x)--; } if (tr_state->count_y==0) { y = tr_state->text_end_y; } else { SVG_Coordinate *yc = (SVG_Coordinate *) gf_list_get(*tr_state->text_y, tr_state->chunk_index); y = yc->value; (tr_state->count_y)--; } /*apply x-anchor*/ ptr = (Fixed *)gf_list_get(tr_state->x_anchors, tr_state->chunk_index); x_anchor = ptr ? *ptr : 0; if (span->dx) span->dx[i] = x_anchor + x; else if (!i) span->off_x = x_anchor + x; if (span->dy) span->dy[i] = y; else span->off_y = y; if (tr_state->count_rotate) { SVG_Coordinate *rc = (SVG_Coordinate *) gf_list_get(*tr_state->text_rotate, tr_state->idx_rotate); span->rot[i] = gf_mulfix(GF_PI/180, rc->value); if (tr_state->idx_rotate+1<tr_state->count_rotate) tr_state->idx_rotate++; } /*update last glyph position*/ block_width = (span->glyphs[i] ? span->glyphs[i]->horiz_advance : font->max_advance_h) * span->font_scale; tr_state->text_end_x = x+block_width; tr_state->text_end_y = y; (tr_state->chunk_index)++; i++; } /* no more positions, add remaining glyphs as a block*/ if (i<span->nb_glyphs) { Fixed offset; if ((tr_state->count_x==1) && tr_state->text_x) { SVG_Coordinate *xc = (SVG_Coordinate *) gf_list_get(*tr_state->text_x, tr_state->chunk_index); tr_state->text_end_x = xc->value; (tr_state->count_x)--; } if ((tr_state->count_y==1) && tr_state->text_y) { SVG_Coordinate *yc = (SVG_Coordinate *) gf_list_get(*tr_state->text_y, tr_state->chunk_index); tr_state->text_end_y = yc->value; (tr_state->count_y)--; } x = tr_state->text_end_x; y = tr_state->text_end_y; /*apply x anchor*/ ptr = (Fixed *)gf_list_get(tr_state->x_anchors, tr_state->chunk_index); x_anchor = ptr ? *ptr : 0; offset = x_anchor + x - (span->dx ? span->dx[i] : span->off_x); if (!span->dx && (tr_state->text_x || x_anchor)) span->off_x = x_anchor + x; if (!span->dy && tr_state->text_y) span->off_y = y; block_width = 0; while (i<span->nb_glyphs) { if (span->rot) { SVG_Coordinate *rc = (SVG_Coordinate *) gf_list_get(*tr_state->text_rotate, tr_state->idx_rotate); span->rot[i] = gf_mulfix(GF_PI/180, rc->value); if (tr_state->idx_rotate+1<tr_state->count_rotate) tr_state->idx_rotate++; } if (span->dx) span->dx[i] = offset + block_width; if (span->dy) span->dy[i] = y; block_width += (span->glyphs[i] ? span->glyphs[i]->horiz_advance : font->max_advance_h) * span->font_scale; i++; } tr_state->text_end_x += block_width; } /*add span path to list of spans*/ gf_list_add(spans, span); span->anchor = anchor_node; }
GF_EXPORT void gf_sc_invalidate(GF_Compositor *compositor, GF_Node *byObj) { if (!byObj) { gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); return; } switch (gf_node_get_tag(byObj)) { #ifndef GPAC_DISABLE_VRML case TAG_MPEG4_AnimationStream: compositor_animationstream_modified(byObj); break; case TAG_MPEG4_AudioBuffer: compositor_audiobuffer_modified(byObj); break; case TAG_MPEG4_AudioSource: compositor_audiosource_modified(byObj); break; case TAG_MPEG4_AudioClip: #ifndef GPAC_DISABLE_X3D case TAG_X3D_AudioClip: #endif compositor_audioclip_modified(byObj); break; case TAG_MPEG4_TimeSensor: #ifndef GPAC_DISABLE_X3D case TAG_X3D_TimeSensor: #endif compositor_timesensor_modified(byObj); break; case TAG_MPEG4_ImageTexture: #ifndef GPAC_DISABLE_X3D case TAG_X3D_ImageTexture: #endif case TAG_MPEG4_CacheTexture: compositor_imagetexture_modified(byObj); break; case TAG_MPEG4_MovieTexture: #ifndef GPAC_DISABLE_X3D case TAG_X3D_MovieTexture: #endif compositor_movietexture_modified(byObj); break; case TAG_MPEG4_Background2D: compositor_background2d_modified(byObj); break; #ifndef GPAC_DISABLE_3D case TAG_MPEG4_Background: #ifndef GPAC_DISABLE_X3D case TAG_X3D_Background: #endif compositor_background_modified(byObj); break; #endif case TAG_MPEG4_Layout: compositor_layout_modified(compositor, byObj); break; case TAG_MPEG4_EnvironmentTest: compositor_envtest_modified(byObj); break; #endif /*GPAC_DISABLE_VRML*/ #ifndef GPAC_DISABLE_SVG case TAG_SVG_video: compositor_svg_video_modified(compositor, byObj); break; #endif /*GPAC_DISABLE_SVG*/ default: /*for all nodes, invalidate parent graph - note we do that for sensors as well to force recomputing sensor list cached at grouping node level*/ gf_node_dirty_set(byObj, 0, 1); gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME); break; } }
void visual_2d_texture_path_extended(GF_VisualManager *visual, GF_Path *path, GF_TextureHandler *txh, struct _drawable_context *ctx, GF_Rect *orig_bounds, GF_Matrix2D *ext_mx, GF_TraverseState *tr_state) { Fixed sS, sT; u32 tx_tile; GF_STENCIL tx_raster; GF_Matrix2D mx_texture; GF_Rect orig_rc; GF_Raster2D *raster; if (! visual->CheckAttached(visual) ) return; raster = visual->compositor->rasterizer; if (!txh) txh = ctx->aspect.fill_texture; if (!txh) return; if (!txh->tx_io) { gf_node_dirty_set(txh->owner, 0, 1); txh->needs_refresh=1; return; } /*this is gradient draw*/ if (txh->compute_gradient_matrix) { visual_2d_draw_gradient(visual, path, txh, ctx, tr_state, ext_mx, orig_bounds); return; } #ifndef GPAC_DISABLE_3D if (visual->compositor->hybrid_opengl) { visual_2d_texture_path_opengl_auto(visual, path, txh, ctx, orig_bounds, ext_mx, tr_state); return; } #endif if (txh->flags & GF_SR_TEXTURE_PRIVATE_MEDIA) { GF_Window src, dst; visual_2d_fill_path(visual, ctx, NULL, tr_state, 0); /*if texture not ready, update the size before computing output rectangles */ if (!txh->width || !txh->height) { gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped); /*in case the node is an MPEG-4 bitmap, force stack rebuild at next frame */ gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1); } if (compositor_texture_rectangles(visual, txh, &ctx->bi->clip, &ctx->bi->unclip, &src, &dst, NULL, NULL)) { if (txh->stream && gf_mo_set_position(txh->stream, &src, &dst)) { gf_mo_get_visual_info(txh->stream, &txh->width, &txh->height, &txh->stride, &txh->pixel_ar, &txh->pixelformat, &txh->is_flipped); /*force dirty flag to get called again*/ gf_node_dirty_set(ctx->drawable->node, GF_SG_NODE_DIRTY, 1); gf_sc_next_frame_state(visual->compositor, GF_SC_DRAW_FRAME); } } return; } if (!gf_sc_texture_push_image(txh, 0, 1)) return; tx_raster = gf_sc_texture_get_stencil(txh); /*setup quality even for background (since quality concerns images)*/ visual_2d_set_options(visual->compositor, visual->raster_surface, ctx->flags & CTX_IS_TEXT, ctx->flags & CTX_NO_ANTIALIAS); /*get original bounds*/ if (orig_bounds) { orig_rc = *orig_bounds; } else { gf_path_get_bounds(path, &orig_rc); } /*get scaling ratio so that active texture view is stretched to original bounds (std 2D shape texture mapping in MPEG4)*/ sS = orig_rc.width / txh->width; sT = orig_rc.height / txh->height; gf_mx2d_init(mx_texture); gf_mx2d_add_scale(&mx_texture, sS, sT); #ifndef GPAC_DISABLE_VRML /*apply texture transform*/ if (ctx->flags & CTX_HAS_APPEARANCE) { GF_Matrix2D tex_trans; visual_2d_get_texture_transform(ctx->appear, txh, &tex_trans, (txh == ctx->aspect.fill_texture) ? 0 : 1, txh->width * sS, txh->height * sT); gf_mx2d_add_matrix(&mx_texture, &tex_trans); } #endif /*move to bottom-left corner of bounds */ gf_mx2d_add_translation(&mx_texture, (orig_rc.x), (orig_rc.y - orig_rc.height)); if (ext_mx) gf_mx2d_add_matrix(&mx_texture, ext_mx); /*move to final coordinate system (except background which is built directly in final coord system)*/ if (!(ctx->flags & CTX_IS_BACKGROUND) ) gf_mx2d_add_matrix(&mx_texture, &ctx->transform); /*set path transform*/ raster->stencil_set_matrix(tx_raster, &mx_texture); tx_tile = 0; if (txh->flags & GF_SR_TEXTURE_REPEAT_S) tx_tile |= GF_TEXTURE_REPEAT_S; if (txh->flags & GF_SR_TEXTURE_REPEAT_T) tx_tile |= GF_TEXTURE_REPEAT_T; if (ctx->flags & CTX_FLIPED_COORDS) tx_tile |= GF_TEXTURE_FLIP; raster->stencil_set_tiling(tx_raster, (GF_TextureTiling) tx_tile); if (!(ctx->flags & CTX_IS_BACKGROUND) ) { u8 a = GF_COL_A(ctx->aspect.fill_color); if (!a) a = GF_COL_A(ctx->aspect.line_color); /*texture alpha scale is the original material transparency, NOT the one after color transform*/ raster->stencil_set_alpha(tx_raster, a ); raster->stencil_set_color_matrix(tx_raster, ctx->col_mat); raster->surface_set_matrix(visual->raster_surface, &ctx->transform); } else { raster->surface_set_matrix(visual->raster_surface, NULL); } txh->flags |= GF_SR_TEXTURE_USED; /*push path & draw*/ raster->surface_set_path(visual->raster_surface, path); visual_2d_fill_path(visual, ctx, tx_raster, tr_state, 0); raster->surface_set_path(visual->raster_surface, NULL); ctx->flags |= CTX_PATH_FILLED; }