ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
reflow_layout_image.c
Go to the documentation of this file.
1
26
27#include <stddef.h>
28#include <stdint.h>
29
30#include "ra8_attributes.h"
31#include "ra8_err.h"
32#include "reflow.h"
33#include "reflow_image.h"
34#include "reflow_internal.h"
36#include "stb_truetype.h"
37
56{
57 const int32_t advance = (int32_t)k_priv_image_placeholder_px;
58 const int32_t right_limit = (int32_t)engine->viewport_w - (int32_t)k_reflow_margin_px;
60 advance,
61 right_limit,
62 cur->line_has_content)) {
63 if (!priv_reflow_layout_newline(engine, cur, false)) {
64 return false;
65 }
66 }
67 cur->x += advance;
68 cur->line_has_content = 1U;
69 return true;
70}
71
88static bool internal_page_has_content(const reflow_t* engine, const priv_cursor_t* cur)
89{
90 return (engine->glyph_count > cur->page_first_glyph) ||
91 (engine->image_box_count > cur->page_first_image);
92}
93
114static void internal_image_fit(int32_t iw,
115 int32_t ih,
116 int32_t col_w,
117 int32_t avail_h,
118 int32_t* out_w,
119 int32_t* out_h)
120{
121 int32_t bw = (iw < col_w) ? iw : col_w;
122 int32_t bh = (int32_t)(((int64_t)ih * (int64_t)bw) / (int64_t)iw);
123 if (bh > avail_h) {
124 bh = avail_h;
125 bw = (int32_t)(((int64_t)iw * (int64_t)bh) / (int64_t)ih);
126 }
127 *out_w = (bw < 1) ? 1 : bw;
128 *out_h = (bh < 1) ? 1 : bh;
129}
130
152 const reflow_token_t* tok,
153 int32_t* out_w,
154 int32_t* out_h)
155{
156 const char* href = (const char*)&engine->text_pool[tok->text_off];
157 const uint8_t* bytes = nullptr;
158 size_t blen = 0U;
159 if (engine->img_loader(engine->img_loader_ctx, href, tok->text_len, &bytes, &blen) != k_ra8_ok) {
160 return false;
161 }
162 int32_t iw = 0;
163 int32_t ih = 0;
164 if ((ra8_img_probe_size(bytes, blen, &iw, &ih) != k_ra8_ok) || (iw <= 0) || (ih <= 0)) {
165 return false;
166 }
167 const int32_t col_w = (int32_t)engine->viewport_w - (2 * (int32_t)k_reflow_margin_px);
168 const int32_t avail_h = (int32_t)engine->viewport_h - (2 * (int32_t)k_reflow_margin_px);
169 if ((col_w < 1) || (avail_h < 1)) {
170 return false;
171 }
172 internal_image_fit(iw, ih, col_w, avail_h, out_w, out_h);
173 return true;
174}
175
195static void internal_image_record(reflow_t* engine,
196 priv_cursor_t* cur,
197 const reflow_token_t* tok,
198 int32_t bw,
199 int32_t bh)
200{
201 reflow_image_box_t* box = &engine->image_boxes[engine->image_box_count];
202 box->x = (int32_t)k_reflow_margin_px;
203 box->y = cur->y;
204 box->w = bw;
205 box->h = bh;
206 box->src_off = tok->text_off;
207 box->src_len = tok->text_len;
208 box->page_index = engine->page_count;
209 box->reserved = 0U;
210 engine->image_box_count++;
211
212 cur->y += bh + (int32_t)k_reflow_paragraph_gap_px;
213 cur->line_top = cur->y;
214 cur->x = (int32_t)k_reflow_margin_px + (int32_t)cur->indent_px;
215 cur->line_has_content = 0U;
216}
217
237static bool internal_place_image(reflow_t* engine, priv_cursor_t* cur, const reflow_token_t* tok)
238{
239 if (engine->image_box_count >= (uint32_t)k_reflow_max_images) {
240 return false;
241 }
242 int32_t bw = 0;
243 int32_t bh = 0;
244 if (!internal_image_resolve_size(engine, tok, &bw, &bh)) {
245 return false;
246 }
247 /* Block-level: drop below the current line, then page-break if needed. */
248 if (cur->line_has_content != 0U) {
249 if (!priv_reflow_layout_newline(engine, cur, false)) {
250 return false;
251 }
252 }
253 const int32_t bottom_limit = (int32_t)engine->viewport_h - (int32_t)k_reflow_margin_px;
254 if (((cur->y + bh) > bottom_limit) && internal_page_has_content(engine, cur)) {
255 if (!priv_reflow_layout_finish_page(engine, cur)) {
256 return false;
257 }
258 }
259 internal_image_record(engine, cur, tok, bw, bh);
260 /* mcdc-deactivated: internal_image_record incremented image_box_count immediately above, so internal_page_has_content is invariantly true here; its false arm is unreachable once an image box has been recorded on the current page. */
261 if (((cur->y + (int32_t)cur->line_height_px) > bottom_limit) &&
262 internal_page_has_content(engine, cur)) {
263 if (!priv_reflow_layout_finish_page(engine, cur)) {
264 return false;
265 }
266 }
267 return true;
268}
269
271{
272 if ((engine->img_loader != nullptr) && (engine->img_arena != nullptr) && (tok->text_len > 0U)) {
273 if (internal_place_image(engine, cur, tok)) {
274 return true;
275 }
276 /* Resolution / pool overflow: fall back to the placeholder advance. */
277 }
278 return internal_apply_image_placeholder(engine, cur);
279}
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Error Code Definitions for ra8-firmware.
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
HTML / CSS reflow + paginate engine for the ra8d2 ereader.
Zero-heap raster image decode + scale + blit for reflow (#106).
ra8_err_t ra8_img_probe_size(const uint8_t *bytes, size_t len, int32_t *out_w, int32_t *out_h)
Probe an image's intrinsic dimensions without a full decode.
Test-access surface for reflow internal helpers (MC/DC).
bool priv_reflow_internal_right_overflow_break(int32_t cursor_x, int32_t advance, int32_t right_limit, uint8_t line_has_content)
Decide whether a glyph emission would overflow the right margin AND the current line already has cont...
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.
bool priv_reflow_layout_finish_page(reflow_t *engine, priv_cursor_t *cur)
Implementation of priv_reflow_layout_finish_page() – flush + reset cursor.
bool priv_reflow_layout_apply_image(reflow_t *engine, priv_cursor_t *cur, const reflow_token_t *tok)
Apply an <img> token: real image when a loader is bound, else a placeholder.
static bool internal_apply_image_placeholder(reflow_t *engine, priv_cursor_t *cur)
Apply an <img> token without a bound loader: placeholder advance.
static void internal_image_record(reflow_t *engine, priv_cursor_t *cur, const reflow_token_t *tok, int32_t bw, int32_t bh)
Record a laid-out image box and advance the cursor below it.
static void internal_image_fit(int32_t iw, int32_t ih, int32_t col_w, int32_t avail_h, int32_t *out_w, int32_t *out_h)
Scale an intrinsic image size to fit the text column (no upscaling).
static bool internal_place_image(reflow_t *engine, priv_cursor_t *cur, const reflow_token_t *tok)
Lay out a real <img> as a block: size it, page-break, record it.
static bool internal_image_resolve_size(reflow_t *engine, const reflow_token_t *tok, int32_t *out_w, int32_t *out_h)
Resolve an image token to a column-fitted box size via the loader.
static bool internal_page_has_content(const reflow_t *engine, const priv_cursor_t *cur)
True iff the page under construction already holds glyphs or images.
Cross-TU shared declarations for the reflow layout engine.
@ k_priv_image_placeholder_px
Side length of <img> placeholder.
@ k_reflow_max_images
Max laid-out <img> boxes.
@ k_reflow_paragraph_gap_px
Vertical gap after a block.
@ k_reflow_margin_px
Page edge inset, pixels.
Mutable state carried through the layout loop.
uint32_t page_first_image
First image-box index of the active page.
uint8_t line_has_content
1 once any glyph landed on this line.
int32_t line_top
Pixel row of the current line's top.
uint32_t page_first_glyph
First glyph index of the active page.
int32_t x
Pixel column for next glyph.
uint16_t line_height_px
Active line height in pixels.
int32_t y
Pixel row baseline for next glyph.
uint16_t indent_px
Active left indent (li, blockquote).
One laid-out <img> rectangle (decoded + blitted at render time).
uint32_t src_len
Href slice length, bytes.
int32_t y
Page-local top edge, pixels.
int32_t x
Page-local left edge, pixels.
uint32_t page_index
Page this image belongs to.
uint32_t reserved
Padding to 32-byte stride.
int32_t w
Scaled box width, pixels.
uint32_t src_off
Href slice offset into text pool.
int32_t h
Scaled box height, pixels.
Reflow / pagination engine state.
uint32_t page_count
Pages used.
reflow_image_loader_fn img_loader
<img> byte loader (NULL = off).
ra8_img_arena_t * img_arena
Decode scratch (NULL = off).
uint32_t glyph_count
Glyphs used.
uint8_t text_pool[k_reflow_text_pool_bytes]
Text bytes.
void * img_loader_ctx
Opaque context for img_loader.
uint16_t viewport_w
Viewport width, pixels.
uint16_t viewport_h
Viewport height, pixels.
reflow_image_box_t image_boxes[k_reflow_max_images]
Laid-out images.
uint32_t image_box_count
Image boxes used.
One parsed token in the engine's token stream.
uint32_t text_off
Byte offset into the text pool.
uint32_t text_len
Byte length within the text pool.