ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
reflow_layout_table.c
Go to the documentation of this file.
1
25
26#include <stddef.h>
27#include <stdint.h>
28
29#include "ra8_attributes.h"
30#include "ra8_err.h"
31#include "reflow.h"
32#include "reflow_internal.h"
34#include "stb_truetype.h"
35
36/* ===========================================================================
37 * Table layout (#107): equal-column grid, per-cell text flow, row page-break
38 * ===========================================================================
39 */
40
68static uint32_t internal_match_block_end(const reflow_t* engine, uint32_t start, uint32_t limit)
69{
70 const uint8_t tag = engine->tokens[start].tag;
71 int32_t depth = 1;
72 for (uint32_t i = start + 1U; i < limit; ++i) {
73 const reflow_token_t* tok = &engine->tokens[i];
74 if (tok->tag != tag) {
75 continue;
76 }
77 if (tok->kind == (uint8_t)k_reflow_tok_block_start) {
78 depth++;
79 } else if (tok->kind == (uint8_t)k_reflow_tok_block_end) {
80 depth--;
81 if (depth == 0) {
82 return i;
83 }
84 } else {
85 /* Other token kinds do not change the matching-block depth. */
86 }
87 }
88 return limit;
89}
90
115static bool internal_is_cell_start(const reflow_t* engine, uint32_t i)
116{
117 const reflow_token_t* tok = &engine->tokens[i];
118 return (tok->kind == (uint8_t)k_reflow_tok_block_start) &&
119 ((tok->tag == (uint8_t)k_reflow_tag_td) || (tok->tag == (uint8_t)k_reflow_tag_th));
120}
121
146static bool internal_is_row_start(const reflow_t* engine, uint32_t i)
147{
148 const reflow_token_t* tok = &engine->tokens[i];
149 return (tok->kind == (uint8_t)k_reflow_tok_block_start) && (tok->tag == (uint8_t)k_reflow_tag_tr);
150}
151
178static uint32_t internal_table_columns(const reflow_t* engine, uint32_t start, uint32_t end)
179{
180 uint32_t cols = 0U;
181 uint32_t i = start + 1U;
182 while (i < end) {
183 if (!internal_is_row_start(engine, i)) {
184 i++;
185 continue;
186 }
187 const uint32_t tr_end = internal_match_block_end(engine, i, end);
188 uint32_t cells = 0U;
189 for (uint32_t j = i + 1U; j < tr_end; ++j) {
190 if (internal_is_cell_start(engine, j)) {
191 cells++;
192 }
193 }
194 if (cells > cols) {
195 cols = cells;
196 }
197 i = tr_end + 1U;
198 }
199 return cols;
200}
201
239static void internal_cell_text(reflow_t* engine,
240 const stbtt_fontinfo* font,
241 const reflow_token_t* tok,
242 int32_t cell_x,
243 int32_t cell_right,
244 uint16_t font_px,
245 uint32_t color,
246 int32_t* cx,
247 int32_t* cy,
248 uint32_t* lines)
249{
250 const int32_t line_h = (int32_t)priv_reflow_layout_line_height(font_px);
251 const uint8_t* base = &engine->text_pool[tok->text_off];
252 const uint32_t len = tok->text_len;
253 uint32_t i = 0U;
254 while (i < len) {
255 if (base[i] == (uint8_t)' ') {
256 const int32_t adv = priv_reflow_layout_glyph_advance(font, font_px, (int32_t)' ');
257 /* mcdc-deactivated: priv_reflow_tok_stash_run collapses leading whitespace of every text run (last_ws starts true), so a cell text token never begins with a space, and the pen always advances past cell_x after a word is emitted; a space is therefore only ever seen with *cx > cell_x, making the (*cx > cell_x) false arm unreachable. */
258 if ((*cx > cell_x) && ((*cx + adv) <= cell_right)) {
259 (void)priv_reflow_layout_push_glyph(engine, *cx, *cy, (int32_t)' ', font_px, 0U, color, 0U);
260 *cx += adv;
261 }
262 ++i;
263 continue;
264 }
265 uint32_t word_end = i;
266 int32_t word_w = 0;
267 while ((word_end < len) && (base[word_end] != (uint8_t)' ')) {
268 word_w += priv_reflow_layout_glyph_advance(font, font_px, (int32_t)base[word_end]);
269 ++word_end;
270 }
271 if (((*cx + word_w) > cell_right) && (*cx > cell_x)) {
272 *cx = cell_x;
273 *cy += line_h;
274 (*lines)++;
275 }
276 while (i < word_end) {
277 const int32_t adv = priv_reflow_layout_glyph_advance(font, font_px, (int32_t)base[i]);
278 (void)
279 priv_reflow_layout_push_glyph(engine, *cx, *cy, (int32_t)base[i], font_px, 0U, color, 0U);
280 *cx += adv;
281 ++i;
282 }
283 }
284}
285
318static uint32_t internal_layout_cell(reflow_t* engine,
319 const stbtt_fontinfo* font,
320 int32_t cell_x,
321 int32_t cell_w,
322 int32_t top_y,
323 uint32_t color,
324 uint32_t tstart,
325 uint32_t tend)
326{
327 const int32_t cell_right = cell_x + cell_w;
328 const uint16_t font_px = engine->font_px;
329 int32_t cx = cell_x;
330 int32_t cy = top_y;
331 uint32_t lines = 1U;
332 for (uint32_t t = tstart; t < tend; ++t) {
333 const reflow_token_t* tok = &engine->tokens[t];
334 if (tok->kind == (uint8_t)k_reflow_tok_text) {
335 internal_cell_text(engine, font, tok, cell_x, cell_right, font_px, color, &cx, &cy, &lines);
336 }
337 }
338 return lines;
339}
340
371static uint32_t internal_row_cells(reflow_t* engine,
372 const stbtt_fontinfo* font,
373 uint32_t tr_start,
374 uint32_t tr_end,
375 int32_t col_w,
376 int32_t row_y)
377{
378 const int32_t pad = (int32_t)k_priv_cell_pad_px;
379 const uint32_t color = engine->body_color;
380 uint32_t rows = 1U;
381 uint32_t col = 0U;
382 uint32_t i = tr_start + 1U;
383 while (i < tr_end) {
384 if (!internal_is_cell_start(engine, i)) {
385 i++;
386 continue;
387 }
388 const uint32_t cell_end = internal_match_block_end(engine, i, tr_end);
389 const int32_t cell_x = (int32_t)k_reflow_margin_px + ((int32_t)col * col_w) + pad;
390 const int32_t cell_w = col_w - (2 * pad);
391 const uint32_t lines =
392 internal_layout_cell(engine, font, cell_x, cell_w, row_y, color, i + 1U, cell_end);
393 if (lines > rows) {
394 rows = lines;
395 }
396 col++;
397 i = cell_end + 1U;
398 }
399 return rows;
400}
401
433static uint32_t internal_layout_row(reflow_t* engine,
434 priv_cursor_t* cur,
435 const stbtt_fontinfo* font,
436 uint32_t tr_start,
437 uint32_t table_end,
438 int32_t col_w)
439{
440 const uint32_t tr_end = internal_match_block_end(engine, tr_start, table_end);
441 const int32_t line_h = (int32_t)priv_reflow_layout_line_height(engine->font_px);
442 const int32_t bottom_limit = (int32_t)engine->viewport_h - (int32_t)k_reflow_margin_px;
443
444 const uint32_t glyphs_before = engine->glyph_count;
445 uint32_t row_lines = internal_row_cells(engine, font, tr_start, tr_end, col_w, cur->y);
446 int32_t row_h = (int32_t)row_lines * line_h;
447
448 if (((cur->y + row_h) > bottom_limit) && (cur->y > (int32_t)k_reflow_margin_px)) {
449 engine->glyph_count = glyphs_before; /* roll the row back ... */
451 cur); /* ... flush the page (cur->y -> margin) ... */
452 /* ... re-lay it */
453 row_lines = internal_row_cells(engine, font, tr_start, tr_end, col_w, cur->y);
454 row_h = (int32_t)row_lines * line_h;
455 }
456 cur->y += row_h + (int32_t)k_priv_row_gap_px;
457 return tr_end + 1U;
458}
459
461 priv_cursor_t* cur,
462 const stbtt_fontinfo* font,
463 uint32_t start,
464 uint32_t* out_next)
465{
466 if (cur->line_has_content != 0U) {
467 if (!priv_reflow_layout_newline(engine, cur, false)) {
468 return k_ra8_err_no_mem;
469 }
470 }
471 const uint32_t end = internal_match_block_end(engine, start, engine->token_count);
472 const uint32_t cols = internal_table_columns(engine, start, end);
473 if (cols == 0U) {
474 *out_next = (end < engine->token_count) ? (end + 1U) : engine->token_count;
475 return k_ra8_ok;
476 }
477 const int32_t content_w = (int32_t)engine->viewport_w - (2 * (int32_t)k_reflow_margin_px);
478 const int32_t col_w = content_w / (int32_t)cols;
479
480 uint32_t i = start + 1U;
481 while (i < end) {
482 if (internal_is_row_start(engine, i)) {
483 i = internal_layout_row(engine, cur, font, i, end, col_w);
484 } else {
485 i++;
486 }
487 }
488
489 /* Resume linear flow below the table. */
490 cur->x = (int32_t)k_reflow_margin_px + (int32_t)cur->indent_px;
491 cur->align = (uint8_t)k_reflow_align_left;
492 cur->line_has_content = 0U;
493 cur->y += (int32_t)k_reflow_paragraph_gap_px;
494 cur->line_top = cur->y;
495 cur->line_first_glyph = engine->glyph_count;
496 *out_next = (end < engine->token_count) ? (end + 1U) : engine->token_count;
497 return k_ra8_ok;
498}
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_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
HTML / CSS reflow + paginate engine for the ra8d2 ereader.
Test-access surface for reflow internal helpers (MC/DC).
bool priv_reflow_layout_newline(reflow_t *engine, priv_cursor_t *cur, bool allow_justify)
Implementation of priv_reflow_layout_newline() – align, advance, page-break.
int32_t priv_reflow_layout_glyph_advance(const stbtt_fontinfo *font, uint16_t font_px, int32_t cp)
Implementation of priv_reflow_layout_glyph_advance() – scaled hmetrics.
bool priv_reflow_layout_push_glyph(reflow_t *engine, int32_t x, int32_t y, int32_t cp, uint16_t font_px, uint8_t style, uint32_t color, uint8_t link_id)
Implementation of priv_reflow_layout_push_glyph() – append + bounds check.
bool priv_reflow_layout_finish_page(reflow_t *engine, priv_cursor_t *cur)
Implementation of priv_reflow_layout_finish_page() – flush + reset cursor.
uint16_t priv_reflow_layout_line_height(uint16_t font_px)
Implementation of priv_reflow_layout_line_height() – scaled integer ratio.
Cross-TU shared declarations for the reflow layout engine.
@ k_priv_row_gap_px
Vertical gap between table rows.
@ k_priv_cell_pad_px
Left/right inset inside a table cell.
static uint32_t internal_layout_cell(reflow_t *engine, const stbtt_fontinfo *font, int32_t cell_x, int32_t cell_w, int32_t top_y, uint32_t color, uint32_t tstart, uint32_t tend)
Lay out one cell's text tokens within a fixed column box (left-flow).
static uint32_t internal_match_block_end(const reflow_t *engine, uint32_t start, uint32_t limit)
Find the block-end token matching the block-start at start.
static uint32_t internal_layout_row(reflow_t *engine, priv_cursor_t *cur, const stbtt_fontinfo *font, uint32_t tr_start, uint32_t table_end, int32_t col_w)
Lay out one table row, page-breaking before it if it would overflow.
static void internal_cell_text(reflow_t *engine, const stbtt_fontinfo *font, const reflow_token_t *tok, int32_t cell_x, int32_t cell_right, uint16_t font_px, uint32_t color, int32_t *cx, int32_t *cy, uint32_t *lines)
Flow one text token inside a cell box, wrapping at the column edge.
static uint32_t internal_table_columns(const reflow_t *engine, uint32_t start, uint32_t end)
Column count = the maximum number of cells in any row of the table.
static bool internal_is_cell_start(const reflow_t *engine, uint32_t i)
True iff token i opens a table cell (<td> or <th>).
static bool internal_is_row_start(const reflow_t *engine, uint32_t i)
True iff token i opens a table row (<tr>).
static uint32_t internal_row_cells(reflow_t *engine, const stbtt_fontinfo *font, uint32_t tr_start, uint32_t tr_end, int32_t col_w, int32_t row_y)
Lay out every cell of one row at row_y; return the row's line count.
ra8_err_t priv_reflow_layout_table(reflow_t *engine, priv_cursor_t *cur, const stbtt_fontinfo *font, uint32_t start, uint32_t *out_next)
Lay out a <table> token range as an equal-column grid.
@ k_reflow_tag_th
Table header cell.
@ k_reflow_tag_td
Table cell.
@ k_reflow_tag_tr
Table row.
@ k_reflow_paragraph_gap_px
Vertical gap after a block.
@ k_reflow_margin_px
Page edge inset, pixels.
@ k_reflow_align_left
Left (default, ragged right).
@ k_reflow_tok_block_end
Close of a block-flow element.
@ k_reflow_tok_text
Text run (slice into pool).
@ k_reflow_tok_block_start
Open of a block-flow element.
Mutable state carried through the layout loop.
uint8_t line_has_content
1 once any glyph landed on this line.
int32_t line_top
Pixel row of the current line's top.
int32_t x
Pixel column for next glyph.
uint32_t line_first_glyph
First glyph index of the active line.
int32_t y
Pixel row baseline for next glyph.
uint8_t align
Active block alignment (reflow_align_t).
uint16_t indent_px
Active left indent (li, blockquote).
Reflow / pagination engine state.
uint32_t glyph_count
Glyphs used.
uint8_t text_pool[k_reflow_text_pool_bytes]
Text bytes.
uint32_t token_count
Tokens used.
uint16_t font_px
Body font size in pixels.
uint16_t viewport_w
Viewport width, pixels.
reflow_token_t tokens[k_reflow_max_tokens]
Parsed tokens.
uint16_t viewport_h
Viewport height, pixels.
uint32_t body_color
Body text colour (0xRRGGBB).
One parsed token in the engine's token stream.
uint32_t text_off
Byte offset into the text pool.
uint32_t text_len
Byte length within the text pool.
uint8_t kind
reflow_token_kind_t.
uint8_t tag
reflow_html_tag_t (0 if N/A).