ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
reflow_layout.c File Reference

Greedy line-break + page-break engine for reflow. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_attributes.h"
#include "ra8_err.h"
#include "reflow.h"
#include "reflow_internal.h"
#include "reflow_layout_internal.h"
#include "stb_truetype.h"
Include dependency graph for reflow_layout.c:

Go to the source code of this file.

Functions

bool priv_reflow_internal_is_indent_tag (uint8_t tag)
 Return true iff tag is a block-level indent tag.
bool priv_reflow_internal_right_overflow_break (int32_t cursor_x, int32_t advance, int32_t right_limit, uint8_t line_has_content)
 AND helper for the right-margin overflow break decision.
bool priv_reflow_internal_xhtml_invalid (const void *xhtml_buf, size_t xhtml_len)
 OR helper for the cached-XHTML invalid decision.
bool priv_reflow_internal_final_page_needed (uint32_t page_count, uint32_t token_count)
 AND helper for the synthesise-final-page decision.
void priv_reflow_layout_byte_zero (uint8_t *dst, size_t n)
 Implementation of priv_reflow_layout_byte_zero() – bounded byte-walk.
ra8_err_t priv_reflow_layout_init_font (const reflow_t *engine, stbtt_fontinfo *out_font)
 Implementation of priv_reflow_layout_init_font() – parse the TTF blob.
uint16_t priv_reflow_layout_line_height (uint16_t font_px)
 Implementation of priv_reflow_layout_line_height() – scaled integer ratio.
static uint16_t internal_block_font_px (uint16_t body_px, reflow_html_tag_t tag)
 Pick the font size for a given block tag.
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.
static void internal_justify_glyphs (reflow_t *engine, uint32_t lo, uint32_t hi, int32_t slack)
 Spread slack across the inter-word gaps of glyphs [lo, hi).
static void internal_finish_line (reflow_t *engine, priv_cursor_t *cur, bool allow_justify)
 Apply the active block alignment to the just-completed line.
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.
static ra8_err_t internal_emit_char (reflow_t *engine, priv_cursor_t *cur, const stbtt_fontinfo *font, int32_t cp, uint32_t color, uint8_t link_id)
 Append one ASCII code point at the current cursor, wrapping if it would overflow the right margin.
static ra8_err_t internal_layout_text (reflow_t *engine, priv_cursor_t *cur, const stbtt_fontinfo *font, const reflow_token_t *tok)
 Lay out one text token: walk byte-by-byte, breaking at whitespace, and emit each character through internal_emit_char.
static bool internal_open_block (reflow_t *engine, priv_cursor_t *cur, const reflow_token_t *tok)
 Apply a block_start token: flush current line, set heading font size, set indent.
static bool internal_close_block (reflow_t *engine, priv_cursor_t *cur, const reflow_token_t *tok)
 Apply a block_end token: flush line + add paragraph gap.
static bool internal_apply_rule (reflow_t *engine, priv_cursor_t *cur)
 Apply a <hr> rule token: flush the line and bump the cursor.
static void internal_emit_link_rect (reflow_t *engine, const stbtt_fontinfo *font, uint32_t lo, uint32_t hi, uint8_t link, uint32_t page)
 Record one tappable link rect spanning glyphs [lo, hi).
void priv_reflow_layout_build_link_rects (reflow_t *engine, const stbtt_fontinfo *font)
 Implementation of priv_reflow_layout_build_link_rects() – per-page link runs.
ra8_err_t priv_reflow_layout_apply_token (reflow_t *engine, priv_cursor_t *cur, const stbtt_fontinfo *font, const reflow_token_t *tok)
 Implementation of priv_reflow_layout_apply_token() – per-token switch.

Detailed Description

Greedy line-break + page-break engine for reflow.

Consumes the token stream produced by reflow_parse_xhtml() and lays it out as a flat list of positioned glyphs grouped into pages. The algorithm is a textbook greedy break-on-overflow:

  1. Walk tokens in order.
  2. For a text token, split the run into words ([A-Z]+ runs separated by spaces). Measure each word with stb_truetype's advance widths.
  3. If the cursor would cross the right margin, finalise the line.
  4. If the cursor would cross the bottom margin, finalise the page.

Block-level tokens (<p>, <h1> ..) flush the current line, add a paragraph gap, and (for headings) bump the active font size.

No floating-point allocations and no recursion – the recursion already happened during the parse pass; layout is a flat loop.

[Ring 4 / Reflow] {World: NS}

Since
0.1.0

Definition in file reflow_layout.c.

Function Documentation

◆ internal_apply_rule()

