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

Page-rasteriser for reflow. More...

#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "ra8_attributes.h"
#include "ra8_err.h"
#include "ra8_gfx.h"
#include "ra8_glyph_atlas.h"
#include "reflow.h"
#include "reflow_svg.h"
#include "stb_truetype.h"
Include dependency graph for reflow_render.c:

Go to the source code of this file.

Data Structures

struct  priv_glyph_render_ctx_t
 Per-glyph state handed to the glyph-atlas render-on-miss callback. More...

Enumerations

enum  priv_render_consts_t : uint16_t {
  k_priv_alpha_threshold = 96U ,
  k_priv_alpha_max_byte = 255U ,
  k_priv_underline_offset_px = 2U ,
  k_priv_underline_thick_px = 1U ,
  k_priv_glyph_dim_max = 192U ,
  k_priv_svg_href_max = 256U ,
  k_priv_glyph_mode_aa = 0U
}
 Internal sizing knobs for the render pass. More...

Functions

static ra8_err_t internal_atlas_render_glyph (void *ctx, const ra8_glyph_key_t *key, uint8_t *cell, uint32_t cell_bytes, uint16_t *out_w, uint16_t *out_h)
 Glyph-atlas render-on-miss callback: rasterise one glyph into a cell.
static ra8_err_t internal_init_font (const reflow_t *engine, stbtt_fontinfo *out_font)
 Initialise an stbtt_fontinfo from the engine's font blob.
static void internal_blit_alpha_mask (const reflow_glyph_t *g, const unsigned char *bitmap, int w, int h, int xoff, int yoff, int32_t ox, int32_t oy)
 Walk one glyph bitmap and blit any sufficiently-covered pixels into the bound framebuffer.
static void internal_draw_underline (const stbtt_fontinfo *font, const reflow_glyph_t *g, float scale, int32_t ox, int32_t oy)
 Draw the underline strip for a link glyph.
static void internal_glyph_render_direct (const stbtt_fontinfo *font, float scale, const reflow_glyph_t *g, int w, int h, int x0, int y0, int32_t ox, int32_t oy)
 Rasterise one glyph into a function-local static mask and blit it.
static bool internal_glyph_render_cached (ra8_glyph_atlas_t *atlas, uint8_t face_id, const stbtt_fontinfo *font, float scale, const reflow_glyph_t *g, int w, int h, int x0, int y0, int32_t ox, int32_t oy)
 Draw one glyph through the bound glyph atlas (cache hit or render-miss).
static void internal_blit_glyph (ra8_glyph_atlas_t *atlas, uint8_t face_id, const stbtt_fontinfo *font, const reflow_glyph_t *g, int32_t ox, int32_t oy)
 Rasterise one glyph at its baseline position into the bound framebuffer.
static void internal_render_svg (const reflow_t *engine, const uint8_t *svg, size_t len, int32_t x, int32_t y, int32_t w, int32_t h)
 Render an SVG image box: unwrap a cover <image> href, else draw shapes.
static void internal_render_one_image (const reflow_t *engine, const reflow_image_box_t *box, int32_t ox, int32_t oy)
 Render one image box: SVG-route or raster-decode at the page offset.
static void internal_render_images (const reflow_t *engine, uint32_t page_idx, int32_t ox, int32_t oy)
 Decode and blit every laid-out image that belongs to one page.
static ra8_err_t internal_init_faces (const reflow_t *engine, stbtt_fontinfo *faces, uint8_t *out_n)
 Build the per-render stbtt_fontinfo set: default at 0, faces at 1..N.
static ra8_err_t internal_render_page (const reflow_t *engine, uint32_t page_idx, int32_t ox, int32_t oy)
 Shared render body for one page, offsetting every element by (ox, oy).
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_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).

Variables

static priv_glyph_render_ctx_t s_glyph_render_ctx
 File-static render context shared with the bound glyph atlas.

Detailed Description

Page-rasteriser for reflow.

Walks the slice of engine->glyphs[] belonging to one page and blits each glyph's alpha-8 bitmap into the framebuffer bound by ra8_gfx_init(). Each glyph is rasterised on demand through the two-step stbtt_GetCodepointBitmapBox() + stbtt_MakeCodepointBitmap() path so the glyph bitmap lands in a fixed file-scope mask buffer rather than a STBTT_malloc'd one; stb's remaining per-glyph scratch (vertex / edge lists) is served by the no-heap static arena in ra8_stbtt_alloc.c. The alpha mask is composited against the engine's body / link colour using a simple "alpha >= threshold" test so the output is binary (no per-pixel multiplies). This keeps the render path ARM-Cortex-M cheap while still producing crisp anti-aliased shapes thanks to stb's coverage-based rasteriser.

