ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
reflow_tokenize.c
Go to the documentation of this file.
1
32
33#include <stddef.h>
34#include <stdint.h>
35#include <string.h>
36
37#include "ra8_attributes.h"
38#include "ra8_err.h"
39#include "reflow.h"
41
42/* ===========================================================================
43 * Mutable tokenizer context (markup-engine private; lexical + attribute
44 * primitives live in the companion TUs and never touch this struct).
45 * ===========================================================================
46 */
47
74
75/* ===========================================================================
76 * Internal flow helpers (context-aware)
77 * ===========================================================================
78 */
79
100static bool internal_suppressed(const tok_ctx_t* ctx)
101{
102 return ctx->suppress_sp != 0U;
103}
104
105/* ===========================================================================
106 * Markup handlers (advance *pi)
107 * ===========================================================================
108 */
109
131static ra8_err_t internal_handle_cdata(tok_ctx_t* ctx, const uint8_t* buf, size_t* pi, size_t len)
132{
133 const size_t inner = *pi + strlen("<![CDATA[");
134 size_t close = inner;
135 while (((close + 3U) <= len) &&
136 !((buf[close] == (uint8_t)']') && (buf[close + 1U] == (uint8_t)']') &&
137 (buf[close + 2U] == (uint8_t)'>'))) {
138 ++close;
139 }
140 if ((ctx->sp > 0U) && !internal_suppressed(ctx)) {
141 uint32_t off = ctx->engine->text_pool_used;
142 bool last_ws = true;
143 for (size_t k = inner; k < close; ++k) {
144 if (!priv_reflow_tok_feed(ctx->engine, (char)buf[k], &last_ws)) {
145 return k_ra8_err_no_mem;
146 }
147 }
148 const uint32_t tlen = ctx->engine->text_pool_used - off;
149 if ((tlen > 0U) && !priv_reflow_tok_emit(ctx->engine,
152 ctx->style,
153 off,
154 tlen)) {
155 return k_ra8_err_no_mem;
156 }
157 if (tlen > 0U) {
158 ctx->engine->tokens[ctx->engine->token_count - 1U].reserved16 = (uint16_t)ctx->face_slot;
159 }
160 }
161 *pi = ((close + 3U) <= len) ? (close + 3U) : len;
162 return k_ra8_ok;
163}
164
185static ra8_err_t internal_handle_end(tok_ctx_t* ctx, const uint8_t* buf, size_t* pi, size_t len)
186{
187 size_t i = *pi + 2U; /* past "</" */
188 while ((i < len) && (buf[i] != (uint8_t)'>')) {
189 ++i;
190 }
191 *pi = (i < len) ? (i + 1U) : len;
192 if (ctx->sp == 0U) {
194 }
195 ctx->sp--;
196 const reflow_html_tag_t tag = (reflow_html_tag_t)ctx->stack_el[ctx->sp].tag;
197 ctx->style = ctx->stack_style[ctx->sp];
198 ctx->active_link = ctx->stack_link[ctx->sp];
199 ctx->color = ctx->stack_color[ctx->sp];
200 ctx->css_font_px = ctx->stack_font[ctx->sp];
201 ctx->family_off = ctx->stack_fam_off[ctx->sp];
202 ctx->family_len = ctx->stack_fam_len[ctx->sp];
203 ctx->face_slot = ctx->stack_face[ctx->sp];
205 !priv_reflow_tok_emit(ctx->engine, k_reflow_tok_block_end, tag, ctx->style, 0U, 0U)) {
206 return k_ra8_err_no_mem;
207 }
208 /* Exited the display:none subtree once we pop back above its depth. */
209 if ((ctx->suppress_sp != 0U) && (ctx->sp < ctx->suppress_sp)) {
210 ctx->suppress_sp = 0U;
211 }
212 return k_ra8_ok;
213}
214
236internal_parse_start(const uint8_t* buf, size_t* pi, size_t len, bool* selfclose)
237{
238 size_t i = *pi + 1U; /* past '<' */
239 const size_t nstart = i;
240 while ((i < len) && (buf[i] != (uint8_t)'>') && (buf[i] != (uint8_t)'/') &&
241 !priv_reflow_tok_is_xml_whitespace((char)buf[i])) {
242 ++i;
243 }
244 const reflow_html_tag_t tag = priv_reflow_tok_classify((const char*)&buf[nstart], i - nstart);
245 *selfclose = false;
246 while ((i < len) && (buf[i] != (uint8_t)'>')) {
247 const char c = (char)buf[i];
248 if ((c == '"') || (c == '\'')) {
249 ++i;
250 while ((i < len) && (buf[i] != (uint8_t)c)) {
251 ++i;
252 }
253 } else if ((c == '/') && ((i + 1U) < len) && (buf[i + 1U] == (uint8_t)'>')) {
254 *selfclose = true;
255 } else {
256 /* Continue scanning the current start tag. */
257 }
258 ++i;
259 }
260 *pi = (i < len) ? (i + 1U) : len;
261 return tag;
262}
263
289 const uint8_t* tag,
290 size_t span,
292 bool block,
293 const ra8_css_style_t* comp,
294 uint16_t css_font_px)
295{
296 if (internal_suppressed(ctx)) {
297 return k_ra8_ok; /* inside a display:none subtree -> emit nothing */
298 }
299 if (block) {
300 uint32_t id_off = 0U;
301 uint32_t id_len = 0U;
302 priv_reflow_tok_capture_attr(ctx->engine, tag, span, "id", sizeof("id") - 1U, &id_off, &id_len);
305 kind,
306 ctx->style,
307 id_off,
308 id_len)) {
309 return k_ra8_err_no_mem;
310 }
311 /* Stash the block's cascaded alignment + CSS font px on the block-start token
312 * (left + 0 = unstyled defaults, so unstyled blocks lay out byte-identically). */
313 const uint8_t align = ((comp->set & (uint8_t)k_ra8_css_set_align) != 0U)
314 ? comp->align
315 : (uint8_t)k_reflow_align_left;
316 reflow_token_t* bst = &ctx->engine->tokens[ctx->engine->token_count - 1U];
317 bst->reserved = align;
318 bst->css_font_px = css_font_px;
319 return k_ra8_ok;
320 }
321 if (kind == k_reflow_tag_a) {
322 uint32_t href_off = 0U;
323 uint32_t href_len = 0U;
325 tag,
326 span,
327 "href",
328 sizeof("href") - 1U,
329 &href_off,
330 &href_len);
331 ctx->active_link = priv_reflow_tok_intern_link(ctx->engine, href_off, href_len);
332 }
333 return k_ra8_ok;
334}
335
358static void internal_handle_link(tok_ctx_t* ctx, const uint8_t* buf, size_t tag_lt, size_t end)
359{
360 if (ctx->engine->css_loader == nullptr) {
361 return;
362 }
363 const uint8_t* tagbuf = &buf[tag_lt];
364 const size_t span = (end > tag_lt) ? (end - tag_lt) : 0U;
365 size_t rel_off = 0U;
366 size_t rel_len = 0U;
367 size_t href_off = 0U;
368 size_t href_len = 0U;
369 if (!priv_reflow_tok_find_attr(tagbuf, span, "rel", sizeof("rel") - 1U, &rel_off, &rel_len) ||
370 !priv_reflow_tok_find_attr(tagbuf, span, "href", sizeof("href") - 1U, &href_off, &href_len) ||
371 !priv_reflow_tok_rel_is_stylesheet(&tagbuf[rel_off], rel_len)) {
372 return;
373 }
374 const uint8_t* css_bytes = nullptr;
375 size_t css_len = 0U;
376 if ((ctx->engine->css_loader(ctx->engine->css_loader_ctx,
377 (const char*)&tagbuf[href_off],
378 (uint32_t)href_len,
379 &css_bytes,
380 &css_len) == k_ra8_ok) &&
381 (css_bytes != nullptr) && (css_len > 0U)) {
382 (void)ra8_css_parse(&ctx->engine->css, (const char*)css_bytes, (uint32_t)css_len);
383 }
384}
385
413 const uint8_t* buf,
414 size_t tag_lt,
415 size_t end,
417 ra8_err_t* out_err)
418{
419 if (tag == k_reflow_tag_link) {
420 internal_handle_link(ctx, buf, tag_lt, end); /* external stylesheet (no token) */
421 *out_err = k_ra8_ok;
422 return true;
423 }
424 const bool is_void =
425 (tag == k_reflow_tag_br) || (tag == k_reflow_tag_hr) || (tag == k_reflow_tag_img);
426 if (is_void && internal_suppressed(ctx)) {
427 *out_err = k_ra8_ok; /* void tag inside a display:none subtree -> drop */
428 return true;
429 }
430 if (tag == k_reflow_tag_br) {
431 *out_err = priv_reflow_tok_emit(ctx->engine, k_reflow_tok_break, tag, ctx->style, 0U, 0U)
432 ? k_ra8_ok
434 return true;
435 }
436 if (tag == k_reflow_tag_hr) {
437 *out_err = priv_reflow_tok_emit(ctx->engine, k_reflow_tok_rule, tag, ctx->style, 0U, 0U)
438 ? k_ra8_ok
440 return true;
441 }
442 if (tag == k_reflow_tag_img) {
443 uint32_t src_off = 0U;
444 uint32_t src_len = 0U;
445 const size_t span = (end > tag_lt) ? (end - tag_lt) : 0U;
447 &buf[tag_lt],
448 span,
449 "src",
450 sizeof("src") - 1U,
451 &src_off,
452 &src_len);
453 *out_err =
454 priv_reflow_tok_emit(ctx->engine, k_reflow_tok_image, tag, ctx->style, src_off, src_len)
455 ? k_ra8_ok
457 return true;
458 }
459 return false;
460}
461
482static uint16_t internal_css_font_px(const tok_ctx_t* ctx, const ra8_css_style_t* comp)
483{
484 if ((comp->set & (uint8_t)k_ra8_css_set_fontsize) == 0U) {
485 return ctx->css_font_px; /* inherit (0 = none -> UA default) */
486 }
487 const uint16_t parent = (ctx->css_font_px != 0U) ? ctx->css_font_px : ctx->engine->font_px;
488 uint32_t px = ((ra8_css_font_unit_t)comp->font_unit == k_ra8_css_font_pct)
489 ? (((uint32_t)parent * (uint32_t)comp->font_val) / (uint32_t)k_reflow_pct_full)
490 : (uint32_t)comp->font_val;
491 if (px < (uint32_t)k_reflow_min_font_px) {
492 px = (uint32_t)k_reflow_min_font_px;
493 }
494 if (px > (uint32_t)k_reflow_max_font_px) {
495 px = (uint32_t)k_reflow_max_font_px;
496 }
497 return (uint16_t)px;
498}
499
529 const uint8_t* tagbuf,
530 size_t span,
532 bool block)
533{
534 const uint8_t base = (uint8_t)(ctx->style | priv_reflow_tok_style_for(tag));
535 const ra8_css_element_t el = ctx->stack_el[ctx->sp - 1U]; /* pushed by the caller */
536 ra8_css_style_t inh = {.set = (uint8_t)k_priv_style_mask, .style = base};
537 if (ctx->color != (uint32_t)k_reflow_color_inherit) {
538 inh.set = (uint8_t)(inh.set | (uint8_t)k_ra8_css_set_color);
539 inh.color = ctx->color;
540 }
541 /* font-family inherits (#109): seed the cascade with the parent's resolved
542 * family so a child without its own `font-family` keeps the ancestor's face. */
543 if (ctx->family_len != 0U) {
544 inh.set = (uint8_t)(inh.set | (uint8_t)k_ra8_css_set_family);
545 inh.family_off = ctx->family_off;
546 inh.family_len = ctx->family_len;
547 }
548 const ra8_css_style_t inl = priv_reflow_tok_css_inline(tagbuf, span);
549 /* Ancestors = the open-element stack below this one (stack_el[0 .. sp-2]). */
550 const uint8_t n_anc = (uint8_t)(ctx->sp - 1U);
551 const ra8_css_style_t comp =
552 ra8_css_cascade_ctx(&ctx->engine->css, &el, inh, inl, ctx->stack_el, n_anc);
553 const uint16_t fpx = internal_css_font_px(ctx, &comp);
554 /* display:none (#140): begin suppressing this element + its subtree at the
555 * current depth; internal_open_attrs and the emit sites then drop every token
556 * until the matching close pops back above this depth. */
557 const bool hidden = ((comp.set & (uint8_t)k_ra8_css_set_display) != 0U) && (comp.display != 0U);
558 if (hidden && (ctx->suppress_sp == 0U)) {
559 ctx->suppress_sp = ctx->sp;
560 }
561 const ra8_err_t aerr = internal_open_attrs(ctx, tagbuf, span, tag, block, &comp, fpx);
562 if (aerr != k_ra8_ok) {
563 return aerr;
564 }
565 ctx->style = (uint8_t)(comp.style & (uint8_t)k_priv_style_mask);
566 ctx->color = ((comp.set & (uint8_t)k_ra8_css_set_color) != 0U) ? comp.color
567 : (uint32_t)k_reflow_color_inherit;
568 ctx->css_font_px = fpx;
569 /* Resolve the embedded face for this element from its cascaded family +
570 * emphasis (#109). Children inherit the family slice; text runs stamp the
571 * resolved slot. Both are 0 / unchanged for content without `@font-face`. */
572 if ((comp.set & (uint8_t)k_ra8_css_set_family) != 0U) {
573 ctx->family_off = comp.family_off;
574 ctx->family_len = comp.family_len;
575 }
577 return k_ra8_ok;
578}
579
604static ra8_err_t internal_handle_start(tok_ctx_t* ctx, const uint8_t* buf, size_t* pi, size_t len)
605{
606 const size_t tag_lt = *pi; /* index of '<' before parse */
607 bool selfclose = false;
608 const reflow_html_tag_t tag = internal_parse_start(buf, pi, len, &selfclose);
609 ctx->saw_element = true;
610
611 ra8_err_t verr = k_ra8_ok;
612 if (internal_handle_void(ctx, buf, tag_lt, *pi, tag, &verr)) {
613 return verr;
614 }
615
616 const bool block = priv_reflow_tok_is_block(tag);
617 if (selfclose) {
618 if (block && !internal_suppressed(ctx)) {
619 if (!priv_reflow_tok_emit(ctx->engine, k_reflow_tok_block_start, tag, ctx->style, 0U, 0U)) {
620 return k_ra8_err_no_mem;
621 }
622 if (!priv_reflow_tok_emit(ctx->engine, k_reflow_tok_block_end, tag, ctx->style, 0U, 0U)) {
623 return k_ra8_err_no_mem;
624 }
625 }
626 return k_ra8_ok;
627 }
628
629 if (ctx->sp >= (uint32_t)k_priv_max_depth) {
630 return k_ra8_err_no_mem;
631 }
632 const size_t span = (*pi > tag_lt) ? (*pi - tag_lt) : 0U;
633 /* Record the element's full identity (tag + id + class, aliasing the chapter
634 * buffer) so the cascade reads it back and descendant selectors can match it
635 * as an ancestor of a later element. */
636 ctx->stack_el[ctx->sp] = priv_reflow_tok_css_element(tag, &buf[tag_lt], span);
637 ctx->stack_style[ctx->sp] = ctx->style;
638 ctx->stack_link[ctx->sp] = ctx->active_link;
639 ctx->stack_color[ctx->sp] = ctx->color;
640 ctx->stack_font[ctx->sp] = ctx->css_font_px;
641 ctx->stack_fam_off[ctx->sp] = ctx->family_off;
642 ctx->stack_fam_len[ctx->sp] = ctx->family_len;
643 ctx->stack_face[ctx->sp] = ctx->face_slot;
644 ctx->sp++;
645 return internal_open_styled(ctx, &buf[tag_lt], span, tag, block);
646}
647
669static bool internal_tag_is(const uint8_t* buf, size_t i, size_t len, const char* name)
670{
671 if (!priv_reflow_tok_starts_with(buf, i, len, name)) {
672 return false;
673 }
674 const size_t n = strlen(name);
675 if ((i + n) >= len) {
676 return true;
677 }
678 const char c = (char)buf[i + n];
679 return (c == '>') || (c == '/') || priv_reflow_tok_is_xml_whitespace(c);
680}
681
706 const uint8_t* buf,
707 size_t* pi,
708 size_t len,
709 const char* close_lit,
710 bool is_style)
711{
712 ctx->saw_element = true;
713 const size_t open_end = priv_reflow_tok_skip_past(buf, *pi, len, ">");
714 const size_t close_at = priv_reflow_tok_find_lit(buf, open_end, len, close_lit);
715 if (is_style && (close_at > open_end)) {
716 (void)ra8_css_parse(&ctx->engine->css,
717 (const char*)&buf[open_end],
718 (uint32_t)(close_at - open_end));
719 }
720 *pi = (close_at < len) ? (close_at + strlen(close_lit)) : len;
721}
722
743static ra8_err_t internal_handle_lt(tok_ctx_t* ctx, const uint8_t* buf, size_t* pi, size_t len)
744{
745 if (priv_reflow_tok_starts_with(buf, *pi, len, "<!--")) {
746 *pi = priv_reflow_tok_skip_past(buf, *pi + 4U, len, "-->");
747 return k_ra8_ok;
748 }
749 if (priv_reflow_tok_starts_with(buf, *pi, len, "<![CDATA[")) {
750 return internal_handle_cdata(ctx, buf, pi, len);
751 }
752 if (priv_reflow_tok_starts_with(buf, *pi, len, "<?")) {
753 *pi = priv_reflow_tok_skip_past(buf, *pi + 2U, len, "?>");
754 return k_ra8_ok;
755 }
756 if (priv_reflow_tok_starts_with(buf, *pi, len, "<!")) {
757 *pi = priv_reflow_tok_skip_past(buf, *pi + 2U, len, ">");
758 return k_ra8_ok;
759 }
760 if (internal_tag_is(buf, *pi, len, "<style")) {
761 internal_handle_raw_text(ctx, buf, pi, len, "</style>", true);
762 return k_ra8_ok;
763 }
764 if (internal_tag_is(buf, *pi, len, "<script")) {
765 internal_handle_raw_text(ctx, buf, pi, len, "</script>", false);
766 return k_ra8_ok;
767 }
768 if (((*pi + 1U) < len) && (buf[*pi + 1U] == (uint8_t)'/')) {
769 return internal_handle_end(ctx, buf, pi, len);
770 }
771 return internal_handle_start(ctx, buf, pi, len);
772}
773
795static bool internal_emit_text_run(tok_ctx_t* ctx, const uint8_t* buf, size_t run, size_t end)
796{
797 if ((ctx->sp == 0U) || internal_suppressed(ctx)) {
798 return true; /* outside any element, or inside display:none -> drop */
799 }
800 uint32_t off = 0U;
801 uint32_t tln = 0U;
802 if (!priv_reflow_tok_stash_run(ctx->engine, buf, run, end, &off, &tln)) {
803 return false;
804 }
805 if (tln == 0U) {
806 return true;
807 }
811 ctx->style,
812 off,
813 tln)) {
814 return false;
815 }
816 ctx->engine->tokens[ctx->engine->token_count - 1U].reserved = ctx->active_link;
817 ctx->engine->tokens[ctx->engine->token_count - 1U].color = ctx->color;
818 ctx->engine->tokens[ctx->engine->token_count - 1U].reserved16 = (uint16_t)ctx->face_slot;
819 return true;
820}
821
822/* ===========================================================================
823 * Entry point (called by reflow_parse.c)
824 * ===========================================================================
825 */
826
827ra8_err_t priv_reflow_xml_walk(reflow_t* engine, const uint8_t* xhtml_buf, size_t xhtml_len)
828{
829 if ((engine == nullptr) || (xhtml_buf == nullptr)) {
830 return k_ra8_err_null_ptr;
831 }
832 if (xhtml_len == 0U) {
834 }
835
836 (void)ra8_css_sheet_reset(&engine->css); /* fresh CSS rules per chapter (#111) */
837
838 /* The tokenizer scratch (per-open-element cascade stacks) is ~2 kB, which
839 * would push this frame past the project stack-usage budget. Hold it in
840 * module-static storage instead of on the stack and reset it on entry.
841 * Safe: priv_reflow_xml_walk has a single, non-recursive, single-threaded
842 * caller (priv_reflow_parse), so the shared instance never overlaps. */
843 static tok_ctx_t s_walk_ctx;
844 s_walk_ctx = (tok_ctx_t){};
845 tok_ctx_t* ctx = &s_walk_ctx;
846 ctx->engine = engine;
847 ctx->style = (uint8_t)k_reflow_style_normal;
848 ctx->color = (uint32_t)k_reflow_color_inherit;
849
850 size_t i = 0U;
851 while (i < xhtml_len) {
852 if (xhtml_buf[i] == (uint8_t)'<') {
853 const ra8_err_t err = internal_handle_lt(ctx, xhtml_buf, &i, xhtml_len);
854 if (err != k_ra8_ok) {
855 return err;
856 }
857 continue;
858 }
859 const size_t run = i;
860 while ((i < xhtml_len) && (xhtml_buf[i] != (uint8_t)'<')) {
861 ++i;
862 }
863 if (!internal_emit_text_run(ctx, xhtml_buf, run, i)) {
864 return k_ra8_err_no_mem;
865 }
866 }
867
868 if (!ctx->saw_element) {
870 }
871 if (ctx->sp != 0U) {
873 }
874 return k_ra8_ok;
875}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_err_no_mem
Static buffer exhausted (no dynamic memory on this project).
Definition ra8_err.h:142
@ k_ra8_err_validation_failed
Validation rule failed (caller-supplied invariant not satisfied).
Definition ra8_err.h:459
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_null_ptr
Pointer was NULL where a valid pointer was required.
Definition ra8_err.h:478
@ k_ra8_err_invalid_size
Invalid size parameter (too large, too small, or misaligned).
Definition ra8_err.h:167
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
size_t strlen(const char *s)
Calculate string length.
HTML / CSS reflow + paginate engine for the ra8d2 ereader.
ra8_css_style_t ra8_css_cascade_ctx(const ra8_css_sheet_t *sheet, const ra8_css_element_t *el, ra8_css_style_t inherited, ra8_css_style_t inline_decl, const ra8_css_element_t *ancestors, uint8_t n_anc)
Compute an element's cascaded style with descendant-selector context.
@ k_ra8_css_set_fontsize
font-size was declared.
Definition reflow_css.h:96
@ k_ra8_css_set_align
text-align was declared.
Definition reflow_css.h:94
@ k_ra8_css_set_display
display was declared.
Definition reflow_css.h:97
@ k_ra8_css_set_color
color was declared.
Definition reflow_css.h:95
@ k_ra8_css_set_family
font-family was declared.
Definition reflow_css.h:98
ra8_err_t ra8_css_sheet_reset(ra8_css_sheet_t *sheet)
Reset a stylesheet to empty (no rules, no names, order 0).
ra8_err_t ra8_css_parse(ra8_css_sheet_t *sheet, const char *css, uint32_t len)
Parse one <style> block's CSS text, appending rules to sheet.
ra8_css_font_unit_t
How a declared font-size value is interpreted.
Definition reflow_css.h:108
@ k_ra8_css_font_pct
Value is a percentage of inherited px.
Definition reflow_css.h:110
static ra8_err_t internal_handle_lt(tok_ctx_t *ctx, const uint8_t *buf, size_t *pi, size_t len)
Dispatch the markup construct beginning at buf[*pi] == '<'.
ra8_err_t priv_reflow_xml_walk(reflow_t *engine, const uint8_t *xhtml_buf, size_t xhtml_len)
Tokenize the XHTML buffer and populate engine->tokens[].
static bool internal_suppressed(const tok_ctx_t *ctx)
Test whether the tokenizer is inside a display:none subtree.
static ra8_err_t internal_handle_start(tok_ctx_t *ctx, const uint8_t *buf, size_t *pi, size_t len)
Handle an opening, void, or self-closing start tag.
static ra8_err_t internal_open_styled(tok_ctx_t *ctx, const uint8_t *tagbuf, size_t span, reflow_html_tag_t tag, bool block)
Run the CSS cascade for a just-pushed element and apply the result.
static bool internal_tag_is(const uint8_t *buf, size_t i, size_t len, const char *name)
True iff <name starts at buf[i] and is followed by a tag delimiter.
static ra8_err_t internal_open_attrs(tok_ctx_t *ctx, const uint8_t *tag, size_t span, reflow_html_tag_t kind, bool block, const ra8_css_style_t *comp, uint16_t css_font_px)
Capture a just-opened tag's id (block) or href (<a>).
static uint16_t internal_css_font_px(const tok_ctx_t *ctx, const ra8_css_style_t *comp)
Resolve an element's effective CSS font px from the cascade + inherited.
static ra8_err_t internal_handle_end(tok_ctx_t *ctx, const uint8_t *buf, size_t *pi, size_t len)
Handle a closing tag, popping the stack and emitting block-end.
static reflow_html_tag_t internal_parse_start(const uint8_t *buf, size_t *pi, size_t len, bool *selfclose)
Parse a start tag's name and self-close flag, advancing past '>'.
static ra8_err_t internal_handle_cdata(tok_ctx_t *ctx, const uint8_t *buf, size_t *pi, size_t len)
Handle a CDATA section, emitting its inner text verbatim.
static void internal_handle_raw_text(tok_ctx_t *ctx, const uint8_t *buf, size_t *pi, size_t len, const char *close_lit, bool is_style)
Consume a raw-text element (<style> / <script>) without emitting.
static void internal_handle_link(tok_ctx_t *ctx, const uint8_t *buf, size_t tag_lt, size_t end)
Resolve a <link rel="stylesheet" href> via the bound CSS loader.
static bool internal_emit_text_run(tok_ctx_t *ctx, const uint8_t *buf, size_t run, size_t end)
Stash + emit a character-data run, tagging it with the active link id.
static bool internal_handle_void(tok_ctx_t *ctx, const uint8_t *buf, size_t tag_lt, size_t end, reflow_html_tag_t tag, ra8_err_t *out_err)
Emit the single token for a void tag (<br> / <hr> / <img>), or resolve a <link> stylesheet.
ra8_css_style_t priv_reflow_tok_css_inline(const uint8_t *tag, size_t span)
Parse a just-opened tag's inline style="..." into a CSS declaration.
ra8_css_element_t priv_reflow_tok_css_element(reflow_html_tag_t kind, const uint8_t *tag, size_t span)
Build a CSS element identity from a just-opened tag's attributes.
bool priv_reflow_tok_find_attr(const uint8_t *tag, size_t tag_len, const char *name, size_t name_len, size_t *out_voff, size_t *out_vlen)
Locate a named attribute's quoted value span within a tag (no copy).
void priv_reflow_tok_capture_attr(reflow_t *engine, const uint8_t *tag, size_t tag_len, const char *name, size_t name_len, uint32_t *out_off, uint32_t *out_len)
Copy a named attribute's quoted value from a tag span into the text pool.
bool priv_reflow_tok_rel_is_stylesheet(const uint8_t *rel, size_t len)
True if a rel attribute value contains the stylesheet token.
uint8_t priv_reflow_tok_resolve_face_slot(const reflow_t *engine, const ra8_css_style_t *comp)
Map a cascaded run's (font-family + emphasis) to an embedded face slot.
uint8_t priv_reflow_tok_intern_link(reflow_t *engine, uint32_t href_off, uint32_t href_len)
Intern an <a> href slice into the link-target table.
Test-access surface for reflow_tokenize.c internal helpers.
bool priv_reflow_tok_starts_with(const uint8_t *buf, size_t i, size_t len, const char *lit)
Test whether buf at i begins with the literal lit.
bool priv_reflow_tok_stash_run(reflow_t *engine, const uint8_t *buf, size_t start, size_t end, uint32_t *out_off, uint32_t *out_len)
Entity-decode and whitespace-collapse a text run into the pool.
size_t priv_reflow_tok_find_lit(const uint8_t *buf, size_t i, size_t len, const char *lit)
Return the index of the first occurrence of lit (its start), or len.
bool priv_reflow_tok_emit(reflow_t *engine, reflow_token_kind_t kind, reflow_html_tag_t tag, uint8_t style, uint32_t off, uint32_t len)
Append one token to the engine's token pool.
bool priv_reflow_tok_is_block(reflow_html_tag_t tag)
Test whether a tag is a block-flow container in the v1 subset.
@ k_priv_max_depth
Max element nesting (matches old shim).
@ k_priv_style_mask
Run-style bits.
reflow_html_tag_t priv_reflow_tok_classify(const char *name, size_t len)
Map a (possibly namespace-prefixed) tag name to its enum.
size_t priv_reflow_tok_skip_past(const uint8_t *buf, size_t i, size_t len, const char *lit)
Return the index just past the first occurrence of lit.
uint8_t priv_reflow_tok_style_for(reflow_html_tag_t tag)
Return the style bit an inline tag contributes to its subtree.
bool priv_reflow_tok_is_xml_whitespace(char c)
True for the ASCII characters XHTML treats as whitespace.
bool priv_reflow_tok_feed(reflow_t *engine, char ch, bool *last_ws)
Write one byte through the whitespace-collapse state machine.
reflow_html_tag_t
Recognised HTML element kinds.
@ k_reflow_tag_hr
Horizontal rule (void).
@ k_reflow_tag_link
<link> (void; stylesheet ref).
@ k_reflow_tag_br
Line break (void).
@ k_reflow_tag_img
Image (placeholder rect).
@ k_reflow_tag_a
Anchor (renders underlined).
@ k_reflow_tag_unknown
Anything not in this enum.
@ k_reflow_color_inherit
No per-run CSS colour.
@ k_reflow_min_font_px
Smallest accepted font size.
@ k_reflow_max_font_px
Largest accepted font size.
@ k_reflow_pct_full
Percentage denominator.
@ k_reflow_align_left
Left (default, ragged right).
@ k_reflow_tok_block_end
Close of a block-flow element.
@ k_reflow_tok_break
Forced line break (<br>).
@ k_reflow_tok_image
Image placeholder (<img>).
@ k_reflow_tok_text
Text run (slice into pool).
@ k_reflow_tok_block_start
Open of a block-flow element.
@ k_reflow_tok_rule
Horizontal rule (<hr>).
@ k_reflow_style_normal
No emphasis.
The identity of one element, used to match selectors.
Definition reflow_css.h:230
uint8_t tag
reflow_html_tag_t of the element.
Definition reflow_css.h:231
A declared or computed style: a presence mask plus property values.
Definition reflow_css.h:122
uint16_t font_val
font-size number: px or % (valid iff set & fontsize).
Definition reflow_css.h:128
uint16_t family_len
font-family name slice length (0 = none).
Definition reflow_css.h:132
uint8_t font_unit
ra8_css_font_unit_t (valid iff set & fontsize).
Definition reflow_css.h:126
uint8_t display
1 = display:none (valid iff set & display).
Definition reflow_css.h:129
uint8_t style
reflow_font_style_t bit VALUES (bold/italic/ul).
Definition reflow_css.h:124
uint8_t set
ra8_css_set_t bitmask: which properties are present.
Definition reflow_css.h:123
uint16_t family_off
font-family name slice offset (valid iff set&family).
Definition reflow_css.h:131
uint32_t color
0xRRGGBB text colour (valid iff set & color).
Definition reflow_css.h:127
uint8_t align
reflow_align_t (valid iff set & align).
Definition reflow_css.h:125
Reflow / pagination engine state.
reflow_css_loader_fn css_loader
<link> CSS loader (NULL = off).
ra8_css_sheet_t css
Parsed <style> rules for the chapter.
uint32_t text_pool_used
Bytes consumed in text_pool.
uint32_t token_count
Tokens used.
uint16_t font_px
Body font size in pixels.
reflow_token_t tokens[k_reflow_max_tokens]
Parsed tokens.
void * css_loader_ctx
Opaque context for css_loader.
One parsed token in the engine's token stream.
uint16_t css_font_px
Block-start CSS font px (0 = none -> UA default).
uint32_t color
0xRRGGBB CSS colour, or k_reflow_color_inherit.
uint16_t reserved16
Padding to 4-byte stride.
uint8_t reserved
Block align / <a> link id.
Mutable tokenizer state threaded through the scan helpers.
uint16_t family_len
Inherited font-family len (0=none).
uint16_t css_font_px
Inherited CSS font px (0=none).
bool saw_element
At least one element seen.
uint16_t stack_fam_off[k_priv_max_depth]
font-family off to restore.
reflow_t * engine
Target engine pools.
uint32_t color
Current CSS colour / inherit.
uint8_t style
Current inline-style bits.
uint16_t stack_font[k_priv_max_depth]
CSS font px to restore on pop.
uint8_t stack_style[k_priv_max_depth]
Style to restore on pop.
uint32_t suppress_sp
display:none subtree depth (0=off).
uint32_t stack_color[k_priv_max_depth]
Colour to restore on pop.
uint8_t stack_link[k_priv_max_depth]
Link id to restore on pop.
uint8_t stack_face[k_priv_max_depth]
Face slot to restore on pop.
uint8_t face_slot
Resolved embedded face (0=default).
uint16_t family_off
Inherited font-family slice off.
uint8_t active_link
1-based link id (0 = none).
uint32_t sp
Stack depth.
uint16_t stack_fam_len[k_priv_max_depth]
font-family len to restore.
ra8_css_element_t stack_el[k_priv_max_depth]
Open-element identities (tag+id+class) for the cascade + descendant match.