bool internal_apply_rule ( reflow_t * engine,
priv_cursor_t * cur )
static

Apply a <hr> rule token: flush the line and bump the cursor.

See implementation.

Parameters
[in]engineSee implementation.
[in]curSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 666 of file reflow_layout.c.

References k_priv_hr_thickness_px, priv_cursor_t::line_has_content, priv_cursor_t::line_top, priv_reflow_layout_newline(), and priv_cursor_t::y.

Referenced by priv_reflow_layout_apply_token().

◆ internal_block_font_px()

uint16_t internal_block_font_px ( uint16_t body_px,
reflow_html_tag_t tag )
static

Pick the font size for a given block tag.

Returns
Pixel size for headings, or the body size otherwise.

See implementation.

Parameters
[in]body_pxSee implementation.
[in]tagSee implementation.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 195 of file reflow_layout.c.

References k_reflow_h1_scale_pct, k_reflow_h2_scale_pct, k_reflow_h3_scale_pct, k_reflow_h4_scale_pct, k_reflow_h5_scale_pct, k_reflow_h6_scale_pct, k_reflow_pct_full, k_reflow_tag_h1, k_reflow_tag_h2, k_reflow_tag_h3, k_reflow_tag_h4, k_reflow_tag_h5, and k_reflow_tag_h6.

Referenced by internal_open_block().

◆ internal_close_block()

bool internal_close_block ( reflow_t * engine,
priv_cursor_t * cur,
const reflow_token_t * tok )
static

Apply a block_end token: flush line + add paragraph gap.

See implementation.

Parameters
[in]engineSee implementation.
[in]curSee implementation.
[in]tokSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 624 of file reflow_layout.c.

References priv_cursor_t::active_font_px, reflow_t::font_px, priv_cursor_t::indent_px, k_reflow_margin_px, k_reflow_paragraph_gap_px, priv_cursor_t::line_has_content, priv_cursor_t::line_height_px, priv_cursor_t::line_top, priv_reflow_internal_is_indent_tag(), priv_reflow_layout_finish_page(), priv_reflow_layout_line_height(), priv_reflow_layout_newline(), reflow_token_t::tag, reflow_t::viewport_h, priv_cursor_t::x, and priv_cursor_t::y.

Referenced by priv_reflow_layout_apply_token().

◆ internal_emit_char()

ra8_err_t internal_emit_char ( reflow_t * engine,
priv_cursor_t * cur,
const stbtt_fontinfo * font,
int32_t cp,
uint32_t color,
uint8_t link_id )
static

Append one ASCII code point at the current cursor, wrapping if it would overflow the right margin.

Measures the advance width of cp via priv_reflow_layout_glyph_advance, clamps it to at least k_priv_min_word_w_px to prevent zero-width stalls, and checks the right-overflow predicate (priv_reflow_internal_right_overflow_break). If a line break is needed and the line already has content, priv_reflow_layout_newline is called before the glyph is pushed. The glyph is then appended via priv_reflow_layout_push_glyph and cur->x is advanced by the clamped advance. cur->line_has_content is set to 1 after the first glyph lands.

Parameters
[in,out]engineEngine whose glyph pool grows.
[in,out]curLayout cursor; x and line state are updated.
[in]fontFont metrics for advance measurement.
[in]cpUnicode code point to emit (ASCII range in practice).
[in]colorPacked ARGB glyph colour.
[in]link_id1-based link identifier; 0 means not a link.
Returns
ra8_err_t error code.
Return values
k_ra8_okGlyph emitted successfully.
k_ra8_err_no_memPage pool or glyph pool overflowed.
Precondition
engine != nullptr, cur != nullptr, font != nullptr.
cur->active_font_px > 0.
Postcondition
On k_ra8_ok, engine->glyph_count has increased by one.
On k_ra8_ok, cur->line_has_content == 1.
Note
Not thread-safe; caller must serialize access to engine.
Since
0.1.0

Definition at line 442 of file reflow_layout.c.

References priv_cursor_t::active_font_px, priv_cursor_t::active_style, k_priv_min_word_w_px, k_ra8_err_no_mem, k_ra8_ok, k_reflow_margin_px, priv_cursor_t::line_has_content, priv_reflow_internal_right_overflow_break(), priv_reflow_layout_glyph_advance(), priv_reflow_layout_newline(), priv_reflow_layout_push_glyph(), reflow_t::viewport_w, priv_cursor_t::x, and priv_cursor_t::y.

Referenced by internal_layout_text().

◆ internal_emit_link_rect()

