Line data Source code
1 : /*
2 : * GPAC - Multimedia Framework C SDK
3 : *
4 : * Authors: Jean Le Feuvre
5 : * Copyright (c) Telecom ParisTech 2000-2012
6 : * All rights reserved
7 : *
8 : * This file is part of GPAC / Scene Compositor sub-project
9 : *
10 : * GPAC is free software; you can redistribute it and/or modify
11 : * it under the terms of the GNU Lesser General Public License as published by
12 : * the Free Software Foundation; either version 2, or (at your option)
13 : * any later version.
14 : *
15 : * GPAC is distributed in the hope that it will be useful,
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : * GNU Lesser General Public License for more details.
19 : *
20 : * You should have received a copy of the GNU Lesser General Public
21 : * License along with this library; see the file COPYING. If not, write to
22 : * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
23 : *
24 : */
25 :
26 : #include "drawable.h"
27 : #include "visual_manager.h"
28 : #include "nodes_stacks.h"
29 :
30 :
31 :
32 : /*default draw routine*/
33 47959 : void drawable_draw(Drawable *drawable, GF_TraverseState *tr_state)
34 : {
35 47959 : visual_2d_texture_path(tr_state->visual, tr_state->ctx->drawable->path, tr_state->ctx, tr_state);
36 47959 : visual_2d_draw_path(tr_state->visual, tr_state->ctx->drawable->path, tr_state->ctx, NULL, NULL, tr_state);
37 47959 : }
38 :
39 : /*default point_over routine*/
40 : #ifndef GPAC_DISABLE_VRML
41 88567 : void vrml_drawable_pick(Drawable *drawable, GF_TraverseState *tr_state)
42 : {
43 : DrawAspect2D asp;
44 : GF_Matrix2D inv_2d;
45 : StrikeInfo2D *si;
46 : Fixed x, y;
47 : u32 i, count;
48 88567 : GF_Node *appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear;
49 88567 : GF_Compositor *compositor = tr_state->visual->compositor;
50 :
51 : #ifndef GPAC_DISABLE_3D
52 88567 : if (tr_state->visual->type_3d) {
53 234 : visual_3d_vrml_drawable_pick(drawable->node, tr_state, NULL, drawable);
54 234 : return;
55 : }
56 : #endif
57 88333 : gf_mx2d_copy(inv_2d, tr_state->transform);
58 88333 : gf_mx2d_inverse(&inv_2d);
59 88333 : x = tr_state->ray.orig.x;
60 88333 : y = tr_state->ray.orig.y;
61 88333 : gf_mx2d_apply_coords(&inv_2d, &x, &y);
62 :
63 : memset(&asp, 0, sizeof(DrawAspect2D));
64 88333 : drawable_get_aspect_2d_mpeg4(drawable->node, &asp, tr_state);
65 :
66 : /*MPEG-4 picking is always on regardless of color properties*/
67 : if (/*tr_state->ctx->aspect.fill_texture */
68 : /* (tr_state->pick_type<PICK_FULL) */
69 : /* GF_COL_A(asp.fill_color)*/
70 : 1) {
71 88333 : if (gf_path_point_over(drawable->path, x, y)) {
72 : goto picked;
73 : }
74 : }
75 :
76 86072 : if (asp.pen_props.width || asp.line_texture ) {
77 22453 : si = drawable_get_strikeinfo(tr_state->visual->compositor, drawable, &asp, appear, NULL, 0, NULL);
78 22453 : if (si && si->outline && gf_path_point_over(si->outline, x, y)) {
79 : goto picked;
80 : }
81 : }
82 : return;
83 :
84 2278 : picked:
85 2278 : compositor->hit_local_point.x = x;
86 2278 : compositor->hit_local_point.y = y;
87 2278 : compositor->hit_local_point.z = 0;
88 :
89 2278 : gf_mx_from_mx2d(&compositor->hit_world_to_local, &tr_state->transform);
90 2278 : gf_mx_from_mx2d(&compositor->hit_local_to_world, &inv_2d);
91 :
92 2278 : gf_list_reset(compositor->hit_use_stack);
93 2278 : compositor->hit_node = drawable->node;
94 2278 : compositor->hit_use_dom_events = 0;
95 2278 : compositor->hit_normal.x = compositor->hit_normal.y = 0;
96 2278 : compositor->hit_normal.z = FIX_ONE;
97 2278 : compositor->hit_texcoords.x = gf_divfix(x - drawable->path->bbox.x, drawable->path->bbox.width);
98 2278 : compositor->hit_texcoords.y = FIX_ONE - gf_divfix(drawable->path->bbox.y - y, drawable->path->bbox.height);
99 :
100 : #ifndef GPAC_DISABLE_VRML
101 2278 : if (compositor_is_composite_texture(appear)) {
102 68 : compositor->hit_appear = appear;
103 : } else
104 : #endif
105 : {
106 2210 : compositor->hit_appear = NULL;
107 : }
108 2278 : compositor->hit_text = NULL;
109 :
110 2278 : gf_list_reset(tr_state->visual->compositor->sensors);
111 2278 : count = gf_list_count(tr_state->vrml_sensors);
112 4314 : for (i=0; i<count; i++) {
113 2036 : gf_list_add(tr_state->visual->compositor->sensors, gf_list_get(tr_state->vrml_sensors, i));
114 : }
115 : }
116 : #endif /*GPAC_DISABLE_VRML*/
117 :
118 1277 : void drawable_init_ex(Drawable *tmp)
119 : {
120 1277 : tmp->path = gf_path_new();
121 1277 : GF_SAFEALLOC(tmp->dri, DRInfo);
122 1277 : if (tmp->dri) {
123 : /*allocate a default bounds container*/
124 1277 : GF_SAFEALLOC(tmp->dri->current_bounds, BoundInfo);
125 : }
126 1277 : }
127 :
128 4822 : Drawable *drawable_new()
129 : {
130 : Drawable *tmp;
131 4822 : GF_SAFEALLOC(tmp, Drawable)
132 4822 : if (!tmp) {
133 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate drawable object\n"));
134 : return NULL;
135 : }
136 4822 : tmp->path = gf_path_new();
137 : /*allocate a default visual container*/
138 4822 : GF_SAFEALLOC(tmp->dri, DRInfo);
139 4822 : if (tmp->dri) {
140 : /*allocate a default bounds container*/
141 4822 : GF_SAFEALLOC(tmp->dri->current_bounds, BoundInfo);
142 : }
143 :
144 4822 : if (!tmp->dri || !tmp->dri->current_bounds) {
145 0 : if (tmp->dri) gf_free(tmp->dri);
146 0 : gf_path_del(tmp->path);
147 0 : gf_free(tmp);
148 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate drawable object bounds\n"));
149 : return NULL;
150 : }
151 : return tmp;
152 : }
153 :
154 1813 : void drawable_reset_bounds(Drawable *dr, GF_VisualManager *visual)
155 : {
156 : DRInfo *dri;
157 : BoundInfo *bi, *_cur;
158 :
159 1813 : dri = dr->dri;
160 3633 : while (dri) {
161 1814 : if (dri->visual != visual) {
162 7 : dri = dri->next;
163 7 : continue;
164 : }
165 : /*destroy previous bounds only, since current ones are always used during traversing*/
166 1807 : bi = dri->previous_bounds;
167 5549 : while (bi) {
168 : _cur = bi;
169 1935 : bi = bi->next;
170 1935 : gf_free(_cur);
171 : }
172 1807 : dri->previous_bounds = NULL;
173 1807 : return;
174 : }
175 : }
176 :
177 6098 : void drawable_del_ex(Drawable *dr, GF_Compositor *compositor, Bool no_free)
178 : {
179 : StrikeInfo2D *si;
180 : DRInfo *dri;
181 : BoundInfo *bi, *_cur;
182 :
183 :
184 : /*remove node from all visuals it's on*/
185 6098 : dri = dr->dri;
186 18300 : while (dri) {
187 : DRInfo *cur;
188 6104 : Bool is_reg = compositor ? gf_sc_visual_is_registered(compositor, dri->visual) : 0;
189 :
190 6104 : bi = dri->current_bounds;
191 20612 : while (bi) {
192 : _cur = bi;
193 8404 : if (is_reg && bi->clip.width) {
194 5562 : ra_add(&dri->visual->to_redraw, &bi->clip);
195 : }
196 8404 : bi = bi->next;
197 8404 : gf_free(_cur);
198 : }
199 6104 : bi = dri->previous_bounds;
200 16013 : while (bi) {
201 : _cur = bi;
202 3805 : if (is_reg && bi->clip.width) {
203 1 : ra_add(&dri->visual->to_redraw, &bi->clip);
204 : }
205 3805 : bi = bi->next;
206 3805 : gf_free(_cur);
207 : }
208 6104 : if (is_reg) visual_2d_drawable_delete(dri->visual, dr);
209 : cur = dri;
210 6104 : dri = dri->next;
211 6104 : gf_free(cur);
212 : }
213 6098 : if (compositor) {
214 6098 : gf_sc_next_frame_state(compositor, GF_SC_DRAW_FRAME);
215 :
216 : /*check node isn't being tracked*/
217 6098 : if (compositor->grab_node==dr->node)
218 0 : compositor->grab_node = NULL;
219 :
220 6098 : if (compositor->focus_node==dr->node) {
221 0 : compositor->focus_node = NULL;
222 0 : compositor->focus_text_type = 0;
223 : }
224 6098 : if (compositor->hit_node==dr->node) compositor->hit_node = NULL;
225 6098 : if (compositor->hit_text==dr->node) compositor->hit_text = NULL;
226 : }
227 :
228 : /*remove path object*/
229 6098 : if (dr->path) gf_path_del(dr->path);
230 :
231 : #ifndef GPAC_DISABLE_3D
232 6098 : if (dr->mesh) mesh_free(dr->mesh);
233 : #endif
234 :
235 6098 : si = dr->outline;
236 13229 : while (si) {
237 1033 : StrikeInfo2D *next = si->next;
238 : /*remove from main strike list*/
239 1033 : if (compositor) gf_list_del_item(compositor->strike_bank, si);
240 1033 : delete_strikeinfo2d(si);
241 : si = next;
242 : }
243 6098 : if (!no_free)
244 4821 : gf_free(dr);
245 6098 : }
246 :
247 4217 : void drawable_del(Drawable *dr)
248 : {
249 4217 : GF_Compositor *compositor = gf_sc_get_compositor(dr->node);
250 4217 : drawable_del_ex(dr, compositor, GF_FALSE);
251 4217 : }
252 3266 : void drawable_node_del(GF_Node *node)
253 : {
254 3266 : drawable_del( (Drawable *)gf_node_get_private(node) );
255 3266 : }
256 :
257 3888 : Drawable *drawable_stack_new(GF_Compositor *compositor, GF_Node *node)
258 : {
259 3888 : Drawable *stack = drawable_new();
260 3888 : stack->node = node;
261 3888 : gf_node_set_private(node, stack);
262 3888 : return stack;
263 : }
264 :
265 142320 : static BoundInfo *drawable_check_alloc_bounds(struct _drawable_context *ctx, GF_VisualManager *visual)
266 : {
267 : DRInfo *dri, *prev;
268 : BoundInfo *bi, *_prev;
269 :
270 : /*get bounds info for this visual manager*/
271 : prev = NULL;
272 142320 : dri = ctx->drawable->dri;
273 142717 : while (dri) {
274 142710 : if (dri->visual == visual) break;
275 4357 : if (!dri->visual) {
276 3960 : dri->visual = visual;
277 : break;
278 : }
279 : prev = dri;
280 397 : dri = dri->next;
281 : }
282 142320 : if (!dri) {
283 7 : GF_SAFEALLOC(dri, DRInfo);
284 7 : if (!dri) return NULL;
285 7 : dri->visual = visual;
286 7 : if (prev) prev->next = dri;
287 0 : else ctx->drawable->dri = dri;
288 7 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Allocating new bound info storage on visual %08x for drawable %s\n", visual, gf_node_get_class_name(ctx->drawable->node)));
289 : }
290 :
291 : /*get available bound info slot*/
292 : _prev = NULL;
293 142320 : bi = dri->current_bounds;
294 348408 : while (bi) {
295 340360 : if (!bi->clip.width) break;
296 : _prev = bi;
297 206088 : bi = bi->next;
298 : }
299 142320 : if (!bi) {
300 8048 : GF_SAFEALLOC(bi, BoundInfo);
301 8048 : if (!bi) return NULL;
302 8048 : if (_prev) {
303 : // assert(!_prev->next);
304 4383 : _prev->next = bi;
305 : }
306 : else {
307 : // assert(!dri->current_bounds);
308 3665 : dri->current_bounds = bi;
309 : }
310 : //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Visual2D] Allocating new bound info for drawable %s\n", gf_node_get_class_name(ctx->drawable->node)));
311 : }
312 : /*reset next bound info*/
313 142320 : if (bi->next) bi->next->clip.width = 0;
314 : return bi;
315 : }
316 :
317 64318 : void drawable_reset_group_highlight(GF_TraverseState *tr_state, GF_Node *n)
318 : {
319 64318 : Drawable *hlight = tr_state->visual->compositor->focus_highlight;
320 64318 : if (hlight && (n == gf_node_get_private(hlight->node))) gf_node_set_private(hlight->node, NULL);
321 64318 : }
322 :
323 8888 : void drawable_mark_modified(Drawable *drawable, GF_TraverseState *tr_state)
324 : {
325 : /*mark drawable as modified*/
326 8888 : drawable->flags |= tr_state->visual->bounds_tracker_modif_flag;
327 : /*and remove overlay flag*/
328 8888 : drawable->flags &= ~DRAWABLE_IS_OVERLAY;
329 :
330 8888 : drawable_reset_group_highlight(tr_state, drawable->node);
331 8888 : }
332 :
333 : /*move current bounds to previous bounds*/
334 103218 : Bool drawable_flush_bounds(Drawable *drawable, GF_VisualManager *on_visual, u32 mode2d)
335 : {
336 : Bool was_drawn;
337 : DRInfo *dri;
338 : BoundInfo *tmp;
339 :
340 : /*reset node modified flag*/
341 103218 : drawable->flags &= ~DRAWABLE_HAS_CHANGED;
342 103218 : if (drawable->flags & DRAWABLE_HAS_CHANGED_IN_LAST_TRAVERSE) {
343 15 : drawable->flags |= DRAWABLE_HAS_CHANGED;
344 15 : drawable->flags &= ~DRAWABLE_HAS_CHANGED_IN_LAST_TRAVERSE;
345 : }
346 :
347 103218 : dri = drawable->dri;
348 206832 : while (dri) {
349 103608 : if (dri->visual == on_visual) break;
350 396 : dri = dri->next;
351 : }
352 103218 : if (!dri) return 0;
353 :
354 103212 : was_drawn = (dri->current_bounds && dri->current_bounds->clip.width) ? 1 : 0;
355 :
356 103212 : if (mode2d) {
357 : /*permanent direct drawing mode, destroy previous bounds*/
358 648 : if (mode2d==1) {
359 554 : if (dri->previous_bounds) {
360 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Destroying previous bounds info for drawable %s\n", gf_node_get_class_name(drawable->node)));
361 0 : while (dri->previous_bounds) {
362 : BoundInfo *bi = dri->previous_bounds;
363 0 : dri->previous_bounds = bi->next;
364 0 : gf_free(bi);
365 : }
366 : }
367 : }
368 : }
369 : /*indirect drawing, flush bounds*/
370 : else {
371 102564 : tmp = dri->previous_bounds;
372 102564 : dri->previous_bounds = dri->current_bounds;
373 102564 : dri->current_bounds = tmp;
374 : }
375 : /*reset first allocated bound*/
376 103212 : if (dri->current_bounds) dri->current_bounds->clip.width = 0;
377 :
378 103212 : drawable->flags &= ~DRAWABLE_DRAWN_ON_VISUAL;
379 103212 : return was_drawn;
380 : }
381 :
382 : /*
383 : return 1 if same bound is found in previous list (and remove it from the list)
384 : return 0 otherwise
385 : */
386 :
387 126320 : Bool drawable_has_same_bounds(struct _drawable_context *ctx, GF_VisualManager *visual)
388 : {
389 : DRInfo *dri;
390 : BoundInfo *bi;
391 :
392 126320 : dri = ctx->drawable->dri;
393 253030 : while (dri) {
394 126710 : if (dri->visual == visual) break;
395 390 : dri = dri->next;
396 : }
397 126320 : if (!dri) return 0;
398 :
399 126320 : bi = dri->previous_bounds;
400 469090 : while (bi) {
401 327849 : if (
402 : /*if 0, end of bounds used in the previous pass*/
403 327849 : bi->clip.width
404 : /*we need the same Appearance || parent <use>*/
405 158103 : && (bi->extra_check == ctx->appear)
406 : /*we need exact same cliper*/
407 155514 : && (bi->clip.x==ctx->bi->clip.x) && (bi->clip.y==ctx->bi->clip.y)
408 114314 : && (bi->clip.width==ctx->bi->clip.width) && (bi->clip.height==ctx->bi->clip.height)
409 : /*only check x and y (if w or h have changed, object has changed -> bounds info has been reset*/
410 113480 : && (bi->unclip.x==ctx->bi->unclip.x) && (bi->unclip.y==ctx->bi->unclip.y)
411 : ) {
412 : /*remove*/
413 111399 : bi->clip.width = 0;
414 111399 : return 1;
415 : }
416 216450 : bi = bi->next;
417 : }
418 : return 0;
419 : }
420 :
421 : /*
422 : return any previous bounds related to the same visual in @rc if any
423 : if nothing found return 0
424 : */
425 123456 : Bool drawable_get_previous_bound(Drawable *drawable, GF_IRect *rc, GF_VisualManager *visual)
426 : {
427 : DRInfo *dri;
428 : BoundInfo *bi;
429 :
430 123456 : dri = drawable->dri;
431 247603 : while (dri) {
432 124147 : if (dri->visual == visual) break;
433 691 : dri = dri->next;
434 : }
435 123456 : if (!dri) return 0;
436 :
437 123456 : bi = dri->previous_bounds;
438 395228 : while (bi) {
439 166795 : if (bi->clip.width) {
440 18479 : *rc = bi->clip;
441 18479 : bi->clip.width = 0;
442 18479 : return 1;
443 : }
444 148316 : bi = bi->next;
445 : }
446 : return 0;
447 : }
448 :
449 :
450 :
451 5542 : DrawableContext *NewDrawableContext()
452 : {
453 : DrawableContext *tmp;
454 5542 : GF_SAFEALLOC(tmp, DrawableContext);
455 5542 : return tmp;
456 : }
457 5539 : void DeleteDrawableContext(DrawableContext *ctx)
458 : {
459 5539 : drawctx_reset(ctx);
460 5539 : gf_free(ctx);
461 5539 : }
462 184205 : void drawctx_reset(DrawableContext *ctx)
463 : {
464 184205 : DrawableContext *next = ctx->next;
465 184205 : if (ctx->col_mat) gf_free(ctx->col_mat);
466 : memset(ctx, 0, sizeof(DrawableContext));
467 184205 : ctx->next = next;
468 :
469 : /*by default all nodes are transparent*/
470 184205 : ctx->flags |= CTX_IS_TRANSPARENT;
471 :
472 : /*BIFS has default value for 2D appearance ...*/
473 184205 : ctx->aspect.fill_color = 0xFFCCCCCC;
474 184205 : ctx->aspect.line_color = 0xFFCCCCCC;
475 184205 : ctx->aspect.pen_props.width = FIX_ONE;
476 184205 : ctx->aspect.pen_props.cap = GF_LINE_CAP_FLAT;
477 184205 : ctx->aspect.pen_props.join = GF_LINE_JOIN_BEVEL;
478 184205 : ctx->aspect.pen_props.miterLimit = 4*FIX_ONE;
479 :
480 184205 : }
481 :
482 130924 : void drawctx_update_info(DrawableContext *ctx, GF_VisualManager *visual)
483 : {
484 : DRInfo *dri;
485 : Bool moved, need_redraw, drawn;
486 130924 : need_redraw = (ctx->flags & CTX_REDRAW_MASK) ? 1 : 0;
487 :
488 : drawn = 0;
489 130924 : dri = ctx->drawable->dri;
490 262238 : while (dri) {
491 131314 : if (dri->visual==visual) {
492 130924 : if (dri->current_bounds && dri->current_bounds->clip.width) drawn = 1;
493 : break;
494 : }
495 390 : dri = dri->next;
496 : }
497 : if (drawn) {
498 130924 : ctx->drawable->flags |= DRAWABLE_DRAWN_ON_VISUAL;
499 : /*node has been modified, do not check bounds, just assumed it moved*/
500 130924 : if (ctx->drawable->flags & DRAWABLE_HAS_CHANGED) {
501 : moved = 1;
502 : } else {
503 : /*check if same bounds are used*/
504 126320 : moved = !drawable_has_same_bounds(ctx, visual);
505 : }
506 :
507 130924 : if (need_redraw || moved)
508 29655 : ctx->flags |= CTX_REDRAW_MASK;
509 : }
510 :
511 : /*in all cases reset dirty flag of appearance and its sub-nodes*/
512 : //if (ctx->flags & CTX_HAS_APPEARANCE) gf_node_dirty_reset(ctx->appear);
513 130924 : }
514 :
515 : #ifndef GPAC_DISABLE_VRML
516 171682 : static Bool drawable_lineprops_dirty(GF_Node *node)
517 : {
518 171682 : LinePropStack *st = (LinePropStack *)gf_node_get_private(node);
519 171682 : if (!st) return 0;
520 :
521 171682 : if (st->compositor->current_frame == st->last_mod_time) return st->is_dirty;
522 48115 : if (gf_node_dirty_get(node) & GF_SG_NODE_DIRTY) {
523 2522 : gf_node_dirty_clear(node, 0);
524 2522 : st->is_dirty = 1;
525 : } else {
526 45593 : st->is_dirty = 0;
527 : }
528 48115 : st->last_mod_time = st->compositor->current_frame;
529 48115 : return st->is_dirty;
530 : }
531 :
532 249866 : u32 drawable_get_aspect_2d_mpeg4(GF_Node *node, DrawAspect2D *asp, GF_TraverseState *tr_state)
533 : {
534 : M_Material2D *m = NULL;
535 : M_LineProperties *LP;
536 : M_XLineProperties *XLP;
537 249866 : GF_Node *appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear;
538 : u32 ret = 0;
539 :
540 249866 : asp->pen_props.cap = GF_LINE_CAP_FLAT;
541 249866 : asp->pen_props.join = GF_LINE_JOIN_MITER;
542 249866 : asp->pen_props.align = GF_PATH_LINE_CENTER;
543 249866 : asp->pen_props.miterLimit = 4*FIX_ONE;
544 249866 : asp->line_color = 0xFFCCCCCC;
545 249866 : asp->pen_props.width = 0;
546 :
547 249866 : if (appear == NULL) goto check_default;
548 :
549 247923 : if ( ((M_Appearance *) appear)->texture ) {
550 41686 : asp->fill_texture = gf_sc_texture_get_handler( ((M_Appearance *) appear)->texture );
551 : }
552 :
553 :
554 247923 : m = (M_Material2D *) ((M_Appearance *)appear)->material;
555 247923 : if ( m == NULL) {
556 14662 : asp->fill_color &= 0x00FFFFFF;
557 14662 : goto check_default;
558 : }
559 233261 : switch (gf_node_get_tag((GF_Node *) m) ) {
560 : case TAG_MPEG4_Material2D:
561 : break;
562 16 : case TAG_MPEG4_Material:
563 : #ifndef GPAC_DISABLE_X3D
564 : case TAG_X3D_Material:
565 : #endif
566 : {
567 : M_Material *mat = (M_Material *)m;
568 16 : asp->pen_props.width = 0;
569 16 : asp->fill_color = GF_COL_ARGB_FIXED(FIX_ONE, mat->diffuseColor.red, mat->diffuseColor.green, mat->diffuseColor.blue);
570 16 : if (!tr_state->color_mat.identity)
571 0 : asp->fill_color = gf_cmx_apply(&tr_state->color_mat, asp->fill_color);
572 : }
573 : return 0;
574 : default:
575 : return 0;
576 : }
577 :
578 233078 : asp->fill_color = GF_COL_ARGB_FIXED(FIX_ONE-m->transparency, m->emissiveColor.red, m->emissiveColor.green, m->emissiveColor.blue);
579 233078 : if (!tr_state->color_mat.identity)
580 24376 : asp->fill_color = gf_cmx_apply(&tr_state->color_mat, asp->fill_color);
581 :
582 233078 : asp->line_color = asp->fill_color;
583 233078 : if (!m->filled) asp->fill_color = 0;
584 :
585 233078 : if (m->lineProps == NULL) {
586 125034 : check_default:
587 : /*this is a bug in the spec: by default line width is 1.0, but in meterMetrics this means half of the screen :)*/
588 139696 : asp->pen_props.width = FIX_ONE;
589 139696 : if (!tr_state->pixel_metrics) asp->pen_props.width = gf_divfix(asp->pen_props.width, tr_state->min_hsize);
590 139696 : if (m && m->transparency==FIX_ONE) {
591 2169 : asp->pen_props.width = 0;
592 : } else {
593 137527 : switch (gf_node_get_tag(node)) {
594 662 : case TAG_MPEG4_IndexedLineSet2D:
595 662 : asp->fill_color &= 0x00FFFFFF;
596 662 : break;
597 296 : case TAG_MPEG4_PointSet2D:
598 296 : asp->fill_color |= ((u32 )(FIX2INT(255 * (m ? (FIX_ONE - m->transparency) : FIX_ONE))) ) << 24;
599 296 : asp->pen_props.width = 0;
600 296 : break;
601 136569 : default:
602 136569 : if (GF_COL_A(asp->fill_color)) asp->pen_props.width = 0;
603 : /*spec is unclear about that*/
604 : //else if (!m && ctx->aspect.fill_texture) ctx->aspect.pen_props.width = 0;
605 : break;
606 : }
607 : }
608 : return 0;
609 : }
610 : LP = NULL;
611 : XLP = NULL;
612 109987 : switch (gf_node_get_tag((GF_Node *) m->lineProps) ) {
613 83183 : case TAG_MPEG4_LineProperties:
614 83183 : LP = (M_LineProperties *) m->lineProps;
615 83183 : break;
616 26804 : case TAG_MPEG4_XLineProperties:
617 26804 : XLP = (M_XLineProperties *) m->lineProps;
618 26804 : break;
619 0 : default:
620 0 : asp->pen_props.width = 0;
621 0 : return 0;
622 : }
623 109987 : if (m->lineProps && drawable_lineprops_dirty(m->lineProps))
624 : ret = CTX_APP_DIRTY;
625 :
626 109987 : if (LP) {
627 83183 : asp->pen_props.dash = (u8) LP->lineStyle;
628 83183 : asp->line_color = GF_COL_ARGB_FIXED(FIX_ONE-m->transparency, LP->lineColor.red, LP->lineColor.green, LP->lineColor.blue);
629 83183 : asp->pen_props.width = LP->width;
630 83183 : if (!tr_state->color_mat.identity) {
631 116 : asp->line_color = gf_cmx_apply(&tr_state->color_mat, asp->line_color);
632 : }
633 : return ret;
634 : }
635 :
636 26804 : asp->pen_props.dash = (u8) XLP->lineStyle;
637 26804 : asp->line_color = GF_COL_ARGB_FIXED(FIX_ONE-XLP->transparency, XLP->lineColor.red, XLP->lineColor.green, XLP->lineColor.blue);
638 26804 : asp->pen_props.width = XLP->width;
639 26804 : if (!tr_state->color_mat.identity) {
640 142 : asp->line_color = gf_cmx_apply(&tr_state->color_mat, asp->line_color);
641 : }
642 :
643 26804 : asp->line_scale = XLP->isScalable ? FIX_ONE : 0;
644 26804 : asp->pen_props.align = XLP->isCenterAligned ? GF_PATH_LINE_CENTER : GF_PATH_LINE_INSIDE;
645 26804 : asp->pen_props.cap = (u8) XLP->lineCap;
646 26804 : asp->pen_props.join = (u8) XLP->lineJoin;
647 26804 : asp->pen_props.miterLimit = XLP->miterLimit;
648 26804 : asp->pen_props.dash_offset = XLP->dashOffset;
649 :
650 : /*dash settings strutc is the same as MFFloat from XLP, typecast without storing*/
651 26804 : if (XLP->dashes.count) {
652 302 : asp->pen_props.dash_set = (GF_DashSettings *) &XLP->dashes;
653 : } else {
654 26502 : asp->pen_props.dash_set = NULL;
655 : }
656 26804 : asp->line_texture = gf_sc_texture_get_handler(XLP->texture);
657 26804 : return ret;
658 : }
659 : #endif /*GPAC_DISABLE_VRML*/
660 :
661 :
662 : static Bool check_transparent_skip(DrawableContext *ctx, Bool skipFill)
663 : {
664 : /*if texture, cannot skip*/
665 152571 : if (ctx->aspect.fill_texture) return 0;
666 133763 : if (! GF_COL_A(ctx->aspect.fill_color) && !GF_COL_A(ctx->aspect.line_color) ) return 1;
667 131755 : if (ctx->aspect.pen_props.width == 0) {
668 106515 : if (skipFill) return 1;
669 106515 : if (!GF_COL_A(ctx->aspect.fill_color) ) return 1;
670 : }
671 : return 0;
672 : }
673 :
674 :
675 178186 : void drawable_check_texture_dirty(DrawableContext *ctx, Drawable *drawable, GF_TraverseState *tr_state)
676 : {
677 : #ifndef GPAC_DISABLE_3D
678 : Bool texture_ready=0;
679 : #endif
680 :
681 : /*Update texture info - draw even if texture not created (this may happen if the media is removed)*/
682 178186 : if (ctx->aspect.fill_texture) {
683 21935 : if (ctx->aspect.fill_texture->needs_refresh) {
684 6486 : ctx->flags |= CTX_TEXTURE_DIRTY;
685 : }
686 : #ifndef GPAC_DISABLE_3D
687 : //in autoGL mode, a texture is dirty only if transparent. If not, the area covered over the video doesn't need to be repainted if unchanged
688 : //disable for color matrix as we don't yet handle them in GL
689 21935 : if (tr_state->visual->compositor->hybrid_opengl && !tr_state->visual->offscreen) {
690 818 : u8 alpha = GF_COL_A(ctx->aspect.fill_color);
691 818 : if (!alpha) alpha = GF_COL_A(ctx->aspect.line_color);
692 :
693 818 : if (!ctx->aspect.fill_texture->transparent && (alpha==0xFF) && !ctx->aspect.fill_texture->compute_gradient_matrix && (drawable->flags & DRAWABLE_HYBGL_INIT)) {
694 322 : ctx->flags |= CTX_HYBOGL_NO_CLEAR;
695 : }
696 : //otherwise, we need to redraw all object below, wether they changed ot not, because we have erased this part of the canvas
697 : else {
698 496 : ctx->flags |= CTX_TEXTURE_DIRTY;
699 : }
700 : //wait until we have something to draw to decide that the texture is ready, otherwise we will not clear the canvas when texture is ready
701 818 : if (ctx->aspect.fill_texture->compute_gradient_matrix || ctx->aspect.fill_texture->data)
702 : texture_ready=1;
703 : }
704 : #endif
705 : }
706 : //same as above
707 178186 : if (ctx->aspect.line_texture) {
708 1821 : if (ctx->aspect.line_texture->needs_refresh)
709 1055 : ctx->flags |= CTX_TEXTURE_DIRTY;
710 :
711 : #ifndef GPAC_DISABLE_3D
712 : //in autoGL mode, a texture is dirty only if transparent. If not, the area covered over the video doesn't need to be repainted if unchanged
713 : //disable for color matrix as we don't yet handle them in GL
714 1821 : if (tr_state->visual->compositor->hybrid_opengl && !tr_state->visual->offscreen) {
715 6 : u8 alpha = GF_COL_A(ctx->aspect.line_color);
716 6 : if (!ctx->aspect.line_texture->transparent && (alpha==0xFF) && !ctx->aspect.line_texture->compute_gradient_matrix && (drawable->flags & DRAWABLE_HYBGL_INIT))
717 0 : ctx->flags |= CTX_HYBOGL_NO_CLEAR;
718 : //otherwise, we need to redraw all object below, wether they changed ot not, bacause we have erased this part of the canvas
719 : else
720 6 : ctx->flags |= CTX_TEXTURE_DIRTY;
721 :
722 : //wait until we have something to draw to decide that the texture is ready, otherwise we will not clear the canvas when texture is ready
723 6 : if (ctx->aspect.line_texture->compute_gradient_matrix || ctx->aspect.line_texture->data)
724 : texture_ready=1;
725 : }
726 : #endif
727 : }
728 :
729 : #ifndef GPAC_DISABLE_3D
730 : //from now on, we won't clear the canvas when updating this texture (unless transparent, cf above)
731 178186 : if (texture_ready)
732 492 : drawable->flags |= DRAWABLE_HYBGL_INIT;
733 : #endif
734 178186 : }
735 :
736 : #ifndef GPAC_DISABLE_VRML
737 :
738 152571 : DrawableContext *drawable_init_context_mpeg4(Drawable *drawable, GF_TraverseState *tr_state)
739 : {
740 : DrawableContext *ctx;
741 : Bool skipFill;
742 : GF_Node *appear;
743 : assert(tr_state->visual);
744 :
745 : /*switched-off geometry nodes are not drawn*/
746 152571 : if (tr_state->switched_off) {
747 0 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Drawable is switched off - skipping\n"));
748 : return NULL;
749 : }
750 :
751 : //Get a empty context from the current visual
752 152571 : ctx = visual_2d_get_drawable_context(tr_state->visual);
753 152571 : if (!ctx) return NULL;
754 :
755 152571 : ctx->drawable = drawable;
756 :
757 152571 : appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear;
758 :
759 : /*usually set by colorTransform or changes in OrderedGroup*/
760 152571 : if (tr_state->invalidate_all)
761 1615 : ctx->flags |= CTX_APP_DIRTY;
762 :
763 152571 : ctx->aspect.fill_texture = NULL;
764 152571 : if (appear) {
765 150923 : ctx->appear = appear;
766 150923 : if (gf_node_dirty_get(appear))
767 51339 : ctx->flags |= CTX_APP_DIRTY;
768 : }
769 : /*todo cliper*/
770 :
771 : /*FIXME - only needed for texture*/
772 152571 : if (!tr_state->color_mat.identity) {
773 5285 : GF_SAFEALLOC(ctx->col_mat, GF_ColorMatrix);
774 5285 : if (ctx->col_mat)
775 5285 : gf_cmx_copy(ctx->col_mat, &tr_state->color_mat);
776 : }
777 :
778 : /*IndexedLineSet2D and PointSet2D ignores fill flag and texturing*/
779 : skipFill = 0;
780 152571 : ctx->aspect.fill_texture = NULL;
781 152571 : switch (gf_node_get_tag(ctx->drawable->node) ) {
782 : #ifndef GPAC_DISABLE_VRML
783 904 : case TAG_MPEG4_IndexedLineSet2D:
784 : skipFill = 1;
785 904 : break;
786 : #endif
787 : default:
788 : break;
789 : }
790 :
791 152571 : ctx->flags |= drawable_get_aspect_2d_mpeg4(drawable->node, &ctx->aspect, tr_state);
792 :
793 152571 : drawable_check_texture_dirty(ctx, drawable, tr_state);
794 :
795 : /*not clear in the spec: what happens when a transparent node is in form/layout ?? this may
796 : completely break layout of children. We consider the node should be drawn*/
797 152571 : if (!tr_state->parent && check_transparent_skip(ctx, skipFill)) {
798 36214 : visual_2d_remove_last_context(tr_state->visual);
799 36214 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Drawable is fully transparent - skipping\n"));
800 : return NULL;
801 : }
802 116357 : ctx->flags |= CTX_HAS_APPEARANCE;
803 :
804 : /*we are drawing on a fliped coord surface, remember to flip the texture*/
805 116357 : if (tr_state->fliped_coords)
806 341 : ctx->flags |= CTX_FLIPED_COORDS;
807 :
808 : #ifdef GF_SR_USE_DEPTH
809 116357 : ctx->depth_gain=tr_state->depth_gain;
810 116357 : ctx->depth_offset=tr_state->depth_offset;
811 : #endif
812 :
813 116357 : return ctx;
814 : }
815 : #endif
816 :
817 141466 : static Bool drawable_finalize_end(struct _drawable_context *ctx, GF_TraverseState *tr_state)
818 : {
819 : /*if direct draw we can remove the context*/
820 141466 : Bool res = tr_state->immediate_draw ? 1 : 0;
821 : /*copy final transform, once all parent layout is done*/
822 141466 : gf_mx2d_copy(ctx->transform, tr_state->transform);
823 :
824 : /*setup clipper and register bounds & sensors*/
825 141466 : gf_irect_intersect(&ctx->bi->clip, &tr_state->visual->top_clipper);
826 141466 : if (!ctx->bi->clip.width || !ctx->bi->clip.height) {
827 6017 : ctx->bi->clip.width = 0;
828 : /*remove if this is the last context*/
829 6017 : if (tr_state->visual->cur_context == ctx) tr_state->visual->cur_context->drawable = NULL;
830 :
831 : return res;
832 : }
833 :
834 : /*keep track of node drawn, whether direct or indirect drawing*/
835 135449 : if (!(ctx->drawable->flags & DRAWABLE_REGISTERED_WITH_VISUAL) ) {
836 : struct _drawable_store *it;
837 5036 : GF_SAFEALLOC(it, struct _drawable_store);
838 5036 : if (!it) {
839 : return 0;
840 : }
841 5036 : it->drawable = ctx->drawable;
842 5036 : if (tr_state->visual->last_prev_entry) {
843 4480 : tr_state->visual->last_prev_entry->next = it;
844 4480 : tr_state->visual->last_prev_entry = it;
845 : } else {
846 556 : tr_state->visual->prev_nodes = tr_state->visual->last_prev_entry = it;
847 : }
848 : //GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("[Compositor2D] Registering new drawn node %s on visual\n", gf_node_get_class_name(it->drawable->node)));
849 5036 : ctx->drawable->flags |= DRAWABLE_REGISTERED_WITH_VISUAL;
850 : }
851 :
852 : /*we are in direct draw mode, draw ...*/
853 135449 : if (res) {
854 : /*if over an overlay we cannot remove the context and cannot draw directly*/
855 5242 : if (visual_2d_overlaps_overlay(tr_state->visual, ctx, tr_state))
856 : return 0;
857 :
858 : assert(!tr_state->traversing_mode);
859 5242 : tr_state->traversing_mode = TRAVERSE_DRAW_2D;
860 5242 : tr_state->ctx = ctx;
861 :
862 5242 : if (ctx->drawable->flags & DRAWABLE_USE_TRAVERSE_DRAW) {
863 3484 : gf_node_allow_cyclic_traverse(ctx->drawable->node);
864 3484 : gf_node_traverse(ctx->drawable->node, tr_state);
865 : } else {
866 1758 : drawable_draw(ctx->drawable, tr_state);
867 : }
868 :
869 5242 : tr_state->ctx = NULL;
870 5242 : tr_state->traversing_mode = TRAVERSE_SORT;
871 : }
872 : /*if the drawable is an overlay, always mark it as dirty to avoid flickering*/
873 130207 : else if (ctx->drawable->flags & DRAWABLE_IS_OVERLAY) {
874 0 : ctx->flags |= CTX_APP_DIRTY;
875 : }
876 : /*if direct draw we can remove the context*/
877 : return res;
878 : }
879 :
880 14130 : void drawable_check_bounds(struct _drawable_context *ctx, GF_VisualManager *visual)
881 : {
882 155596 : if (!ctx->bi) {
883 142320 : ctx->bi = drawable_check_alloc_bounds(ctx, visual);
884 : assert(ctx->bi);
885 142320 : ctx->bi->extra_check = ctx->appear;
886 : }
887 14130 : }
888 :
889 26502 : void drawable_compute_line_scale(GF_TraverseState *tr_state, DrawAspect2D *asp)
890 : {
891 : GF_Rect rc;
892 26502 : rc.x = rc.y = 0;
893 26502 : rc.width = rc.height = FIX_ONE;
894 : #ifndef GPAC_DISABLE_3D
895 26502 : if (tr_state->visual->type_3d)
896 1350 : gf_mx_apply_rect(&tr_state->model_matrix, &rc);
897 : else
898 : #endif
899 25152 : gf_mx2d_apply_rect(&tr_state->transform, &rc);
900 :
901 26502 : asp->line_scale = MAX(gf_divfix(tr_state->visual->compositor->scale_x, rc.width), gf_divfix(tr_state->visual->compositor->scale_y, rc.height));
902 26502 : }
903 :
904 : //#define REMOVE_UNUSED_CTX
905 141466 : void drawable_finalize_sort_ex(DrawableContext *ctx, GF_TraverseState *tr_state, GF_Rect *orig_bounds, Bool skip_focus)
906 : {
907 : #ifdef REMVE_UNUSED_CTX
908 : Bool can_remove = 0;
909 : #endif
910 : Fixed pw;
911 : GF_Rect unclip, store_orig_bounds;
912 141466 : GF_Node *appear = tr_state->override_appearance ? tr_state->override_appearance : tr_state->appear;
913 :
914 :
915 141466 : drawable_check_bounds(ctx, tr_state->visual);
916 :
917 141466 : if (orig_bounds) {
918 45939 : store_orig_bounds = *orig_bounds;
919 : } else {
920 95527 : gf_path_get_bounds(ctx->drawable->path, &store_orig_bounds);
921 : }
922 141466 : ctx->bi->unclip = store_orig_bounds;
923 141466 : gf_mx2d_apply_rect(&tr_state->transform, &ctx->bi->unclip);
924 :
925 : /*apply pen width*/
926 141466 : if (ctx->aspect.pen_props.width) {
927 : StrikeInfo2D *si = NULL;
928 :
929 37385 : if (!ctx->aspect.line_scale)
930 25141 : drawable_compute_line_scale(tr_state, &ctx->aspect);
931 :
932 : #if 0
933 : /*if pen is not scalable, apply user/viewport transform so that original aspect is kept*/
934 : if (!ctx->aspect.line_scale) {
935 : GF_Point2D pt;
936 : pt.x = tr_state->transform.m[0] + tr_state->transform.m[1];
937 : pt.y = tr_state->transform.m[3] + tr_state->transform.m[4];
938 : ctx->aspect.line_scale = gf_divfix(FLT2FIX(1.41421356f) , gf_v2d_len(&pt));
939 : }
940 : #endif
941 :
942 : /*get strike info & outline for exact bounds compute. If failure use default offset*/
943 37385 : si = drawable_get_strikeinfo(tr_state->visual->compositor, ctx->drawable, &ctx->aspect, appear, ctx->drawable->path, ctx->flags, NULL);
944 37385 : if (si && si->outline) {
945 37078 : gf_path_get_bounds(si->outline, &ctx->bi->unclip);
946 37078 : gf_mx2d_apply_rect(&tr_state->transform, &ctx->bi->unclip);
947 : } else {
948 307 : pw = gf_mulfix(ctx->aspect.pen_props.width, ctx->aspect.line_scale);
949 307 : ctx->bi->unclip.x -= pw/2;
950 307 : ctx->bi->unclip.y += pw/2;
951 307 : ctx->bi->unclip.width += pw;
952 307 : ctx->bi->unclip.height += pw;
953 : }
954 : }
955 :
956 141466 : if (ctx->bi->unclip.width && ctx->bi->unclip.height) {
957 136520 : unclip = ctx->bi->unclip;
958 136520 : if (! (ctx->flags & CTX_NO_ANTIALIAS)) {
959 : /*grow of 2 pixels (-1 and +1) to handle AA, but ONLY on cliper otherwise we will modify layout/form */
960 113342 : pw = (tr_state->pixel_metrics) ? FIX_ONE : 2*FIX_ONE/tr_state->visual->width;
961 113342 : unclip.x -= pw;
962 113342 : unclip.y += pw;
963 113342 : unclip.width += 2*pw;
964 113342 : unclip.height += 2*pw;
965 : }
966 136520 : ctx->bi->clip = gf_rect_pixelize(&unclip);
967 : } else {
968 4946 : ctx->bi->clip.width = 0;
969 : }
970 :
971 : #ifdef REMVE_UNUSED_CTX
972 : can_remove = drawable_finalize_end(ctx, tr_state);
973 : #else
974 141466 : drawable_finalize_end(ctx, tr_state);
975 : #endif
976 141466 : if (ctx->drawable && !skip_focus)
977 135145 : drawable_check_focus_highlight(ctx->drawable->node, tr_state, &store_orig_bounds);
978 :
979 : /*remove if this is the last context*/
980 : #ifdef REMVE_UNUSED_CTX
981 : if (can_remove && (tr_state->visual->cur_context == ctx))
982 : tr_state->visual->cur_context->drawable = NULL;
983 : #endif
984 141466 : }
985 :
986 141162 : void drawable_finalize_sort(struct _drawable_context *ctx, GF_TraverseState *tr_state, GF_Rect *orig_bounds)
987 : {
988 141162 : drawable_finalize_sort_ex(ctx, tr_state, orig_bounds, 0);
989 141162 : }
990 :
991 :
992 372878 : void drawable_check_focus_highlight(GF_Node *node, GF_TraverseState *tr_state, GF_Rect *orig_bounds)
993 : {
994 : DrawableContext *hl_ctx;
995 : Drawable *hlight;
996 : GF_Node *prev_node;
997 : u32 prev_mode;
998 : GF_Matrix2D cur;
999 372878 : GF_Compositor *compositor = tr_state->visual->compositor;
1000 :
1001 745452 : if (compositor->disable_focus_highlight) return;
1002 :
1003 372878 : if (compositor->focus_node!=node) return;
1004 : /*if key navigator, don't draw a focus highlight*/
1005 327 : if (compositor->keynav_node) return;
1006 :
1007 304 : if (compositor->focus_used) {
1008 0 : u32 count = gf_list_count(tr_state->use_stack);
1009 0 : if (!count || (gf_list_get(tr_state->use_stack, count-1)!=compositor->focus_used) )
1010 : return;
1011 : }
1012 :
1013 304 : hlight = compositor->focus_highlight;
1014 304 : if (!hlight) return;
1015 :
1016 : /*check if focus node has changed*/
1017 304 : prev_node = gf_node_get_private(hlight->node);
1018 304 : if (prev_node != node) {
1019 : GF_Rect *bounds;
1020 : /*this is a grouping node, get its bounds*/
1021 83 : if (!orig_bounds) {
1022 83 : gf_mx2d_copy(cur, tr_state->transform);
1023 83 : gf_mx2d_init(tr_state->transform);
1024 83 : prev_mode = tr_state->traversing_mode;
1025 83 : tr_state->traversing_mode = TRAVERSE_GET_BOUNDS;
1026 83 : tr_state->bounds.width = tr_state->bounds.height = 0;
1027 83 : tr_state->bounds.x = tr_state->bounds.y = 0;
1028 :
1029 83 : gf_sc_get_nodes_bounds(node, ((GF_ParentNode *)node)->children, tr_state, NULL);
1030 :
1031 83 : tr_state->traversing_mode = prev_mode;
1032 : gf_mx2d_copy(tr_state->transform, cur);
1033 83 : bounds = &tr_state->bounds;
1034 : } else {
1035 : bounds = orig_bounds;
1036 : }
1037 83 : gf_node_set_private(hlight->node, node);
1038 :
1039 83 : drawable_reset_path(hlight);
1040 83 : gf_path_reset(hlight->path);
1041 83 : gf_path_add_rect(hlight->path, bounds->x, bounds->y, bounds->width, bounds->height);
1042 : }
1043 304 : hl_ctx = visual_2d_get_drawable_context(tr_state->visual);
1044 304 : hl_ctx->drawable = hlight;
1045 304 : hl_ctx->aspect.fill_color = compositor->hlfill;
1046 304 : hl_ctx->aspect.line_color = compositor->hlline;
1047 304 : hl_ctx->aspect.line_scale = 0;
1048 304 : hl_ctx->aspect.pen_props.width = compositor->hllinew;
1049 304 : hl_ctx->aspect.pen_props.join = GF_LINE_JOIN_BEVEL;
1050 304 : hl_ctx->aspect.pen_props.dash = GF_DASH_STYLE_DOT;
1051 :
1052 : /*editing this node - move to solid stroke*/
1053 304 : if (compositor->edited_text) {
1054 0 : hl_ctx->aspect.pen_props.width = 2*FIX_ONE;
1055 0 : hl_ctx->aspect.pen_props.dash = 1;
1056 0 : hl_ctx->aspect.line_color = compositor->hlline;
1057 : }
1058 :
1059 :
1060 : #ifndef GPAC_DISABLE_3D
1061 304 : if (tr_state->visual->type_3d) {
1062 0 : gf_mx2d_copy(hl_ctx->transform, tr_state->transform);
1063 0 : visual_3d_draw_2d_with_aspect(hl_ctx->drawable, tr_state, &hl_ctx->aspect);
1064 0 : return;
1065 : }
1066 : #endif
1067 304 : gf_mx2d_copy(hl_ctx->transform, tr_state->transform);
1068 304 : drawable_finalize_sort_ex(hl_ctx, tr_state, NULL, 1);
1069 : }
1070 :
1071 :
1072 604 : void drawable_traverse_focus(GF_Node *node, void *rs, Bool is_destroy)
1073 : {
1074 : GF_TraverseState *tr_state = (GF_TraverseState *)rs;
1075 604 : if (is_destroy) return;
1076 0 : if (tr_state->traversing_mode == TRAVERSE_DRAW_2D)
1077 0 : visual_2d_draw_path(tr_state->visual, tr_state->ctx->drawable->path, tr_state->ctx, NULL, NULL, tr_state);
1078 : }
1079 :
1080 :
1081 1609 : void delete_strikeinfo2d(StrikeInfo2D *info)
1082 : {
1083 1609 : if (info->outline) gf_path_del(info->outline);
1084 : #ifndef GPAC_DISABLE_3D
1085 1609 : if (info->mesh_outline) mesh_free(info->mesh_outline);
1086 : #endif
1087 1609 : gf_free(info);
1088 1609 : }
1089 :
1090 :
1091 99035 : StrikeInfo2D *drawable_get_strikeinfo(GF_Compositor *compositor, Drawable *drawable, DrawAspect2D *asp, GF_Node *appear, GF_Path *path, u32 svg_flags, GF_TraverseState *tr_state)
1092 : {
1093 : StrikeInfo2D *si, *prev;
1094 : GF_Node *lp;
1095 : #ifndef GPAC_DISABLE_VRML
1096 : Bool dirty;
1097 : #endif
1098 99035 : if (!asp->pen_props.width) return NULL;
1099 99035 : if (path && !path->n_points) return NULL;
1100 :
1101 : lp = NULL;
1102 : #ifndef GPAC_DISABLE_VRML
1103 98421 : if (appear && (gf_node_get_tag(appear) < GF_NODE_RANGE_LAST_X3D) ) {
1104 85537 : lp = ((M_Appearance *)appear)->material;
1105 85537 : if (lp) lp = ((M_Material2D *) lp)->lineProps;
1106 : }
1107 : #endif
1108 :
1109 : prev = NULL;
1110 98421 : si = drawable->outline;
1111 203889 : while (si) {
1112 : /*note this includes default LP (NULL)*/
1113 98522 : if ((si->lineProps == lp) && (!path || (path==si->original)) ) break;
1114 7047 : if (!si->lineProps) {
1115 5336 : gf_list_del_item(compositor->strike_bank, si);
1116 5336 : if (si->outline) gf_path_del(si->outline);
1117 : #ifndef GPAC_DISABLE_3D
1118 5336 : if (si->mesh_outline) mesh_free(si->mesh_outline);
1119 : #endif
1120 5336 : if (prev) prev->next = si->next;
1121 5329 : else drawable->outline = si->next;
1122 5336 : gf_free(si);
1123 5336 : si = prev ? prev->next : drawable->outline;
1124 5336 : continue;
1125 : }
1126 : prev = si;
1127 1711 : si = si->next;
1128 : }
1129 : /*not found, add*/
1130 98421 : if (!si) {
1131 6946 : GF_SAFEALLOC(si, StrikeInfo2D);
1132 6946 : if (!si) {
1133 : return NULL;
1134 : }
1135 6946 : si->lineProps = lp;
1136 6946 : si->drawable = drawable;
1137 :
1138 6946 : if (drawable->outline) {
1139 : prev = drawable->outline;
1140 132 : while (prev->next) prev = prev->next;
1141 78 : prev->next = si;
1142 : } else {
1143 6868 : drawable->outline = si;
1144 : }
1145 6946 : gf_list_add(compositor->strike_bank, si);
1146 : }
1147 :
1148 : /*3D drawing of outlines*/
1149 : #ifndef GPAC_DISABLE_3D
1150 98421 : if (tr_state && !asp->line_scale) {
1151 1214 : drawable_compute_line_scale(tr_state, asp);
1152 : }
1153 : #endif
1154 :
1155 : /*picking*/
1156 98421 : if (!asp->line_scale) return si;
1157 :
1158 : /*node changed or outline not build*/
1159 : #ifndef GPAC_DISABLE_VRML
1160 95222 : dirty = lp ? drawable_lineprops_dirty(lp) : 0;
1161 : #endif
1162 :
1163 95222 : if (!si->outline
1164 : #ifndef GPAC_DISABLE_VRML
1165 88268 : || dirty
1166 : #endif
1167 84677 : || (si->line_scale != asp->line_scale) || (si->path_length != asp->pen_props.path_length) || (svg_flags & CTX_SVG_OUTLINE_GEOMETRY_DIRTY)) {
1168 : u32 i;
1169 13639 : Fixed w = asp->pen_props.width;
1170 13639 : Fixed dash_o = asp->pen_props.dash_offset;
1171 13639 : si->line_scale = asp->line_scale;
1172 13639 : if (si->outline) gf_path_del(si->outline);
1173 : #ifndef GPAC_DISABLE_3D
1174 13639 : if (si->mesh_outline) {
1175 614 : mesh_free(si->mesh_outline);
1176 614 : si->mesh_outline = NULL;
1177 : }
1178 : #endif
1179 : /*apply scale whether scalable or not (if not scalable, scale is still needed for scalable zoom)*/
1180 13639 : asp->pen_props.width = gf_mulfix(asp->pen_props.width, asp->line_scale);
1181 13639 : if (asp->pen_props.dash != GF_DASH_STYLE_SVG)
1182 13639 : asp->pen_props.dash_offset = gf_mulfix(asp->pen_props.dash_offset, asp->pen_props.width);
1183 :
1184 13639 : if (asp->pen_props.dash_set) {
1185 1192 : for(i=0; i<asp->pen_props.dash_set->num_dash; i++) {
1186 1192 : asp->pen_props.dash_set->dashes[i] = gf_mulfix(asp->pen_props.dash_set->dashes[i], asp->line_scale);
1187 : }
1188 : }
1189 :
1190 13639 : if (path) {
1191 12886 : si->outline = gf_path_get_outline(path, asp->pen_props);
1192 12886 : si->original = path;
1193 : } else {
1194 753 : si->outline = gf_path_get_outline(drawable->path, asp->pen_props);
1195 : }
1196 : /*restore*/
1197 13639 : asp->pen_props.width = w;
1198 13639 : asp->pen_props.dash_offset = dash_o;
1199 13639 : if (asp->pen_props.dash_set) {
1200 1192 : for(i=0; i<asp->pen_props.dash_set->num_dash; i++) {
1201 1192 : asp->pen_props.dash_set->dashes[i] = gf_divfix(asp->pen_props.dash_set->dashes[i], asp->line_scale);
1202 : }
1203 : }
1204 : }
1205 :
1206 : return si;
1207 : }
1208 :
1209 9933 : void drawable_reset_path_outline(Drawable *st)
1210 : {
1211 9933 : StrikeInfo2D *si = st->outline;
1212 20429 : while (si) {
1213 563 : if (si->outline) gf_path_del(si->outline);
1214 563 : si->outline = NULL;
1215 : #ifndef GPAC_DISABLE_3D
1216 563 : if (si->mesh_outline) mesh_free(si->mesh_outline);
1217 563 : si->mesh_outline = NULL;
1218 : #endif
1219 563 : si->original = NULL;
1220 563 : si = si->next;
1221 : }
1222 : #ifndef GPAC_DISABLE_3D
1223 9933 : if (st->mesh) {
1224 174 : mesh_free(st->mesh);
1225 174 : st->mesh = NULL;
1226 : }
1227 : #endif
1228 9933 : }
1229 :
1230 9010 : void drawable_reset_path(Drawable *st)
1231 : {
1232 9010 : drawable_reset_path_outline(st);
1233 9010 : if (st->path) gf_path_reset(st->path);
1234 : #ifndef GPAC_DISABLE_3D
1235 9010 : if (st->mesh) {
1236 0 : mesh_free(st->mesh);
1237 0 : st->mesh = NULL;
1238 : }
1239 : #endif
1240 9010 : }
1241 :
1242 : #ifndef GPAC_DISABLE_VRML
1243 :
1244 983 : static void DestroyLineProps(GF_Node *n, void *rs, Bool is_destroy)
1245 : {
1246 : StrikeInfo2D *si, *cur, *prev;
1247 : u32 i;
1248 : LinePropStack *st;
1249 983 : if (!is_destroy) return;
1250 :
1251 983 : st = (LinePropStack *)gf_node_get_private(n);
1252 983 : i = 0;
1253 :
1254 86528 : while ((si = (StrikeInfo2D*)gf_list_enum(st->compositor->strike_bank, &i))) {
1255 84562 : if (si->lineProps == n) {
1256 : /*remove from node*/
1257 576 : if (si->drawable) {
1258 : assert(si->drawable->outline);
1259 576 : cur = si->drawable->outline;
1260 : prev = NULL;
1261 1176 : while (cur) {
1262 600 : if (cur!=si) {
1263 : prev = cur;
1264 24 : cur = cur->next;
1265 24 : continue;
1266 : }
1267 576 : if (prev) prev->next = cur->next;
1268 562 : else si->drawable->outline = cur->next;
1269 : break;
1270 : }
1271 : }
1272 576 : i--;
1273 576 : gf_list_rem(st->compositor->strike_bank, i);
1274 576 : delete_strikeinfo2d(si);
1275 : }
1276 : }
1277 :
1278 983 : gf_free(st);
1279 :
1280 : }
1281 :
1282 983 : void compositor_init_lineprops(GF_Compositor *compositor, GF_Node *node)
1283 : {
1284 : LinePropStack *st;
1285 983 : GF_SAFEALLOC(st, LinePropStack);
1286 983 : if (!st) {
1287 0 : GF_LOG(GF_LOG_ERROR, GF_LOG_COMPOSE, ("[Compositor] Failed to allocate line properties stack\n"));
1288 : return;
1289 : }
1290 983 : st->compositor = compositor;
1291 983 : st->last_mod_time = 0;
1292 983 : gf_node_set_private(node, st);
1293 983 : gf_node_set_callback_function(node, DestroyLineProps);
1294 : }
1295 :
1296 : #endif /*GPAC_DISABLE_VRML*/
1297 :
1298 :
1299 : #ifdef GPAC_DISABLE_SVG
1300 :
1301 : Bool drawable_get_aspect_2d_svg(GF_Node *node, DrawAspect2D *asp, GF_TraverseState *tr_state)
1302 : {
1303 : return 0;
1304 : }
1305 :
1306 : #else
1307 :
1308 25443 : Bool drawable_get_aspect_2d_svg(GF_Node *node, DrawAspect2D *asp, GF_TraverseState *tr_state)
1309 : {
1310 : Bool ret = 0;
1311 25443 : SVGPropertiesPointers *props = tr_state->svg_props;
1312 : Fixed clamped_opacity = FIX_ONE;
1313 : Fixed clamped_solid_opacity = FIX_ONE;
1314 25443 : Fixed clamped_fill_opacity = (props->fill_opacity->value < 0 ? 0 : (props->fill_opacity->value > FIX_ONE ? FIX_ONE : props->fill_opacity->value));
1315 25443 : Fixed clamped_stroke_opacity = (props->stroke_opacity->value < 0 ? 0 : (props->stroke_opacity->value > FIX_ONE ? FIX_ONE : props->stroke_opacity->value));
1316 :
1317 25443 : if (props->opacity) {
1318 315 : clamped_opacity = (props->opacity->value < 0 ? 0 : (props->opacity->value > FIX_ONE ? FIX_ONE : props->opacity->value));
1319 315 : if (clamped_opacity!=FIX_ONE) {
1320 315 : clamped_fill_opacity = gf_mulfix(clamped_fill_opacity, clamped_opacity);
1321 315 : clamped_stroke_opacity = gf_mulfix(clamped_stroke_opacity, clamped_opacity);
1322 : }
1323 : }
1324 25443 : asp->fill_color = 0;
1325 :
1326 25443 : if (props->fill->type==SVG_PAINT_URI) {
1327 62 : if (props->fill->iri.type != XMLRI_ELEMENTID) {
1328 : /* trying to resolve the IRI to the Paint Server */
1329 0 : XMLRI *iri = &props->fill->iri;
1330 0 : GF_SceneGraph *sg = gf_node_get_graph(node);
1331 0 : GF_Node *n = gf_sg_find_node_by_name(sg, &(iri->string[1]));
1332 0 : if (n) {
1333 0 : iri->type = XMLRI_ELEMENTID;
1334 0 : iri->target = n;
1335 0 : gf_node_register_iri(sg, iri);
1336 0 : gf_free(iri->string);
1337 0 : iri->string = NULL;
1338 : }
1339 : }
1340 : /* If paint server not found, paint is equivalent to none */
1341 62 : if (props->fill->iri.type == XMLRI_ELEMENTID) {
1342 62 : asp->fill_color = GF_COL_ARGB_FIXED(clamped_opacity, 0, 0, 0);
1343 62 : switch (gf_node_get_tag((GF_Node *)props->fill->iri.target)) {
1344 2 : case TAG_SVG_solidColor:
1345 : {
1346 : SVGAllAttributes all_atts;
1347 2 : gf_svg_flatten_attributes((SVG_Element*)props->fill->iri.target, &all_atts);
1348 :
1349 2 : gf_node_traverse(props->fill->iri.target, tr_state);
1350 :
1351 2 : ret += compositor_svg_solid_color_dirty(tr_state->visual->compositor, props->fill->iri.target);
1352 :
1353 2 : if (all_atts.solid_color) {
1354 2 : if (all_atts.solid_opacity) {
1355 0 : Fixed val = all_atts.solid_opacity->value;
1356 0 : clamped_solid_opacity = MIN(FIX_ONE, MAX(0, val) );
1357 0 : clamped_solid_opacity = gf_mulfix(clamped_solid_opacity, clamped_opacity);
1358 : }
1359 2 : asp->fill_color = GF_COL_ARGB_FIXED(clamped_solid_opacity, all_atts.solid_color->color.red, all_atts.solid_color->color.green, all_atts.solid_color->color.blue);
1360 : }
1361 : }
1362 2 : break;
1363 60 : case TAG_SVG_linearGradient:
1364 : case TAG_SVG_radialGradient:
1365 60 : asp->fill_texture = gf_sc_texture_get_handler((GF_Node *)props->fill->iri.target);
1366 60 : break;
1367 : /*FIXME*/
1368 : default:
1369 : break;
1370 : }
1371 0 : }
1372 25381 : } else if (props->fill->type == SVG_PAINT_COLOR) {
1373 23233 : if (props->fill->color.type == SVG_COLOR_CURRENTCOLOR) {
1374 0 : asp->fill_color = GF_COL_ARGB_FIXED(clamped_fill_opacity, props->color->color.red, props->color->color.green, props->color->color.blue);
1375 23233 : } else if (props->fill->color.type == SVG_COLOR_RGBCOLOR) {
1376 23233 : asp->fill_color = GF_COL_ARGB_FIXED(clamped_fill_opacity, props->fill->color.red, props->fill->color.green, props->fill->color.blue);
1377 0 : } else if (props->fill->color.type >= SVG_COLOR_ACTIVE_BORDER) {
1378 0 : asp->fill_color = tr_state->visual->compositor->sys_colors[props->fill->color.type - 3];
1379 0 : asp->fill_color |= ((u32) (clamped_fill_opacity*255) ) << 24;
1380 : }
1381 : }
1382 25443 : if (!tr_state->color_mat.identity)
1383 0 : asp->fill_color = gf_cmx_apply(&tr_state->color_mat, asp->fill_color);
1384 :
1385 25443 : asp->line_color = 0;
1386 25443 : asp->pen_props.width = (props->stroke->type != SVG_PAINT_NONE) ? props->stroke_width->value : 0;
1387 25443 : if (props->stroke->type==SVG_PAINT_URI) {
1388 154 : if (props->stroke->iri.type != XMLRI_ELEMENTID) {
1389 : /* trying to resolve the IRI to the Paint Server */
1390 0 : XMLRI *iri = &props->stroke->iri;
1391 0 : GF_SceneGraph *sg = gf_node_get_graph(node);
1392 0 : GF_Node *n = gf_sg_find_node_by_name(sg, &(iri->string[1]));
1393 0 : if (n) {
1394 0 : iri->type = XMLRI_ELEMENTID;
1395 0 : iri->target = n;
1396 0 : gf_node_register_iri(sg, iri);
1397 0 : gf_free(iri->string);
1398 0 : iri->string = NULL;
1399 : }
1400 : }
1401 : /* Paint server not found, stroke is equivalent to none */
1402 308 : if ((props->stroke->iri.type == XMLRI_ELEMENTID) && props->stroke->iri.target) {
1403 154 : switch (gf_node_get_tag((GF_Node *)props->stroke->iri.target)) {
1404 4 : case TAG_SVG_solidColor:
1405 : {
1406 : SVGAllAttributes all_atts;
1407 4 : gf_svg_flatten_attributes((SVG_Element*)props->stroke->iri.target, &all_atts);
1408 :
1409 4 : gf_node_traverse(props->stroke->iri.target, tr_state);
1410 :
1411 4 : ret += compositor_svg_solid_color_dirty(tr_state->visual->compositor, props->stroke->iri.target);
1412 :
1413 4 : if (all_atts.solid_color) {
1414 4 : if (all_atts.solid_opacity) {
1415 0 : Fixed val = all_atts.solid_opacity->value;
1416 0 : clamped_solid_opacity = MIN(FIX_ONE, MAX(0, val) );
1417 : }
1418 4 : asp->line_color = GF_COL_ARGB_FIXED(clamped_solid_opacity, all_atts.solid_color->color.red, all_atts.solid_color->color.green, all_atts.solid_color->color.blue);
1419 : }
1420 : }
1421 4 : break;
1422 150 : case TAG_SVG_linearGradient:
1423 : case TAG_SVG_radialGradient:
1424 150 : asp->line_texture = gf_sc_texture_get_handler((GF_Node *)props->stroke->iri.target);
1425 150 : break;
1426 : default:
1427 : break;
1428 : }
1429 0 : }
1430 25289 : } else if (props->stroke->type == SVG_PAINT_COLOR) {
1431 5794 : if (props->stroke->color.type == SVG_COLOR_CURRENTCOLOR) {
1432 0 : asp->line_color = GF_COL_ARGB_FIXED(clamped_stroke_opacity, props->color->color.red, props->color->color.green, props->color->color.blue);
1433 5794 : } else if (props->stroke->color.type == SVG_COLOR_RGBCOLOR) {
1434 5794 : asp->line_color = GF_COL_ARGB_FIXED(clamped_stroke_opacity, props->stroke->color.red, props->stroke->color.green, props->stroke->color.blue);
1435 0 : } else if (props->stroke->color.type >= SVG_COLOR_ACTIVE_BORDER) {
1436 0 : asp->line_color = tr_state->visual->compositor->sys_colors[SVG_COLOR_ACTIVE_BORDER - 3];
1437 0 : asp->line_color |= ((u32) (clamped_stroke_opacity*255)) << 24;
1438 : }
1439 : }
1440 25443 : if (!tr_state->color_mat.identity)
1441 0 : asp->line_color = gf_cmx_apply(&tr_state->color_mat, asp->line_color);
1442 :
1443 25443 : if (props->stroke_dasharray->type != SVG_STROKEDASHARRAY_NONE) {
1444 900 : asp->pen_props.dash = GF_DASH_STYLE_SVG;
1445 900 : asp->pen_props.dash_offset = props->stroke_dashoffset->value;
1446 900 : asp->pen_props.dash_set = (GF_DashSettings *) &(props->stroke_dasharray->array);
1447 : }
1448 25443 : asp->line_scale = (props->vector_effect && (*props->vector_effect == SVG_VECTOREFFECT_NONSCALINGSTROKE)) ? 0 : FIX_ONE;
1449 :
1450 25443 : asp->pen_props.cap = (u8) *props->stroke_linecap;
1451 25443 : asp->pen_props.join = (u8) *props->stroke_linejoin;
1452 25443 : asp->pen_props.miterLimit = props->stroke_miterlimit->value;
1453 :
1454 25443 : if (!tr_state->color_mat.identity) {
1455 0 : asp->fill_color = gf_cmx_apply(&tr_state->color_mat, asp->fill_color);
1456 0 : asp->line_color = gf_cmx_apply(&tr_state->color_mat, asp->line_color);
1457 : }
1458 25443 : return ret;
1459 : }
1460 :
1461 24872 : static Bool svg_appearance_flag_dirty(u32 flags)
1462 : {
1463 : #if 1
1464 : /* fill-related */
1465 24872 : if (flags & GF_SG_SVG_FILL_DIRTY) return 1;
1466 24647 : if (flags & GF_SG_SVG_FILLOPACITY_DIRTY) return 1;
1467 24556 : if (flags & GF_SG_SVG_FILLRULE_DIRTY) return 1;
1468 :
1469 : /* stroke-related */
1470 24552 : if (flags & GF_SG_SVG_STROKE_DIRTY) return 1;
1471 24552 : if (flags & GF_SG_SVG_STROKEDASHARRAY_DIRTY) return 1;
1472 24552 : if (flags & GF_SG_SVG_STROKEDASHOFFSET_DIRTY) return 1;
1473 24552 : if (flags & GF_SG_SVG_STROKELINECAP_DIRTY) return 1;
1474 24552 : if (flags & GF_SG_SVG_STROKELINEJOIN_DIRTY) return 1;
1475 24552 : if (flags & GF_SG_SVG_STROKEMITERLIMIT_DIRTY) return 1;
1476 24552 : if (flags & GF_SG_SVG_STROKEOPACITY_DIRTY) return 1;
1477 24552 : if (flags & GF_SG_SVG_STROKEWIDTH_DIRTY) return 1;
1478 24552 : if (flags & GF_SG_SVG_VECTOREFFECT_DIRTY) return 1;
1479 :
1480 : /* gradients stops and solidcolor do not affect appearance directly */
1481 24552 : return 0;
1482 : #else
1483 : if (flags &
1484 : (GF_SG_SVG_FILL_DIRTY | GF_SG_SVG_FILLOPACITY_DIRTY | GF_SG_SVG_FILLRULE_DIRTY
1485 : | GF_SG_SVG_STROKE_DIRTY | GF_SG_SVG_STROKEDASHARRAY_DIRTY
1486 : | GF_SG_SVG_STROKEDASHOFFSET_DIRTY | GF_SG_SVG_STROKELINECAP_DIRTY
1487 : | GF_SG_SVG_STROKELINEJOIN_DIRTY | GF_SG_SVG_STROKEMITERLIMIT_DIRTY
1488 : | GF_SG_SVG_STROKEOPACITY_DIRTY | GF_SG_SVG_STROKEWIDTH_DIRTY
1489 : | GF_SG_SVG_VECTOREFFECT_DIRTY) )
1490 : return 1;
1491 : return 0;
1492 : #endif
1493 : }
1494 :
1495 25278 : DrawableContext *drawable_init_context_svg(Drawable *drawable, GF_TraverseState *tr_state)
1496 : {
1497 : DrawableContext *ctx;
1498 : assert(tr_state->visual);
1499 :
1500 : #ifndef GPAC_DISABLE_VRML
1501 : /*setup SVG based on override appearance node */
1502 25278 : if (tr_state->override_appearance) {
1503 341 : return drawable_init_context_mpeg4(drawable, tr_state);
1504 : }
1505 : #endif
1506 :
1507 : /*switched-off geometry nodes are not drawn*/
1508 24937 : if (tr_state->switched_off) return NULL;
1509 :
1510 : //Get a empty context from the current visual
1511 24937 : ctx = visual_2d_get_drawable_context(tr_state->visual);
1512 24937 : if (!ctx) return NULL;
1513 :
1514 24937 : gf_mx2d_copy(ctx->transform, tr_state->transform);
1515 :
1516 24937 : ctx->drawable = drawable;
1517 :
1518 24937 : if (tr_state->invalidate_all || svg_appearance_flag_dirty(tr_state->svg_flags)) {
1519 385 : ctx->flags |= CTX_APP_DIRTY;
1520 385 : GF_LOG(GF_LOG_DEBUG, GF_LOG_COMPOSE, ("Node %s dirty - invalidating\n", gf_node_get_log_name(drawable->node) ));
1521 : }
1522 24937 : if (tr_state->svg_flags & (GF_SG_SVG_STROKEDASHARRAY_DIRTY |
1523 : GF_SG_SVG_STROKEDASHOFFSET_DIRTY |
1524 : GF_SG_SVG_STROKELINECAP_DIRTY |
1525 : GF_SG_SVG_STROKELINEJOIN_DIRTY |
1526 : GF_SG_SVG_STROKEMITERLIMIT_DIRTY |
1527 : GF_SG_SVG_STROKEWIDTH_DIRTY |
1528 : GF_SG_SVG_VECTOREFFECT_DIRTY ))
1529 5 : ctx->flags |= CTX_SVG_OUTLINE_GEOMETRY_DIRTY;
1530 :
1531 24937 : ctx->aspect.fill_texture = NULL;
1532 :
1533 : /*FIXME - only needed for texture*/
1534 24937 : if (!tr_state->color_mat.identity) {
1535 0 : GF_SAFEALLOC(ctx->col_mat, GF_ColorMatrix);
1536 0 : if (ctx->col_mat)
1537 0 : gf_cmx_copy(ctx->col_mat, &tr_state->color_mat);
1538 : }
1539 :
1540 24937 : switch (gf_node_get_tag(ctx->drawable->node) ) {
1541 2389 : case TAG_SVG_image:
1542 : case TAG_SVG_video:
1543 2389 : ctx->aspect.fill_texture = gf_sc_texture_get_handler(ctx->drawable->node);
1544 2389 : break;
1545 : case TAG_SVG_line:
1546 : case TAG_SVG_polyline:
1547 : break;
1548 : default:
1549 : break;
1550 : }
1551 :
1552 24937 : if (drawable_get_aspect_2d_svg(drawable->node, &ctx->aspect, tr_state))
1553 0 : ctx->flags |= CTX_APP_DIRTY;
1554 :
1555 24937 : if (ctx->drawable->path) {
1556 24937 : if (*tr_state->svg_props->fill_rule == SVG_FILLRULE_NONZERO) {
1557 24862 : ctx->drawable->path->flags |= GF_PATH_FILL_ZERO_NONZERO;
1558 : } else {
1559 75 : ctx->drawable->path->flags &= ~GF_PATH_FILL_ZERO_NONZERO;
1560 : }
1561 : }
1562 :
1563 24937 : drawable_check_texture_dirty(ctx, drawable, tr_state);
1564 :
1565 : /*we are drawing on a centered coord surface, remember to flip the texture*/
1566 24937 : if (tr_state->fliped_coords)
1567 158 : ctx->flags |= CTX_FLIPED_COORDS;
1568 :
1569 :
1570 : #ifdef GF_SR_USE_DEPTH
1571 24937 : ctx->depth_gain=tr_state->depth_gain;
1572 24937 : ctx->depth_offset=tr_state->depth_offset;
1573 : #endif
1574 :
1575 24937 : return ctx;
1576 : }
1577 :
1578 :
1579 :
1580 : #endif //SVG
|