[Ring 4 / Reflow] {World: NS}

Since
0.1.0

Definition in file reflow_render.c.

Enumeration Type Documentation

◆ priv_render_consts_t

enum priv_render_consts_t : uint16_t

Internal sizing knobs for the render pass.

Enumerator
k_priv_alpha_threshold 

Coverage cutoff for binary blit.

k_priv_alpha_max_byte 

Upper bound from stb's mask.

k_priv_underline_offset_px 

Pixels below baseline for the underline.

k_priv_underline_thick_px 

Thickness of the anchor underline.

k_priv_glyph_dim_max 

Mask edge bound = 2 * k_reflow_max_font_px.

k_priv_svg_href_max 

Max unwrapped SVG cover-image href length.

k_priv_glyph_mode_aa 

Glyph-cache render mode: stb coverage AA.

Definition at line 49 of file reflow_render.c.

Function Documentation

◆ internal_atlas_render_glyph()

ra8_err_t internal_atlas_render_glyph ( void * ctx,
const ra8_glyph_key_t * key,
uint8_t * cell,
uint32_t cell_bytes,
uint16_t * out_w,
uint16_t * out_h )
static

Glyph-atlas render-on-miss callback: rasterise one glyph into a cell.

Bridges ::ra8_glyph_atlas to the engine's stb_truetype rasteriser. On a cache miss the atlas calls this (only ever through ra8_glyph_atlas_get, which validates ctx/key/cell and supplies its own cell + out_w/out_h storage, so no argument null-check is needed here – the same caller-guarantee convention as internal_blit_alpha_mask). The font, scale, and extent come from s_glyph_render_ctx (already computed and validated by internal_blit_glyph before the get); the code point rides in key->glyph_id. stbtt_MakeCodepointBitmap runs with stride == w exactly as the direct path, so a cached bitmap is byte-identical to a freshly rasterised one. A glyph whose bitmap exceeds the cell is rejected so the caller falls back to direct rasterisation.