void internal_emit_link_rect ( reflow_t * engine,
const stbtt_fontinfo * font,
uint32_t lo,
uint32_t hi,
uint8_t link,
uint32_t page )
static

Record one tappable link rect spanning glyphs [lo, hi).

The glyphs are a same-link, same-baseline run on one page. The rect spans from the first glyph's left edge to the last glyph's right edge (measured by priv_reflow_layout_glyph_advance), with a generous vertical band (approximately 1.5 em centered on the baseline) for forgiving tap targets. The target field is stored 0-based (link - 1). If the link-rect pool is already full the function returns immediately without modifying state.

Parameters
[in,out]engineEngine whose link-rect pool grows by one entry.
[in]fontFont metrics for last-glyph advance measurement.
[in]loFirst glyph index in engine->glyphs[] (inclusive).
[in]hiOne past the last glyph index (exclusive).
[in]link1-based link identifier; stored as link - 1.
[in]pagePage index the rect belongs to.
Returns
Nothing.
Precondition
hi > lo and both indices are within engine->glyphs[].
link > 0.
Postcondition
One link rect appended and engine->link_rect_count incremented, or pool full and no mutation occurred.
rect->target == link - 1 when a rect is appended.
Note
Not thread-safe; caller must serialize access to engine.
Since
0.1.0

Definition at line 707 of file reflow_layout.c.

References reflow_glyph_t::cp, reflow_glyph_t::font_px, reflow_t::glyphs, reflow_link_rect_t::h, k_reflow_max_link_rects, reflow_t::link_rect_count, reflow_t::link_rects, reflow_link_rect_t::page_index, priv_reflow_layout_glyph_advance(), reflow_link_rect_t::target, reflow_link_rect_t::w, reflow_glyph_t::x, reflow_link_rect_t::x, reflow_glyph_t::y, and reflow_link_rect_t::y.

Referenced by priv_reflow_layout_build_link_rects().

◆ internal_finish_line()

void internal_finish_line ( reflow_t * engine,
priv_cursor_t * cur,
bool allow_justify )
static

Apply the active block alignment to the just-completed line.

Left alignment is a no-op (the default). Centre and right shift every glyph in the range [cur->line_first_glyph, engine->glyph_count) so the content edge meets the centre or right margin. Justify distributes the slack across inter-word gaps via internal_justify_glyphs – but only when allow_justify is true (wrapped lines); the last line of a paragraph keeps its left alignment. A trailing space at the break point is excluded from the content extent before computing the slack so justification does not over-expand.

Parameters
[in,out]engineEngine whose laid-out glyphs are aligned.
[in]curCursor (line range + alignment + pen x).
[in]allow_justifyTrue on a wrapped line, false on a paragraph end.
Returns
Nothing.
Precondition
cur->line_first_glyph <= engine->glyph_count.
cur->align is a valid reflow_align_t value.
Postcondition
Glyph x positions in the line range are adjusted per the alignment.
For justify mode with no space glyphs, positions are left unchanged.
Note
Not thread-safe; caller must serialize access to engine.
Since
0.1.0

Definition at line 358 of file reflow_layout.c.

References priv_cursor_t::align, reflow_glyph_t::cp, reflow_t::glyph_count, reflow_t::glyphs, internal_justify_glyphs(), k_reflow_align_center, k_reflow_align_justify, k_reflow_align_left, k_reflow_margin_px, priv_cursor_t::line_first_glyph, reflow_t::viewport_w, priv_cursor_t::x, and reflow_glyph_t::x.

Referenced by priv_reflow_layout_newline().

◆ internal_justify_glyphs()

void internal_justify_glyphs ( reflow_t * engine,
uint32_t lo,
uint32_t hi,
int32_t slack )
static

Spread slack across the inter-word gaps of glyphs [lo, hi).

Each space glyph absorbs an equal share of the slack (with the remainder spread one pixel at a time across the leftmost gaps); every glyph shifts right by the accumulated widening to its left, so the run's right edge lands at the margin with an even gap distribution. If the run contains no space glyphs the function returns early without modifying anything.

Parameters
[in,out]engineEngine whose glyph x positions are adjusted.
[in]loFirst glyph index (inclusive).
[in]hiOne past the last glyph index.
[in]slackTotal pixels to distribute (> 0).
Returns
Nothing.
Precondition
hi > lo; the run contains at least one space to justify against.
slack > 0.
Postcondition
Glyph x positions in [lo, hi) are widened by up to slack total.
Glyphs with no space neighbour are shifted right by the cumulative delta.
Note
Not thread-safe; caller must serialize access to engine.
Since
0.1.0

Definition at line 305 of file reflow_layout.c.

