📄 drawable.c
字号:
ctx->aspect.pen_props.join = GF_LINE_JOIN_MITER; if (m->lineProps == NULL) {check_default: /*this is a bug in the spec: by default line width is 1.0, but in meterMetrics this means half of the screen :)*/ ctx->aspect.pen_props.width = FIX_ONE; if (!eff->is_pixel_metrics) ctx->aspect.pen_props.width = gf_divfix(ctx->aspect.pen_props.width, eff->min_hsize); if (m && m->transparency==FIX_ONE) { ctx->aspect.pen_props.width = 0; } else { switch (gf_node_get_tag(ctx->drawable->node)) { case TAG_MPEG4_IndexedLineSet2D: ctx->aspect.fill_color &= 0x00FFFFFF; break; case TAG_MPEG4_PointSet2D: ctx->aspect.fill_color |= FIX2INT(255 * (m ? (FIX_ONE - m->transparency) : FIX_ONE)) << 24; ctx->aspect.pen_props.width = 0; break; default: if (GF_COL_A(ctx->aspect.fill_color)) ctx->aspect.pen_props.width = 0; /*spec is unclear about that*/ else if (!m && ctx->h_texture) ctx->aspect.pen_props.width = 0; break; } } return; } LP = NULL; XLP = NULL; switch (gf_node_get_tag((GF_Node *) m->lineProps) ) { case TAG_MPEG4_LineProperties: LP = (M_LineProperties *) m->lineProps; break; case TAG_MPEG4_XLineProperties: XLP = (M_XLineProperties *) m->lineProps; break; default: ctx->aspect.pen_props.width = 0; return; } if (m->lineProps && gf_node_dirty_get(m->lineProps)) ctx->flags |= CTX_APP_DIRTY; if (LP) { ctx->aspect.pen_props.dash = (u8) LP->lineStyle; ctx->aspect.line_color = GF_COL_ARGB_FIXED(FIX_ONE-m->transparency, LP->lineColor.red, LP->lineColor.green, LP->lineColor.blue); ctx->aspect.pen_props.width = LP->width; if (ctx->col_mat) { ctx->aspect.line_color = gf_cmx_apply(ctx->col_mat, ctx->aspect.line_color); } return; } ctx->aspect.pen_props.dash = (u8) XLP->lineStyle; ctx->aspect.line_color = GF_COL_ARGB_FIXED(FIX_ONE-XLP->transparency, XLP->lineColor.red, XLP->lineColor.green, XLP->lineColor.blue); ctx->aspect.pen_props.width = XLP->width; if (ctx->col_mat) { ctx->aspect.line_color = gf_cmx_apply(ctx->col_mat, ctx->aspect.line_color); } ctx->aspect.line_scale = XLP->isScalable ? FIX_ONE : 0; ctx->aspect.pen_props.align = XLP->isCenterAligned ? GF_PATH_LINE_CENTER : GF_PATH_LINE_INSIDE; ctx->aspect.pen_props.cap = (u8) XLP->lineCap; ctx->aspect.pen_props.join = (u8) XLP->lineJoin; ctx->aspect.pen_props.miterLimit = XLP->miterLimit; ctx->aspect.pen_props.dash_offset = XLP->dashOffset; /*dash settings strutc is the same as MFFloat from XLP, typecast without storing*/ if (XLP->dashes.count) { ctx->aspect.pen_props.dash_set = (GF_DashSettings *) &XLP->dashes; } else { ctx->aspect.pen_props.dash_set = NULL; } ctx->aspect.line_texture = R2D_GetTextureHandler(XLP->texture);}static Bool check_transparent_skip(DrawableContext *ctx, Bool skipFill){ /*if sensor cannot skip*/ if (ctx->sensor) return 0; /*if texture, cannot skip*/ if (ctx->h_texture) return 0; if (! GF_COL_A(ctx->aspect.fill_color) && !GF_COL_A(ctx->aspect.line_color) ) return 1; if (ctx->aspect.pen_props.width == 0) { if (skipFill) return 1; if (!GF_COL_A(ctx->aspect.fill_color) ) return 1; } return 0;}GF_TextureHandler *drawable_get_texture(RenderEffect2D *eff){ M_Appearance *appear = (M_Appearance *) eff->appear; if (!appear || !appear->texture) return NULL; return R2D_GetTextureHandler(appear->texture);}DrawableContext *drawable_init_context(Drawable *drawable, RenderEffect2D *eff){ DrawableContext *ctx; u32 i, count; Bool skipFill; assert(eff->surface); /*switched-off geometry nodes are not rendered*/ if (eff->trav_flags & GF_SR_TRAV_SWITCHED_OFF) { GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render2D] Drawable is switched off - skipping\n")); return NULL; } //Get a empty context from the current surface ctx = VS2D_GetDrawableContext(eff->surface); gf_mx2d_copy(ctx->transform, eff->transform); ctx->drawable = drawable; /*usually set by colorTransform or changes in OrderedGroup*/ if (eff->invalidate_all) ctx->flags |= CTX_APP_DIRTY; ctx->h_texture = NULL; if (eff->appear) { ctx->appear = eff->appear; if (gf_node_dirty_get(eff->appear)) ctx->flags |= CTX_APP_DIRTY; }#ifndef FIXME /*todo cliper*/#else else { VS2D_RemoveLastContext(eff->surface); return NULL; }#endif /*FIXME - only needed for texture*/ if (!eff->color_mat.identity) { GF_SAFEALLOC(ctx->col_mat, GF_ColorMatrix); gf_cmx_copy(ctx->col_mat, &eff->color_mat); } /*IndexedLineSet2D and PointSet2D ignores fill flag and texturing*/ skipFill = 0; ctx->h_texture = NULL; switch (gf_node_get_tag(ctx->drawable->node) ) { case TAG_MPEG4_IndexedLineSet2D: skipFill = 1; break; default: ctx->h_texture = drawable_get_texture(eff); break; } /*setup sensors*/ count = gf_list_count(eff->sensors); for (i=0; i<count; i++) drawctx_add_sensor(ctx, (SensorContext*)gf_list_get(eff->sensors, i)); setup_drawable_context(ctx, eff); /*Update texture info - draw even if texture not created (this may happen if the media is removed)*/ if (ctx->h_texture && ctx->h_texture->needs_refresh) ctx->flags |= CTX_TEXTURE_DIRTY; /*not clear in the spec: what happens when a transparent node is in form/layout ?? this may completely break layout of children. We consider the node should be drawn*/ if (!eff->parent && check_transparent_skip(ctx, skipFill)) { VS2D_RemoveLastContext(eff->surface); GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render2D] Drawable is fully transparent - skipping\n")); return NULL; } ctx->flags |= CTX_HAS_APPEARANCE; //setup clipper if needed return ctx;}void drawable_finalize_end(struct _drawable_context *ctx, RenderEffect2D *eff){ if (eff->parent) { group2d_add_to_context_list(eff->parent, ctx); } else { /*setup clipper and register bounds & sensors*/ gf_irect_intersect(&ctx->bi->clip, &eff->surface->top_clipper); if (!ctx->bi->clip.width || !ctx->bi->clip.height) { ctx->bi->clip.width = 0; /*remove if this is the last context*/ if (eff->surface->cur_context == ctx) eff->surface->cur_context->drawable = NULL; return; } VS2D_RegisterSensor(eff->surface, ctx); /*keep track of node drawn, whether direct or indirect rendering*/ if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_SURFACE) ) { struct _drawable_store *it; GF_SAFEALLOC(it, struct _drawable_store); it->drawable = ctx->drawable; if (eff->surface->last_prev_entry) { eff->surface->last_prev_entry->next = it; eff->surface->last_prev_entry = it; } else { eff->surface->prev_nodes = eff->surface->last_prev_entry = it; } GF_LOG(GF_LOG_DEBUG, GF_LOG_RENDER, ("[Render 2D] Registering new drawn node %s on surface\n", gf_node_get_class_name(it->drawable->node))); ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_SURFACE; } if (eff->trav_flags & TF_RENDER_DIRECT) { assert(!eff->traversing_mode); eff->traversing_mode = TRAVERSE_DRAW; eff->ctx = ctx; gf_node_allow_cyclic_render(ctx->drawable->node); gf_node_render(ctx->drawable->node, eff); eff->ctx = NULL; eff->traversing_mode = 0; } }}void drawable_check_bounds(struct _drawable_context *ctx, VisualSurface2D *surf){ if (!ctx->bi) { ctx->bi = drawable_check_alloc_bounds(ctx, surf); assert(ctx->bi); ctx->bi->extra_check = ctx->appear; }}static void drawable_finalize_render_ex(struct _drawable_context *ctx, RenderEffect2D *eff, GF_Rect *orig_bounds, Bool is_focus){ Fixed pw; GF_Rect unclip, store_orig_bounds; drawable_check_bounds(ctx, eff->surface); if (orig_bounds) { store_orig_bounds = *orig_bounds; } else { gf_path_get_bounds(ctx->drawable->path, &store_orig_bounds); } ctx->bi->unclip = store_orig_bounds; gf_mx2d_apply_rect(&eff->transform, &ctx->bi->unclip); /*apply pen width*/ if (ctx->aspect.pen_props.width) { StrikeInfo2D *si = NULL; /*if pen is not scalable, apply user/viewport transform so that original aspect is kept*/ if (!ctx->aspect.line_scale) { GF_Point2D pt; pt.x = ctx->transform.m[0] + ctx->transform.m[1]; pt.y = ctx->transform.m[3] + ctx->transform.m[4]; ctx->aspect.line_scale = gf_divfix(FLT2FIX(1.41421356f) , gf_v2d_len(&pt)); } /*get strike info & outline for exact bounds compute. If failure use default offset*/ si = drawctx_get_strikeinfo(eff->surface->render, ctx, ctx->drawable->path); if (si && si->outline) { gf_path_get_bounds(si->outline, &ctx->bi->unclip); gf_mx2d_apply_rect(&eff->transform, &ctx->bi->unclip); } else { pw = gf_mulfix(ctx->aspect.pen_props.width, ctx->aspect.line_scale); ctx->bi->unclip.x -= pw/2; ctx->bi->unclip.y += pw/2; ctx->bi->unclip.width += pw; ctx->bi->unclip.height += pw; } } if (ctx->bi->unclip.width && ctx->bi->unclip.height) { unclip = ctx->bi->unclip; if (! (ctx->flags & CTX_NO_ANTIALIAS)) { /*grow of 2 pixels (-1 and +1) to handle AA, but ONLY on cliper otherwise we will modify layout/form */ pw = (eff->is_pixel_metrics) ? FIX_ONE : 2*FIX_ONE/eff->surface->width; unclip.x -= pw; unclip.y += pw; unclip.width += 2*pw; unclip.height += 2*pw; } ctx->bi->clip = gf_rect_pixelize(&unclip); } else { ctx->bi->clip.width = 0; } drawable_finalize_end(ctx, eff); if (ctx->drawable && !is_focus) drawable_check_focus_highlight(ctx->drawable->node, eff, &store_orig_bounds);}void drawable_finalize_render(struct _drawable_context *ctx, RenderEffect2D *eff, GF_Rect *orig_bounds){ drawable_finalize_render_ex(ctx, eff, orig_bounds, 0);}void drawable_check_focus_highlight(GF_Node *node, RenderEffect2D *eff, GF_Rect *orig_bounds){ DrawableContext *hl; GF_Node *prev_node; u32 prev_mode; GF_Rect *bounds; GF_Matrix2D cur; if (eff->surface->render->focus_node!=node) return; if (!eff->surface->render->focus_highlight) return; hl = VS2D_GetDrawableContext(eff->surface); hl->drawable = eff->surface->render->focus_highlight; /*check if focus node has changed*/ prev_node = gf_node_get_private(hl->drawable->node); if (prev_node != node) { if (!orig_bounds) { gf_mx2d_copy(cur, eff->transform); gf_mx2d_init(eff->transform); prev_mode = eff->traversing_mode; eff->traversing_mode = TRAVERSE_GET_BOUNDS; eff->bounds.width = eff->bounds.height = 0; eff->bounds.x = eff->bounds.y = 0; svg_get_nodes_bounds(node, ((SVG_Element *)node)->children, eff); eff->traversing_mode = prev_mode; gf_mx2d_copy(eff->transform, cur); bounds = &eff->bounds; } else { bounds = orig_bounds; } gf_node_set_private(hl->drawable->node, node); drawable_reset_path(hl->drawable); gf_path_reset(hl->drawable->path); gf_path_add_rect(hl->drawable->path, bounds->x, bounds->y, bounds->width, bounds->height); } hl->aspect.fill_color = eff->surface->render->highlight_fill; hl->aspect.line_color = eff->surface->render->highlight_stroke; hl->aspect.line_scale = 0; hl->aspect.pen_props.width = 1; hl->aspect.pen_props.join = GF_LINE_JOIN_BEVEL; hl->aspect.pen_props.dash = GF_DASH_STYLE_DOT; gf_mx2d_copy(hl->transform, eff->transform); drawable_finalize_render_ex(hl, eff, NULL, 1);}void drawable_render_focus(GF_Node *node, void *rs, Bool is_destroy) { RenderEffect2D *eff = (RenderEffect2D *)rs; if (is_destroy) return; if (eff->traversing_mode == TRAVERSE_DRAW) VS2D_DrawPath(eff->surface, eff->ctx->drawable->path, eff->ctx, NULL, NULL);}void delete_strikeinfo2d(StrikeInfo2D *info){ if (info->outline) gf_path_del(info->outline); free(info);}StrikeInfo2D *drawctx_get_strikeinfo(Render2D *sr, DrawableContext *ctx, GF_Path *path){ StrikeInfo2D *si, *prev; GF_Node *lp; u32 now; if (ctx->appear && !ctx->aspect.pen_props.width) return NULL; if (path && !path->n_points) return NULL; lp = NULL; if (ctx->appear && (gf_node_get_tag(ctx->appear) < GF_NODE_RANGE_LAST_X3D) ) { lp = ((M_Appearance *)ctx->appear)->material; if (lp) lp = ((M_Material2D *) lp)->lineProps; } prev = NULL; si = ctx->drawable->outline; while (si) { /*note this includes default LP (NULL)*/ if ((si->lineProps == lp) && (!path || (path==si->original)) ) break; if (!si->lineProps) { gf_list_del_item(sr->strike_bank, si); if (si->outline) gf_path_del(si->outline); if (prev) prev->next = si->next; else ctx->drawable->outline = si->next; free(si); si = prev ? prev->next : ctx->drawable->outline; continue; } prev = si; si = si->next; } /*not found, add*/ if (!si) { GF_SAFEALLOC(si, StrikeInfo2D); si->lineProps = lp; si->node = ctx->drawable->node; if (ctx->drawable->outline) { prev = ctx->drawable->outline; while (prev->next) prev = prev->next; prev->next = si; } else { ctx->drawable->outline = si; } gf_list_add(sr->strike_bank, si); } /*node changed or outline not build*/ now = lp ? R2D_LP_GetLastUpdateTime(lp) : si->last_update_time; if (!si->outline || (now!=si->last_update_time) || (si->line_scale != ctx->aspect.line_scale) || (si->path_length != ctx->aspect.pen_props.path_length) || (ctx->flags & CTX_SVG_OUTLINE_GEOMETRY_DIRTY)) { u32 i; Fixed w = ctx->aspect.pen_props.width; Fixed dash_o = ctx->aspect.pen_props.dash_offset; si->last_update_time = now; si->line_scale = ctx->aspect.line_scale; if (si->outline) gf_path_del(si->outline); /*apply scale whether scalable or not (if not scalable, scale is still needed for scalable zoom)*/ ctx->aspect.pen_props.width = gf_mulfix(ctx->aspect.pen_props.width, ctx->aspect.line_scale); if (ctx->aspect.pen_props.dash != GF_DASH_STYLE_CUSTOM_ABS) ctx->aspect.pen_props.dash_offset = gf_mulfix(ctx->aspect.pen_props.dash_offset, ctx->aspect.pen_props.width); if (ctx->aspect.pen_props.dash_set) { for(i=0; i<ctx->aspect.pen_props.dash_set->num_dash; i++) { ctx->aspect.pen_props.dash_set->dashes[i] = gf_mulfix(ctx->aspect.pen_props.dash_set->dashes[i], ctx->aspect.line_scale); } } if (path) { si->outline = gf_path_get_outline(path, ctx->aspect.pen_props); si->original = path; } else { si->outline = gf_path_get_outline(ctx->drawable->path, ctx->aspect.pen_props); } /*restore*/ ctx->aspect.pen_props.width = w; ctx->aspect.pen_props.dash_offset = dash_o; if (ctx->aspect.pen_props.dash_set) { for(i=0; i<ctx->aspect.pen_props.dash_set->num_dash; i++) { ctx->aspect.pen_props.dash_set->dashes[i] = gf_divfix(ctx->aspect.pen_props.dash_set->dashes[i], ctx->aspect.line_scale); } } } return si;}void drawable_reset_path_outline(Drawable *st){ StrikeInfo2D *si = st->outline; while (si) { if (si->outline) gf_path_del(si->outline); si->outline = NULL; si->original = NULL; si = si->next; }}void drawable_reset_path(Drawable *st){ drawable_reset_path_outline(st); if (st->path) gf_path_reset(st->path);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -