File Coverage

src/pdfmake_render.c
Criterion Covered Total %
statement 0 183 0.0
branch 0 136 0.0
condition n/a
subroutine n/a
pod n/a
total 0 319 0.0


line stmt bran cond sub pod time code
1             /* pdfmake_render.c
2             *
3             * Render-context API stubs.
4             *
5             * The full software rasterizer (scanline fill, stroke flattening, AA, image
6             * blitting, etc.) has not been ported into this distribution yet. The
7             * companion source files for sub-systems that *are* implemented live in:
8             *
9             * src/pdfmake_render_path.c — pdfmake_path_* construction
10             * src/pdfmake_render_bezier.c — bezier flattening
11             * src/pdfmake_render_fill.c — fill / fill_preserve
12             * src/pdfmake_render_stroke.c — stroke / stroke_preserve
13             * src/pdfmake_render_clip.c — clip / reset_clip
14             *
15             * This file provides minimal stubs for every pdfmake_render_* symbol
16             * declared in include/pdfmake_render.h that doesn't already have an
17             * implementation elsewhere. The stubs:
18             *
19             * - allocate / free a zero-initialised pdfmake_render_ctx_t (so create
20             * and destroy round-trip safely);
21             * - record the most-recently set graphics-state field on the context
22             * where it makes sense (so future incremental work can replace stubs
23             * one at a time without breaking calling code);
24             * - no-op for path / blit / scan operations and return a non-OK code
25             * when the signature returns pdfmake_render_err_t.
26             *
27             * The point of these stubs is simply to make the bundle link cleanly so
28             * Perl can load Make.bundle under PERL_DL_NONLAZY=1 (which `make test`
29             * sets). No live test exercises this API today; when the rasterizer
30             * lands these stubs should be removed and replaced with real code.
31             */
32              
33             #include
34             #include
35             #include
36              
37             #include "pdfmake_render.h"
38              
39             /*============================================================================
40             * Render context lifecycle
41             *==========================================================================*/
42              
43 0           static pdfmake_render_ctx_t *render_ctx_alloc(int width, int height)
44             {
45 0           pdfmake_render_ctx_t *ctx = calloc(1, sizeof(*ctx));
46 0 0         if (!ctx) return NULL;
47 0           ctx->width = width > 0 ? width : 0;
48 0           ctx->height = height > 0 ? height : 0;
49 0           ctx->stride = ctx->width * (int)sizeof(uint32_t);
50             /* Identity CTM */
51 0           ctx->ctm = (pdfmake_matrix_t){1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
52 0           ctx->fill_color = (pdfmake_rgba_t){0.0, 0.0, 0.0, 1.0};
53 0           ctx->stroke_color = (pdfmake_rgba_t){0.0, 0.0, 0.0, 1.0};
54 0           ctx->fill_rule = PDFMAKE_FILL_NONZERO;
55 0           ctx->flatness = 1.0;
56 0           ctx->antialias = 2;
57 0           ctx->stroke_style.width = 1.0;
58 0           ctx->stroke_style.cap = PDFMAKE_CAP_BUTT;
59 0           ctx->stroke_style.join = PDFMAKE_JOIN_MITER;
60 0           ctx->stroke_style.miter_limit = 10.0;
61 0           return ctx;
62             }
63              
64 0           pdfmake_render_ctx_t *pdfmake_render_create(int width, int height)
65             {
66 0           pdfmake_render_ctx_t *ctx = render_ctx_alloc(width, height);
67 0 0         if (!ctx) return NULL;
68 0 0         if (ctx->width > 0 && ctx->height > 0) {
    0          
69 0           ctx->pixels = calloc((size_t)ctx->width * (size_t)ctx->height,
70             sizeof(uint32_t));
71 0 0         if (!ctx->pixels) {
72 0           free(ctx);
73 0           return NULL;
74             }
75 0           ctx->owns_buffer = 1;
76             }
77 0           return ctx;
78             }
79              
80 0           pdfmake_render_ctx_t *pdfmake_render_create_with_buffer(
81             uint32_t *pixels, int width, int height, int stride)
82             {
83 0           pdfmake_render_ctx_t *ctx = render_ctx_alloc(width, height);
84 0 0         if (!ctx) return NULL;
85 0           ctx->pixels = pixels;
86 0 0         ctx->stride = stride > 0 ? stride : ctx->stride;
87 0           ctx->owns_buffer = 0;
88 0           return ctx;
89             }
90              
91 0           void pdfmake_render_destroy(pdfmake_render_ctx_t *ctx)
92             {
93 0 0         if (!ctx) return;
94 0 0         if (ctx->owns_buffer && ctx->pixels) free(ctx->pixels);
    0          
95 0 0         if (ctx->clip_mask) free(ctx->clip_mask);
96 0 0         if (ctx->stroke_style.dash_array) free(ctx->stroke_style.dash_array);
97 0 0         if (ctx->gstate_stack) free(ctx->gstate_stack);
98 0           free(ctx);
99             }
100              
101             /*============================================================================
102             * Buffer ops
103             *==========================================================================*/
104              
105 0           static uint32_t rgba_to_argb(pdfmake_rgba_t c)
106             {
107 0 0         double a = c.a < 0 ? 0 : (c.a > 1 ? 1 : c.a);
    0          
108 0 0         double r = c.r < 0 ? 0 : (c.r > 1 ? 1 : c.r);
    0          
109 0 0         double g = c.g < 0 ? 0 : (c.g > 1 ? 1 : c.g);
    0          
110 0 0         double b = c.b < 0 ? 0 : (c.b > 1 ? 1 : c.b);
    0          
111 0           return ((uint32_t)(a * 255.0 + 0.5) << 24)
112 0           | ((uint32_t)(r * 255.0 + 0.5) << 16)
113 0           | ((uint32_t)(g * 255.0 + 0.5) << 8)
114 0           | (uint32_t)(b * 255.0 + 0.5);
115             }
116              
117 0           void pdfmake_render_clear(pdfmake_render_ctx_t *ctx, pdfmake_rgba_t color)
118             {
119             uint32_t packed;
120             size_t total;
121             size_t i;
122 0 0         if (!ctx || !ctx->pixels) return;
    0          
123 0           packed = rgba_to_argb(color);
124 0           total = (size_t)ctx->width * (size_t)ctx->height;
125 0 0         for (i = 0; i < total; i++) ctx->pixels[i] = packed;
126             }
127              
128 0           uint32_t pdfmake_render_get_pixel(pdfmake_render_ctx_t *ctx, int x, int y)
129             {
130 0 0         if (!ctx || !ctx->pixels) return 0;
    0          
131 0 0         if (x < 0 || y < 0 || x >= ctx->width || y >= ctx->height) return 0;
    0          
    0          
    0          
132 0           return ctx->pixels[(size_t)y * (size_t)ctx->width + (size_t)x];
133             }
134              
135             /*============================================================================
136             * Graphics-state stack (save / restore)
137             *==========================================================================*/
138              
139 0           pdfmake_render_err_t pdfmake_render_save(pdfmake_render_ctx_t *ctx)
140             {
141             pdfmake_gstate_t *g;
142 0 0         if (!ctx) return PDFMAKE_RENDER_ERR_NULL;
143 0 0         if (ctx->gstate_depth >= ctx->gstate_max) {
144 0 0         int new_max = ctx->gstate_max ? ctx->gstate_max * 2 : 8;
145 0           pdfmake_gstate_t *grown = realloc(ctx->gstate_stack,
146 0           (size_t)new_max * sizeof(*grown));
147 0 0         if (!grown) return PDFMAKE_RENDER_ERR_MEMORY;
148 0           ctx->gstate_stack = grown;
149 0           ctx->gstate_max = new_max;
150             }
151 0           g = &ctx->gstate_stack[ctx->gstate_depth++];
152 0           g->ctm = ctx->ctm;
153 0           g->fill_color = ctx->fill_color;
154 0           g->stroke_color = ctx->stroke_color;
155 0           g->stroke_style = ctx->stroke_style;
156 0           g->fill_rule = ctx->fill_rule;
157 0           g->clip_mask = NULL; /* shallow snapshot only */
158 0           g->has_clip = ctx->has_clip;
159 0           g->flatness = ctx->flatness;
160 0           return PDFMAKE_RENDER_OK;
161             }
162              
163 0           pdfmake_render_err_t pdfmake_render_restore(pdfmake_render_ctx_t *ctx)
164             {
165             pdfmake_gstate_t *g;
166 0 0         if (!ctx) return PDFMAKE_RENDER_ERR_NULL;
167 0 0         if (ctx->gstate_depth <= 0) return PDFMAKE_RENDER_ERR_INVALID;
168 0           g = &ctx->gstate_stack[--ctx->gstate_depth];
169 0           ctx->ctm = g->ctm;
170 0           ctx->fill_color = g->fill_color;
171 0           ctx->stroke_color = g->stroke_color;
172 0           ctx->stroke_style = g->stroke_style;
173 0           ctx->fill_rule = g->fill_rule;
174 0           ctx->has_clip = g->has_clip;
175 0           ctx->flatness = g->flatness;
176 0           return PDFMAKE_RENDER_OK;
177             }
178              
179             /*============================================================================
180             * Graphics-state setters
181             *==========================================================================*/
182              
183 0           void pdfmake_render_set_fill_color(pdfmake_render_ctx_t *ctx,
184             double r, double g, double b, double a)
185             {
186 0 0         if (!ctx) return;
187 0           ctx->fill_color = (pdfmake_rgba_t){r, g, b, a};
188             }
189              
190 0           void pdfmake_render_set_stroke_color(pdfmake_render_ctx_t *ctx,
191             double r, double g, double b, double a)
192             {
193 0 0         if (!ctx) return;
194 0           ctx->stroke_color = (pdfmake_rgba_t){r, g, b, a};
195             }
196              
197 0           void pdfmake_render_set_line_width(pdfmake_render_ctx_t *ctx, double width)
198             {
199 0 0         if (!ctx) return;
200 0           ctx->stroke_style.width = width;
201             }
202              
203 0           void pdfmake_render_set_line_cap(pdfmake_render_ctx_t *ctx,
204             pdfmake_line_cap_t cap)
205             {
206 0 0         if (!ctx) return;
207 0           ctx->stroke_style.cap = cap;
208             }
209              
210 0           void pdfmake_render_set_line_join(pdfmake_render_ctx_t *ctx,
211             pdfmake_line_join_t join)
212             {
213 0 0         if (!ctx) return;
214 0           ctx->stroke_style.join = join;
215             }
216              
217 0           void pdfmake_render_set_miter_limit(pdfmake_render_ctx_t *ctx, double limit)
218             {
219 0 0         if (!ctx) return;
220 0           ctx->stroke_style.miter_limit = limit;
221             }
222              
223 0           pdfmake_render_err_t pdfmake_render_set_dash(pdfmake_render_ctx_t *ctx,
224             double *array, size_t count,
225             double phase)
226             {
227 0 0         if (!ctx) return PDFMAKE_RENDER_ERR_NULL;
228 0 0         if (ctx->stroke_style.dash_array) {
229 0           free(ctx->stroke_style.dash_array);
230 0           ctx->stroke_style.dash_array = NULL;
231 0           ctx->stroke_style.dash_count = 0;
232             }
233 0 0         if (array && count > 0) {
    0          
234 0           double *copy = malloc(count * sizeof(double));
235 0 0         if (!copy) return PDFMAKE_RENDER_ERR_MEMORY;
236 0           memcpy(copy, array, count * sizeof(double));
237 0           ctx->stroke_style.dash_array = copy;
238 0           ctx->stroke_style.dash_count = count;
239             }
240 0           ctx->stroke_style.dash_phase = phase;
241 0           return PDFMAKE_RENDER_OK;
242             }
243              
244 0           void pdfmake_render_set_fill_rule(pdfmake_render_ctx_t *ctx,
245             pdfmake_fill_rule_t rule)
246             {
247 0 0         if (!ctx) return;
248 0           ctx->fill_rule = rule;
249             }
250              
251 0           void pdfmake_render_set_flatness(pdfmake_render_ctx_t *ctx, double flatness)
252             {
253 0 0         if (!ctx) return;
254 0 0         ctx->flatness = flatness > 0 ? flatness : 1.0;
255             }
256              
257             /*============================================================================
258             * Transformations
259             *
260             * NOTE: pdfmake_matrix_identity / multiply / transform_point / invert are
261             * already provided by src/pdfmake_interpreter.c (with a different ABI —
262             * double[6] arrays — declared in pdfmake_interpreter.h). We deliberately
263             * do NOT redefine them here; instead the context helpers below operate
264             * directly on the pdfmake_matrix_t struct fields to avoid linker
265             * collisions.
266             *==========================================================================*/
267              
268 0           static pdfmake_matrix_t matrix_mul_struct(pdfmake_matrix_t a,
269             pdfmake_matrix_t b)
270             {
271             pdfmake_matrix_t r;
272 0           r.a = a.a * b.a + a.b * b.c;
273 0           r.b = a.a * b.b + a.b * b.d;
274 0           r.c = a.c * b.a + a.d * b.c;
275 0           r.d = a.c * b.b + a.d * b.d;
276 0           r.e = a.e * b.a + a.f * b.c + b.e;
277 0           r.f = a.e * b.b + a.f * b.d + b.f;
278 0           return r;
279             }
280              
281 0           void pdfmake_render_set_matrix(pdfmake_render_ctx_t *ctx, pdfmake_matrix_t *m)
282             {
283 0 0         if (!ctx || !m) return;
    0          
284 0           ctx->ctm = *m;
285             }
286              
287 0           void pdfmake_render_concat_matrix(pdfmake_render_ctx_t *ctx,
288             pdfmake_matrix_t *m)
289             {
290 0 0         if (!ctx || !m) return;
    0          
291 0           ctx->ctm = matrix_mul_struct(*m, ctx->ctm);
292             }
293              
294 0           void pdfmake_render_translate(pdfmake_render_ctx_t *ctx,
295             double tx, double ty)
296             {
297             pdfmake_matrix_t t;
298 0 0         if (!ctx) return;
299 0           t.a = 1.0; t.b = 0.0; t.c = 0.0; t.d = 1.0; t.e = tx; t.f = ty;
300 0           ctx->ctm = matrix_mul_struct(t, ctx->ctm);
301             }
302              
303 0           void pdfmake_render_scale(pdfmake_render_ctx_t *ctx, double sx, double sy)
304             {
305             pdfmake_matrix_t s;
306 0 0         if (!ctx) return;
307 0           s.a = sx; s.b = 0.0; s.c = 0.0; s.d = sy; s.e = 0.0; s.f = 0.0;
308 0           ctx->ctm = matrix_mul_struct(s, ctx->ctm);
309             }
310              
311 0           void pdfmake_render_rotate(pdfmake_render_ctx_t *ctx, double angle)
312             {
313             double c, s;
314             pdfmake_matrix_t r;
315 0 0         if (!ctx) return;
316 0           c = cos(angle); s = sin(angle);
317 0           r.a = c; r.b = s; r.c = -s; r.d = c; r.e = 0.0; r.f = 0.0;
318 0           ctx->ctm = matrix_mul_struct(r, ctx->ctm);
319             }
320              
321             /*============================================================================
322             * Context-level path helpers
323             *
324             * These wrap the pdfmake_path_* construction API onto the context's
325             * current path. They are real, working implementations.
326             *==========================================================================*/
327              
328 0           static pdfmake_render_err_t ensure_path(pdfmake_render_ctx_t *ctx)
329             {
330 0 0         if (!ctx) return PDFMAKE_RENDER_ERR_NULL;
331 0 0         if (!ctx->path) {
332 0           ctx->path = pdfmake_path_create();
333 0 0         if (!ctx->path) return PDFMAKE_RENDER_ERR_MEMORY;
334             }
335 0           return PDFMAKE_RENDER_OK;
336             }
337              
338 0           pdfmake_render_err_t pdfmake_render_move_to(pdfmake_render_ctx_t *ctx,
339             double x, double y)
340             {
341 0           pdfmake_render_err_t e = ensure_path(ctx);
342 0 0         if (e != PDFMAKE_RENDER_OK) return e;
343 0           return pdfmake_path_move_to(ctx->path, x, y);
344             }
345              
346 0           pdfmake_render_err_t pdfmake_render_line_to(pdfmake_render_ctx_t *ctx,
347             double x, double y)
348             {
349 0           pdfmake_render_err_t e = ensure_path(ctx);
350 0 0         if (e != PDFMAKE_RENDER_OK) return e;
351 0           return pdfmake_path_line_to(ctx->path, x, y);
352             }
353              
354 0           pdfmake_render_err_t pdfmake_render_curve_to(pdfmake_render_ctx_t *ctx,
355             double x1, double y1, double x2, double y2, double x3, double y3)
356             {
357 0           pdfmake_render_err_t e = ensure_path(ctx);
358 0 0         if (e != PDFMAKE_RENDER_OK) return e;
359 0           return pdfmake_path_curve_to(ctx->path, x1, y1, x2, y2, x3, y3);
360             }
361              
362 0           pdfmake_render_err_t pdfmake_render_close_path(pdfmake_render_ctx_t *ctx)
363             {
364 0 0         if (!ctx || !ctx->path) return PDFMAKE_RENDER_ERR_NULL;
    0          
365 0           return pdfmake_path_close(ctx->path);
366             }
367              
368 0           pdfmake_render_err_t pdfmake_render_rect(pdfmake_render_ctx_t *ctx,
369             double x, double y,
370             double w, double h)
371             {
372 0           pdfmake_render_err_t e = ensure_path(ctx);
373 0 0         if (e != PDFMAKE_RENDER_OK) return e;
374 0           return pdfmake_path_rect(ctx->path, x, y, w, h);
375             }
376              
377 0           void pdfmake_render_new_path(pdfmake_render_ctx_t *ctx)
378             {
379 0 0         if (!ctx) return;
380 0 0         if (ctx->path) pdfmake_path_clear(ctx->path);
381             }