Coverage Report

Created: 2023-03-26 07:20

/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