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

Reflow-engine public + internal function prototypes. More...

#include <stddef.h>
#include <stdint.h>
#include "ra8_err.h"
#include "ra8_glyph_atlas.h"
#include "reflow_image.h"
#include "reflow_types.h"
Include dependency graph for reflow_api.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  reflow_glyph_atlas_storage_t
 Caller-owned backing storage for the render-path glyph cache (#164). More...

Functions

ra8_err_t reflow_init (uint16_t viewport_w, uint16_t viewport_h, const uint8_t *font_data, size_t font_len, uint16_t font_px, uint32_t body_color, uint32_t link_color, reflow_t *out_engine)
 Initialise a reflow engine for a given viewport / font.
ra8_err_t reflow_close (reflow_t *engine)
 Release a previously initialized engine.
ra8_err_t reflow_set_image_loader (reflow_t *engine, reflow_image_loader_fn loader, void *ctx, ra8_img_arena_t *arena)
 Bind an <img> byte loader + decode arena to enable image rendering.
ra8_err_t reflow_set_css_loader (reflow_t *engine, reflow_css_loader_fn loader, void *ctx)
 Bind the external-stylesheet loader for <link rel="stylesheet">.
ra8_err_t reflow_set_glyph_atlas (reflow_t *engine, ra8_glyph_atlas_t *atlas, const reflow_glyph_atlas_storage_t *storage)
 Bind a Layer-3 glyph cache to the engine's render path (#164).
ra8_err_t reflow_hit_test_link (const reflow_t *engine, uint32_t page_idx, int32_t x, int32_t y, uint32_t *out_href_off, uint32_t *out_href_len)
 Hit-test a point on a page against the laid-out <a> link rectangles.
ra8_err_t reflow_hit_test_image (const reflow_t *engine, uint32_t page_idx, int32_t x, int32_t y, uint32_t *out_index)
 Hit-test a point on a page against the laid-out <img> boxes (#478).
ra8_err_t reflow_find_anchor (const reflow_t *engine, const char *id, uint32_t id_len, uint32_t *out_page)
 Find the page of a same-chapter id anchor (for #fragment jumps).
ra8_err_t reflow_href_split (const char *href, uint32_t len, reflow_href_kind_t *out_kind, uint32_t *out_path_len, uint32_t *out_frag_off, uint32_t *out_frag_len)
 Split + classify an <a href> into a path part and a #fragment.
ra8_err_t reflow_layout_chapter (reflow_t *engine, const uint8_t *xhtml_buf, size_t xhtml_len, uint32_t *out_total_pages)
 Parse + lay out one chapter of XHTML.
ra8_err_t reflow_render_page (const reflow_t *engine, uint32_t page_idx, void *framebuffer)
 Render one page into the active ra8_gfx framebuffer.
ra8_err_t reflow_render_page_at (const reflow_t *engine, uint32_t page_idx, int32_t origin_x, int32_t origin_y)
 Render one page offset by (origin_x, origin_y) into the bound framebuffer.
ra8_err_t reflow_get_page_count (const reflow_t *engine, uint32_t *out_count)
 Report the laid-out page count.
ra8_err_t reflow_set_font_size (reflow_t *engine, uint16_t new_font_px)
 Change the body font size and re-flow the cached chapter.
ra8_err_t reflow_bind_font (reflow_t *engine, const uint8_t *font_data, size_t font_len)
 Bind an EPUB-embedded typeface as the engine's active face (#109).
ra8_err_t reflow_register_face (reflow_t *engine, uint8_t css_face_idx, const uint8_t *blob, size_t len)
 Register one embedded @font-face typeface for per-run selection (#109).
ra8_err_t reflow_parse_xhtml (reflow_t *engine, const uint8_t *xhtml_buf, size_t xhtml_len)
 Parse the XHTML buffer into the engine's token stream.
ra8_err_t reflow_run_layout (reflow_t *engine)
 Run the line-break + page-break pass over engine->tokens[].

Detailed Description

Reflow-engine public + internal function prototypes.

This sub-header holds the reflow engine's callable surface: the lifecycle entry points (reflow_init / _close), the loader-binding setters, the hit-test / anchor / href helpers, the layout + render passes, and the parse / layout internals exposed to the engine's TUs. It is split out of the umbrella reflow.h so that header stays small; consumers still include reflow.h and never reference this file directly. The data model these functions operate on lives in reflow_types.h.

[Ring 4 / Reflow] {World: NS}

Since
0.1.0

Definition in file reflow_api.h.

Function Documentation

◆ reflow_bind_font()

ra8_err_t reflow_bind_font ( reflow_t * engine,
const uint8_t * font_data,
size_t font_len )
nodiscard

Bind an EPUB-embedded typeface as the engine's active face (#109).

Replaces the face bound at reflow_init() with font_data so subsequent layout + render use the book's own typeface (the common "the EPUB ships one font" case). The blob is validated with stbtt_InitFont first; on any failure the engine keeps its current face unchanged (graceful degradation – never a crash). The bytes are referenced, not copied (zero-heap), so they MUST outlive the engine, exactly like the reflow_init() font. If a chapter is already laid out, the engine re-flows it against the new face (like reflow_set_font_size()); otherwise the next layout picks it up.

Per-run family / bold / italic face selection across multiple embedded faces is intentionally out of scope here and tracked on #109 (blocked on the @font-face / font-family resolution prerequisite, #142).

Parameters
[in,out]engineInitialised engine.
[in]font_dataTTF/OTF blob; must outlive the engine.
[in]font_lenLength of font_data, bytes.
Returns
ra8_err_t Error code.
Return values
k_ra8_okFace bound (and re-flowed if a chapter was laid out).
k_ra8_err_null_ptrengine or font_data is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_sizefont_len < k_reflow_min_font_bytes.
k_ra8_err_not_supportedstbtt_InitFont rejected the blob (face unchanged).
Precondition
engine->in_use == 1.
font_data is non-NULL and outlives the engine.
Postcondition
On success engine->font_data == font_data; on failure the prior face is preserved byte-for-byte.
Note
Not thread-safe; single-threaded init/layout context.
See also
reflow_init(), reflow_set_font_size()
Since
0.1.0

Bind an EPUB-embedded typeface as the engine's active face (#109).

Definition at line 301 of file reflow_layout_driver.c.

References reflow_t::font_data, reflow_t::font_len, reflow_t::in_use, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_not_supported, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_min_font_bytes, priv_reflow_internal_xhtml_invalid(), ra8_stbtt_sfnt_dir_in_bounds(), reflow_layout_chapter(), reflow_t::xhtml_buf, and reflow_t::xhtml_len.

◆ reflow_close()

ra8_err_t reflow_close ( reflow_t * engine)
nodiscard

Release a previously initialized engine.

Parameters
[in,out]engineEngine returned by reflow_init().
Returns
ra8_err_t
Return values
k_ra8_okClosed.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
Precondition
engine non-NULL.
engine->in_use == 1.
Postcondition
engine->in_use == 0.
engine->page_count == 0.
Since
0.1.0

Definition at line 184 of file reflow_layout_driver.c.

References reflow_t::glyph_count, reflow_t::image_box_count, reflow_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, reflow_t::page_count, reflow_t::text_pool_used, reflow_t::token_count, reflow_t::xhtml_buf, and reflow_t::xhtml_len.

Referenced by er_reflow_relayout().

◆ reflow_find_anchor()

ra8_err_t reflow_find_anchor ( const reflow_t * engine,
const char * id,
uint32_t id_len,
uint32_t * out_page )
nodiscard

Find the page of a same-chapter id anchor (for #fragment jumps).

Linear-scans engine->anchors[] for an element whose captured id equals id (exact byte compare). Used to resolve a #frag link to the page holding the target element.

Parameters
[in]engineInitialized engine handle.
[in]idFragment id bytes (no leading '#').
[in]id_lenLength of id, bytes.
[out]out_pageReceives the page index of the anchor.
Returns
ra8_err_t
Return values
k_ra8_okAnchor found; *out_page set.
k_ra8_err_null_ptrA required pointer is NULL.
k_ra8_err_invalid_argid_len is 0.
k_ra8_err_not_foundNo anchor matches id.
Precondition
engine is laid out; id / out_page are valid.
id_len > 0.
Postcondition
On success *out_page < engine page count.
Note
Read-only.
Since
0.1.0

Definition at line 88 of file reflow_link.c.

References reflow_t::anchor_count, reflow_t::anchors, reflow_anchor_t::id_len, reflow_anchor_t::id_off, k_ra8_err_invalid_arg, k_ra8_err_not_found, k_ra8_ok, reflow_anchor_t::page_index, RA8_CHECK_NULL_PTR, s_tag_link, and reflow_t::text_pool.

Referenced by er_nav_fragment(), and main().

◆ reflow_get_page_count()

ra8_err_t reflow_get_page_count ( const reflow_t * engine,
uint32_t * out_count )
nodiscard

Report the laid-out page count.

Parameters
[in]engineLaid-out engine.
[out]out_countPage count (0 if no chapter laid out yet).
Returns
ra8_err_t
Return values
k_ra8_okReported.
k_ra8_err_null_ptrAny pointer is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
Since
0.1.0

Definition at line 267 of file reflow_layout_driver.c.

References reflow_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, and reflow_t::page_count.

Referenced by erb_render_all(), and internal_rc_render_all().

◆ reflow_hit_test_image()

ra8_err_t reflow_hit_test_image ( const reflow_t * engine,
uint32_t page_idx,
int32_t x,
int32_t y,
uint32_t * out_index )
nodiscard

Hit-test a point on a page against the laid-out <img> boxes (#478).

The sibling of reflow_hit_test_link, and the entry point of the reader's tap-to-zoom gesture: a tap that lands on a figure opens that figure full screen, at retained full resolution, rather than the column-scaled thumbnail the page shows. Walks engine->image_boxes[] for page_idx and returns the index of the first box containing (x, y). Coordinates are page-local – the same space reflow_render_page() uses – so subtract the render origin first if the page was drawn at an offset.

The index (rather than a copy of the box) is what a caller needs: it addresses engine->image_boxes[i] for the laid-out rectangle and its src_off / src_len href slice, which is how the tapped figure is resolved to the image a zoom source binds to.

Parameters
[in]engineInitialized engine handle.
[in]page_idxPage to test.
[in]xPage-local x, pixels.
[in]yPage-local y, pixels.
[out]out_indexReceives the index into engine->image_boxes[].
Returns
ra8_err_t
Return values
k_ra8_okAn image box contains the point; *out_index set.
k_ra8_err_null_ptrengine or out_index is NULL.
k_ra8_err_not_foundNo image box on page_idx contains the point.
Precondition
engine is initialized and laid out.
out_index is writable.
Postcondition
On success *out_index < engine->image_box_count.
On failure *out_index is unchanged.
Note
Read-only; safe to call between render passes. Earlier boxes win on overlap, matching reflow_hit_test_link and ra8_ui_hit_test.
Example:
uint32_t idx = 0U;
if (reflow_hit_test_image(engine, page, tx, ty, &idx) == k_ra8_ok) {
er_open_zoom(&engine->image_boxes[idx]);
}
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_t reflow_hit_test_image(const reflow_t *engine, uint32_t page_idx, int32_t x, int32_t y, uint32_t *out_index)
Hit-test a point on a page against the laid-out <img> boxes (#478).
Definition reflow_link.c:63
See also
reflow_hit_test_link
Since
0.1.0

Definition at line 63 of file reflow_link.c.

References reflow_image_box_t::h, reflow_t::image_box_count, reflow_t::image_boxes, k_ra8_err_not_found, k_ra8_ok, reflow_image_box_t::page_index, RA8_CHECK_NULL_PTR, s_tag_link, reflow_image_box_t::w, reflow_image_box_t::x, and reflow_image_box_t::y.

◆ reflow_hit_test_link()

ra8_err_t reflow_hit_test_link ( const reflow_t * engine,
uint32_t page_idx,
int32_t x,
int32_t y,
uint32_t * out_href_off,
uint32_t * out_href_len )
nodiscard

Hit-test a point on a page against the laid-out <a> link rectangles.

Walks engine->link_rects[] for page_idx and returns the href of the first rectangle containing (x, y). Coordinates are page-local (the same space reflow_render_page() uses); subtract the render origin first if the page was drawn at an offset. The href is returned as a slice into the engine text pool – read &engine->...text...[*out_href_off] for *out_href_len bytes via the engine, or pass it straight to reflow_href_split().

Parameters
[in]engineInitialized engine handle.
[in]page_idxPage to test.
[in]xPage-local x, pixels.
[in]yPage-local y, pixels.
[out]out_href_offReceives the href text-pool offset.
[out]out_href_lenReceives the href length, bytes.
Returns
ra8_err_t
Return values
k_ra8_okA link rect contains the point; outputs set.
k_ra8_err_null_ptrA required pointer is NULL.
k_ra8_err_not_foundNo link rect on page_idx contains the point.
Precondition
engine is initialized and laid out.
out_href_off / out_href_len are writable.
Postcondition
On success the outputs slice the engine text pool.
On failure the outputs are unchanged.
Note
Read-only; safe to call between render passes.
Since
0.1.0

Definition at line 36 of file reflow_link.c.

References reflow_link_rect_t::h, reflow_link_target_t::href_len, reflow_link_target_t::href_off, k_ra8_err_not_found, k_ra8_ok, reflow_t::link_rect_count, reflow_t::link_rects, reflow_t::link_targets, reflow_link_rect_t::page_index, RA8_CHECK_NULL_PTR, s_tag_link, reflow_link_rect_t::target, reflow_link_rect_t::w, reflow_link_rect_t::x, and reflow_link_rect_t::y.

Referenced by er_reading_link_tap(), and lk_probe_rect().

◆ reflow_href_split()

ra8_err_t reflow_href_split ( const char * href,
uint32_t len,
reflow_href_kind_t * out_kind,
uint32_t * out_path_len,
uint32_t * out_frag_off,
uint32_t * out_frag_len )
nodiscard

Split + classify an <a href> into a path part and a #fragment.

Pure string logic (no engine state): detects a URI scheme (external, unsupported), a leading '#' (same-chapter fragment), or an embedded '#' (chapter + fragment). The path part is href[0 .. *out_path_len); the fragment, if any, is href[*out_frag_off .. *out_frag_off + *out_frag_len) (excluding the '#').

Parameters
[in]hrefHref bytes (not NUL-terminated).
[in]lenLength of href, bytes.
[out]out_kindReceives the classification.
[out]out_path_lenReceives the path-part length (0 for fragment-only).
[out]out_frag_offReceives the fragment start offset (0 if none).
[out]out_frag_lenReceives the fragment length (0 if none).
Returns
ra8_err_t
Return values
k_ra8_okClassified; all outputs set.
k_ra8_err_null_ptrA required pointer is NULL.
Precondition
href holds len bytes; all out pointers are writable.
Postcondition
*out_kind reflects the href shape; the spans index within href.
Note
Pure function; thread-safe.
Since
0.1.0

Definition at line 218 of file reflow_link.c.

References internal_href_classify(), k_ra8_ok, k_reflow_href_empty, RA8_CHECK_NULL_PTR, and s_tag_link.

Referenced by er_reading_link_tap(), and lk_probe_rect().

◆ reflow_init()

ra8_err_t reflow_init ( uint16_t viewport_w,
uint16_t viewport_h,
const uint8_t * font_data,
size_t font_len,
uint16_t font_px,
uint32_t body_color,
uint32_t link_color,
reflow_t * out_engine )
nodiscard

Initialise a reflow engine for a given viewport / font.

Records the viewport size, font handle and colour palette into the engine handle and clears the cached chapter / glyph / page state.

Parameters
[in]viewport_wViewport width, pixels (1..4096).
[in]viewport_hViewport height, pixels (1..4096).
[in]font_dataTTF blob; must outlive the engine.
[in]font_lenLength of font_data, bytes (>= 16).
[in]font_pxInitial font size, pixels (k_reflow_min_font_px .. k_reflow_max_font_px).
[in]body_colorBody text colour (0xRRGGBB).
[in]link_colorAnchor colour (0xRRGGBB).
[out]out_engineEngine handle to populate.
Returns
ra8_err_t
Return values
k_ra8_okInitialized.
k_ra8_err_null_ptrfont_data or out_engine is NULL.
k_ra8_err_invalid_argViewport or font size out of range.
k_ra8_err_invalid_sizefont_len too small.
Precondition
font_data non-NULL, out_engine non-NULL.
Viewport and font size in their documented ranges.
Postcondition
On success, out_engine->in_use == 1 and out_engine->page_count == 0.
On failure, *out_engine is zero-initialized.
Note
Not thread-safe. Single-threaded init context.
See also
reflow_close()
Since
0.1.0

Definition at line 149 of file reflow_layout_driver.c.

References reflow_t::body_color, reflow_t::font_data, reflow_t::font_len, reflow_t::font_px, reflow_t::in_use, k_ra8_err_invalid_arg, k_ra8_err_invalid_size, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_max_font_px, k_reflow_min_font_px, reflow_t::link_color, priv_reflow_layout_byte_zero(), reflow_t::viewport_h, and reflow_t::viewport_w.

Referenced by er_reflow_relayout(), internal_pc_engine_init(), main(), and sfr_render_or_halt().

◆ reflow_layout_chapter()

ra8_err_t reflow_layout_chapter ( reflow_t * engine,
const uint8_t * xhtml_buf,
size_t xhtml_len,
uint32_t * out_total_pages )
nodiscard

Parse + lay out one chapter of XHTML.

Walks the XHTML once with the no-heap streaming tokenizer, emits a token stream, then runs the greedy line-break + page-break engine to produce a flat list of positioned glyphs grouped by page. The engine caches the input buffer so reflow_set_font_size() can re-flow without the caller re-supplying it.

Algorithm summary:

  1. Tokenize the XHTML in a single no-heap forward pass, emitting tokens (block_start / text / break / ...).
  2. For each token, if it is a text run, walk word-by-word.
  3. Measure word_width = sum(stbtt advance per glyph).
  4. If cursor_x + word_width > viewport_w - margins then break to a new line.
  5. If cursor_y + line_height > viewport_h - margins then start a new page.
  6. After all tokens, record page_count.
Parameters
[in,out]engineInitialized engine handle.
[in]xhtml_bufUTF-8 / ASCII XHTML source bytes.
[in]xhtml_lenLength of xhtml_buf, bytes (>0).
[out]out_total_pagesTotal page count (>= 1 on success).
Returns
ra8_err_t
Return values
k_ra8_okLaid out.
k_ra8_err_null_ptrAny required pointer is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_sizexhtml_len == 0.
k_ra8_err_validation_failedXHTML did not parse.
k_ra8_err_no_memToken / glyph / page pool full.
Precondition
engine, xhtml_buf, out_total_pages non-NULL.
engine->in_use == 1.
Postcondition
On success, *out_total_pages == engine->page_count >= 1.
Since
0.1.0

Definition at line 233 of file reflow_layout_driver.c.

References reflow_t::in_use, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, reflow_t::page_count, reflow_parse_xhtml(), reflow_run_layout(), reflow_t::xhtml_buf, and reflow_t::xhtml_len.

Referenced by er_reflow_relayout(), erb_render_chapter(), internal_pc_live_layout_or_halt(), main(), reflow_bind_font(), reflow_set_font_size(), and sfr_render_or_halt().

◆ reflow_parse_xhtml()

ra8_err_t reflow_parse_xhtml ( reflow_t * engine,
const uint8_t * xhtml_buf,
size_t xhtml_len )
nodiscard

Parse the XHTML buffer into the engine's token stream.

Internal helper used by reflow_layout_chapter(). Implemented by the no-heap streaming tokenizer in reflow_tokenize.c. Declared here so reflow_layout.c can call it without a forward declaration.

Parameters
[in,out]engineEngine whose token / text pools will be populated.
[in]xhtml_bufXHTML source bytes.
[in]xhtml_lenLength of xhtml_buf.
Returns
ra8_err_t
Return values
k_ra8_okTokens emitted.
k_ra8_err_validation_failedXHTML did not parse.
k_ra8_err_no_memToken or text pool full.
Since
0.1.0

Definition at line 38 of file reflow_parse.c.

References reflow_t::in_use, k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, reflow_t::link_target_count, priv_reflow_xml_walk(), reflow_t::text_pool_used, reflow_t::token_count, reflow_t::xhtml_buf, and reflow_t::xhtml_len.

Referenced by reflow_layout_chapter().

◆ reflow_register_face()

ra8_err_t reflow_register_face ( reflow_t * engine,
uint8_t css_face_idx,
const uint8_t * blob,
size_t len )
nodiscard

Register one embedded @font-face typeface for per-run selection (#109).

Validates blob with stbtt_InitFont and, on success, appends it to the engine's face registry keyed by css_face_idx (the index ra8_css_match_face returns for the parsed <style> @font-face table). After layout, a text run whose cascaded font-family + emphasis match that table entry is rendered with this face instead of the default bound at reflow_init(); unmatched runs fall back to the default. The app drives this after epub_open by walking the sheet's @font-face table, matching each src href to a manifest font.

The blob is stored by pointer (zero-copy) and MUST outlive the engine. While a face is registered (engine->face_count > 0) the pagination cache is bypassed (reflow_cache_serialize / _load return k_ra8_err_invalid_state), so a multi-face book is never serialized or mis-served under a different face set.

Parameters
[in,out]engineInitialised engine.
[in]css_face_idx@font-face table index this blob satisfies (0 .. sheet face_count - 1).
[in]blobTTF/OTF bytes; must outlive the engine.
[in]lenLength of blob, bytes.
Returns
ra8_err_t Error code.
Return values
k_ra8_okFace registered.
k_ra8_err_null_ptrengine or blob is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_sizelen < k_reflow_min_font_bytes.
k_ra8_err_no_memThe registry is full (k_reflow_max_faces).
k_ra8_err_not_supportedstbtt_InitFont rejected the blob.
Precondition
engine->in_use == 1; blob non-NULL and outlives the engine.
css_face_idx is a valid @font-face table index.
Postcondition
On success engine->face_count grows by one; on failure it is unchanged.
Subsequent layouts may select this face per run; the cache is bypassed.
Note
Not thread-safe; single-threaded init/layout context.
See also
reflow_init(), reflow_bind_font(), ra8_css_match_face()
Since
0.1.0

Register one embedded @font-face typeface for per-run selection (#109).

Definition at line 346 of file reflow_layout_driver.c.

References reflow_face_t::blob, reflow_face_t::css_face_idx, reflow_t::face_count, reflow_t::faces, reflow_t::in_use, k_ra8_err_invalid_size, k_ra8_err_no_mem, k_ra8_err_not_initialized, k_ra8_err_not_supported, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_max_faces, k_reflow_min_font_bytes, reflow_face_t::len, and ra8_stbtt_sfnt_dir_in_bounds().

◆ reflow_render_page()

ra8_err_t reflow_render_page ( const reflow_t * engine,
uint32_t page_idx,
void * framebuffer )
nodiscard

Render one page into the active ra8_gfx framebuffer.

Walks the slice of engine->glyphs[] that belongs to page_idx, rasterises each code point through the two-step stbtt_GetCodepointBitmapBox() + stbtt_MakeCodepointBitmap() path (glyph bitmap into a fixed buffer; stb scratch via the no-heap arena in ra8_stbtt_alloc.c), and blits the alpha-8 mask into the framebuffer with ra8_gfx_pixel().

The framebuffer must already be bound by ra8_gfx_init(). The background is NOT cleared; the caller chooses the background colour with a prior ra8_gfx_clear().

Parameters
[in]engineLaid-out engine.
[in]page_idxPage to render ([0, page_count)).
[in,out]framebufferReserved for future use; pass NULL while ra8_gfx is bound. (Forward-compat hook so future builds can blit straight into a non-active buffer without re-binding ra8_gfx.)
Returns
ra8_err_t
Return values
k_ra8_okRendered.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_out_of_rangepage_idx >= page_count.
k_ra8_err_validation_failedFont blob malformed.
Precondition
ra8_gfx_init() has been called.
A chapter has been laid out.
Postcondition
Glyph pixels of the requested page are blitted into the bound framebuffer.
Since
0.1.0

Definition at line 724 of file reflow_render.c.

References internal_render_page(), k_ra8_err_out_of_range, k_ra8_ok, and reflow_t::page_count.

Referenced by erb_render_all(), internal_rc_render_all(), and sfr_render_or_halt().

◆ reflow_render_page_at()

ra8_err_t reflow_render_page_at ( const reflow_t * engine,
uint32_t page_idx,
int32_t origin_x,
int32_t origin_y )
nodiscard

Render one page offset by (origin_x, origin_y) into the bound framebuffer.

Identical to reflow_render_page() except every glyph (and link underline) is shifted by the given origin before it is blitted with ra8_gfx_pixel(). This lets the engine paint into a sub-region of a larger panel – e.g. an e-reader Reading body inset below a status bar and above a footer – without the layout knowing about the chrome: lay out against the body's viewport_w/viewport_h, then render at the body's top-left. reflow_render_page() is exactly this with a (0, 0) origin. ra8_gfx owns the framebuffer stride, so only an origin (not a stride) is required.

Parameters
[in]engineLaid-out engine.
[in]page_idxPage to render ([0, page_count)).
[in]origin_xPixel offset added to every glyph's x coordinate.
[in]origin_yPixel offset added to every glyph's y coordinate.
Returns
ra8_err_t
Return values
k_ra8_okRendered.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_out_of_rangepage_idx >= page_count.
k_ra8_err_validation_failedFont blob malformed.
Precondition
ra8_gfx_init() has been called and a chapter laid out.
The offset region lies within the bound framebuffer.
Postcondition
Glyph pixels of the requested page are blitted at the offset.
Pixels that fall outside the framebuffer are dropped by ra8_gfx.
Since
0.1.0

Definition at line 731 of file reflow_render.c.

References internal_render_page().

Referenced by er_draw_reading_body_reflow().

◆ reflow_run_layout()

ra8_err_t reflow_run_layout ( reflow_t * engine)
nodiscard

Run the line-break + page-break pass over engine->tokens[].

Internal helper. Consumes the token stream populated by reflow_parse_xhtml() and writes positioned glyphs into engine->glyphs[] plus page index ranges into engine->pages[].

Parameters
[in,out]engineEngine in in_use == 1 state with a populated token stream.
Returns
ra8_err_t
Return values
k_ra8_okLayout complete.
k_ra8_err_no_memGlyph or page pool full.
Since
0.1.0

Definition at line 105 of file reflow_layout_driver.c.

References reflow_t::anchor_count, reflow_page_t::glyph_count, reflow_t::glyph_count, reflow_page_t::glyph_first, reflow_t::image_box_count, reflow_t::in_use, internal_layout_tokens(), k_priv_min_chapter_pages, k_ra8_err_no_mem, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_max_pages, reflow_t::link_rect_count, reflow_t::page_count, reflow_t::pages, priv_reflow_internal_final_page_needed(), priv_reflow_layout_build_link_rects(), priv_reflow_layout_init_font(), and reflow_t::token_count.

Referenced by reflow_layout_chapter().

◆ reflow_set_css_loader()

ra8_err_t reflow_set_css_loader ( reflow_t * engine,
reflow_css_loader_fn loader,
void * ctx )
nodiscard

Bind the external-stylesheet loader for <link rel="stylesheet">.

Mirrors reflow_set_image_loader(). When bound, reflow_layout_chapter() resolves each <link rel="stylesheet" href> in the chapter via loader and parses the returned CSS into the chapter sheet in document order (so a later inline <style> / style= overrides it). NULL loader disables the feature (chapters parse only their inline CSS, exactly as before).

Parameters
[in,out]engineEngine to bind.
[in]loaderStylesheet byte loader, or NULL to disable.
[in]ctxOpaque context handed back to loader.
Returns
ra8_err_t Error code.
Return values
k_ra8_okBinding recorded.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
Precondition
engine is non-NULL and initialized.
Postcondition
On success the engine uses (loader, ctx) for <link> stylesheets.
Binding takes effect on the next reflow_layout_chapter().
Note
Not thread-safe; bind before laying out.
Since
0.1.0

Definition at line 220 of file reflow_layout_driver.c.

References reflow_t::css_loader, reflow_t::css_loader_ctx, reflow_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

◆ reflow_set_font_size()

ra8_err_t reflow_set_font_size ( reflow_t * engine,
uint16_t new_font_px )
nodiscard

Change the body font size and re-flow the cached chapter.

Re-runs the line-break + page-break engine against the most recent chapter handed to reflow_layout_chapter(). Glyph and page state are rebuilt from scratch; the previous page count and page-glyph ranges are invalidated.

Parameters
[in,out]engineInitialized + laid-out engine.
[in]new_font_pxNew body font size, pixels (k_reflow_min_font_px .. k_reflow_max_font_px).
Returns
ra8_err_t
Return values
k_ra8_okRe-flowed.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_stateNo chapter cached yet.
k_ra8_err_invalid_argnew_font_px out of range.
Since
0.1.0

Definition at line 279 of file reflow_layout_driver.c.

References reflow_t::font_px, reflow_t::in_use, k_ra8_err_invalid_arg, k_ra8_err_invalid_state, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_max_font_px, k_reflow_min_font_px, priv_reflow_internal_xhtml_invalid(), reflow_layout_chapter(), reflow_t::xhtml_buf, and reflow_t::xhtml_len.

Referenced by main().

◆ reflow_set_glyph_atlas()

ra8_err_t reflow_set_glyph_atlas ( reflow_t * engine,
ra8_glyph_atlas_t * atlas,
const reflow_glyph_atlas_storage_t * storage )
nodiscard

Bind a Layer-3 glyph cache to the engine's render path (#164).

Mirrors reflow_set_image_loader(). When bound, the per-page rasteriser routes every glyph through atlas: a hit reuses the cached bitmap, a miss rasterises once (through the engine's stb_truetype path) into a cache cell and pins it for the blit. Resident glyph RAM stays bounded by the supplied storage regardless of how many distinct glyphs a book touches, so a page re-render never re-rasterises a glyph it drew recently. Output is byte-for-byte identical to the direct path – the same rasteriser fills the cell, and oversized glyphs (bitmap > storage->cell_bytes) transparently fall back to direct rasterisation.

atlas is initialised in place from storage (the caller need not call ra8_glyph_atlas_init); both atlas and the storage arrays are caller-owned and must out-live the engine. Passing atlas == NULL detaches any bound cache and reverts to direct rasterisation.

Parameters
[in,out]engineEngine to bind; must be initialized.
[in,out]atlasCaller-owned atlas state to initialise and bind, or NULL to detach the current cache.
[in]storageBacking storage; required (non-NULL) when atlas is non-NULL, ignored when atlas is NULL.
Returns
ra8_err_t Error code.
Return values
k_ra8_okCache bound (or detached when atlas NULL).
k_ra8_err_null_ptrengine NULL, or atlas non-NULL with storage NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_sizeA required storage size field is zero.
Precondition
engine is non-NULL and initialized.
When atlas is non-NULL, storage and its arrays out-live engine.
Postcondition
On success with atlas non-NULL, glyph rendering consults the cache.
On success with atlas NULL, the engine renders glyphs directly.
Note
Not thread-safe; bind before rendering. The cache is consulted only by reflow_render_page() / reflow_render_page_at().
See also
reflow_glyph_atlas_storage_t
Since
0.1.0

Definition at line 736 of file reflow_render.c.

References reflow_glyph_atlas_storage_t::bucket_count, reflow_glyph_atlas_storage_t::buckets, reflow_glyph_atlas_storage_t::cell_bytes, reflow_glyph_atlas_storage_t::cell_count, reflow_glyph_atlas_storage_t::cell_mem, reflow_glyph_atlas_storage_t::dims, reflow_t::glyph_atlas, reflow_t::in_use, internal_atlas_render_glyph(), k_ra8_err_invalid_size, k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, reflow_glyph_atlas_storage_t::keys, reflow_glyph_atlas_storage_t::meta, ra8_glyph_atlas_init(), and s_glyph_render_ctx.

Referenced by er_bind_glyph_atlas().

◆ reflow_set_image_loader()

ra8_err_t reflow_set_image_loader ( reflow_t * engine,
reflow_image_loader_fn loader,
void * ctx,
ra8_img_arena_t * arena )
nodiscard

Bind an <img> byte loader + decode arena to enable image rendering.

Without this binding (the default), <img> elements reserve a small placeholder advance and draw nothing – the historical v1 behaviour, kept so image-free content lays out byte-identically. Once a loader + arena are bound, the layout pass resolves each <img src> to its intrinsic size, reserves a scaled block (text flows below), and the render pass decodes + blits the image on demand. Pass loader == NULL or arena == NULL to disable again.

Parameters
[in,out]engineInitialized engine handle.
[in]loaderResolves an href to encoded image bytes (NULL = off).
[in]ctxOpaque context handed back to loader.
[in]arenaCaller-owned decode scratch (NULL = off); sized for the largest image (a few KiB SRAM .. a few MiB SDRAM).
Returns
ra8_err_t
Return values
k_ra8_okBinding recorded.
k_ra8_err_null_ptrengine is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
Precondition
engine is non-NULL and initialized.
If non-NULL, arena->base addresses arena->cap writable bytes.
Postcondition
On success the engine uses (loader, ctx, arena) for <img>.
Binding takes effect on the next reflow_layout_chapter() / re-flow.
Note
Not thread-safe; bind before laying out.
Since
0.1.0

Definition at line 203 of file reflow_layout_driver.c.

References reflow_t::img_arena, reflow_t::img_loader, reflow_t::img_loader_ctx, reflow_t::in_use, k_ra8_err_not_initialized, k_ra8_err_null_ptr, and k_ra8_ok.

Referenced by er_reflow_relayout().