References reflow_glyph_t::cp, reflow_t::glyphs, and reflow_glyph_t::x.

Referenced by internal_finish_line().

◆ internal_layout_text()

ra8_err_t internal_layout_text ( reflow_t * engine,
priv_cursor_t * cur,
const stbtt_fontinfo * font,
const reflow_token_t * tok )
static

Lay out one text token: walk byte-by-byte, breaking at whitespace, and emit each character through internal_emit_char.

See implementation.

Parameters
[in]engineSee implementation.
[in]curSee implementation.
[in]fontSee implementation.
[in]tokSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 496 of file reflow_layout.c.

References priv_cursor_t::active_font_px, reflow_t::body_color, reflow_token_t::color, internal_emit_char(), k_ra8_err_no_mem, k_ra8_ok, k_reflow_color_inherit, k_reflow_margin_px, priv_cursor_t::line_has_content, reflow_t::link_color, priv_reflow_internal_right_overflow_break(), priv_reflow_layout_glyph_advance(), priv_reflow_layout_newline(), reflow_token_t::reserved, reflow_token_t::text_len, reflow_token_t::text_off, reflow_t::text_pool, reflow_t::viewport_w, and priv_cursor_t::x.

Referenced by priv_reflow_layout_apply_token().

◆ internal_open_block()

bool internal_open_block ( reflow_t * engine,
priv_cursor_t * cur,
const reflow_token_t * tok )
static

Apply a block_start token: flush current line, set heading font size, set indent.

See implementation.

Parameters
[in]engineSee implementation.
[in]curSee implementation.
[in]tokSee implementation.
Returns
Result code.
Return values
k_ra8_okOperation succeeded.
Precondition
Module state is consistent.
Module state is consistent.
Postcondition
Caller-visible state matches the documented contract.
Caller-visible state matches the documented contract.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 573 of file reflow_layout.c.

References priv_cursor_t::active_font_px, priv_cursor_t::align, reflow_t::anchor_count, reflow_t::anchors, reflow_token_t::css_font_px, reflow_t::font_px, reflow_anchor_t::id_len, reflow_anchor_t::id_off, priv_cursor_t::indent_px, internal_block_font_px(), k_reflow_indent_px, k_reflow_margin_px, k_reflow_max_anchors, priv_cursor_t::line_has_content, priv_cursor_t::line_height_px, reflow_t::page_count, reflow_anchor_t::page_index, priv_reflow_internal_is_indent_tag(), priv_reflow_layout_line_height(), priv_reflow_layout_newline(), reflow_token_t::reserved, reflow_token_t::tag, reflow_token_t::text_len, reflow_token_t::text_off, priv_cursor_t::x, priv_cursor_t::y, and reflow_anchor_t::y.

Referenced by priv_reflow_layout_apply_token().

◆ priv_reflow_internal_final_page_needed()

bool priv_reflow_internal_final_page_needed ( uint32_t page_count,
uint32_t token_count )

AND helper for the synthesise-final-page decision.

Decide whether the layout pass produced zero pages but the token stream was non-empty (must synthesise a final page).

Promoted from line 750 in reflow_run_layout.

Parameters
[in]page_countNumber of pages flushed during the pass.
[in]token_countTotal parsed-token count.
Returns
Boolean fixup-needed predicate.
Return values
trueCaller must synthesise a single final page.
falseNo fixup required.
Precondition
None.
None.
Postcondition
No state mutated.
Return value depends solely on the two arguments.
Note
Pure function; thread-safe.
Since
0.1.0

Definition at line 135 of file reflow_layout.c.

Referenced by reflow_run_layout().

◆ priv_reflow_internal_is_indent_tag()

bool priv_reflow_internal_is_indent_tag ( uint8_t tag)

Return true iff tag is a block-level indent tag.

Return true iff tag is a tag that introduces / removes a block-level indent (currently <li> and <blockquote>).

Pure helper factored out of internal_open_block (line 479) and internal_close_block (line 513) so the tag == li || tag == blockquote decision can be driven directly by host MC/DC tests via priv_reflow_internal_is_indent_tag.

Parameters
[in]tagToken tag value (raw uint8_t storage of reflow_html_tag_t).
Returns
Boolean indent-tag predicate.
Return values
trueTag is k_reflow_tag_li or k_reflow_tag_blockquote.
falseOtherwise.
Precondition
None.
None.
Postcondition
No state mutated.
Return value depends solely on tag.
Note
Pure function; thread-safe.
Since
0.1.0

Definition at line 67 of file reflow_layout.c.

References k_reflow_tag_blockquote, and k_reflow_tag_li.

