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

Import-time pagination cache for reflow (#79). More...

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

Go to the source code of this file.

Enumerations

enum  reflow_cache_id_t : uint32_t {
  k_reflow_cache_magic = 0x52464331U ,
  k_reflow_cache_version = 2U
}
 On-wire format identity for a serialised pagination cache. More...
enum  reflow_cache_layout_t : size_t {
  k_reflow_cache_header_bytes = 52U ,
  k_reflow_cache_glyph_bytes = 20U ,
  k_reflow_cache_page_bytes = 8U
}
 Byte sizes of the serialised header and per-record payloads. More...

Functions

ra8_err_t reflow_cache_size (const reflow_t *engine, size_t *out_bytes)
 Report the exact serialised size of an engine's current layout.
ra8_err_t reflow_cache_serialize (const reflow_t *engine, const uint8_t *content, size_t content_len, uint8_t *out_buf, size_t out_cap, size_t *out_len)
 Serialise the laid-out pages of engine into a keyed byte blob.
ra8_err_t reflow_cache_load (reflow_t *engine, const uint8_t *content, size_t content_len, const uint8_t *buf, size_t len)
 Validate a cache blob and, if it matches, restore the layout.

Detailed Description

Import-time pagination cache for reflow (#79).

Laying out a chapter (reflow_layout_chapter()) is the expensive step in the e-reader open path: it tokenizes the XHTML, measures every glyph through stb_truetype, and runs the greedy line-break / page-break engine. For a given book that result never changes unless the viewport, font, colours, font blob or chapter bytes change – so it is wasteful to repeat it every time the book is opened.

This module serialises the laid-out result – the flat glyphs[] array and the pages[] index ranges, which is all the renderer needs (render is a flat glyph walk) – into a small, self-describing byte blob, keyed by everything that would invalidate the layout:

  • viewport width / height,
  • body font size (font_px),
  • body + link colours,
  • the font blob (length + FNV-1a hash),
  • the chapter content (length + FNV-1a hash).

The blob is storage-agnostic: the application persists it however it already stores data (e.g. a file on the microSD via ra8_fs_write_file() / ra8_fs_open() + ra8_fs_read()), so this module pulls in no filesystem dependency. The intended flow:

// open path -- skip layout when the cache is valid:
if (reflow_cache_load(&eng, body, body_len, blob, blob_len) != k_ra8_ok) {
uint32_t pages = 0U;
(void)reflow_layout_chapter(&eng, body, body_len, &pages);
size_t n = 0U;
(void)reflow_cache_serialize(&eng, body, body_len, blob, sizeof blob, &n);
// ... persist blob[0..n) for next time ...
}
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
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_cache_serialize(const reflow_t *engine, const uint8_t *content, size_t content_len, uint8_t *out_buf, size_t out_cap, size_t *out_len)
Serialise the laid-out pages of engine into a keyed byte blob.
ra8_err_t reflow_cache_load(reflow_t *engine, const uint8_t *content, size_t content_len, const uint8_t *buf, size_t len)
Validate a cache blob and, if it matches, restore the layout.

reflow_cache_load() validates the blob's key against the engine's current viewport / font / colours and the supplied content; on any mismatch it returns k_ra8_err_invalid_state so the caller re-lays-out. A body checksum guards against a corrupt blob.

The blob is device-local: it is written and read back by the same firmware build (same struct layout, same endianness), but the on-wire form is still explicit little-endian per field – so the checksum is deterministic (no padding bytes) and a future format change is caught by the version field rather than silently mis-parsed.

[Ring 4 / Reflow] {World: NS}

Since
0.1.0

Definition in file reflow_cache.h.

Enumeration Type Documentation

◆ reflow_cache_id_t

enum reflow_cache_id_t : uint32_t

On-wire format identity for a serialised pagination cache.

k_reflow_cache_magic is the first 4 bytes of every blob (stored little-endian). k_reflow_cache_version is bumped whenever the serialised layout changes; a load of a different version is treated as stale (re-layout) rather than mis-parsed.

Enumerator
k_reflow_cache_magic 

Blob magic ('R''F''C''1').

k_reflow_cache_version 

Serialised format version.

Definition at line 88 of file reflow_cache.h.

◆ reflow_cache_layout_t

enum reflow_cache_layout_t : size_t

Byte sizes of the serialised header and per-record payloads.

The blob is header + glyph_count * glyph_bytes + page_count * page_bytes. A glyph serialises its 7 meaningful fields (x, y, cp, colour, font_px, style, reserved = 4+4+4+4+2+1+1); reserved carries the 1-based <a> link id used by hyperlink navigation, so it must round-trip (it is layout state, not padding). A page serialises its two uint32_t index fields.

Enumerator
k_reflow_cache_header_bytes 

Fixed header size, bytes.

k_reflow_cache_glyph_bytes 

Serialised bytes per glyph.

k_reflow_cache_page_bytes 

Serialised bytes per page.

Definition at line 105 of file reflow_cache.h.

Function Documentation

◆ reflow_cache_load()

ra8_err_t reflow_cache_load ( reflow_t * engine,
const uint8_t * content,
size_t content_len,
const uint8_t * buf,
size_t len )
nodiscard

Validate a cache blob and, if it matches, restore the layout.

Parses the blob header, then validates – in order – the magic, the format version, the record counts (against the engine's static pools and the blob length), the invalidation key (viewport / font / colours / font hash / content hash) and the body checksum. Only when all pass are the glyphs[] and pages[] arrays copied back into engine and engine->xhtml_buf / xhtml_len repointed at content (so a later reflow_set_font_size() can still re-flow). On any mismatch the engine is left untouched and the caller should re-lay-out.

Parameters
[in,out]engineEngine initialised with the same viewport / font / colours the blob was made with (the load validates this).
[in]contentChapter bytes (hashed and compared to the blob's content hash). May be NULL only when content_len == 0.
[in]content_lenLength of content, bytes.
[in]bufSerialised blob.
[in]lenLength of buf, bytes.
Returns
ra8_err_t
Return values
k_ra8_okLoaded; glyphs / pages restored.
k_ra8_err_null_ptrengine or buf is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_argcontent NULL with content_len>0.
k_ra8_err_not_foundMagic mismatch (not a cache blob).
k_ra8_err_invalid_stateVersion or key mismatch – the layout is stale; re-lay-out and re-serialise.
k_ra8_err_invalid_sizeTruncated blob or counts exceed pools.
k_ra8_err_checksum_mismatchBody checksum failed (corrupt blob).
Precondition
engine->in_use == 1.
Postcondition
On k_ra8_ok, engine->glyph_count / page_count and the restored arrays match the serialised layout and rendering may proceed without reflow_layout_chapter().
On any non-k_ra8_ok return the engine is unchanged.
See also
reflow_cache_serialize()
Since
0.1.0

Definition at line 716 of file reflow_cache.c.

References priv_cache_key_t::body_checksum, priv_cache_key_t::glyph_count, reflow_t::glyph_count, reflow_t::glyphs, internal_cache_precheck(), internal_fnv1a(), internal_get_glyph(), internal_get_page(), internal_key_matches(), internal_parse_header(), k_ra8_err_checksum_mismatch, k_ra8_err_invalid_state, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_cache_header_bytes, priv_cache_key_t::page_count, reflow_t::page_count, reflow_t::pages, reflow_t::xhtml_buf, and reflow_t::xhtml_len.

Referenced by internal_pc_invalidate_check_or_halt(), and internal_pc_reload_check_or_halt().

◆ reflow_cache_serialize()

ra8_err_t reflow_cache_serialize ( const reflow_t * engine,
const uint8_t * content,
size_t content_len,
uint8_t * out_buf,
size_t out_cap,
size_t * out_len )
nodiscard

Serialise the laid-out pages of engine into a keyed byte blob.

Writes the header (magic, version, the invalidation key, glyph / page counts and a body checksum) followed by the flat glyphs[] array and the pages[] index ranges, each field little-endian. The key captures the engine's viewport, font size, colours, the font blob (length + FNV-1a hash) and the supplied content (length + FNV-1a hash) so a later reflow_cache_load() can detect any change that would invalidate the layout.

Parameters
[in]engineLaid-out engine handle.
[in]contentChapter bytes the layout was produced from (hashed into the key). May be NULL only when content_len == 0.
[in]content_lenLength of content, bytes.
[out]out_bufDestination buffer.
[in]out_capCapacity of out_buf, bytes.
[out]out_lenReceives the number of bytes written.
Returns
ra8_err_t
Return values
k_ra8_okSerialised; *out_len bytes written.
k_ra8_err_null_ptrengine, out_buf or out_len NULL.
k_ra8_err_not_initializedengine->in_use == 0.
k_ra8_err_invalid_argcontent NULL with content_len > 0.
k_ra8_err_invalid_sizeout_cap smaller than the blob size.
Precondition
engine->in_use == 1; a chapter has been laid out.
Postcondition
On success the first *out_len bytes of out_buf are a valid blob accepted by reflow_cache_load().
See also
reflow_cache_size()
reflow_cache_load()
Since
0.1.0

Definition at line 679 of file reflow_cache.c.

References reflow_t::glyph_count, reflow_t::glyphs, internal_blob_size(), internal_cache_precheck(), internal_fnv1a(), internal_put_glyph(), internal_put_header(), internal_put_page(), internal_put_u32(), k_priv_checksum_off, k_ra8_err_invalid_size, k_ra8_err_null_ptr, k_ra8_ok, k_reflow_cache_header_bytes, reflow_t::page_count, and reflow_t::pages.

Referenced by internal_pc_live_layout_or_halt(), and internal_pc_reload_check_or_halt().

◆ reflow_cache_size()

ra8_err_t reflow_cache_size ( const reflow_t * engine,
size_t * out_bytes )
nodiscard

Report the exact serialised size of an engine's current layout.

Lets the caller size (or bounds-check) the destination buffer before calling reflow_cache_serialize(). The value is k_reflow_cache_header_bytes + engine->glyph_count * k_reflow_cache_glyph_bytes + engine->page_count * k_reflow_cache_page_bytes.

Parameters
[in]engineInitialised engine (a chapter need not be laid out yet; an empty layout serialises to just the header).
[out]out_bytesReceives the required buffer size in bytes.
Returns
ra8_err_t
Return values
k_ra8_okSize reported.
k_ra8_err_null_ptrengine or out_bytes is NULL.
k_ra8_err_not_initializedengine->in_use == 0.
Precondition
engine non-NULL and engine->in_use == 1.
Postcondition
*out_bytes >= k_reflow_cache_header_bytes.
Since
0.1.0

Definition at line 622 of file reflow_cache.c.

References reflow_t::glyph_count, reflow_t::in_use, internal_blob_size(), k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_ok, and reflow_t::page_count.