/src/libwebsockets/lib/misc/dlo/dlo.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * lws abstract display |
3 | | * |
4 | | * Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com> |
5 | | * |
6 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
7 | | * of this software and associated documentation files (the "Software"), to |
8 | | * deal in the Software without restriction, including without limitation the |
9 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
10 | | * sell copies of the Software, and to permit persons to whom the Software is |
11 | | * furnished to do so, subject to the following conditions: |
12 | | * |
13 | | * The above copyright notice and this permission notice shall be included in |
14 | | * all copies or substantial portions of the Software. |
15 | | * |
16 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
17 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
18 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
19 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
20 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
21 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
22 | | * IN THE SOFTWARE. |
23 | | * |
24 | | * Display List Object handling |
25 | | */ |
26 | | |
27 | | #include <private-lib-core.h> |
28 | | #include "private-lib-drivers-display-dlo.h" |
29 | | |
30 | 0 | #define dlodump_loglevel LLL_NOTICE |
31 | | #if (_LWS_ENABLED_LOGS & dlodump_loglevel) |
32 | 0 | #define lwsl_dlodump(...) _lws_log(dlodump_loglevel, __VA_ARGS__) |
33 | | #else |
34 | | #define lwsl_dlodump(...) |
35 | | #endif |
36 | | |
37 | | void |
38 | | lws_display_dl_init(lws_displaylist_t *dl, lws_display_state_t *ds) |
39 | 0 | { |
40 | 0 | lws_dll2_owner_clear(&dl->dl); |
41 | 0 | dl->ds = ds; |
42 | 0 | } |
43 | | |
44 | | int |
45 | | lws_display_dlo_add(lws_displaylist_t *dl, lws_dlo_t *dlo_parent, lws_dlo_t *dlo) |
46 | 0 | { |
47 | 0 | if (!dlo_parent && !dl->dl.head) { |
48 | 0 | lws_dll2_add_tail(&dlo->list, &dl->dl); |
49 | |
|
50 | 0 | return 0; |
51 | 0 | } |
52 | | |
53 | 0 | if (!dlo_parent) { |
54 | 0 | if (!dl->dl.head) |
55 | 0 | return 0; |
56 | | |
57 | 0 | dlo_parent = lws_container_of(dl->dl.head, lws_dlo_t, list); |
58 | 0 | } |
59 | | |
60 | 0 | lws_dll2_add_tail(&dlo->list, &dlo_parent->children); |
61 | |
|
62 | 0 | return 0; |
63 | 0 | } |
64 | | |
65 | | void |
66 | | lws_surface_set_px(const lws_surface_info_t *ic, uint8_t *line, int x, |
67 | | const lws_display_colour_t *c) |
68 | 0 | { |
69 | 0 | unsigned int alpha, ialpha; |
70 | 0 | lws_display_colour_t oc; |
71 | 0 | lws_display_colour_t y; |
72 | 0 | uint8_t rgb[3]; |
73 | |
|
74 | 0 | if (x < 0 || x >= ic->wh_px[0].whole) |
75 | 0 | return; |
76 | | |
77 | | /* |
78 | | * All alpha composition takes place at 8bpp grey or 24bpp |
79 | | */ |
80 | | |
81 | 0 | if (ic->greyscale) { |
82 | | |
83 | | /* line composition buffer is 8-bit Y per pixel */ |
84 | |
|
85 | 0 | oc = line[x]; |
86 | 0 | alpha = LWSDC_ALPHA(*c); |
87 | 0 | ialpha = 255 - alpha; |
88 | |
|
89 | 0 | y = RGB_TO_Y(LWSDC_R(*c), LWSDC_G(*c), LWSDC_B(*c)); |
90 | |
|
91 | 0 | line[x] = (uint8_t)(((y * alpha) / 255) + |
92 | 0 | ((LWSDC_R(oc) * ialpha) / 255)); |
93 | 0 | return; |
94 | 0 | } |
95 | | |
96 | | /* line composition buffer is 24-bit RGB per pixel */ |
97 | | |
98 | 0 | line += (ic->render_to_rgba ? 4 : 3) * x; |
99 | |
|
100 | 0 | alpha = LWSDC_ALPHA(*c); |
101 | 0 | ialpha = 255 - alpha; |
102 | |
|
103 | 0 | rgb[0] = (uint8_t)(((LWSDC_R(*c) * alpha) / 255) + |
104 | 0 | ((line[0] * ialpha) / 255)); |
105 | 0 | rgb[1] = (uint8_t)(((LWSDC_G(*c) * alpha) / 255) + |
106 | 0 | ((line[1] * ialpha) / 255)); |
107 | 0 | rgb[2] = (uint8_t)(((LWSDC_B(*c) * alpha) / 255) + |
108 | 0 | ((line[2] * ialpha) / 255)); |
109 | |
|
110 | 0 | *line++ = rgb[0]; |
111 | 0 | *line++ = rgb[1]; |
112 | 0 | *line++ = rgb[2]; |
113 | |
|
114 | 0 | if (ic->render_to_rgba) |
115 | 0 | *line = 0xff; |
116 | 0 | } |
117 | | |
118 | | /* |
119 | | * Recursively find out the total width and height of the contents of a DLO |
120 | | */ |
121 | | |
122 | | void |
123 | | lws_dlo_contents(lws_dlo_t *parent, lws_dlo_dim_t *dim) |
124 | 0 | { |
125 | 0 | lws_display_render_stack_t st[12]; /* DLO child stack */ |
126 | 0 | lws_dll2_t *d; |
127 | 0 | lws_fx_t t1; |
128 | 0 | int sp = 0; |
129 | |
|
130 | 0 | dim->w.whole = 0; |
131 | 0 | dim->w.frac = 0; |
132 | 0 | dim->h.whole = 0; |
133 | 0 | dim->h.frac = 0; |
134 | |
|
135 | 0 | if (!parent) |
136 | 0 | return; |
137 | | |
138 | 0 | d = lws_dll2_get_head(&parent->children); |
139 | 0 | if (!d) |
140 | 0 | return; |
141 | | |
142 | 0 | memset(&st, 0, sizeof(st)); |
143 | 0 | st[0].dlo = lws_container_of(d, lws_dlo_t, list); |
144 | 0 | st[0].co.w.whole = 0; |
145 | 0 | st[0].co.w.frac = 0; |
146 | 0 | st[0].co.h.whole = 0; |
147 | 0 | st[0].co.h.frac = 0; |
148 | | |
149 | | /* We are collecting worst dlo->box.x + dlo->box.w and .y + .h */ |
150 | |
|
151 | 0 | while (sp || st[0].dlo) { |
152 | 0 | lws_dlo_t *dlo = st[sp].dlo; |
153 | |
|
154 | 0 | if (!dlo) { |
155 | 0 | if (!sp) { |
156 | 0 | lwsl_err("%s: underflow\n", __func__); |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | 0 | if (lws_fx_comp(&st[sp].co.w, &st[sp - 1].co.w) > 0) |
161 | 0 | st[sp - 1].co.w = st[sp].co.w; |
162 | |
|
163 | 0 | if (lws_fx_comp(&st[sp].co.h, &st[sp - 1].co.h) > 0) |
164 | 0 | st[sp - 1].co.h = st[sp].co.h; |
165 | | |
166 | | // lwsl_notice("sp %d: passing back w: %d, h: %d\n", sp, st[sp - 1].co.w.whole, st[sp - 1].co.h.whole); |
167 | |
|
168 | 0 | sp--; |
169 | |
|
170 | 0 | continue; |
171 | 0 | } |
172 | | |
173 | 0 | lws_fx_add(&t1, &dlo->box.w, &dlo->box.x); |
174 | | // lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_LEFT]); |
175 | 0 | lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_LEFT]); |
176 | | // lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_RIGHT]); |
177 | | // lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_RIGHT]); |
178 | 0 | if (lws_fx_comp(&t1, &st[sp].co.w) > 0) |
179 | 0 | st[sp].co.w = t1; |
180 | |
|
181 | 0 | lws_fx_add(&t1, &dlo->box.h, &dlo->box.y); |
182 | | // lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_TOP]); |
183 | 0 | lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_TOP]); |
184 | | // lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_BOTTOM]); |
185 | | // lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_BOTTOM]); |
186 | 0 | if (lws_fx_comp(&t1, &st[sp].co.h) > 0) |
187 | 0 | st[sp].co.h = t1; |
188 | |
|
189 | 0 | d = dlo->list.next; |
190 | 0 | if (d) |
191 | 0 | st[sp].dlo = lws_container_of(d, lws_dlo_t, list); |
192 | 0 | else |
193 | 0 | st[sp].dlo = NULL; |
194 | | |
195 | | /* go into any children */ |
196 | |
|
197 | 0 | if (dlo->children.head) { |
198 | 0 | if (++sp == LWS_ARRAY_SIZE(st)) { |
199 | 0 | lwsl_err("%s: DLO stack overflow\n", __func__); |
200 | 0 | return; |
201 | 0 | } |
202 | 0 | st[sp].dlo = lws_container_of( |
203 | 0 | dlo->children.head, lws_dlo_t, list); |
204 | 0 | st[sp].co.w.whole = 0; |
205 | 0 | st[sp].co.h.whole = 0; |
206 | 0 | st[sp].co.w.frac = 0; |
207 | 0 | st[sp].co.h.frac = 0; |
208 | 0 | } |
209 | 0 | } |
210 | | |
211 | 0 | dim->w = st[0].co.w; |
212 | 0 | dim->h = st[0].co.h; |
213 | |
|
214 | 0 | if (parent->col_list.owner) { |
215 | 0 | lhp_table_col_t *tc = lws_container_of(parent->col_list.owner, |
216 | 0 | lhp_table_col_t, col_dlos); |
217 | |
|
218 | 0 | if (lws_fx_comp(&dim->w, &tc->width) < 0) { |
219 | | // lws_fx_add(&t1, &tc->width, &parent->padding[CCPAS_LEFT]); |
220 | | // lws_fx_add(&dim->w, &tc->width, &parent->padding[CCPAS_RIGHT]); |
221 | 0 | dim->w = tc->width; |
222 | 0 | } |
223 | 0 | } |
224 | |
|
225 | 0 | if (parent->row_list.owner) { |
226 | 0 | lhp_table_row_t *tr = lws_container_of(parent->row_list.owner, |
227 | 0 | lhp_table_row_t, row_dlos); |
228 | |
|
229 | 0 | if (lws_fx_comp(&dim->h, &tr->height) < 0) { |
230 | | // lws_fx_add(&t1, &tr->height, &parent->padding[CCPAS_TOP]); |
231 | 0 | lws_fx_add(&dim->h, &tr->height, &parent->padding[CCPAS_BOTTOM]); |
232 | | // dim->h = tr->height; |
233 | 0 | } |
234 | 0 | } |
235 | | |
236 | | /* |
237 | | lwsl_user("%s: dlo %p: FINAL w:%d -> %d h:%d -> %d\n", __func__, parent, |
238 | | parent->box.w.whole, dim->w.whole, |
239 | | parent->box.h.whole, dim->h.whole); |
240 | | */ |
241 | 0 | } |
242 | | |
243 | | /* |
244 | | * Some DLO is changing height, adjust its height, and that of everybody below. |
245 | | */ |
246 | | |
247 | | void |
248 | | lws_display_dlo_adjust_dims(lws_dlo_t *dlo, lws_dlo_dim_t *dim) |
249 | 0 | { |
250 | 0 | lws_dlo_dim_t delta; |
251 | |
|
252 | 0 | if (!dim->w.whole && !dim->h.whole) |
253 | 0 | return; |
254 | | |
255 | | /* adjust the target's width / height */ |
256 | | |
257 | 0 | lws_fx_sub(&delta.w, &dim->w, &dlo->box.w); |
258 | 0 | lws_fx_sub(&delta.h, &dim->h, &dlo->box.h); |
259 | |
|
260 | 0 | dlo->box.w = dim->w; |
261 | 0 | dlo->box.h = dim->h; |
262 | | |
263 | | // lwsl_notice("%s: dlo %p: delta w:%d h:%d\n", __func__, dlo, delta.w.whole, delta.h.whole); |
264 | | |
265 | | /* move peers below him accordingly */ |
266 | |
|
267 | 0 | do { |
268 | 0 | lws_dlo_t *dp = lws_container_of(dlo->list.owner, lws_dlo_t, children); |
269 | |
|
270 | 0 | if (!dlo->list.owner) |
271 | 0 | break; |
272 | | |
273 | | /* |
274 | | * Adjust y pos of siblings below us |
275 | | */ |
276 | | |
277 | 0 | do { |
278 | 0 | dlo = lws_container_of(dlo->list.next, lws_dlo_t, list); |
279 | 0 | if (dlo) { |
280 | | //lwsl_notice("%s: dlo %p: adj y %d -> %d\n", __func__, dlo, dlo->box.y.whole, dlo->box.y.whole + delta.h.whole); |
281 | 0 | lws_fx_add(&dlo->box.y, &dlo->box.y, &delta.h); |
282 | 0 | } |
283 | 0 | } while (dlo); |
284 | | |
285 | | |
286 | | /* go up parent chain until toplevel adjusting height of |
287 | | * parent siblings below parent */ |
288 | |
|
289 | 0 | if (dp->flag_toplevel) |
290 | 0 | break; |
291 | | |
292 | 0 | dlo = dp; |
293 | | //lwsl_notice("%s: dlo %p: adj h by %d\n", __func__, dlo, delta.h.whole); |
294 | 0 | lws_fx_add(&dlo->box.h, &dlo->box.h, &delta.h); |
295 | 0 | } while (1); |
296 | 0 | } |
297 | | |
298 | | //#if defined(_DEBUG) |
299 | | void |
300 | | lws_display_dl_dump(lws_displaylist_t *dl) |
301 | 0 | { |
302 | 0 | lws_display_render_stack_t st[12]; /* DLO child stack */ |
303 | 0 | int sp = 0; |
304 | 0 | lws_dll2_t *d = lws_dll2_get_head(&dl->dl); |
305 | 0 | #if (_LWS_ENABLED_LOGS & dlodump_loglevel) |
306 | 0 | static const char * const ind = " "; |
307 | 0 | #endif |
308 | 0 | char b[4][22], b1[4][22], dt[96]; |
309 | |
|
310 | 0 | if (!d) { |
311 | 0 | lwsl_notice("%s: empty dl\n", __func__); |
312 | |
|
313 | 0 | return; |
314 | 0 | } |
315 | | |
316 | 0 | lwsl_notice("%s\n", __func__); |
317 | |
|
318 | 0 | memset(&st, 0, sizeof(st)); |
319 | 0 | st[0].dlo = lws_container_of(d, lws_dlo_t, list); |
320 | |
|
321 | 0 | while (sp || st[0].dlo) { |
322 | 0 | lws_dlo_t *dlo = st[sp].dlo; |
323 | 0 | lws_box_t co; |
324 | | //lws_fx_t t2; |
325 | |
|
326 | 0 | if (!dlo) { |
327 | 0 | if (!sp) { |
328 | 0 | lwsl_err("%s: underflow\n", __func__); |
329 | 0 | return; |
330 | 0 | } |
331 | 0 | sp--; |
332 | 0 | continue; |
333 | 0 | } |
334 | | |
335 | 0 | lws_fx_add(&co.x, &st[sp].co.x, &dlo->box.x); |
336 | 0 | lws_fx_add(&co.y, &st[sp].co.y, &dlo->box.y); |
337 | 0 | co.w = dlo->box.w; |
338 | 0 | co.h = dlo->box.h; |
339 | |
|
340 | 0 | lws_snprintf(dt, sizeof(dt), "rect: RGBA 0x%08X", (unsigned int)dlo->dc); |
341 | 0 | if (dlo->_destroy == lws_display_dlo_text_destroy) { |
342 | 0 | lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo); |
343 | 0 | lws_snprintf(dt, sizeof(dt), "text: RGBA 0x%08X, chars: %u, %.*s", |
344 | 0 | (unsigned int)dlo->dc, (unsigned int)text->text_len, |
345 | 0 | (int)text->text_len, text->text ? text->text : "(empty)"); |
346 | 0 | } |
347 | 0 | #if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_UPNG) && defined(LWS_WITH_CLIENT) |
348 | 0 | else if (dlo->_destroy == lws_display_dlo_png_destroy) |
349 | 0 | lws_snprintf(dt, sizeof(dt), "png"); |
350 | 0 | #endif |
351 | 0 | #if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_JPEG) && defined(LWS_WITH_CLIENT) |
352 | 0 | else if (dlo->_destroy == lws_display_dlo_jpeg_destroy) |
353 | 0 | lws_snprintf(dt, sizeof(dt), "jpeg"); |
354 | 0 | #endif |
355 | |
|
356 | 0 | lws_fx_string(&dlo->box.x, b[0], sizeof(b[0])); |
357 | 0 | lws_fx_string(&dlo->box.y, b[1], sizeof(b[1])); |
358 | 0 | lws_fx_string(&dlo->box.w, b[2], sizeof(b[2])); |
359 | 0 | lws_fx_string(&dlo->box.h, b[3], sizeof(b[3])); |
360 | 0 | lws_fx_string(&co.x, b1[0], sizeof(b1[0])); |
361 | 0 | lws_fx_string(&co.y, b1[1], sizeof(b1[1])); |
362 | 0 | lws_fx_string(&co.w, b1[2], sizeof(b1[2])); |
363 | 0 | lws_fx_string(&co.h, b1[3], sizeof(b1[3])); |
364 | |
|
365 | 0 | lwsl_dlodump("%.*s %p box: (%s, %s) [%s x %s], co: (%s, %s) [%s x %s], %s\n", |
366 | 0 | sp, ind, dlo, b[0], b[1], b[2], b[3], |
367 | 0 | b1[0], b1[1], b1[2], b1[3], dt); |
368 | |
|
369 | 0 | d = dlo->list.next; |
370 | 0 | if (d) |
371 | 0 | st[sp].dlo = lws_container_of(d, lws_dlo_t, list); |
372 | 0 | else |
373 | 0 | st[sp].dlo = NULL; |
374 | | |
375 | | /* go into any children */ |
376 | |
|
377 | 0 | if (dlo->children.head) { |
378 | 0 | if (sp + 1 == LWS_ARRAY_SIZE(st)) { |
379 | 0 | lwsl_err("%s: DLO stack overflow\n", __func__); |
380 | 0 | return; |
381 | 0 | } |
382 | 0 | st[++sp].dlo = lws_container_of( |
383 | 0 | dlo->children.head, lws_dlo_t, list); |
384 | 0 | st[sp].co = co; |
385 | 0 | } |
386 | |
|
387 | 0 | } |
388 | 0 | } |
389 | | //#endif |
390 | | |
391 | | /* |
392 | | * Go through every DLO once, setting its id->box to the final layout for the |
393 | | * related dlo, if any |
394 | | */ |
395 | | |
396 | | lws_stateful_ret_t |
397 | | lws_display_get_ids_boxes(lws_display_render_state_t *rs) |
398 | 0 | { |
399 | 0 | lws_dll2_t *d; |
400 | |
|
401 | 0 | rs->lowest_id_y = 0; |
402 | |
|
403 | 0 | d = lws_dll2_get_head(&rs->displaylist.dl); |
404 | 0 | if (!d) |
405 | | /* nothing in dlo */ |
406 | 0 | return LWS_SRET_OK; |
407 | | |
408 | 0 | memset(&rs->st[0].co, 0, sizeof(rs->st[0].co)); |
409 | 0 | rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list); |
410 | |
|
411 | 0 | while (rs->sp || rs->st[0].dlo) { |
412 | 0 | lws_dlo_t *dlo = rs->st[rs->sp].dlo; |
413 | 0 | lws_box_t co; |
414 | 0 | lws_fx_t t2; |
415 | |
|
416 | 0 | if (!dlo) { |
417 | 0 | rs->sp--; |
418 | 0 | continue; |
419 | 0 | } |
420 | | |
421 | 0 | lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x); |
422 | 0 | lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y); |
423 | 0 | co.w = dlo->box.w; |
424 | 0 | co.h = dlo->box.h; |
425 | |
|
426 | 0 | lws_fx_add(&t2, &co.y, &dlo->box.h); |
427 | |
|
428 | 0 | if (dlo->id) { |
429 | 0 | lws_display_id_t *id = dlo->id; |
430 | |
|
431 | 0 | lwsl_debug("%s: set id box %s\n", __func__, id->id); |
432 | 0 | id->box = co; |
433 | 0 | dlo->id = NULL; /* decouple us */ |
434 | 0 | } |
435 | |
|
436 | 0 | if (co.y.whole + co.h.whole > rs->lowest_id_y) { |
437 | 0 | rs->lowest_id_y = (lws_display_scalar)(co.y.whole + co.h.whole); |
438 | 0 | if (rs->lowest_id_y > rs->ic->wh_px[1].whole) |
439 | 0 | rs->lowest_id_y = (lws_display_scalar)rs->ic->wh_px[1].whole; |
440 | 0 | } |
441 | | |
442 | | /* next sibling at this level if any */ |
443 | |
|
444 | 0 | d = dlo->list.next; |
445 | 0 | if (d) |
446 | 0 | rs->st[rs->sp].dlo = lws_container_of(d, |
447 | 0 | lws_dlo_t, list); |
448 | 0 | else |
449 | 0 | rs->st[rs->sp].dlo = NULL; |
450 | | |
451 | | /* go into any children */ |
452 | |
|
453 | 0 | if (dlo->children.head) { |
454 | 0 | if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) { |
455 | 0 | lwsl_err("%s: DLO stack overflow\n", |
456 | 0 | __func__); |
457 | 0 | return LWS_SRET_FATAL; |
458 | 0 | } |
459 | 0 | rs->st[++rs->sp].dlo = lws_container_of( |
460 | 0 | dlo->children.head, lws_dlo_t, list); |
461 | 0 | rs->st[rs->sp].co = co; |
462 | 0 | continue; |
463 | 0 | } |
464 | 0 | } |
465 | | |
466 | 0 | lws_display_render_dump_ids(&rs->ids); |
467 | |
|
468 | 0 | return LWS_SRET_OK; |
469 | 0 | } |
470 | | |
471 | | lws_stateful_ret_t |
472 | | lws_display_list_render_line(lws_display_render_state_t *rs) |
473 | 0 | { |
474 | 0 | lws_dll2_t *d; |
475 | |
|
476 | 0 | if (rs->html == 1) |
477 | 0 | return LWS_SRET_WANT_INPUT; |
478 | | |
479 | 0 | if (!rs->sp && !rs->st[0].dlo) { |
480 | | |
481 | | /* starting a line */ |
482 | |
|
483 | 0 | d = lws_dll2_get_head(&rs->displaylist.dl); |
484 | 0 | if (!d) |
485 | | /* nothing in dlo */ |
486 | 0 | return LWS_SRET_OK; |
487 | | |
488 | | // memset(rs->line, 0, (size_t)rs->ic->wh_px[0].whole * |
489 | | // (rs->ic->greyscale ? 1 : 3)); |
490 | 0 | memset(&rs->st[0].co, 0, sizeof(rs->st[0].co)); |
491 | 0 | rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list); |
492 | 0 | } |
493 | | |
494 | 0 | while (rs->sp || rs->st[0].dlo) { |
495 | 0 | lws_dlo_t *dlo = rs->st[rs->sp].dlo; |
496 | 0 | lws_stateful_ret_t r; |
497 | 0 | lws_box_t co; |
498 | 0 | lws_fx_t t2; |
499 | |
|
500 | 0 | if (!dlo) { |
501 | 0 | rs->sp--; |
502 | 0 | continue; |
503 | 0 | } |
504 | | |
505 | | // lwsl_notice("%s: curr %d: %d %d %d %d\n", __func__, rs->curr, dlo->box.x.whole, dlo->box.y.whole, dlo->box.w.whole, dlo->box.h.whole); |
506 | | |
507 | 0 | lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x); |
508 | 0 | lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y); |
509 | 0 | co.w = dlo->box.w; |
510 | 0 | co.h = dlo->box.h; |
511 | |
|
512 | 0 | lws_fx_add(&t2, &co.y, &dlo->box.h); |
513 | 0 | if (rs->curr > lws_fx_roundup(&t2)) { |
514 | 0 | d = dlo->list.next; |
515 | 0 | rs->st[rs->sp].dlo = d ? lws_container_of(d, lws_dlo_t, |
516 | 0 | list) : NULL; |
517 | |
|
518 | 0 | lws_display_dlo_destroy(&dlo); |
519 | 0 | continue; |
520 | 0 | } |
521 | | |
522 | | #if 0 |
523 | | if (dlo->_destroy == lws_display_dlo_png_destroy) |
524 | | lwsl_err("png line %d %d %d %d\n", rs->curr, co.y.whole - 1, |
525 | | rs->st[rs->sp].co.y.whole, dlo->box.y.whole); |
526 | | #endif |
527 | | |
528 | 0 | if (rs->curr >= co.y.whole - 1) { |
529 | |
|
530 | 0 | r = dlo->render(rs); |
531 | | //rs->ic, dlo, &rs->st[rs->sp].co, |
532 | | // rs->curr, rs->line, &dlo->nle[0]); |
533 | 0 | if (r) |
534 | 0 | return r; |
535 | | |
536 | | /* next sibling at this level if any */ |
537 | | |
538 | 0 | d = dlo->list.next; |
539 | 0 | if (d) |
540 | 0 | rs->st[rs->sp].dlo = lws_container_of(d, |
541 | 0 | lws_dlo_t, list); |
542 | 0 | else |
543 | 0 | rs->st[rs->sp].dlo = NULL; |
544 | | |
545 | | /* go into any children */ |
546 | |
|
547 | 0 | if (dlo->children.head) { |
548 | 0 | if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) { |
549 | 0 | lwsl_err("%s: DLO stack overflow\n", |
550 | 0 | __func__); |
551 | 0 | return LWS_SRET_FATAL; |
552 | 0 | } |
553 | 0 | rs->st[++rs->sp].dlo = lws_container_of( |
554 | 0 | dlo->children.head, lws_dlo_t, list); |
555 | 0 | rs->st[rs->sp].co = co; |
556 | 0 | continue; |
557 | 0 | } |
558 | 0 | } else { |
559 | | /* next sibling at this level if any */ |
560 | |
|
561 | 0 | d = dlo->list.next; |
562 | 0 | if (d) |
563 | 0 | rs->st[rs->sp].dlo = lws_container_of(d, |
564 | 0 | lws_dlo_t, list); |
565 | 0 | else |
566 | 0 | rs->st[rs->sp].dlo = NULL; |
567 | 0 | } |
568 | 0 | } |
569 | | |
570 | 0 | return LWS_SRET_OK; |
571 | 0 | } |
572 | | |
573 | | static int |
574 | | dlo_clean_table_rows(lws_dll2_t *d, void *user) |
575 | 0 | { |
576 | 0 | lhp_table_row_t *r = lws_container_of(d, lhp_table_row_t, list); |
577 | |
|
578 | 0 | lws_dll2_remove(d); |
579 | 0 | lws_free(r); |
580 | |
|
581 | 0 | return 0; |
582 | 0 | } |
583 | | |
584 | | static int |
585 | | dlo_clean_table_cols(lws_dll2_t *d, void *user) |
586 | 0 | { |
587 | 0 | lhp_table_col_t *c = lws_container_of(d, lhp_table_col_t, list); |
588 | |
|
589 | 0 | lws_dll2_remove(d); |
590 | 0 | lws_free(c); |
591 | |
|
592 | 0 | return 0; |
593 | 0 | } |
594 | | |
595 | | void |
596 | | lws_display_dlo_destroy(lws_dlo_t **r) |
597 | 0 | { |
598 | 0 | if (!(*r)) |
599 | 0 | return; |
600 | | |
601 | 0 | lws_dll2_remove(&(*r)->list); |
602 | 0 | lws_dll2_remove(&(*r)->col_list); |
603 | 0 | lws_dll2_remove(&(*r)->row_list); |
604 | |
|
605 | 0 | while ((*r)->children.head) { |
606 | 0 | lws_dlo_t *d = lws_container_of((*r)->children.head, |
607 | 0 | lws_dlo_t, list); |
608 | |
|
609 | 0 | lws_display_dlo_destroy(&d); |
610 | 0 | } |
611 | |
|
612 | 0 | lws_dll2_foreach_safe(&(*r)->table_cols, NULL, dlo_clean_table_cols); |
613 | 0 | lws_dll2_foreach_safe(&(*r)->table_rows, NULL, dlo_clean_table_rows); |
614 | |
|
615 | 0 | if ((*r)->_destroy) |
616 | 0 | (*r)->_destroy(*r); |
617 | |
|
618 | 0 | lws_free_set_NULL(*r); |
619 | 0 | *r = NULL; |
620 | 0 | } |
621 | | |
622 | | void |
623 | | lws_display_list_destroy(lws_displaylist_t *dl) |
624 | 0 | { |
625 | 0 | if (!dl) |
626 | 0 | return; |
627 | | |
628 | 0 | while (dl->dl.head) { |
629 | 0 | lws_dlo_t *d = lws_container_of(dl->dl.head, lws_dlo_t, list); |
630 | |
|
631 | 0 | lws_display_dlo_destroy(&d); |
632 | 0 | } |
633 | 0 | } |
634 | | |
635 | | lws_dlo_filesystem_t * |
636 | | lws_dlo_file_register(struct lws_context *cx, const lws_dlo_filesystem_t *f) |
637 | 0 | { |
638 | 0 | const lws_dlo_filesystem_t *b; |
639 | 0 | lws_dlo_filesystem_t *a; |
640 | |
|
641 | 0 | b = lws_dlo_file_choose(cx, f->name); |
642 | |
|
643 | 0 | if (b) { |
644 | 0 | lwsl_err("%s: dlo file %s already exists %p\n", __func__, b->name, b); |
645 | 0 | lws_dlo_file_unregister((lws_dlo_filesystem_t **)&b); |
646 | 0 | } |
647 | |
|
648 | 0 | a = lws_malloc(sizeof(*a), __func__); |
649 | 0 | if (!a) |
650 | 0 | return NULL; |
651 | | |
652 | 0 | *a = *f; |
653 | 0 | lws_dll2_clear(&a->list); |
654 | 0 | lws_dll2_add_tail(&a->list, &cx->dlo_file); |
655 | |
|
656 | 0 | lwsl_err("%s: dlo file %s registered at %p\n", __func__, a->name, a); |
657 | |
|
658 | 0 | return a; |
659 | 0 | } |
660 | | |
661 | | /* |
662 | | * Only needed with heap-alloc'd lws_dlo_filesystem_t |
663 | | */ |
664 | | |
665 | | void |
666 | | lws_dlo_file_unregister(lws_dlo_filesystem_t **f) |
667 | 0 | { |
668 | 0 | if (!*f) |
669 | 0 | return; |
670 | | |
671 | 0 | lws_dll2_remove(&(*f)->list); |
672 | 0 | lws_free_set_NULL(*f); |
673 | 0 | } |
674 | | |
675 | | void |
676 | | lws_dlo_file_unregister_by_name(struct lws_context *cx, const char *name) |
677 | 0 | { |
678 | 0 | lws_dlo_filesystem_t *a; |
679 | |
|
680 | 0 | a = (lws_dlo_filesystem_t *)lws_dlo_file_choose(cx, name); |
681 | 0 | if (!a) |
682 | 0 | return; |
683 | | |
684 | 0 | lws_dll2_remove(&a->list); |
685 | 0 | lws_free_set_NULL(a); |
686 | 0 | } |
687 | | |
688 | | static int |
689 | | _lws_dlo_file_destroy(struct lws_dll2 *d, void *user) |
690 | 0 | { |
691 | 0 | lws_free(d); |
692 | 0 | return 0; |
693 | 0 | } |
694 | | |
695 | | void |
696 | | lws_dlo_file_destroy(struct lws_context *cx) |
697 | 0 | { |
698 | 0 | lws_dll2_foreach_safe(&cx->dlo_file, NULL, _lws_dlo_file_destroy); |
699 | 0 | } |
700 | | |
701 | | const lws_dlo_filesystem_t * |
702 | | lws_dlo_file_choose(struct lws_context *cx, const char *name) |
703 | 0 | { |
704 | 0 | lws_start_foreach_dll(struct lws_dll2 *, p, |
705 | 0 | lws_dll2_get_head(&cx->dlo_file)) { |
706 | 0 | const lws_dlo_filesystem_t *pn = lws_container_of(p, |
707 | 0 | lws_dlo_filesystem_t, list); |
708 | |
|
709 | 0 | if (!strcmp(name, pn->name)) |
710 | 0 | return pn; |
711 | |
|
712 | 0 | } lws_end_foreach_dll(p); |
713 | |
|
714 | 0 | return NULL; |
715 | 0 | } |
716 | | |
717 | | static int |
718 | | lws_display_id_destroy(struct lws_dll2 *d, void *user) |
719 | 0 | { |
720 | 0 | lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list); |
721 | |
|
722 | 0 | lws_dll2_remove(&id->list); |
723 | 0 | lws_free(id); |
724 | 0 | return 0; |
725 | 0 | } |
726 | | |
727 | | void |
728 | | lws_display_render_free_ids(lws_display_render_state_t *rs) |
729 | 0 | { |
730 | 0 | lws_dll2_foreach_safe(&rs->ids, NULL, lws_display_id_destroy); |
731 | 0 | } |
732 | | |
733 | | lws_display_id_t * |
734 | | lws_display_render_get_id(lws_display_render_state_t *rs, const char *_id) |
735 | 0 | { |
736 | 0 | lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(&rs->ids)) { |
737 | 0 | lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list); |
738 | |
|
739 | 0 | if (!strcmp(_id, id->id)) |
740 | 0 | return id; |
741 | |
|
742 | 0 | } lws_end_foreach_dll(d); |
743 | |
|
744 | 0 | return NULL; |
745 | 0 | } |
746 | | |
747 | | lws_display_id_t * |
748 | | lws_display_render_add_id(lws_display_render_state_t *rs, const char *_id, void *priv) |
749 | 0 | { |
750 | 0 | lws_display_id_t *id; |
751 | |
|
752 | 0 | id = lws_display_render_get_id(rs, _id); |
753 | 0 | if (id) { |
754 | 0 | id->priv_user = priv; |
755 | 0 | return id; |
756 | 0 | } |
757 | | |
758 | 0 | id = lws_zalloc(sizeof(*id), __func__); |
759 | |
|
760 | 0 | if (id) { |
761 | 0 | lws_strncpy(id->id, _id, sizeof(id->id)); |
762 | 0 | id->priv_user = priv; |
763 | 0 | lws_dll2_add_tail(&id->list, &rs->ids); |
764 | 0 | } |
765 | |
|
766 | 0 | return id; |
767 | 0 | } |
768 | | |
769 | | void |
770 | | lws_display_render_dump_ids(lws_dll2_owner_t *ids) |
771 | 0 | { |
772 | 0 | lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(ids)) { |
773 | 0 | lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list); |
774 | |
|
775 | 0 | if (!id->exists) |
776 | 0 | lwsl_notice(" id: '%s' (not present)\n", id->id); |
777 | 0 | else |
778 | 0 | lwsl_notice(" id: '%s', (%d,%d), %dx%d\n", id->id, |
779 | 0 | (int)id->box.x.whole, (int)id->box.y.whole, |
780 | 0 | (int)id->box.w.whole, (int)id->box.h.whole); |
781 | 0 | } lws_end_foreach_dll(d); |
782 | 0 | } |
783 | | |
784 | | #if defined (LWS_WITH_FILE_OPS) |
785 | | |
786 | | int |
787 | | dlo_filesystem_fops_close(lws_fop_fd_t *fop_fd) |
788 | 0 | { |
789 | 0 | lws_free_set_NULL(*fop_fd); |
790 | 0 | return 0; |
791 | 0 | } |
792 | | |
793 | | lws_fileofs_t |
794 | | dlo_filesystem_fops_seek_cur(lws_fop_fd_t fop_fd, |
795 | | lws_fileofs_t pos) |
796 | 0 | { |
797 | 0 | if (pos < 0) |
798 | 0 | fop_fd->pos = 0; |
799 | 0 | else |
800 | 0 | if (pos >= (long long)fop_fd->len) |
801 | 0 | fop_fd->pos = fop_fd->len; |
802 | 0 | else |
803 | 0 | fop_fd->pos = (lws_filepos_t)pos; |
804 | |
|
805 | 0 | return (lws_fileofs_t)fop_fd->pos; |
806 | 0 | } |
807 | | |
808 | | int |
809 | | dlo_filesystem_fops_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount, |
810 | | uint8_t *buf, lws_filepos_t len) |
811 | 0 | { |
812 | 0 | *amount = 0; |
813 | |
|
814 | 0 | return -1; |
815 | 0 | } |
816 | | |
817 | | int |
818 | | dlo_filesystem_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount, |
819 | | uint8_t *buf, lws_filepos_t len) |
820 | 0 | { |
821 | 0 | const uint8_t *p = (uint8_t *)fop_fd->filesystem_priv; |
822 | 0 | lws_filepos_t amt = *amount; |
823 | |
|
824 | 0 | *amount = 0; |
825 | 0 | if (fop_fd->len <= fop_fd->pos) |
826 | 0 | return 0; |
827 | | |
828 | 0 | if (amt > fop_fd->len - fop_fd->pos) |
829 | 0 | amt = fop_fd->len - fop_fd->pos; |
830 | |
|
831 | 0 | if (amt > len) |
832 | 0 | amt = len; |
833 | |
|
834 | 0 | memcpy(buf, p + fop_fd->pos, (size_t)amt); |
835 | 0 | fop_fd->pos += amt; |
836 | |
|
837 | 0 | *amount = amt; |
838 | |
|
839 | 0 | return 0; |
840 | 0 | } |
841 | | |
842 | | lws_fop_fd_t |
843 | | lws_dlo_filesystem_fops_open(const struct lws_plat_file_ops *fops_own, |
844 | | const struct lws_plat_file_ops *fops, |
845 | | const char *vfs_path, const char *vpath, |
846 | | lws_fop_flags_t *flags) |
847 | 0 | { |
848 | 0 | const lws_dlo_filesystem_t *f = NULL; |
849 | 0 | lws_fop_fd_t fop_fd; |
850 | | |
851 | | // lwsl_err("%s: %s\n", __func__, vpath); |
852 | |
|
853 | 0 | f = lws_dlo_file_choose(fops->cx, vpath); |
854 | 0 | if (f) { |
855 | | /* we will handle it then */ |
856 | 0 | fop_fd = lws_zalloc(sizeof(*fop_fd), __func__); |
857 | 0 | if (!fop_fd) |
858 | 0 | return NULL; |
859 | | |
860 | 0 | fop_fd->fops = fops_own; |
861 | 0 | fop_fd->filesystem_priv = (void *)f->data; |
862 | 0 | fop_fd->pos = 0; |
863 | 0 | fop_fd->len = f->len; |
864 | | |
865 | | // lwsl_notice("%s: Opened %s\n", __func__, vpath); |
866 | |
|
867 | 0 | return fop_fd; |
868 | 0 | } else |
869 | 0 | lwsl_err("%s: failed to open %s\n", __func__, vpath); |
870 | | |
871 | 0 | return NULL; |
872 | 0 | } |
873 | | |
874 | | const struct lws_plat_file_ops lws_dlo_fops = { |
875 | | .LWS_FOP_OPEN = lws_dlo_filesystem_fops_open, |
876 | | .LWS_FOP_CLOSE = dlo_filesystem_fops_close, |
877 | | .LWS_FOP_SEEK_CUR = dlo_filesystem_fops_seek_cur, |
878 | | .LWS_FOP_READ = dlo_filesystem_fops_read, |
879 | | .LWS_FOP_WRITE = dlo_filesystem_fops_write, |
880 | | .fi = { { "dlofs/", 6 } }, |
881 | | }; |
882 | | |
883 | | #endif |