Referenced by internal_close_block(), and internal_open_block().

◆ priv_reflow_internal_right_overflow_break()

bool priv_reflow_internal_right_overflow_break ( int32_t cursor_x,
int32_t advance,
int32_t right_limit,
uint8_t line_has_content )

AND helper for the right-margin overflow break decision.

Decide whether a glyph emission would overflow the right margin AND the current line already has content.

Promoted from inline expressions at original lines 404, 468 and 605 so MC/DC tests can drive both arms of the (cur->x + advance > right_limit) && line_has_content decision directly.

Parameters
[in]cursor_xPen x position in pixels.
[in]advanceWidth about to be emitted in pixels.
[in]right_limitRight edge in pixels.
[in]line_has_contentNon-zero iff the line already has glyphs.
Returns
Boolean break-needed predicate.
Return values
trueCaller must call priv_reflow_layout_newline before emitting.
falseEmitting in place is safe.
Precondition
None.
None.
Postcondition
No state mutated.
Return value depends solely on the four arguments.
Note
Pure function; thread-safe.
Since
0.1.0

Definition at line 92 of file reflow_layout.c.

Referenced by internal_apply_image_placeholder(), internal_emit_char(), and internal_layout_text().

◆ priv_reflow_internal_xhtml_invalid()

bool priv_reflow_internal_xhtml_invalid ( const void * xhtml_buf,
size_t xhtml_len )

OR helper for the cached-XHTML invalid decision.

Decide whether the cached XHTML buffer pointer/length pair is unusable for a re-flow (NULL pointer OR zero length).

Promoted from line 953 in reflow_set_font_size.

Parameters
[in]xhtml_bufCached buffer pointer (may be NULL).
[in]xhtml_lenCached buffer length (may be zero).
Returns
Boolean invalid-buffer predicate.
Return values
trueBuffer is unusable.
falseBuffer is usable.
Precondition
None.
None.
Postcondition
No state mutated.
Return value depends solely on the two arguments.
Note
Pure function; thread-safe.
Since
0.1.0

Definition at line 115 of file reflow_layout.c.

Referenced by reflow_bind_font(), and reflow_set_font_size().

◆ priv_reflow_layout_apply_token()

◆ priv_reflow_layout_build_link_rects()

void priv_reflow_layout_build_link_rects ( reflow_t * engine,
const stbtt_fontinfo * font )

Implementation of priv_reflow_layout_build_link_rects() – per-page link runs.

Post-layout pass: group link-tagged glyphs into tappable rects.

Definition at line 732 of file reflow_layout.c.

References reflow_page_t::glyph_first, reflow_t::glyphs, internal_emit_link_rect(), reflow_t::page_count, reflow_t::pages, reflow_glyph_t::reserved, and reflow_glyph_t::y.

Referenced by reflow_run_layout().

◆ priv_reflow_layout_byte_zero()

void priv_reflow_layout_byte_zero ( uint8_t * dst,
size_t n )

Implementation of priv_reflow_layout_byte_zero() – bounded byte-walk.

Bounded zero-fill used in place of memset(0).

Definition at line 141 of file reflow_layout.c.

Referenced by reflow_init().

◆ priv_reflow_layout_finish_page()

◆ priv_reflow_layout_glyph_advance()

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.

Measure a single ASCII code point's advance width in pixels.

Definition at line 225 of file reflow_layout.c.

Referenced by internal_cell_text(), internal_emit_char(), internal_emit_link_rect(), and internal_layout_text().

◆ priv_reflow_layout_init_font()

ra8_err_t priv_reflow_layout_init_font ( const reflow_t * engine,
stbtt_fontinfo * out_font )

Implementation of priv_reflow_layout_init_font() – parse the TTF blob.

Initialise an stbtt_fontinfo from engine->font_data.

Definition at line 158 of file reflow_layout.c.

References reflow_t::font_data, reflow_t::font_len, k_ra8_err_validation_failed, and k_ra8_ok.

Referenced by reflow_run_layout().

◆ priv_reflow_layout_line_height()

uint16_t priv_reflow_layout_line_height ( uint16_t font_px)

Implementation of priv_reflow_layout_line_height() – scaled integer ratio.

Compute the line height in pixels for a given font size.

Definition at line 171 of file reflow_layout.c.

References k_reflow_line_spacing_den, and k_reflow_line_spacing_num.

Referenced by internal_cell_text(), internal_close_block(), internal_layout_row(), internal_layout_tokens(), and internal_open_block().

◆ priv_reflow_layout_newline()

◆ priv_reflow_layout_push_glyph()

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 )