Parameters
[in]ctxThe priv_glyph_render_ctx_t set by internal_blit_glyph.
[in]keyGlyph to render (glyph_id is the code point).
[out]cellDestination cell buffer (cell_bytes writable).
[in]cell_bytesCell capacity in bytes.
[out]out_wRendered glyph width in pixels.
[out]out_hRendered glyph height in pixels.
Returns
Result code.
Return values
k_ra8_okGlyph rendered; *out_w/*out_h written.
k_ra8_err_invalid_sizeThe glyph bitmap does not fit the cell.
Precondition
ctx is the bound s_glyph_render_ctx with a valid font/scale/w/h.
cell has room for cell_bytes bytes (guaranteed by the keycache).
Postcondition
On k_ra8_ok the cell holds a tightly packed alpha-8 w*h bitmap.
On k_ra8_err_invalid_size the cell is untouched and stays unpinned.
Note
Not thread-safe; uses s_glyph_render_ctx.
Since
0.1.0

Definition at line 122 of file reflow_render.c.

References priv_glyph_render_ctx_t::font, ra8_glyph_key_t::glyph_id, priv_glyph_render_ctx_t::h, k_ra8_err_invalid_size, k_ra8_ok, priv_glyph_render_ctx_t::scale, and priv_glyph_render_ctx_t::w.

Referenced by reflow_set_glyph_atlas().

◆ internal_blit_alpha_mask()

void internal_blit_alpha_mask ( const reflow_glyph_t * g,
const unsigned char * bitmap,
int w,
int h,
int xoff,
int yoff,
int32_t ox,
int32_t oy )
static

Walk one glyph bitmap and blit any sufficiently-covered pixels into the bound framebuffer.

See implementation.

Parameters
[in]gSee implementation.
[in]bitmapSee implementation.
[in]wSee implementation.
[in]hSee implementation.
[in]xoffSee implementation.
[in]yoffSee implementation.
[in]oxPixel offset added to every glyph x.
[in]oyPixel offset added to every glyph y.
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 196 of file reflow_render.c.

References reflow_glyph_t::color, k_priv_alpha_threshold, ra8_gfx_pixel(), reflow_glyph_t::x, and reflow_glyph_t::y.

Referenced by internal_glyph_render_cached(), and internal_glyph_render_direct().

◆ internal_blit_glyph()

void internal_blit_glyph ( ra8_glyph_atlas_t * atlas,
uint8_t face_id,
const stbtt_fontinfo * font,
const reflow_glyph_t * g,
int32_t ox,
int32_t oy )
static

Rasterise one glyph at its baseline position into the bound framebuffer.

g->x / g->y are the glyph's baseline-left position. The "Box" call reports the bitmap extent and stb baseline offsets (x0, y0) – cheap, no raster – so the bitmap lands in the correct row above the baseline and columns place accents/descenders correctly. When atlas is bound the bitmap is fetched from (or rendered once into) the cache; otherwise it is rasterised directly. Underlined link glyphs additionally get an underline strip.

Parameters
[in]atlasBound glyph cache, or NULL for direct rasterisation.
[in]face_idFace index resolved for this glyph (for the cache key).
[in]fontInitialised font for this glyph.
[in]gPositioned glyph to draw.
[in]oxPixel offset added to every glyph x.
[in]oyPixel offset added to every glyph y.
Precondition
font is initialised and g is non-NULL.
face_id selected font in the caller.
Postcondition
The glyph (and any underline) is blitted into the bound framebuffer.
Engine state is unchanged; only the framebuffer and cache LRU move.
Note
Not thread-safe unless documented otherwise.
Since
0.1.0

Definition at line 395 of file reflow_render.c.

References reflow_glyph_t::cp, reflow_glyph_t::font_px, internal_draw_underline(), internal_glyph_render_cached(), internal_glyph_render_direct(), k_reflow_style_underline, and reflow_glyph_t::style.

Referenced by internal_render_page().

◆ internal_draw_underline()

void internal_draw_underline ( const stbtt_fontinfo * font,
const reflow_glyph_t * g,
float scale,
int32_t ox,
int32_t oy )
static

Draw the underline strip for a link glyph.

See implementation.

Parameters
[in]fontSee implementation.
[in]gSee implementation.
[in]scaleSee implementation.
[in]oxPixel offset added to the underline x.
[in]oyPixel offset added to the underline y.
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 235 of file reflow_render.c.

References reflow_glyph_t::color, reflow_glyph_t::cp, k_priv_underline_offset_px, ra8_gfx_pixel(), reflow_glyph_t::x, and reflow_glyph_t::y.

Referenced by internal_blit_glyph().

◆ internal_glyph_render_cached()

bool internal_glyph_render_cached ( ra8_glyph_atlas_t * atlas,
uint8_t face_id,
const stbtt_fontinfo * font,
float scale,
const reflow_glyph_t * g,
int w,
int h,
int x0,
int y0,
int32_t ox,
int32_t oy )
static

Draw one glyph through the bound glyph atlas (cache hit or render-miss).

Keys the glyph by (face, size, code point, mode), fetches a pinned bitmap from atlas (rendering once on a miss via internal_atlas_render_glyph), blits it, then unpins. Because the cache is filled by the very same stb rasteriser as the direct path, the blitted pixels are byte-identical either way. Any atlas error (oversized glyph, or every cell pinned) returns false so the caller can fall back to internal_glyph_render_direct – the cache is a pure optimisation and never changes output.

Parameters
[in]atlasBound glyph cache (non-NULL).
[in]face_idFace index resolved for this glyph.
[in]fontInitialised font for this glyph.
[in]scalestb pixel-height scale for g.
[in]gPositioned glyph to draw.
[in]wGlyph bitmap width from the box query (> 0).
[in]hGlyph bitmap height from the box query (> 0).
[in]x0stb x baseline offset from the box query.
[in]y0stb y baseline offset from the box query.
[in]oxPixel offset added to every glyph x.
[in]oyPixel offset added to every glyph y.
Returns
true if the glyph was drawn from the cache; false to fall back.
Return values
trueThe glyph was fetched (hit or render-on-miss) and blitted.
falseThe atlas could not service the glyph; caller blits directly.
Precondition
atlas, font, and g are non-NULL.
w and h are the positive extents already validated by the caller.
Postcondition
On true the glyph is blitted and no cache pin is left held.
On false no pixels were drawn and no cache pin is held.
Note
Not thread-safe; mutates s_glyph_render_ctx.
The ra8_glyph_atlas_put return is intentionally (void)-cast: the bitmap pointer came from ra8_glyph_atlas_get on the same atlas in this call frame and the cell is still pinned, so put cannot fail with k_ra8_err_null_ptr (both args non-NULL) or k_ra8_err_invalid_arg (the cell is a member of this atlas and is pinned). The NASA Rule 7 deviation is bounded to this programmer-error-only path.
Since
0.1.0

Definition at line 337 of file reflow_render.c.

References ra8_glyph_t::bitmap, reflow_glyph_t::cp, ra8_glyph_key_t::face_id, reflow_glyph_t::font_px, ra8_glyph_key_t::glyph_id, ra8_glyph_t::height, internal_blit_alpha_mask(), k_priv_glyph_mode_aa, k_ra8_ok, ra8_glyph_key_t::mode, ra8_glyph_atlas_get(), ra8_glyph_atlas_put(), s_glyph_render_ctx, ra8_glyph_key_t::size_px, and ra8_glyph_t::width.

Referenced by internal_blit_glyph().

◆ internal_glyph_render_direct()

void internal_glyph_render_direct ( const stbtt_fontinfo * font,
float scale,
const reflow_glyph_t * g,
int w,
int h,
int x0,
int y0,
int32_t ox,
int32_t oy )
static

Rasterise one glyph into a function-local static mask and blit it.

The heap-free fallback path used when no glyph cache is bound or a glyph is too large to cache. "Make" rasterises into the fixed tightly-packed mask (stride == w, matching internal_blit_alpha_mask) – the bitmap never hits the heap; stb's vertex/edge scratch is served by the static arena in ra8_stbtt_alloc.c. Glyphs larger than the mask are skipped (not truncated), exactly as before the cache existed.

Parameters
[in]fontInitialised font for this glyph.
[in]scalestb pixel-height scale for g.
[in]gPositioned glyph to draw.
[in]wGlyph bitmap width from the box query.
[in]hGlyph bitmap height from the box query.
[in]x0stb x baseline offset from the box query.
[in]y0stb y baseline offset from the box query.
[in]oxPixel offset added to every glyph x.
[in]oyPixel offset added to every glyph y.
Precondition
w and h are the positive extents reported for g.
font is initialised and g is non-NULL.
Postcondition
On a fitting glyph the covered pixels are blitted; oversized are skipped.
No engine or cache state is mutated.
Note
Not thread-safe; uses function-local static mask storage.
Since
0.1.0

Definition at line 278 of file reflow_render.c.

References reflow_glyph_t::cp, internal_blit_alpha_mask(), and k_priv_glyph_dim_max.

Referenced by internal_blit_glyph().

◆ internal_init_faces()

ra8_err_t internal_init_faces ( const reflow_t * engine,
stbtt_fontinfo * faces,
uint8_t * out_n )
static

Build the per-render stbtt_fontinfo set: default at 0, faces at 1..N.

Slot 0 is always the engine's bound default face, initialised through internal_init_font(). Slots 1..face_count are the registered embedded @font-face blobs from engine->faces[]. A registered blob that fails stbtt_InitFont (already validated at register time, so this path is unexpected) is replaced by a copy of the default face so that every slot is always initialised and glyph rendering never indexes an invalid fontinfo. *out_n is set to engine->face_count + 1.

Parameters
[in]engineEngine holding the default font blob and face registry.
[out]facesCaller-allocated array of at least 1 + k_reflow_max_faces stbtt_fontinfo entries.
[out]out_nReceives the count of valid entries written (1 + engine->face_count).
Returns
k_ra8_ok on success, or the error returned by internal_init_font() if the default face cannot be initialised.
Return values
k_ra8_okAll face slots initialised successfully.
k_ra8_err_validation_failedDefault face font data is invalid.
Precondition
engine is non-null and engine->font_data points to a valid TrueType/OpenType blob.
faces and out_n are non-null; faces has capacity for at least 1 + k_reflow_max_faces entries.
Postcondition
On k_ra8_ok, faces[0..*out_n - 1] are all initialised; each slot that failed individual init holds a copy of faces[0].
*out_n equals engine->face_count + 1 on success; its value is unspecified on error.
Note
Not thread-safe; s_faces is a file-static array shared across calls.
Since
0.1.0

Definition at line 628 of file reflow_render.c.

References reflow_face_t::blob, reflow_t::face_count, reflow_t::faces, internal_init_font(), k_ra8_ok, and reflow_face_t::len.

Referenced by internal_render_page().

◆ internal_init_font()

ra8_err_t internal_init_font ( const reflow_t * engine,
stbtt_fontinfo * out_font )
static

Initialise an stbtt_fontinfo from the engine's font blob.

See implementation.

Parameters
[in]engineSee implementation.
[in]out_fontSee 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 163 of file reflow_render.c.

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

Referenced by internal_init_faces().

◆ internal_render_images()

void internal_render_images ( const reflow_t * engine,
uint32_t page_idx,
int32_t ox,
int32_t oy )
static

Decode and blit every laid-out image that belongs to one page.

Walks engine->image_boxes[0..image_box_count-1] and calls internal_render_one_image() for each box whose page_index matches page_idx. The decode is on-demand: decoded pixels are never stored persistently and the arena drains after each box. Boxes whose loader or decode fails are skipped, leaving a blank gap rather than aborting the rest of the page. The function is a no-op if engine->img_loader or engine->img_arena is null, allowing callers that do not bind an image loader to share the same render path.

Parameters
[in]engineEngine handle; image-box array and loader are read.
[in]page_idxIndex of the page being rendered.
[in]oxHorizontal page-origin offset in pixels.
[in]oyVertical page-origin offset in pixels.
Returns
Nothing.
Precondition
engine is non-null and fully initialized.
A framebuffer is bound via ra8_gfx_init().
Postcondition
Every decodable image on page_idx is blitted into the framebuffer; failed boxes are silently skipped.
Engine state is unchanged; the arena drains after each decode.
Note
Not thread-safe; the decode arena uses a file-static allocation pool that must not be re-entered.
Since
0.1.0

Definition at line 576 of file reflow_render.c.

References reflow_t::image_box_count, reflow_t::image_boxes, reflow_t::img_arena, reflow_t::img_loader, internal_render_one_image(), and reflow_image_box_t::page_index.

Referenced by internal_render_page().

◆ internal_render_one_image()

void internal_render_one_image ( const reflow_t * engine,
const reflow_image_box_t * box,
int32_t ox,
int32_t oy )
static

Render one image box: SVG-route or raster-decode at the page offset.

Resolves the source href stored at engine->text_pool[box->src_off] (length box->src_len) through engine->img_loader. On a successful load, the bytes are inspected by ra8_svg_is_svg(): SVG content is forwarded to internal_render_svg() (which handles both cover-wrapper and shape SVGs); all other formats are decoded directly by ra8_img_decode_blit(). In both cases the bounding rectangle is (box->x + ox, box->y + oy, box->w, box->h). A loader failure causes an early return, leaving a blank gap in the framebuffer rather than aborting the page render.

Parameters
[in]engineEngine handle; loader, arena, and text pool are read.
[in]boxImage layout descriptor for the box to render.
[in]oxHorizontal page-origin offset in pixels.
[in]oyVertical page-origin offset in pixels.
Returns
Nothing.
Precondition
engine is non-null with a valid img_loader and text_pool.
box is non-null and its src_off + src_len are within engine->text_pool.
Postcondition
On loader success, the image is blitted into the framebuffer at the computed destination rectangle.
Engine and box state are unchanged; the arena drains after each decode call.
Note
Not thread-safe; shares engine->img_arena with the caller.
Since
0.1.0

Definition at line 526 of file reflow_render.c.

References reflow_image_box_t::h, reflow_t::img_arena, reflow_t::img_loader, reflow_t::img_loader_ctx, internal_render_svg(), k_ra8_ok, ra8_img_decode_blit(), ra8_svg_is_svg(), reflow_image_box_t::src_len, reflow_image_box_t::src_off, reflow_t::text_pool, reflow_image_box_t::w, reflow_image_box_t::x, and reflow_image_box_t::y.

Referenced by internal_render_images().

◆ internal_render_page()

ra8_err_t internal_render_page ( const reflow_t * engine,
uint32_t page_idx,
int32_t ox,
int32_t oy )
static

Shared render body for one page, offsetting every element by (ox, oy).

Validates engine and page_idx, then builds the per-render stbtt_fontinfo array via internal_init_faces(). Iterates over every glyph in engine->pages[page_idx], extracts the face index from the high bits of g->style, clamps any out-of-range index to 0 (the default face), and calls internal_blit_glyph() with the resolved font. After all glyphs are rendered, internal_render_images() blits any image boxes that belong to the page. Both glyph and image positions are shifted by the origin (ox, oy), allowing callers to composite the page into an arbitrary framebuffer region. This function is the shared body called by both reflow_render_page (ox=oy=0) and reflow_render_page_at (caller-supplied origin).

Parameters
[in]engineEngine handle; must be fully initialised.
[in]page_idxZero-based page index to render; must be less than engine->page_count.
[in]oxHorizontal pixel offset added to every glyph and image box x-coordinate.
[in]oyVertical pixel offset added to every glyph and image box y-coordinate.
Returns
ra8_err_t status of the render operation.
Return values
k_ra8_okPage rendered successfully.
k_ra8_err_null_ptrengine is null.
k_ra8_err_not_initializedengine->in_use is zero.
k_ra8_err_out_of_rangepage_idx >= engine->page_count.
k_ra8_err_validation_failedDefault font data in the engine is invalid and cannot be initialised.
Precondition
engine is non-null and engine->in_use is non-zero.
page_idx is a valid index within engine->pages[].
Postcondition
On k_ra8_ok, all glyphs and images for page_idx are blitted into the bound framebuffer.
Engine, glyph, and image-box state are unchanged; only the framebuffer (via ra8_gfx_pixel()) is modified.
Note
Not thread-safe; uses the function-local static glyph mask and face storage that must not be accessed concurrently.
Since
0.1.0

Definition at line 688 of file reflow_render.c.

References reflow_t::glyph_atlas, reflow_page_t::glyph_count, reflow_page_t::glyph_first, reflow_t::glyphs, reflow_t::in_use, internal_blit_glyph(), internal_init_faces(), internal_render_images(), k_ra8_err_not_initialized, k_ra8_err_null_ptr, k_ra8_err_out_of_range, k_ra8_ok, k_reflow_face_mask, k_reflow_face_shift, k_reflow_max_faces, reflow_t::page_count, reflow_t::pages, and reflow_glyph_t::style.

Referenced by reflow_render_page(), and reflow_render_page_at().

◆ internal_render_svg()

void internal_render_svg ( const reflow_t * engine,
const uint8_t * svg,
size_t len,
int32_t x,
int32_t y,
int32_t w,
int32_t h )
static

Render an SVG image box: unwrap a cover <image> href, else draw shapes.

A cover-wrapper SVG (<svg><image href=.../></svg>) is detected by ra8_svg_image_href(). When found, the href string is copied into a stack buffer (bounded by k_priv_svg_href_max) before re-invoking engine->img_loader to fetch the referenced raster; the copy is necessary because the loader call may overwrite the SVG buffer. The decoded raster is then blitted by ra8_img_decode_blit() into the supplied bounding box. When no <image> wrapper is detected, the SVG is passed directly to ra8_svg_render() as a shape document (<rect>, <circle>, <line>, <path>, etc.). Href strings longer than k_priv_svg_href_max - 1 bytes are silently dropped.

Parameters
[in]engineEngine handle; img_loader and img_loader_ctx are used when a raster href is found.
[in]svgPointer to the raw SVG bytes.
[in]lenByte length of svg.
[in]xLeft edge of the destination bounding box in pixels.
[in]yTop edge of the destination bounding box in pixels.
[in]wWidth of the destination bounding box in pixels.
[in]hHeight of the destination bounding box in pixels.
Returns
Nothing.
Precondition
engine is non-null and its img_loader field is set.
svg is non-null and len bytes are readable.
Postcondition
If a valid cover-image href is found, the referenced raster is decoded and blitted into (x, y, w, h); otherwise the SVG shapes are rendered into the same box.
The framebuffer state reflects the drawn content; engine state is unchanged.
Note
Not thread-safe; shares the engine's img_arena with callers.
Since
0.1.0

Definition at line 469 of file reflow_render.c.

References reflow_t::img_arena, reflow_t::img_loader, reflow_t::img_loader_ctx, k_priv_svg_href_max, k_ra8_ok, memcpy(), ra8_img_decode_blit(), ra8_svg_image_href(), and ra8_svg_render().

Referenced by internal_render_one_image().

◆ 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.

◆ 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_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().

Variable Documentation

◆ s_glyph_render_ctx

priv_glyph_render_ctx_t s_glyph_render_ctx
static

File-static render context shared with the bound glyph atlas.

Warning
Mutated by the blit path before each ra8_glyph_atlas_get; not re-entrant.

Definition at line 88 of file reflow_render.c.

Referenced by internal_glyph_render_cached(), and reflow_set_glyph_atlas().