maug
Quick and dirty C mini-augmentation library.
retrohtr.h
Go to the documentation of this file.
1
2#ifndef RETROHTR_H
3#define RETROHTR_H
4
11#define RETROHTR_TREE_FLAG_GUI_ACTIVE 1
12
13#define RETROHTR_NODE_FLAG_DIRTY 2
14
15#ifndef RETROHTR_RENDER_NODES_INIT_SZ
16# define RETROHTR_RENDER_NODES_INIT_SZ 10
17#endif /* !RETROHTR_RENDER_NODES_INIT_SZ */
18
19#ifndef RETROHTR_TRACE_LVL
20# define RETROHTR_TRACE_LVL 0
21#endif /* !RETROHTR_TRACE_LVL */
22
23#define RETROHTR_EDGE_UNKNOWN 0
24#define RETROHTR_EDGE_LEFT 1
25#define RETROHTR_EDGE_TOP 2
26#define RETROHTR_EDGE_INSIDE 4
27
29 uint8_t flags;
30 /* TODO: Maybe get rid of these and replace them with MCSS_STYLE node? */
39 uint8_t pos;
40 uint8_t pos_flags;
41 uint8_t edge;
44 union RETROGXC_CACHABLE font;
45 ssize_t tag;
47 ssize_t parent;
49 ssize_t first_child;
51 ssize_t next_sibling;
52 struct RETROFLAT_BITMAP bitmap;
53};
54
56 uint8_t flags;
57 MAUG_MHANDLE nodes_h;
61 size_t nodes_sz;
64 struct RETROGUI gui;
65};
66
67/* TODO: Function names should be verb_noun! */
68
69#define retrohtr_node( tree, idx ) \
70 (0 <= (ssize_t)idx ? &((tree)->nodes[idx]) : NULL)
71
72#define retrohtr_node_parent( tree, idx ) \
73 (0 <= idx && 0 <= (tree)->nodes[idx].parent ? \
74 &((tree)->nodes[(tree)->nodes[idx].parent]) : NULL)
75
76#define retrohtr_tree_lock( tree ) \
77 if( NULL == (tree)->nodes ) { \
78 maug_mlock( (tree)->nodes_h, (tree)->nodes ); \
79 maug_cleanup_if_null_alloc( struct RETROHTR_RENDER_NODE*, (tree)->nodes ); \
80 }
81
82#define retrohtr_tree_unlock( tree ) \
83 if( NULL != (tree)->nodes ) { \
84 maug_munlock( (tree)->nodes_h, (tree)->nodes ); \
85 }
86
87#define retrohtr_tree_is_locked( tree ) (NULL != (tree)->nodes)
88
89/* TODO: Make these offset by element scroll on screen. */
90
91#define retrohtr_node_screen_x( tree, node_idx ) \
92 ((tree)->nodes[node_idx].x)
93
94#define retrohtr_node_screen_y( tree, node_idx ) \
95 ((tree)->nodes[node_idx].y)
96
97void retrohtr_merge_prop(
98 int p_id,
99 const char* prop_name,
100 size_t prop_sz,
101 size_t tag_type,
102 void* parent_prop, uint8_t* parent_prop_flags,
103 void* effect_prop, uint8_t* effect_prop_flags,
104 void* tag_prop, uint8_t* tag_prop_flags );
105
106void retrohtr_merge_styles(
107 struct MCSS_STYLE* effect_style,
108 struct MCSS_STYLE* parent_style,
109 struct MCSS_STYLE* tag_style,
110 size_t tag_type );
111
112MERROR_RETVAL retrohtr_tree_create(
113 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
116 ssize_t tag_idx, ssize_t node_idx, size_t d );
117
130 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
131 struct MCSS_STYLE* parent_style, struct MCSS_STYLE* effect_style,
132 ssize_t tag_idx );
133
134MERROR_RETVAL retrohtr_tree_size(
135 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
136 struct MCSS_STYLE* prev_sibling_style,
137 struct MCSS_STYLE* parent_style, ssize_t node_idx, size_t d );
138
139MERROR_RETVAL retrohtr_tree_pos(
140 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
141 struct MCSS_STYLE* prev_sibling_style,
142 struct MCSS_STYLE* parent_style, ssize_t node_idx, size_t d );
143
144MERROR_RETVAL retrohtr_tree_draw(
145 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
146 ssize_t node_idx, size_t d );
147
148retrogui_idc_t retrohtr_tree_poll_ctls(
149 struct RETROHTR_RENDER_TREE* tree,
150 RETROFLAT_IN_KEY* input,
151 struct RETROFLAT_INPUT* input_evt );
152
153MERROR_RETVAL retrohtr_tree_dump(
154 struct RETROHTR_RENDER_TREE* tree, struct MHTML_PARSER* parser,
155 ssize_t iter, size_t d );
156
157void retrohtr_tree_free( struct RETROHTR_RENDER_TREE* tree );
158
159MERROR_RETVAL retrohtr_tree_init( struct RETROHTR_RENDER_TREE* tree );
160
161#ifdef RETROHTR_C
162
163void retrohtr_merge_prop(
164 int p_id,
165 const char* prop_name,
166 size_t prop_sz,
167 size_t tag_type,
168 void* parent_prop, uint8_t* parent_prop_flags,
169 void* effect_prop, uint8_t* effect_prop_flags,
170 void* tag_prop, uint8_t* tag_prop_flags
171) {
172 if(
173 (
174 /* Only do inheritence for some special cases.
175 * e.g. We don't want to inherit width/height/X/etc! */
176 mcss_prop_is_heritable( p_id )
177 ) && (NULL != parent_prop && (
178 (
179 NULL != tag_prop &&
180 /* Parent is important and new property isn't. */
181 mcss_prop_is_active_flag( *parent_prop, IMPORTANT ) &&
182 /* TODO: Is not active OR important? */
183 !mcss_prop_is_important( *tag_prop ) &&
184 !mcss_prop_is_important( *effect_prop )
185 ) || (
186 NULL != tag_prop &&
187 /* New property is not active. */
188 !mcss_prop_is_active( *tag_prop ) &&
189 !mcss_prop_is_active( *effect_prop )
190 ) || (
191 /* No competition. */
192 NULL == tag_prop &&
193 !mcss_prop_is_active( *effect_prop )
194 )
195 ))
196 ) {
197 /* Inherit parent property. */
198 if( MCSS_PROP_BACKGROUND_COLOR == p_id ) {
199#if RETROHTR_TRACE_LVL > 0
200 debug_printf( RETROHTR_TRACE_LVL, "background color was %s",
201 0 <= *(RETROFLAT_COLOR*)effect_prop ?
202 gc_retroflat_color_names[*(RETROFLAT_COLOR*)effect_prop] : "NULL" );
203#endif /* RETROHTR_TRACE_LVL */
204 } else if( MCSS_PROP_COLOR == p_id ) {
205#if RETROHTR_TRACE_LVL > 0
206 debug_printf( RETROHTR_TRACE_LVL, "color was %s",
207 0 <= *(RETROFLAT_COLOR*)effect_prop ?
208 gc_retroflat_color_names[*(RETROFLAT_COLOR*)effect_prop] : "NULL" );
209#endif /* RETROHTR_TRACE_LVL */
210 }
211#if RETROHTR_TRACE_LVL > 0
212 debug_printf( RETROHTR_TRACE_LVL,
213 "%s using parent %s: " SSIZE_T_FMT,
214 gc_mhtml_tag_names[tag_type], prop_name, *(ssize_t*)parent_prop );
215#endif /* RETROHTR_TRACE_LVL */
216 memcpy( effect_prop, parent_prop, prop_sz );
217 *effect_prop_flags = *parent_prop_flags;
218 if( MCSS_PROP_BACKGROUND_COLOR == p_id ) {
219#if RETROHTR_TRACE_LVL > 0
220 debug_printf( RETROHTR_TRACE_LVL, "background color %s",
221 0 <= *(RETROFLAT_COLOR*)effect_prop ?
222 gc_retroflat_color_names[*(RETROFLAT_COLOR*)effect_prop] : "NULL" );
223#endif /* RETROHTR_TRACE_LVL */
224 } else if( MCSS_PROP_COLOR == p_id ) {
225#if RETROHTR_TRACE_LVL > 0
226 debug_printf( RETROHTR_TRACE_LVL, "color %s",
227 0 <= *(RETROFLAT_COLOR*)effect_prop ?
228 gc_retroflat_color_names[*(RETROFLAT_COLOR*)effect_prop] : "NULL" );
229#endif /* RETROHTR_TRACE_LVL */
230 }
231 } else if(
232 NULL != tag_prop &&
233 mcss_prop_is_active( *tag_prop )
234 ) {
235 /* Use new property. */
236#if RETROHTR_TRACE_LVL > 0
237 debug_printf( RETROHTR_TRACE_LVL, "%s using style %s: " SSIZE_T_FMT,
238 gc_mhtml_tag_names[tag_type], prop_name,
239 *(ssize_t*)tag_prop );
240 if( MCSS_PROP_COLOR == p_id ) {
241 debug_printf( RETROHTR_TRACE_LVL, "color %s",
242 0 <= *(RETROFLAT_COLOR*)effect_prop ?
243 gc_retroflat_color_names[*(RETROFLAT_COLOR*)effect_prop] : "NULL" );
244 }
245#endif /* RETROHTR_TRACE_LVL */
246 memcpy( effect_prop, tag_prop, prop_sz );
247 *effect_prop_flags = *tag_prop_flags;
248 }
249}
250
251/* === */
252
253void retrohtr_merge_styles(
254 struct MCSS_STYLE* effect_style,
255 struct MCSS_STYLE* parent_style,
256 struct MCSS_STYLE* tag_style,
257 size_t tag_type
258) {
259 /* At least one of these styles probably comes from the locked vector of the
260 * CSS styles parser, so... keep that in mind?
261 */
262
263 if(
264 MCSS_STYLE_FLAG_ACTIVE !=
265 (MCSS_STYLE_FLAG_ACTIVE & effect_style->flags)
266 ) {
267 mcss_style_init( effect_style );
268 }
269
270 /* Perform inheritence of special cases. */
271
272 #define MCSS_PROP_TABLE_MERGE( p_id, prop_n, prop_t, prop_p, def ) \
273 retrohtr_merge_prop( p_id, \
274 #prop_n, \
275 sizeof( prop_t ), \
276 tag_type, \
277 NULL != parent_style ? &(parent_style->prop_n) : NULL, \
278 NULL != parent_style ? &(parent_style->prop_n ## _flags) : 0, \
279 NULL != effect_style ? &(effect_style->prop_n) : NULL, \
280 NULL != effect_style ? &(effect_style->prop_n ## _flags) : 0, \
281 NULL != tag_style ? &(tag_style->prop_n) : NULL, \
282 NULL != tag_style ? &(tag_style->prop_n ## _flags) : 0 );
283
284 MCSS_PROP_TABLE( MCSS_PROP_TABLE_MERGE )
285
286 /* Apply defaults for display. */
287
288 if(
289 MCSS_PROP_FLAG_ACTIVE !=
290 (MCSS_PROP_FLAG_ACTIVE & effect_style->DISPLAY_flags)
291 ) {
292 /* Set the display property based on the tag's default. */
293
294 #define MHTML_TAG_TABLE_DISP( tag_id, tag_name, fields, disp ) \
295 } else if( tag_id == tag_type ) { \
296 effect_style->DISPLAY = MCSS_DISPLAY_ ## disp; \
297 debug_printf( RETROHTR_TRACE_LVL, "%s defaulting to %s DISPLAY", \
298 gc_mhtml_tag_names[tag_type], \
299 gc_mcss_display_names[effect_style->DISPLAY] );
300
301 if( 0 ) {
302 MHTML_TAG_TABLE( MHTML_TAG_TABLE_DISP )
303 }
304
305 }
306
307 return;
308}
309
310/* === */
311
312ssize_t retrohtr_get_next_free_node( struct RETROHTR_RENDER_TREE* tree ) {
313 MERROR_RETVAL retval = MERROR_OK;
314 uint8_t auto_unlocked = 0;
315 ssize_t retidx = -1;
316 MAUG_MHANDLE new_nodes_h = (MAUG_MHANDLE)NULL;
317
318 if( NULL != tree->nodes ) {
319#if RETROHTR_TRACE_LVL > 0
320 debug_printf( RETROHTR_TRACE_LVL, "auto-unlocking nodes..." );
321#endif /* RETROHTR_TRACE_LVL */
322 maug_munlock( tree->nodes_h, tree->nodes );
323 auto_unlocked = 1;
324 }
325
326 assert( 0 < tree->nodes_sz_max );
327 assert( NULL == tree->nodes );
328 assert( (MAUG_MHANDLE)NULL != tree->nodes_h );
329 if( tree->nodes_sz_max <= tree->nodes_sz + 1 ) {
330 /* We've run out of nodes, so double the available number. */
331 maug_mrealloc_test( new_nodes_h, tree->nodes_h, tree->nodes_sz_max * 2,
332 sizeof( struct RETROHTR_RENDER_NODE ) );
333 tree->nodes_sz_max *= 2;
334 }
335
336 /* Assume handle is unlocked. */
337 assert( NULL == tree->nodes );
338 maug_mlock( tree->nodes_h, tree->nodes );
339 if( NULL == tree->nodes ) {
340 error_printf( "unable to lock nodes!" );
341 goto cleanup;
342 }
343
344 /* Zero out the last node, add it to the list, and return its index. */
345#if RETROHTR_TRACE_LVL > 0
346 debug_printf( RETROHTR_TRACE_LVL,
347 "zeroing node " SIZE_T_FMT " (of " SIZE_T_FMT ")...",
348 tree->nodes_sz, tree->nodes_sz_max );
349#endif /* RETROHTR_TRACE_LVL */
350 maug_mzero( &(tree->nodes[tree->nodes_sz]),
351 sizeof( struct RETROHTR_RENDER_NODE ) );
352 retidx = tree->nodes_sz;
353 tree->nodes_sz++;
354
355 /* Compensate for cleanup below. */
356 maug_munlock( tree->nodes_h, tree->nodes );
357
358cleanup:
359
360 if( auto_unlocked ) {
361#if RETROHTR_TRACE_LVL > 0
362 debug_printf( RETROHTR_TRACE_LVL, "auto-locking nodes..." );
363#endif /* RETROHTR_TRACE_LVL */
364 maug_mlock( tree->nodes_h, tree->nodes );
365 }
366
367 if( MERROR_OK != retval ) {
368 retidx = merror_retval_to_sz( retval );
369 }
370
371 return retidx;
372}
373
374/* === */
375
376ssize_t retrohtr_add_node_child(
377 struct RETROHTR_RENDER_TREE* tree, ssize_t node_parent_idx
378) {
379 ssize_t node_new_idx = -1,
380 node_sibling_idx = -1;
381
382 node_new_idx = retrohtr_get_next_free_node( tree );
383 if( 0 > node_new_idx ) {
384 goto cleanup;
385 }
386
387#ifdef RETROGXC_PRESENT
388 retrohtr_node( tree, node_new_idx )->font.cache_idx = -1;
389#endif /* RETROGXC_PRESENT */
390 retrohtr_node( tree, node_new_idx )->parent = node_parent_idx;
391 retrohtr_node( tree, node_new_idx )->first_child = -1;
392 retrohtr_node( tree, node_new_idx )->next_sibling = -1;
393
394 if( 0 > node_parent_idx ) {
395 debug_printf(
396 1, "adding root node under " SSIZE_T_FMT "...", node_parent_idx );
397 goto cleanup;
398 } else {
399 debug_printf(
400 1, "adding node " SSIZE_T_FMT " under " SSIZE_T_FMT,
401 node_new_idx, node_parent_idx );
402 }
403
404 /* Add new child under current node. */
405 if( 0 > retrohtr_node( tree, node_parent_idx )->first_child ) {
406#if RETROHTR_TRACE_LVL > 0
407 debug_printf( RETROHTR_TRACE_LVL, "adding first child..." );
408#endif /* RETROHTR_TRACE_LVL */
409 assert( -1 == retrohtr_node( tree, node_parent_idx )->first_child );
410 retrohtr_node( tree, node_parent_idx )->first_child = node_new_idx;
411 } else {
412 assert( NULL != retrohtr_node( tree, node_parent_idx ) );
413 node_sibling_idx = retrohtr_node( tree, node_parent_idx )->first_child;
414 assert( NULL != retrohtr_node( tree, node_sibling_idx ) );
415 while( 0 <= retrohtr_node( tree, node_sibling_idx )->next_sibling ) {
416 node_sibling_idx =
417 retrohtr_node( tree, node_sibling_idx )->next_sibling;
418 }
419 retrohtr_node( tree, node_sibling_idx )->next_sibling = node_new_idx;
420 }
421
422cleanup:
423
424 return node_new_idx;
425}
426
427/* === */
428
429MERROR_RETVAL retrohtr_tree_create(
430 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
433 ssize_t tag_idx, ssize_t node_idx, size_t d
434) {
435 ssize_t node_new_idx = -1;
436 ssize_t tag_iter_idx = -1;
437 MERROR_RETVAL retval = MERROR_OK;
438 union MHTML_TAG* p_tag_iter = NULL;
439 ssize_t tag_next_idx = 0;
440
441#if RETROHTR_TRACE_LVL > 0
442 debug_printf( RETROHTR_TRACE_LVL,
443 "creating render node for tag: " SSIZE_T_FMT, tag_idx );
444#endif /* RETROHTR_TRACE_LVL */
445
446 mdata_vector_lock( &(parser->tags) );
447
448 if( 0 > tag_idx ) {
449 goto cleanup;
450 }
451 p_tag_iter = mdata_vector_get( &(parser->tags), tag_idx, union MHTML_TAG );
452 if( NULL == p_tag_iter ) {
453 goto cleanup;
454 }
455
456 /* Make sure we have a single root node. */
457 if( 0 > node_idx ) {
458 assert( MHTML_TAG_TYPE_BODY == p_tag_iter->base.type );
459
460 node_new_idx = retrohtr_add_node_child( tree, node_idx );
461 if( 0 > node_new_idx ) {
462 goto cleanup;
463 }
464#if RETROHTR_TRACE_LVL > 0
465 debug_printf( RETROHTR_TRACE_LVL,
466 "created initial root node: " SIZE_T_FMT, node_new_idx );
467#endif /* RETROHTR_TRACE_LVL */
468
469 node_idx = node_new_idx;
470
471 /* The common root is the body tag. */
472 retrohtr_node( tree, node_idx )->tag = tag_idx;
473
474 retrohtr_node( tree, node_idx )->x = x;
475 retrohtr_node( tree, node_idx )->y = y;
476 retrohtr_node( tree, node_idx )->w = w;
477 retrohtr_node( tree, node_idx )->h = h;
478 }
479
480 tag_iter_idx = p_tag_iter->base.first_child;
481 while( 0 <= tag_iter_idx ) {
482 node_new_idx = retrohtr_add_node_child( tree, node_idx );
483 p_tag_iter = mdata_vector_get(
484 &(parser->tags), tag_iter_idx, union MHTML_TAG );
485 assert( NULL != p_tag_iter );
486 if( 0 > node_new_idx ) {
487 goto cleanup;
488 }
489
490 retrohtr_node( tree, node_new_idx )->tag = tag_iter_idx;
491
492#if RETROHTR_TRACE_LVL > 0
493 debug_printf( RETROHTR_TRACE_LVL,
494 "rendering node " SSIZE_T_FMT " (%s) under node " SSIZE_T_FMT,
495 node_new_idx,
496 gc_mhtml_tag_names[p_tag_iter->base.type],
497 node_idx );
498#endif /* RETROHTR_TRACE_LVL */
499
500 /* Tag-specific rendering preparations. */
501 if( MHTML_TAG_TYPE_IMG == p_tag_iter->base.type ) {
502 /* Load the image for rendering later. */
503 retval = retroflat_load_bitmap(
504 p_tag_iter->IMG.src,
505 &(retrohtr_node( tree, node_new_idx )->bitmap),
507 if( MERROR_OK == retval ) {
508#if RETROHTR_TRACE_LVL > 0
509 debug_printf( RETROHTR_TRACE_LVL, "loaded img: %s",
510 p_tag_iter->IMG.src );
511#endif /* RETROHTR_TRACE_LVL */
512 } else {
513 error_printf( "could not load img: %s", p_tag_iter->IMG.src );
514 }
515 }
516
517 tag_next_idx = p_tag_iter->base.next_sibling;
518
519 mdata_vector_unlock( &(parser->tags) );
520
521 retval = retrohtr_tree_create( parser, tree, x, y, w, h,
522 tag_iter_idx, node_new_idx, d + 1 );
523 maug_cleanup_if_not_ok();
524
525 mdata_vector_lock( &(parser->tags) );
526
527 tag_iter_idx = tag_next_idx;
528 }
529
530cleanup:
531
532 if( mdata_vector_is_locked( &(parser->tags) ) ) {
533 mdata_vector_unlock( &(parser->tags) );
534 }
535
536 return retval;
537}
538
539/* === */
540
542 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
543 struct MCSS_STYLE* parent_style, struct MCSS_STYLE* effect_style,
544 ssize_t tag_idx
545) {
546 MERROR_RETVAL retval = MERROR_OK;
547 ssize_t tag_style_idx = -1;
548 size_t tag_type = 0,
549 i = 0;
550 struct MCSS_STYLE* style = NULL;
551 union MHTML_TAG* p_tag_iter = NULL;
552
553#if RETROHTR_TRACE_LVL > 0
554 debug_printf( RETROHTR_TRACE_LVL,
555 "applying styles for tag: " SSIZE_T_FMT, tag_idx );
556#endif /* RETROHTR_TRACE_LVL */
557
558 assert( !mdata_vector_is_locked( &(parser->tags) ) );
559 mdata_vector_lock( &(parser->styler.styles) );
560 mdata_vector_lock( &(parser->tags) );
561
562 maug_mzero( effect_style, sizeof( struct MCSS_STYLE ) );
563
564 if( 0 >= tag_idx ) {
565 goto cleanup;
566 }
567 p_tag_iter = mdata_vector_get( &(parser->tags), tag_idx, union MHTML_TAG );
568 if( NULL == p_tag_iter ) {
569 goto cleanup;
570 }
571
572 tag_type = p_tag_iter->base.type;
573
574 /* Merge style based on HTML element class. */
575 if( 0 < p_tag_iter->base.classes_sz ) {
576 for( i = 0 ; mdata_vector_ct( &(parser->styler.styles) ) > i ; i++ ) {
577 style = mdata_vector_get(
578 &(parser->styler.styles), i, struct MCSS_STYLE );
579
580 if(
581 NULL != style &&
582 0 == maug_strncmp(
583 p_tag_iter->base.classes,
584 style->class,
585 p_tag_iter->base.classes_sz
586 )
587 ) {
588#if RETROHTR_TRACE_LVL > 0
589 debug_printf( RETROHTR_TRACE_LVL, "found style for tag class: %s",
590 style->class );
591#endif /* RETROHTR_TRACE_LVL */
592
593 retrohtr_merge_styles(
594 effect_style, parent_style, style, tag_type );
595 }
596 }
597 }
598
599 /* Merge style based on HTML element ID. */
600 if( 0 < p_tag_iter->base.id_sz ) {
601 for( i = 0 ; mdata_vector_ct( &(parser->styler.styles) ) > i ; i++ ) {
602 style = mdata_vector_get(
603 &(parser->styler.styles), i, struct MCSS_STYLE );
604
605 if(
606 NULL != style &&
607 0 == maug_strncmp(
608 p_tag_iter->base.id,
609 style->id,
610 p_tag_iter->base.id_sz
611 )
612 ) {
613#if RETROHTR_TRACE_LVL > 0
614 debug_printf( RETROHTR_TRACE_LVL, "found style for tag ID: %s",
615 style->id );
616#endif /* RETROHTR_TRACE_LVL */
617
618 retrohtr_merge_styles(
619 effect_style, parent_style, style, tag_type );
620 }
621 }
622 }
623
624 /* Grab element-specific style last. */
625 tag_style_idx = p_tag_iter->base.style;
626
627cleanup:
628
629 /* TODO: Separate this out of cleanup phase. */
630
631 /* This might be NULL! */
632 style = mdata_vector_get(
633 &(parser->styler.styles), tag_style_idx, struct MCSS_STYLE );
634
635 /* Make sure we have a root style. */
636 retrohtr_merge_styles( effect_style, parent_style, style, tag_type );
637
638 mdata_vector_unlock( &(parser->tags) );
639 mdata_vector_unlock( &(parser->styler.styles) );
640
641 return retval;
642}
643
644/* === */
645
646static MERROR_RETVAL retrohtr_load_font(
647 struct MCSS_PARSER* styler,
648 union RETROGXC_CACHABLE* font,
649 struct MCSS_STYLE* effect_style
650) {
651 MERROR_RETVAL retval = MERROR_OK;
652
653 if( retrogxc_cachable_is_loaded( font ) ) {
654 error_printf( "tried to load font but font already loaded, idx: "
655 SSIZE_T_FMT, font->cache_idx );
656 goto cleanup;
657 }
658
659 mdata_strpool_lock( &(styler->strpool) );
660
661#if RETROHTR_TRACE_LVL > 0
662 debug_printf( RETROHTR_TRACE_LVL,
663 "loading font: %s (" SSIZE_T_FMT ")",
664 mdata_strpool_get( &(styler->strpool), effect_style->FONT_FAMILY ),
665 effect_style->FONT_FAMILY );
666#endif /* RETROHTR_TRACE_LVL */
667
668 if( MDATA_STRPOOL_IDX_ERROR == effect_style->FONT_FAMILY ) {
669 error_printf( "style has no font associated!" );
670 /* TODO: Load fallback font? */
671 retval = MERROR_GUI;
672 goto cleanup;
673 }
674
675 /* Load the font into the cache. */
676#ifdef RETROGXC_PRESENT
677 if(
679 (RETROFLAT_STATE_FLAG_USE_GXC & g_retroflat_state->retroflat_flags)
680 ) {
681 font->cache_idx =
682 retrogxc_load_font(
683 mdata_strpool_get( &(styler->strpool), effect_style->FONT_FAMILY ),
684 0, 33, 93 );
685 } else {
686#endif /* RETROGXC_PRESENT */
687 retval = retrofont_load(
688 mdata_strpool_get( &(styler->strpool), effect_style->FONT_FAMILY ),
689 &(font->handle), 0, 33, 93 );
690#ifdef RETROGXC_PRESENT
691 }
692#endif /* RETROGXC_PRESENT */
693
694cleanup:
695
696 mdata_strpool_unlock( &(styler->strpool) );
697
698 return retval;
699}
700
701/* === */
702
703MERROR_RETVAL retrohtr_tree_gui(
704 struct RETROHTR_RENDER_TREE* tree, struct MCSS_PARSER* styler,
705 struct MCSS_STYLE* effect_style
706) {
707 MERROR_RETVAL retval = MERROR_OK;
708
709 /* Create a GUI handler just for this tree. */
710 if(
711 RETROHTR_TREE_FLAG_GUI_ACTIVE ==
712 (RETROHTR_TREE_FLAG_GUI_ACTIVE & tree->flags)
713 ) {
714#if RETROHTR_TRACE_LVL > 0
715 debug_printf( RETROHTR_TRACE_LVL, "tree GUI already active!" );
716#endif /* RETROHTR_TRACE_LVL */
717 goto cleanup;
718 }
719
720 /* This means all GUI items will use the font from the first node
721 * loaded with a GUI item!
722 */
723 retval = retrogui_init( &(tree->gui) );
724 maug_cleanup_if_not_ok();
725
726 retval = retrohtr_load_font(
727 styler,
728 &(tree->gui.font),
729 effect_style );
730 maug_cleanup_if_not_ok();
731
732 tree->flags |= RETROHTR_TREE_FLAG_GUI_ACTIVE;
733
734#if RETROHTR_TRACE_LVL > 0
735 debug_printf( RETROHTR_TRACE_LVL, "tree GUI initialized!" );
736#endif /* RETROHTR_TRACE_LVL */
737
738cleanup:
739 return retval;
740}
741
742/* === */
743
744MERROR_RETVAL retrohtr_tree_size(
745 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
746 struct MCSS_STYLE* prev_sibling_style,
747 struct MCSS_STYLE* parent_style, ssize_t node_idx, size_t d
748) {
749 struct MCSS_STYLE effect_style;
750 struct MCSS_STYLE child_prev_sibling_style;
751 struct MCSS_STYLE child_style;
752 ssize_t child_iter_idx = -1;
753 ssize_t tag_idx = -1;
754 ssize_t node_iter_idx = -1;
755 size_t this_line_w = 0;
756 size_t this_line_h = 0;
757 MERROR_RETVAL retval = MERROR_OK;
758 union RETROGUI_CTL ctl;
759 union MHTML_TAG* p_tag_iter = NULL;
760 union MHTML_TAG* p_tag_node = NULL;
761 MAUG_MHANDLE font_h = (MAUG_MHANDLE)NULL;
762
763 if( NULL == retrohtr_node( tree, node_idx ) ) {
764 goto cleanup;
765 }
766
767 tag_idx = retrohtr_node( tree, node_idx )->tag;
768
769 retval = retrohtr_apply_styles(
770 parser, tree, parent_style, &effect_style, tag_idx );
771 maug_cleanup_if_not_ok();
772
773 assert( !mdata_vector_is_locked( &(parser->tags) ) );
774 mdata_vector_lock( &(parser->tags) );
775
776 p_tag_iter = mdata_vector_get( &(parser->tags), tag_idx, union MHTML_TAG );
777 assert( NULL != p_tag_iter );
778
779 /* position */
780
781 if( mcss_prop_is_active( effect_style.POSITION ) ) {
782#if RETROHTR_TRACE_LVL > 0
783 debug_printf( RETROHTR_TRACE_LVL,
784 "node " SSIZE_T_FMT ": applying %s positioning",
785 node_idx, gc_mcss_position_names[effect_style.POSITION] );
786#endif /* RETROHTR_TRACE_LVL */
787 /* TODO: MCSS_POS_NOTE: We'd like to get rid of this so all positioning
788 * is done through CSS... unfortunately, we only track the current
789 * and previous effective styles while working that out later, so
790 * we need to pin this to the element directly so we can rule it
791 * out of the box model e.g. when determining x/y coords of its
792 * neighbors.
793 */
794 retrohtr_node( tree, node_idx )->pos = effect_style.POSITION;
795 retrohtr_node( tree, node_idx )->pos_flags = effect_style.POSITION_flags;
796 }
797
798 /* Grab fixed dimensions before content-based calculations of children, so
799 * we know if there are constraints. If these aren't set, then we'll size
800 * based on childrens' sizes after we determine childrens' sizes below.
801 */
802
803 if( mcss_prop_is_active_NOT_flag( effect_style.WIDTH, AUTO ) ) {
804 retrohtr_node( tree, node_idx )->w = effect_style.WIDTH;
805 }
806
807 if( mcss_prop_is_active_NOT_flag( effect_style.HEIGHT, AUTO ) ) {
808 retrohtr_node( tree, node_idx )->h = effect_style.HEIGHT;
809 }
810
811 /* Figure out how big the contents of this node are. */
812
813 /* Font is heritable, so load it for all nodes even if we don't use it. */
814 retval = retrohtr_load_font(
815 &(parser->styler),
816 &(retrohtr_node( tree, node_idx )->font),
817 &effect_style );
818 maug_cleanup_if_not_ok();
819
820 if( 0 <= tag_idx && MHTML_TAG_TYPE_TEXT == p_tag_iter->base.type ) {
821 /* Get text size to use in calculations below. */
822
823#ifdef RETROGXC_PRESENT
824 font_h = retrogxc_get_asset(
825 retrohtr_node( tree, node_idx )->font.cache_idx,
826 RETROGXC_ASSET_TYPE_FONT );
827 maug_cleanup_if_null_alloc( MAUG_MHANDLE, font_h );
828#else
829 font_h = retrohtr_node( tree, node_idx )->font.handle;
830#endif /* RETROGXC_PRESENT */
831
832 mdata_strpool_lock( &(parser->strpool) );
833
834 retrofont_string_sz(
835 NULL,
836 mdata_strpool_get( &(parser->strpool), p_tag_iter->TEXT.content_idx ),
837 p_tag_iter->TEXT.content_sz, font_h,
838 /* Constrain node text size to parent size. */
839 retrohtr_node_parent( tree, node_idx )->w,
840 retrohtr_node_parent( tree, node_idx )->h,
841 &(retrohtr_node( tree, node_idx )->w),
842 &(retrohtr_node( tree, node_idx )->h), 0 );
843
844#if RETROHTR_TRACE_LVL > 0
845 debug_printf( RETROHTR_TRACE_LVL, "TEXT w: " SIZE_T_FMT,
846 retrohtr_node( tree, node_idx )->w );
847#endif /* RETROHTR_TRACE_LVL */
848
849 mdata_strpool_unlock( &(parser->strpool) );
850
851 } else if(
852 0 <= tag_idx &&
853 MHTML_TAG_TYPE_INPUT == p_tag_iter->base.type
854 ) {
855 /* Push the control (for the client renderer to redraw later). */
856
857 retval = retrohtr_tree_gui( tree, &(parser->styler), &effect_style );
858
859 if(
860 /* Use the same ID for the node and control it creates. */
861 MERROR_OK != retrogui_init_ctl(
862 &ctl, RETROGUI_CTL_TYPE_BUTTON, node_idx )
863 ) {
864 error_printf( "could not initialize control!" );
865 goto cleanup;
866 }
867
868 p_tag_node = mdata_vector_get(
869 &(parser->tags),
870 retrohtr_node( tree, node_idx )->tag, union MHTML_TAG );
871
872 ctl.base.x = retrohtr_node( tree, node_idx )->x;
873 ctl.base.y = retrohtr_node( tree, node_idx )->y;
874 ctl.base.w = 0;
875 ctl.base.h = 0;
876 ctl.BUTTON.label = p_tag_node->INPUT.value;
877
878 /* Grab determined size back from control. */
879 retrohtr_node( tree, node_idx )->w = ctl.base.w;
880 retrohtr_node( tree, node_idx )->h = ctl.base.h;
881
882#if RETROHTR_TRACE_LVL > 0
883 debug_printf( RETROHTR_TRACE_LVL, "initialized control for INPUT..." );
884#endif /* RETROHTR_TRACE_LVL */
885
886 retrogui_push_ctl( &(tree->gui), &ctl );
887
888 } else if( 0 <= tag_idx && MHTML_TAG_TYPE_IMG == p_tag_iter->base.type ) {
889
890 if( retroflat_bitmap_ok( &(retrohtr_node( tree, node_idx )->bitmap) ) ) {
891 retrohtr_node( tree, node_idx )->w =
892 retroflat_bitmap_w( &(retrohtr_node( tree, node_idx )->bitmap) );
893 retrohtr_node( tree, node_idx )->h =
894 retroflat_bitmap_h( &(retrohtr_node( tree, node_idx )->bitmap) );
895 }
896
897#if RETROHTR_TRACE_LVL > 0
898 debug_printf( RETROHTR_TRACE_LVL, "TEXT w: " SIZE_T_FMT,
899 retrohtr_node( tree, node_idx )->w );
900#endif /* RETROHTR_TRACE_LVL */
901
902 } else {
903 /* Get sizing of child nodes. */
904
905 maug_mzero( &child_prev_sibling_style, sizeof( struct MCSS_STYLE ) );
906 node_iter_idx = retrohtr_node( tree, node_idx )->first_child;
907 mdata_vector_unlock( &(parser->tags) );
908 while( 0 <= node_iter_idx ) {
909 retrohtr_tree_size(
910 parser, tree, &child_prev_sibling_style, &effect_style,
911 node_iter_idx, d + 1 );
912
913 node_iter_idx = retrohtr_node( tree, node_iter_idx )->next_sibling;
914 }
915 }
916
917 if( mdata_vector_is_locked( &(parser->tags) ) ) {
918 mdata_vector_unlock( &(parser->tags) );
919 }
920
921 /* If our width is still zero, then size based on children. */
922 if( 0 == retrohtr_node( tree, node_idx )->w ) {
923 if(
924 MCSS_DISPLAY_BLOCK == effect_style.DISPLAY &&
925 0 <= retrohtr_node( tree, node_idx )->parent
926 ) {
927 /* Use parent width. */
928 /* TODO: Subtract parent padding! */
929 retrohtr_node( tree, node_idx )->w =
930 retrohtr_node_parent( tree, node_idx )->w;
931 }
932
933 /* Cycle through children and use greatest width. */
934 child_iter_idx = retrohtr_node( tree, node_idx )->first_child;
935 while( 0 <= child_iter_idx ) {
936 assert( !mdata_vector_is_locked( &(parser->tags) ) );
937 retval = retrohtr_apply_styles(
938 parser, tree, &effect_style, &child_style,
939 retrohtr_node( tree, child_iter_idx )->tag );
940 maug_cleanup_if_not_ok();
941
942 /* Skip ABSOLUTE nodes. */
943 if( MCSS_POSITION_ABSOLUTE == child_style.POSITION ) {
944 child_iter_idx =
945 retrohtr_node( tree, child_iter_idx )->next_sibling;
946 continue;
947 }
948
949 if( MCSS_DISPLAY_BLOCK == child_style.DISPLAY ) {
950 /* Reset the line width counter for coming BLOCK node. */
951 this_line_w = 0;
952
953 if(
954 retrohtr_node( tree, child_iter_idx )->w >
955 retrohtr_node( tree, node_idx )->w
956 ) {
957 /* This BLOCK node is the longest yet! */
958 retrohtr_node( tree, node_idx )->w =
959 retrohtr_node( tree, child_iter_idx )->w;
960 }
961 } else {
962 /* Add inline node to this node line's width. */
963 this_line_w += retrohtr_node( tree, child_iter_idx )->w;
964
965 if( this_line_w > retrohtr_node( tree, node_idx )->w ) {
966 /* The line of nodes we've been adding up is the longest yet! */
967 retrohtr_node( tree, node_idx )->w = this_line_w;
968 }
969 }
970 child_iter_idx = retrohtr_node( tree, child_iter_idx )->next_sibling;
971 }
972 }
973
974 /* If our height is still zero, then size based on children. */
975 if( 0 == retrohtr_node( tree, node_idx )->h ) {
976 /* Cycle through children and add heights. */
977 child_iter_idx = retrohtr_node( tree, node_idx )->first_child;
978 while( 0 <= child_iter_idx ) {
979 assert( !mdata_vector_is_locked( &(parser->tags) ) );
981 parser, tree, &effect_style, &child_style,
982 retrohtr_node( tree, child_iter_idx )->tag );
983
984 /* Skip ABSOLUTE nodes. */
985 if( MCSS_POSITION_ABSOLUTE == child_style.POSITION ) {
986 child_iter_idx = retrohtr_node( tree, child_iter_idx )->next_sibling;
987 continue;
988 }
989
990 if( MCSS_DISPLAY_BLOCK == child_style.DISPLAY ) {
991 /* Add the last line to the running height. */
992 retrohtr_node( tree, node_idx )->h += this_line_h;
993
994 /* Start a new running line height with this BLOCK node. */
995 this_line_h = retrohtr_node( tree, child_iter_idx )->h;
996 } else {
997 /* Make sure this line is at least as tall as this INLINE node. */
998 if( this_line_h < retrohtr_node( tree, child_iter_idx )->h ) {
999 this_line_h = retrohtr_node( tree, child_iter_idx )->h;
1000 }
1001 }
1002
1003 child_iter_idx = retrohtr_node( tree, child_iter_idx )->next_sibling;
1004 }
1005
1006 /* Add the last line height the node height. */
1007 retrohtr_node( tree, node_idx )->h += this_line_h;
1008 this_line_h = 0;
1009 }
1010
1011 /* Apply additional modifiers (padding, etc) after children have all been
1012 * calculated.
1013 */
1014
1015 /* Try specific left padding first, then try general padding. */
1016 if( mcss_prop_is_active_NOT_flag( effect_style.PADDING_LEFT, AUTO ) ) {
1017 retrohtr_node( tree, node_idx )->w += effect_style.PADDING_LEFT;
1018 } else if( mcss_prop_is_active_NOT_flag( effect_style.PADDING, AUTO ) ) {
1019 retrohtr_node( tree, node_idx )->w += effect_style.PADDING;
1020 }
1021
1022 /* Try specific right padding first, then try general padding. */
1023 if( mcss_prop_is_active_NOT_flag( effect_style.PADDING_RIGHT, AUTO ) ) {
1024 retrohtr_node( tree, node_idx )->w += effect_style.PADDING_RIGHT;
1025 } else if( mcss_prop_is_active_NOT_flag( effect_style.PADDING, AUTO ) ) {
1026 retrohtr_node( tree, node_idx )->w += effect_style.PADDING;
1027 }
1028
1029 /* Try specific top padding first, then try general padding. */
1030 if( mcss_prop_is_active_NOT_flag( effect_style.PADDING_TOP, AUTO ) ) {
1031 retrohtr_node( tree, node_idx )->h += effect_style.PADDING_TOP;
1032 } else if( mcss_prop_is_active_NOT_flag( effect_style.PADDING, AUTO ) ) {
1033 retrohtr_node( tree, node_idx )->h += effect_style.PADDING;
1034 }
1035
1036 /* Try specific bottom padding first, then try general padding. */
1037 if( mcss_prop_is_active_NOT_flag( effect_style.PADDING_BOTTOM, AUTO ) ) {
1038 retrohtr_node( tree, node_idx )->h += effect_style.PADDING_BOTTOM;
1039 } else if( mcss_prop_is_active_NOT_flag( effect_style.PADDING, AUTO ) ) {
1040 retrohtr_node( tree, node_idx )->h += effect_style.PADDING;
1041 }
1042
1043#if RETROHTR_TRACE_LVL > 0
1044 debug_printf( RETROHTR_TRACE_LVL,
1045 "setting node " SIZE_T_FMT " dirty...", node_idx );
1046#endif /* RETROHTR_TRACE_LVL */
1047 retrohtr_node( tree, node_idx )->flags |= RETROHTR_NODE_FLAG_DIRTY;
1048
1049cleanup:
1050
1051 if( mdata_vector_is_locked( &(parser->tags) ) ) {
1052 mdata_vector_unlock( &(parser->tags) );
1053 }
1054
1055 /* We're done with the prev_sibling_style for this iter, so prepare it for
1056 * the next called by the parent!
1057 */
1058 if( NULL != prev_sibling_style ) {
1059 maug_mcpy(
1060 prev_sibling_style, &effect_style,
1061 sizeof( struct MCSS_STYLE ) );
1062 }
1063
1064 return retval;
1065}
1066
1067/* TODO: See MCSS_POS_NOTE. */
1069#define retrohtr_break_on_active_pos( iter_idx ) \
1070 if( mcss_prop_is_active( retrohtr_node( tree, iter_idx )->pos ) ) { \
1071 break; \
1072 }
1073
1074static ssize_t retrohtr_find_prev_sibling_in_box_model(
1075 struct RETROHTR_RENDER_TREE* tree,
1076 ssize_t node_idx
1077) {
1078 ssize_t sibling_iter_idx = -1;
1079 ssize_t sibling_found_idx = -1;
1080
1081 if( 0 > retrohtr_node( tree, node_idx )->parent ) {
1082 /* Can't determine sibling! */
1083 goto cleanup;
1084 }
1085
1086 sibling_iter_idx = retrohtr_node_parent( tree, node_idx )->first_child;
1087
1088 if( sibling_iter_idx == node_idx ) {
1089 /* No previous siblings! */
1090 goto cleanup;
1091 }
1092
1093 while( 0 <= sibling_iter_idx && node_idx != sibling_iter_idx ) {
1094 if(
1095 /* TODO: See MCSS_POS_NOTE. This is what we were talking about. */
1096 MCSS_POSITION_ABSOLUTE != retrohtr_node( tree, sibling_iter_idx )->pos
1097 ) {
1098 sibling_found_idx = sibling_iter_idx;
1099 }
1100
1101 /* TODO: Reset on <br />? */
1102
1103 sibling_iter_idx = retrohtr_node( tree, sibling_iter_idx )->next_sibling;
1104 }
1105
1106cleanup:
1107 return sibling_found_idx;
1108}
1109
1110/* === */
1111
1112static MERROR_RETVAL retrohtr_mark_edge_child_nodes(
1113 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
1114 ssize_t node_parent_idx
1115) {
1116 ssize_t node_sibling_idx = -1;
1117 MERROR_RETVAL retval = MERROR_OK;
1118 struct MCSS_STYLE effect_style;
1119 size_t col_idx = 0; /* How many nodes right (X)? */
1120 size_t row_idx = 0; /* How many nodes down (Y)? */
1121 union MHTML_TAG* p_tag_iter = NULL;
1122
1123 node_sibling_idx = retrohtr_node( tree, node_parent_idx )->first_child;
1124 while( 0 <= node_sibling_idx ) {
1125 maug_mzero( &effect_style, sizeof( struct MCSS_STYLE ) );
1127 parser, tree, NULL, &effect_style,
1128 retrohtr_node( tree, node_sibling_idx )->tag );
1129
1130 if( MCSS_POSITION_ABSOLUTE == effect_style.POSITION ) {
1131 /* Absolute nodes are never on the edge. */
1132 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_INSIDE;
1133
1134 } else if( MCSS_DISPLAY_INLINE == effect_style.DISPLAY ) {
1135 /* Inline, or something that follows previous column. */
1136 if( 0 == col_idx ) {
1137 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_LEFT;
1138 }
1139 if( 0 == row_idx ) {
1140 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_TOP;
1141 }
1142 if( 0 < row_idx && 0 < col_idx ) {
1143 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_INSIDE;
1144 }
1145 col_idx++;
1146
1147 } else {
1148 /* Block element will be on the next line, so take that into account
1149 * when deciding the edge below.
1150 */
1151 row_idx++;
1152 col_idx = 0;
1153
1154 /* Block, or something else in a new row. */
1155 if( 0 == row_idx ) {
1156 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_TOP;
1157 }
1158
1159 /* Assume block is always on a new line. */
1160 retrohtr_node( tree, node_sibling_idx )->edge |= RETROHTR_EDGE_LEFT;
1161 }
1162
1163 assert( !mdata_vector_is_locked( &(parser->tags) ) );
1164 mdata_vector_lock( &(parser->tags) );
1165
1166 p_tag_iter = mdata_vector_get( &(parser->tags),
1167 retrohtr_node( tree, node_sibling_idx )->tag,
1168 union MHTML_TAG );
1169 assert( NULL != p_tag_iter );
1170
1171 debug_printf( 1, "marking node " SIZE_T_FMT " (%s) edge: %u",
1172 node_sibling_idx,
1173 gc_mhtml_tag_names[p_tag_iter->base.type],
1174 retrohtr_node( tree, node_sibling_idx )->edge );
1175
1176 mdata_vector_unlock( &(parser->tags) );
1177
1178 node_sibling_idx =
1179 retrohtr_node( tree, node_sibling_idx )->next_sibling;
1180 }
1181
1182cleanup:
1183
1184 if( mdata_vector_is_locked( &(parser->tags) ) ) {
1185 mdata_vector_unlock( &(parser->tags) );
1186 }
1187
1188 return retval;
1189}
1190
1191/* === */
1192
1193MERROR_RETVAL retrohtr_tree_pos(
1194 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
1195 struct MCSS_STYLE* prev_sibling_style,
1196 struct MCSS_STYLE* parent_style, ssize_t node_idx, size_t d
1197) {
1198 struct MCSS_STYLE child_prev_sibling_style;
1199 struct MCSS_STYLE effect_style;
1200 ssize_t child_iter_idx = -1;
1201 ssize_t tag_idx = -1;
1202 ssize_t node_iter_idx = -1;
1203 ssize_t prev_sibling_idx = -1;
1204 MERROR_RETVAL retval = MERROR_OK;
1205 union MHTML_TAG* p_tag_iter = NULL;
1206
1207 if( NULL == retrohtr_node( tree, node_idx ) ) {
1208 goto cleanup;
1209 }
1210
1211 tag_idx = retrohtr_node( tree, node_idx )->tag;
1212
1214 parser, tree, parent_style, &effect_style, tag_idx );
1215
1216 prev_sibling_idx =
1217 retrohtr_find_prev_sibling_in_box_model( tree, node_idx );
1218
1219 /* x */
1220
1221 if( MCSS_POSITION_ABSOLUTE == effect_style.POSITION ) {
1222 /* This node is positioned absolutely. (Relatively) simple! */
1223
1224 if( mcss_prop_is_active_NOT_flag( effect_style.LEFT, AUTO ) ) {
1225
1226 child_iter_idx = retrohtr_node( tree, node_idx )->parent;
1227 while( 0 <= retrohtr_node( tree, child_iter_idx )->parent ) {
1228 retrohtr_break_on_active_pos( child_iter_idx );
1229 child_iter_idx = retrohtr_node( tree, child_iter_idx )->parent;
1230 }
1231
1232 /* Set X to highest non-explicit ancestor. */
1233 retrohtr_node( tree, node_idx )->x =
1234 retrohtr_node( tree, child_iter_idx )->x + effect_style.LEFT;
1235 }
1236 if( mcss_prop_is_active_NOT_flag( effect_style.RIGHT, AUTO ) ) {
1237
1238 child_iter_idx = retrohtr_node( tree, node_idx )->parent;
1239 while( 0 <= retrohtr_node( tree, child_iter_idx )->parent ) {
1240 retrohtr_break_on_active_pos( child_iter_idx );
1241 child_iter_idx = retrohtr_node( tree, child_iter_idx )->parent;
1242 }
1243
1244 /* Set X to highest non-explicit ancestor. */
1245 retrohtr_node( tree, node_idx )->x =
1246 retrohtr_node( tree, child_iter_idx )->w -
1247 retrohtr_node( tree, node_idx )->w -
1248 effect_style.RIGHT;
1249 }
1250
1251 } else if(
1252 MCSS_DISPLAY_INLINE == effect_style.DISPLAY &&
1253 MCSS_DISPLAY_INLINE == prev_sibling_style->DISPLAY &&
1254 0 <= prev_sibling_idx
1255 ) {
1256 /* Place to the right of the previous sibling. */
1257 retrohtr_node( tree, node_idx )->x =
1258 retrohtr_node( tree, prev_sibling_idx )->x +
1259 retrohtr_node( tree, prev_sibling_idx )->w;
1260
1261 } else if( 0 <= retrohtr_node( tree, node_idx )->parent ) {
1262 retrohtr_node( tree, node_idx )->x = retrohtr_node_parent( tree, node_idx )->x;
1263 }
1264
1265 /* y */
1266
1267 /* TODO: Add margins of children? */
1268
1269 if( MCSS_POSITION_ABSOLUTE == effect_style.POSITION ) {
1270 /* This node is positioned absolutely. (Relatively) simple! */
1271
1272 if( mcss_prop_is_active_NOT_flag( effect_style.TOP, AUTO ) ) {
1273
1274 child_iter_idx = retrohtr_node( tree, node_idx )->parent;
1275 while( 0 <= retrohtr_node( tree, child_iter_idx )->parent ) {
1276 retrohtr_break_on_active_pos( child_iter_idx );
1277 child_iter_idx = retrohtr_node( tree, child_iter_idx )->parent;
1278 }
1279
1280 /* Set Y to highest non-explicit ancestor. */
1281 retrohtr_node( tree, node_idx )->y =
1282 retrohtr_node( tree, child_iter_idx )->y + effect_style.TOP;
1283 }
1284 if( mcss_prop_is_active_NOT_flag( effect_style.BOTTOM, AUTO ) ) {
1285
1286 child_iter_idx = retrohtr_node( tree, node_idx )->parent;
1287 while( 0 <= retrohtr_node( tree, child_iter_idx )->parent ) {
1288 retrohtr_break_on_active_pos( child_iter_idx );
1289 child_iter_idx = retrohtr_node( tree, child_iter_idx )->parent;
1290 }
1291
1292 /* Set Y to highest non-explicit ancestor. */
1293 retrohtr_node( tree, node_idx )->y =
1294 retrohtr_node( tree, child_iter_idx )->h -
1295 retrohtr_node( tree, node_idx )->h -
1296 effect_style.BOTTOM;
1297 }
1298
1299 } else if(
1300 MCSS_DISPLAY_INLINE == effect_style.DISPLAY &&
1301 MCSS_DISPLAY_INLINE == prev_sibling_style->DISPLAY &&
1302 0 <= prev_sibling_idx
1303 ) {
1304 /* Place to the right of the previous sibling. */
1305 retrohtr_node( tree, node_idx )->y = retrohtr_node( tree, prev_sibling_idx )->y;
1306
1307 } else if( 0 <= prev_sibling_idx ) {
1308 /* Place below the previous block sibling. */
1309
1310 /* TODO: We should probably use the tallest element on the prev sibling's
1311 * line, but that seems hard...
1312 */
1313
1314 retrohtr_node( tree, node_idx )->y =
1315 retrohtr_node( tree, prev_sibling_idx )->y +
1316 retrohtr_node( tree, prev_sibling_idx )->h;
1317
1318 } else if( 0 <= retrohtr_node( tree, node_idx )->parent ) {
1319 /* Position relative to other nodes. */
1320
1321 retrohtr_node( tree, node_idx )->y = retrohtr_node_parent( tree, node_idx )->y;
1322 }
1323
1324 /* margin-left, margin-right */
1325
1326 if(
1327 MCSS_POSITION_ABSOLUTE != retrohtr_node( tree, node_idx )->pos &&
1328 0 <= retrohtr_node( tree, node_idx )->parent &&
1329 mcss_prop_is_active_flag( effect_style.MARGIN_LEFT, AUTO ) &&
1330 mcss_prop_is_active_flag( effect_style.MARGIN_RIGHT, AUTO )
1331 ) {
1332 /* Center */
1333 retrohtr_node( tree, node_idx )->x =
1334 retrohtr_node_parent( tree, node_idx )->x +
1335 (retrohtr_node_parent( tree, node_idx )->w >> 1) -
1336 (retrohtr_node( tree, node_idx )->w >> 1);
1337
1338 } else if(
1339 0 <= retrohtr_node( tree, node_idx )->parent &&
1340 mcss_prop_is_active_flag( effect_style.MARGIN_LEFT, AUTO ) &&
1341 mcss_prop_is_active_NOT_flag( effect_style.MARGIN_RIGHT, AUTO )
1342 ) {
1343 /* Justify right. */
1344 /* TODO: Subtract padding below, as well. */
1345 retrohtr_node( tree, node_idx )->x =
1346 retrohtr_node_parent( tree, node_idx )->w -
1347 retrohtr_node( tree, node_idx )->w;
1348
1349 } else if( mcss_prop_is_active( effect_style.MARGIN_LEFT ) ) {
1350 /* Justify left. */
1351 retrohtr_node( tree, node_idx )->x += effect_style.MARGIN_LEFT;
1352 }
1353
1354 /* padding */
1355
1356 /* TODO: Padding is still broken. Needs more involved understanding of
1357 * where elements are in their container.
1358 */
1359
1360 debug_printf( 1, "(d: " SIZE_T_FMT ") node " SIZE_T_FMT " is on edge: %u",
1361 d, node_idx, retrohtr_node( tree, node_idx )->edge );
1362
1363 assert(
1364 0 == node_idx ||
1365 RETROHTR_EDGE_UNKNOWN != retrohtr_node( tree, node_idx )->edge );
1366
1367 if(
1368 RETROHTR_EDGE_LEFT ==
1369 (RETROHTR_EDGE_LEFT & retrohtr_node( tree, node_idx )->edge)
1370 ) {
1371 /* Try specific left padding first, then try general padding. */
1372 if( mcss_prop_is_active_NOT_flag( parent_style->PADDING_LEFT, AUTO ) ) {
1373 retrohtr_node( tree, node_idx )->x += parent_style->PADDING_LEFT;
1374 } else if( mcss_prop_is_active_NOT_flag( parent_style->PADDING, AUTO ) ) {
1375 retrohtr_node( tree, node_idx )->x += parent_style->PADDING;
1376 }
1377 }
1378
1379 if(
1380 RETROHTR_EDGE_TOP ==
1381 (RETROHTR_EDGE_TOP & retrohtr_node( tree, node_idx )->edge) &&
1382 /* Only apply padding to first node in line. The rest will pick it up. */
1383 RETROHTR_EDGE_LEFT ==
1384 (RETROHTR_EDGE_LEFT & retrohtr_node( tree, node_idx )->edge)
1385 ) {
1386 /* Try specific top padding first, then try general padding. */
1387 if( mcss_prop_is_active_NOT_flag( parent_style->PADDING_TOP, AUTO ) ) {
1388 retrohtr_node( tree, node_idx )->y += parent_style->PADDING_TOP;
1389 } else if( mcss_prop_is_active_NOT_flag( parent_style->PADDING, AUTO ) ) {
1390 retrohtr_node( tree, node_idx )->y += parent_style->PADDING;
1391 }
1392 }
1393
1394 /* color */
1395
1396 if( mcss_prop_is_active( effect_style.COLOR ) ) {
1397 retrohtr_node( tree, node_idx )->fg = effect_style.COLOR;
1398 }
1399
1400 if( mcss_prop_is_active( effect_style.BACKGROUND_COLOR ) ) {
1401 retrohtr_node( tree, node_idx )->bg = effect_style.BACKGROUND_COLOR;
1402 }
1403
1404 /* Figure out child positions. */
1405
1406 retrohtr_mark_edge_child_nodes( parser, tree, node_idx );
1407
1408 maug_mzero( &child_prev_sibling_style, sizeof( struct MCSS_STYLE ) );
1409 node_iter_idx = retrohtr_node( tree, node_idx )->first_child;
1410 while( 0 <= node_iter_idx ) {
1411 /* Mark child nodes on the edge so applying padding can be done. */
1412
1413 /* Figure out child node positioning. */
1414 retrohtr_tree_pos(
1415 parser, tree, &child_prev_sibling_style, &effect_style,
1416 node_iter_idx, d + 1 );
1417
1418 node_iter_idx = retrohtr_node( tree, node_iter_idx )->next_sibling;
1419 }
1420
1421 assert( !mdata_vector_is_locked( &(parser->tags) ) );
1422 mdata_vector_lock( &(parser->tags) );
1423 p_tag_iter = mdata_vector_get( &(parser->tags), tag_idx, union MHTML_TAG );
1424 assert( NULL != p_tag_iter );
1425
1426 if( MHTML_TAG_TYPE_INPUT == p_tag_iter->base.type ) {
1427 /* Feed the position back to the GUI control created during tree_size. */
1428 retval = retrogui_pos_ctl( &(tree->gui), node_idx,
1429 retrohtr_node_screen_x( tree, node_idx ),
1430 retrohtr_node_screen_y( tree, node_idx ),
1431 retrohtr_node( tree, node_idx )->w,
1432 retrohtr_node( tree, node_idx )->h );
1433 maug_cleanup_if_not_ok();
1434 }
1435
1436#if RETROHTR_TRACE_LVL > 0
1437 debug_printf( RETROHTR_TRACE_LVL,
1438 "setting node " SIZE_T_FMT " dirty...", node_idx );
1439#endif /* RETROHTR_TRACE_LVL */
1440 retrohtr_node( tree, node_idx )->flags |= RETROHTR_NODE_FLAG_DIRTY;
1441
1442cleanup:
1443
1444 if( mdata_vector_is_locked( &(parser->tags) ) ) {
1445 mdata_vector_unlock( &(parser->tags) );
1446 }
1447
1448 /* We're done with the prev_sibling_style for this iter, so prepare it for
1449 * the next called by the parent!
1450 */
1451 if( NULL != prev_sibling_style ) {
1452 maug_mcpy(
1453 prev_sibling_style, &effect_style,
1454 sizeof( struct MCSS_STYLE ) );
1455 }
1456
1457 return retval;
1458}
1459
1460/* === */
1461
1462MERROR_RETVAL retrohtr_tree_draw(
1463 struct MHTML_PARSER* parser, struct RETROHTR_RENDER_TREE* tree,
1464 ssize_t node_idx, size_t d
1465) {
1466 union MHTML_TAG* p_tag = NULL;
1467 struct RETROHTR_RENDER_NODE* node = NULL;
1468 MERROR_RETVAL retval = MERROR_OK;
1469 MAUG_MHANDLE font_h = (MAUG_MHANDLE)NULL;
1470
1471 node = retrohtr_node( tree, node_idx );
1472
1473 if( NULL == node ) {
1474 return MERROR_OK;
1475 }
1476
1477 /* TODO: Multi-pass, draw absolute pos afterwards. */
1478
1479 if( 0 > node->tag ) {
1480 goto cleanup;
1481 }
1482
1483 if( RETROHTR_NODE_FLAG_DIRTY != (RETROHTR_NODE_FLAG_DIRTY & node->flags) ) {
1484 goto cleanup;
1485 }
1486
1487 assert( !mdata_vector_is_locked( &(parser->tags) ) );
1488 mdata_vector_lock( &(parser->tags) );
1489
1490 p_tag = mdata_vector_get( &(parser->tags), node->tag, union MHTML_TAG );
1491 if( NULL == p_tag ) {
1492 goto cleanup;
1493 }
1494
1495 /* Perform drawing. */
1496 if( MHTML_TAG_TYPE_TEXT == p_tag->base.type ) {
1497
1498 if(
1499 MDATA_STRPOOL_IDX_ERROR == p_tag->TEXT.content_idx ||
1500 !retrogxc_cachable_is_loaded( &(node->font) )
1501 ) {
1502 goto cleanup;
1503 }
1504
1505#ifdef RETROGXC_PRESENT
1506 font_h = retrogxc_get_asset(
1507 node->font.cache_idx, RETROGXC_ASSET_TYPE_FONT );
1508 maug_cleanup_if_null_alloc( MAUG_MHANDLE, font_h );
1509#else
1510 font_h = node->font.handle;
1511#endif /* RETROGXC_PRESENT */
1512
1513 mdata_strpool_lock( &(parser->strpool) );
1514
1516 NULL, node->fg,
1517 mdata_strpool_get( &(parser->strpool), p_tag->TEXT.content_idx ),
1518 p_tag->TEXT.content_sz, font_h,
1519 retrohtr_node_screen_x( tree, node_idx ),
1520 retrohtr_node_screen_y( tree, node_idx ),
1521 node->w, node->h, 0 );
1522
1523 mdata_strpool_unlock( &(parser->strpool) );
1524
1525 } else if( MHTML_TAG_TYPE_BODY == p_tag->base.type ) {
1526
1527#if RETROHTR_TRACE_LVL > 0
1528 debug_printf(
1529 RETROHTR_TRACE_LVL, "drawing BODY node " SIZE_T_FMT "...", node_idx );
1530#endif /* RETROHTR_TRACE_LVL */
1531
1532 /* Draw body BG. */
1533 if( RETROFLAT_COLOR_NULL != node->bg ) {
1535 NULL, node->bg,
1536 retrohtr_node_screen_x( tree, node_idx ),
1537 retrohtr_node_screen_y( tree, node_idx ),
1538 retrohtr_node( tree, node_idx )->w,
1539 retrohtr_node( tree, node_idx )->h,
1541 }
1542
1543 } else if( MHTML_TAG_TYPE_IMG == p_tag->base.type ) {
1544 /* Blit the image. */
1545
1546 if( !retroflat_bitmap_ok( &(retrohtr_node( tree, node_idx )->bitmap) ) ) {
1547 goto cleanup;
1548 }
1549
1550#if RETROHTR_TRACE_LVL > 0
1551 debug_printf(
1552 RETROHTR_TRACE_LVL, "drawing IMG node " SIZE_T_FMT "...", node_idx );
1553#endif /* RETROHTR_TRACE_LVL */
1554
1556 NULL, &(retrohtr_node( tree, node_idx )->bitmap),
1557 0, 0,
1558 retrohtr_node_screen_x( tree, node_idx ),
1559 retrohtr_node_screen_y( tree, node_idx ),
1560 retroflat_bitmap_w( &(retrohtr_node( tree, node_idx )->bitmap) ),
1561 retroflat_bitmap_h( &(retrohtr_node( tree, node_idx )->bitmap) ),
1563 /* retrohtr_node( tree, node_idx )->w,
1564 retrohtr_node( tree, node_idx )->h */ );
1565
1566 } else if( MHTML_TAG_TYPE_INPUT == p_tag->base.type ) {
1567
1568#if RETROHTR_TRACE_LVL > 0
1569 debug_printf( RETROHTR_TRACE_LVL, "setting tree GUI dirty..." );
1570#endif /* RETROHTR_TRACE_LVL */
1571
1572 tree->gui.flags |= RETROGUI_FLAGS_DIRTY;
1573
1574 } else {
1575 if( RETROFLAT_COLOR_NULL == node->bg ) {
1576 goto cleanup;
1577 }
1578
1579#if RETROHTR_TRACE_LVL > 0
1580 debug_printf(
1581 RETROHTR_TRACE_LVL, "drawing xs node " SIZE_T_FMT "...",
1582 /* gc_mhtml_tag_names[mhtml_tag( parser,
1583 retrohtr_node( tree, node_idx )->tag )->base.type], */
1584 node_idx );
1585#endif /* RETROHTR_TRACE_LVL */
1586
1588 NULL, node->bg,
1589 retrohtr_node_screen_x( tree, node_idx ),
1590 retrohtr_node_screen_y( tree, node_idx ),
1591 node->w, node->h,
1593 }
1594
1595 node->flags &= ~RETROHTR_NODE_FLAG_DIRTY;
1596
1597cleanup:
1598
1599 if( mdata_vector_is_locked( &(parser->tags) ) ) {
1600 mdata_vector_unlock( &(parser->tags) );
1601 }
1602
1603 if( MERROR_OK != retval ) {
1604 error_printf( "failed drawing node: " SIZE_T_FMT, node_idx );
1605 }
1606
1607 /* Keep trying to render children, tho. */
1608
1609 retrohtr_tree_draw( parser, tree, node->first_child, d + 1 );
1610
1611 retrohtr_tree_draw( parser, tree, node->next_sibling, d );
1612
1613 /* If this is the root redraw call, redraw GUI elements. */
1614 if(
1615 0 == d &&
1616 RETROHTR_TREE_FLAG_GUI_ACTIVE ==
1617 (tree->flags & RETROHTR_TREE_FLAG_GUI_ACTIVE)
1618 ) {
1619 retrogui_redraw_ctls( &(tree->gui) );
1620 }
1621
1622 return retval;
1623}
1624
1625/* === */
1626
1627retrogui_idc_t retrohtr_tree_poll_ctls(
1628 struct RETROHTR_RENDER_TREE* tree,
1629 RETROFLAT_IN_KEY* input,
1630 struct RETROFLAT_INPUT* input_evt
1631) {
1632 retrogui_idc_t idc = 0;
1633 MERROR_RETVAL retval = MERROR_OK;
1634
1635 assert( retrohtr_tree_is_locked( tree ) );
1636
1637 if(
1638 RETROHTR_TREE_FLAG_GUI_ACTIVE !=
1639 (RETROHTR_TREE_FLAG_GUI_ACTIVE & tree->flags)
1640 ) {
1641 /* No GUI, so exit without even unlocking. */
1642 return 0;
1643 }
1644
1645 idc = retrogui_poll_ctls( &(tree->gui), input, input_evt );
1646
1647 if( 0 < idc ) {
1648#if RETROHTR_TRACE_LVL > 0
1649 debug_printf(
1650 RETROHTR_TRACE_LVL, "setting node " SIZE_T_FMT " dirty...", idc );
1651#endif /* RETROHTR_TRACE_LVL */
1652 retrohtr_node( tree, idc )->flags |= RETROHTR_NODE_FLAG_DIRTY;
1653 }
1654
1655 if( MERROR_OK != retval ) {
1656 idc = 0;
1657 }
1658
1659 return idc;
1660}
1661
1662/* === */
1663
1664MERROR_RETVAL retrohtr_tree_dump(
1665 struct RETROHTR_RENDER_TREE* tree, struct MHTML_PARSER* parser,
1666 ssize_t node_idx, size_t d
1667) {
1668 size_t i = 0;
1669 char indents[31];
1670 union MHTML_TAG* p_tag_iter = NULL;
1671 MERROR_RETVAL retval = MERROR_OK;
1672
1673 if( 0 > node_idx ) {
1674 return MERROR_OK;
1675 }
1676
1677 assert( !mdata_vector_is_locked( &(parser->tags) ) );
1678 mdata_vector_lock( &(parser->tags) );
1679
1680 p_tag_iter = mdata_vector_get(
1681 &(parser->tags), tree->nodes[node_idx].tag, union MHTML_TAG );
1682 if( NULL == p_tag_iter ) {
1683 goto cleanup;
1684 }
1685
1686 /* Generate the indentation. */
1687 maug_mzero( indents, 30 );
1688 for( i = 0 ; d > i ; i++ ) {
1689 if( maug_strlen( indents ) >= 30 ) {
1690 break;
1691 }
1692 strcat( indents, " " );
1693 }
1694
1695#if RETROHTR_TRACE_LVL > 0
1696 /* Print the debug line. */
1697 debug_printf(
1698 RETROHTR_TRACE_LVL,
1699 "%s" SSIZE_T_FMT " (tag %s): x: " SSIZE_T_FMT ", y: " SSIZE_T_FMT
1700 " (" SSIZE_T_FMT " x " SSIZE_T_FMT ")",
1701 indents, node_idx,
1702 0 <= tree->nodes[node_idx].tag ?
1703 gc_mhtml_tag_names[p_tag_iter->base.type] : "ROOT",
1704 tree->nodes[node_idx].x, tree->nodes[node_idx].y,
1705 tree->nodes[node_idx].w, tree->nodes[node_idx].h
1706 );
1707#endif /* RETROHTR_TRACE_LVL */
1708
1709 mdata_vector_unlock( &(parser->tags) );
1710
1711 retval = retrohtr_tree_dump(
1712 tree, parser, tree->nodes[node_idx].first_child, d + 1 );
1713 maug_cleanup_if_not_ok();
1714
1715 retval = retrohtr_tree_dump(
1716 tree, parser, tree->nodes[node_idx].next_sibling, d );
1717 maug_cleanup_if_not_ok();
1718
1719cleanup:
1720
1721 return retval;
1722}
1723
1724/* === */
1725
1726void retrohtr_tree_free( struct RETROHTR_RENDER_TREE* tree ) {
1727
1728#if RETROHTR_TRACE_LVL > 0
1729 debug_printf( RETROHTR_TRACE_LVL, "freeing render nodes..." );
1730#endif /* RETROHTR_TRACE_LVL */
1731
1732 /* TODO: Free bitmaps from img! */
1733
1734 /* TODO: Free node->font_h! */
1735
1736 /* Free GUI if present. */
1737 if(
1738 RETROHTR_TREE_FLAG_GUI_ACTIVE ==
1739 (tree->flags & RETROHTR_TREE_FLAG_GUI_ACTIVE)
1740 ) {
1741 retrogui_destroy( &(tree->gui) );
1742 }
1743
1744 /* Unlock nodes before trying to free them. */
1745 retrohtr_tree_unlock( tree );
1746
1747 if( (MAUG_MHANDLE)NULL != tree->nodes_h ) {
1748 maug_mfree( tree->nodes_h );
1749 }
1750}
1751
1752/* === */
1753
1754MERROR_RETVAL retrohtr_tree_init( struct RETROHTR_RENDER_TREE* tree ) {
1755 MERROR_RETVAL retval = MERROR_OK;
1756
1757 maug_mzero( tree, sizeof( struct RETROHTR_RENDER_TREE ) );
1758
1759 /* Perform initial node allocation. */
1760 tree->nodes_sz_max = MHTML_PARSER_TAGS_INIT_SZ;
1761#if RETROHTR_TRACE_LVL > 0
1762 debug_printf( RETROHTR_TRACE_LVL,
1763 "allocating " SIZE_T_FMT " nodes...", tree->nodes_sz_max );
1764#endif /* RETROHTR_TRACE_LVL */
1765 maug_malloc_test(
1766 tree->nodes_h,
1767 tree->nodes_sz_max,
1768 sizeof( struct RETROHTR_RENDER_NODE ) );
1769
1770 /* XXX
1771 r.w_max = retroflat_screen_w();
1772 r.h_max = retroflat_screen_h(); */
1773
1774cleanup:
1775
1776 return retval;
1777}
1778
1779#endif /* RETROHTR_C */
1780
1781#endif /* !RETROHTR_H */
1782
uint16_t MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition: merror.h:28
#define RETROFLAT_BITMAP_FLAG_LITERAL_PATH
Flag for retroflat_load_bitmap() to not use assets path.
Definition: retroflt.h:580
MERROR_RETVAL retroflat_load_bitmap(const char *filename, struct RETROFLAT_BITMAP *bmp_out, uint8_t flags)
Load a bitmap into the given ::RETROFLAT_BITMAP structure if it is available. Bitmaps are subject to ...
#define RETROFLAT_INSTANCE_NULL
Pass to retroflat_blit_bitmap() instance arg if this is not a sprite (i.e. if it is a background tile...
Definition: retroflt.h:610
MERROR_RETVAL retroflat_blit_bitmap(struct RETROFLAT_BITMAP *target, struct RETROFLAT_BITMAP *src, retroflat_pxxy_t s_x, retroflat_pxxy_t s_y, retroflat_pxxy_t d_x, retroflat_pxxy_t d_y, retroflat_pxxy_t w, retroflat_pxxy_t h, int16_t instance)
Blit the contents of a ::RETROFLAT_BITMAP onto another ::RETROFLAT_BITMAP.
int8_t RETROFLAT_COLOR
Defines an index in the platform-specific color-table.
Definition: retroflt.h:328
#define RETROFLAT_DRAW_FLAG_FILL
Flag for retroflat_rect() or retroflat_ellipse(), indicating drawn shape should be filled.
Definition: retroflt.h:376
void retroflat_rect(struct RETROFLAT_BITMAP *target, const RETROFLAT_COLOR color, retroflat_pxxy_t x, retroflat_pxxy_t y, retroflat_pxxy_t w, retroflat_pxxy_t h, uint8_t flags)
Draw a rectangle onto the target ::RETROFLAT_BITMAP.
int16_t retroflat_pxxy_t
Type used for surface pixel coordinates.
Definition: retroflt.h:925
retrogui_idc_t retrogui_poll_ctls(struct RETROGUI *gui, RETROFLAT_IN_KEY *p_input, struct RETROFLAT_INPUT *input_evt)
Poll for the last clicked control and maintain listboxes and menus.
MERROR_RETVAL retrogui_destroy(struct RETROGUI *gui)
Free memory held by a RETROGUI controller internally and clean up any subordinate controls.
MERROR_RETVAL retrogui_init(struct RETROGUI *gui)
Prepare a RETROGUI controller for use.
int16_t retrogui_idc_t
Unique identifying constant number for controls.
Definition: retrogui.h:330
MAUG_MHANDLE retrogxc_get_asset(size_t asset_idx, retrogxc_asset_type_t asset_type)
Retrive an asset for which we have a prior cached index.
#define mdata_strpool_get(sp, idx)
Get a string by the index of its first character in the strpool.
Definition: mdata.h:334
MERROR_RETVAL retrofont_load(const char *font_name, MAUG_MHANDLE *p_font_h, uint8_t glyph_h, uint16_t first_glyph, uint16_t glyphs_count)
Load a font for drawing.
void retrofont_string(retroflat_blit_t *target, RETROFLAT_COLOR color, const char *str, size_t str_sz, MAUG_MHANDLE font_h, retroflat_pxxy_t x, retroflat_pxxy_t y, retroflat_pxxy_t max_w, retroflat_pxxy_t max_h, uint8_t flags)
Draw a string with the given font.
size_t nodes_sz_max
Current alloc'd number of nodes in RETROHTR_RENDER_NODE::nodes_h.
Definition: retrohtr.h:63
ssize_t parent
Index of container's render node in RETROHTR_RENDER_TREE.
Definition: retrohtr.h:47
ssize_t first_child
Index of first child's render node in RETROHTR_RENDER_TREE.
Definition: retrohtr.h:49
MERROR_RETVAL retrohtr_apply_styles(struct MHTML_PARSER *parser, struct RETROHTR_RENDER_TREE *tree, struct MCSS_STYLE *parent_style, struct MCSS_STYLE *effect_style, ssize_t tag_idx)
Create a style node that is a composite of a parent style and the styles applicable to the classes/ID...
ssize_t next_sibling
Index of next sibling's render node in RETROHTR_RENDER_TREE.
Definition: retrohtr.h:51
size_t nodes_sz
Current active number of nodes in RETROHTR_RENDER_NODE::nodes_h.
Definition: retrohtr.h:61
struct RETROHTR_RENDER_NODE * nodes
Locked pointer to nodes when locked with retrohtr_tree_lock().
Definition: retrohtr.h:59
#define mdata_vector_lock(v)
Lock the vector. This should be done when items from the vector are actively being referenced,...
Definition: mdata.h:372
#define mdata_vector_unlock(v)
Unlock the vector so items may be added and removed.
Definition: mdata.h:405
#define mdata_vector_ct(v)
Number of items of MDATA_VECTOR::item_sz bytes actively stored in this vector.
Definition: mdata.h:448
Definition: mhtml.h:150
Struct passed to retroflat_poll_input() to hold return data.
Definition: retroflt.h:865
uint8_t retroflat_flags
maug_retroflt_flags indicating current system status.
Definition: retroflt.h:1140
#define RETROFLAT_STATE_FLAG_USE_GXC
Assume all ::RETROGXC_CACHABLE are cache indexes and not handles.
Definition: retroflt.h:432
Definition: retrogui.h:468
#define RETROGUI_FLAGS_DIRTY
RETROGUI::flags indicating controls should be redrawn.
Definition: retrogui.h:263
union RETROGXC_CACHABLE font
Font used to draw any attached RETROGUI_CTL.
Definition: retrogui.h:489
Definition: retrohtr.h:28
Definition: retrohtr.h:55
Definition: mhtml.h:145
Definition: retrogui.h:450