Coverage Report

Created: 2026-07-24 06:13

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libwebsockets/lib/misc/dlo/dlo.c
Line
Count
Source
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_fx_t t1;
126
127
0
  dim->w.whole = 0;
128
0
  dim->w.frac = 0;
129
0
  dim->h.whole = 0;
130
0
  dim->h.frac = 0;
131
132
0
  if (!parent)
133
0
    return;
134
135
0
  lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(&parent->children)) {
136
0
    lws_dlo_t *child = lws_container_of(d, lws_dlo_t, list);
137
138
0
    lws_fx_add(&t1, &child->box.w, &child->box.x);
139
    /*
140
     * Original recursive code added padding here.
141
     * lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_LEFT]);
142
     * But box.w usually includes padding in LHP DLOs.
143
     */
144
    // lws_fx_add(&t1, &t1, &child->padding[CCPAS_LEFT]);
145
146
0
    if (lws_fx_comp(&t1, &dim->w) > 0)
147
0
      dim->w = t1;
148
149
0
    lws_fx_add(&t1, &child->box.h, &child->box.y);
150
    // lws_fx_add(&t1, &t1, &child->padding[CCPAS_TOP]);
151
152
0
    if (lws_fx_comp(&t1, &dim->h) > 0)
153
0
      dim->h = t1;
154
155
0
  } lws_end_foreach_dll(d);
156
157
0
  if (parent->col_list.owner) {
158
0
    lhp_table_col_t *tc = lws_container_of(parent->col_list.owner,
159
0
          lhp_table_col_t, col_dlos);
160
161
0
    if (lws_fx_comp(&dim->w, &tc->width) < 0) {
162
  //    lws_fx_add(&t1, &tc->width, &parent->padding[CCPAS_LEFT]);
163
  //    lws_fx_add(&dim->w, &tc->width, &parent->padding[CCPAS_RIGHT]);
164
0
      dim->w = tc->width;
165
0
    }
166
0
  }
167
168
0
  if (parent->row_list.owner) {
169
0
    lhp_table_row_t *tr = lws_container_of(parent->row_list.owner,
170
0
          lhp_table_row_t, row_dlos);
171
172
0
    if (lws_fx_comp(&dim->h, &tr->height) < 0) {
173
  //    lws_fx_add(&t1, &tr->height, &parent->padding[CCPAS_TOP]);
174
0
      lws_fx_add(&dim->h, &tr->height, &parent->padding[CCPAS_BOTTOM]);
175
//      dim->h = tr->height;
176
0
    }
177
0
  }
178
179
/*
180
  lwsl_user("%s: dlo %p: FINAL w:%d -> %d h:%d -> %d\n", __func__, parent,
181
      parent->box.w.whole, dim->w.whole,
182
      parent->box.h.whole, dim->h.whole);
183
*/
184
0
}
185
186
/*
187
 * Some DLO is changing height, adjust its height, and that of everybody below.
188
 */
189
190
void
191
lws_display_dlo_adjust_dims(lws_dlo_t *dlo, lws_dlo_dim_t *dim)
192
0
{
193
0
  lws_dlo_dim_t delta;
194
195
0
  if (!dim->w.whole && !dim->h.whole)
196
0
    return;
197
198
  /* adjust the target's width / height */
199
200
0
  lws_fx_sub(&delta.w, &dim->w, &dlo->box.w);
201
0
  lws_fx_sub(&delta.h, &dim->h, &dlo->box.h);
202
203
0
  dlo->box.w = dim->w;
204
0
  dlo->box.h = dim->h;
205
206
  // lwsl_notice("%s: dlo %p: delta w:%d h:%d\n", __func__, dlo, delta.w.whole, delta.h.whole);
207
208
  /* move peers below him accordingly */
209
210
0
  do {
211
0
    lws_dlo_t *dp = lws_container_of(dlo->list.owner, lws_dlo_t, children);
212
213
0
    if (!dlo->list.owner)
214
0
      break;
215
216
    /*
217
     * Adjust y pos of siblings below us
218
     */
219
220
0
    do {
221
0
      dlo = lws_container_of(dlo->list.next, lws_dlo_t, list);
222
0
      if (dlo) {
223
        //lwsl_notice("%s: dlo %p: adj y %d -> %d\n", __func__, dlo, dlo->box.y.whole, dlo->box.y.whole + delta.h.whole);
224
0
        lws_fx_add(&dlo->box.y, &dlo->box.y, &delta.h);
225
0
      }
226
0
    } while (dlo);
227
228
229
    /* go up parent chain until toplevel adjusting height of
230
     * parent siblings below parent */
231
232
0
    if (dp->flag_toplevel)
233
0
      break;
234
235
0
    dlo = dp;
236
    //lwsl_notice("%s: dlo %p: adj h by %d\n", __func__, dlo, delta.h.whole);
237
0
    lws_fx_add(&dlo->box.h, &dlo->box.h, &delta.h);
238
0
  } while (1);
239
0
}
240
241
//#if defined(_DEBUG)
242
void
243
lws_display_dl_dump(lws_displaylist_t *dl)
244
0
{
245
0
  lws_display_render_stack_t  st[64]; /* DLO child stack */
246
0
  int       sp = 0;
247
0
  lws_dll2_t *d = lws_dll2_get_head(&dl->dl);
248
0
#if (_LWS_ENABLED_LOGS & dlodump_loglevel)
249
0
  static const char * const ind = "                           ";
250
0
#endif
251
0
  char b[4][22], b1[4][22], dt[96];
252
253
0
  if (!d) {
254
0
    lwsl_notice("%s: empty dl\n", __func__);
255
256
0
    return;
257
0
  }
258
259
0
  lwsl_notice("%s\n", __func__);
260
261
0
  memset(&st, 0, sizeof(st));
262
0
  st[0].dlo = lws_container_of(d, lws_dlo_t, list);
263
264
0
  while (sp || st[0].dlo) {
265
0
    lws_dlo_t *dlo = st[sp].dlo;
266
0
    lws_box_t co;
267
268
0
    if (!dlo) {
269
0
      if (!sp) {
270
0
        lwsl_err("%s: underflow\n", __func__);
271
0
          return;
272
0
      }
273
0
      sp--;
274
0
      continue;
275
0
    }
276
277
0
    lws_fx_add(&co.x, &st[sp].co.x, &dlo->box.x);
278
0
    lws_fx_add(&co.y, &st[sp].co.y, &dlo->box.y);
279
0
    co.w = dlo->box.w;
280
0
    co.h = dlo->box.h;
281
282
0
    lws_snprintf(dt, sizeof(dt), "rect: RGBA 0x%08X", (unsigned int)dlo->dc);
283
0
    if (dlo->_destroy == lws_display_dlo_text_destroy) {
284
0
      lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo);
285
0
      lws_snprintf(dt, sizeof(dt), "text: RGBA 0x%08X, chars: %u, %.*s",
286
0
          (unsigned int)dlo->dc, (unsigned int)text->text_len,
287
0
          (int)text->text_len, text->text ? text->text : "(empty)");
288
0
    }
289
0
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_UPNG) && defined(LWS_WITH_CLIENT)
290
0
    else if (dlo->_destroy == lws_display_dlo_png_destroy)
291
0
      lws_snprintf(dt, sizeof(dt), "png");
292
0
#endif
293
0
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_JPEG) && defined(LWS_WITH_CLIENT)
294
0
    else if (dlo->_destroy == lws_display_dlo_jpeg_destroy)
295
0
      lws_snprintf(dt, sizeof(dt), "jpeg");
296
0
#endif
297
298
0
    lws_fx_string(&dlo->box.x, b[0], sizeof(b[0]));
299
0
    lws_fx_string(&dlo->box.y, b[1], sizeof(b[1]));
300
0
    lws_fx_string(&dlo->box.w, b[2], sizeof(b[2]));
301
0
    lws_fx_string(&dlo->box.h, b[3], sizeof(b[3]));
302
0
    lws_fx_string(&co.x, b1[0], sizeof(b1[0]));
303
0
    lws_fx_string(&co.y, b1[1], sizeof(b1[1]));
304
0
    lws_fx_string(&co.w, b1[2], sizeof(b1[2]));
305
0
    lws_fx_string(&co.h, b1[3], sizeof(b1[3]));
306
307
0
    lwsl_dlodump("%.*s %p box: (%s, %s) [%s x %s], co: (%s, %s) [%s x %s], %s\n",
308
0
        sp, ind, dlo, b[0], b[1], b[2], b[3],
309
0
        b1[0], b1[1], b1[2], b1[3], dt);
310
311
0
    d = dlo->list.next;
312
0
    if (d)
313
0
      st[sp].dlo = lws_container_of(d, lws_dlo_t, list);
314
0
    else
315
0
      st[sp].dlo = NULL;
316
317
    /* go into any children */
318
319
0
    if (dlo->children.head) {
320
0
      if (sp + 1 == LWS_ARRAY_SIZE(st)) {
321
0
        lwsl_err("%s: DLO stack overflow\n", __func__);
322
0
        return;
323
0
      }
324
0
      st[++sp].dlo = lws_container_of(
325
0
        dlo->children.head, lws_dlo_t, list);
326
0
      st[sp].co = co;
327
0
    }
328
329
0
  }
330
0
}
331
//#endif
332
333
/*
334
 * Go through every DLO once, setting its id->box to the final layout for the
335
 * related dlo, if any
336
 */
337
338
lws_stateful_ret_t
339
lws_display_get_ids_boxes(lws_display_render_state_t *rs)
340
0
{
341
0
  lws_dll2_t *d;
342
343
0
  rs->lowest_id_y = 0;
344
345
0
  d = lws_dll2_get_head(&rs->displaylist.dl);
346
0
  if (!d)
347
    /* nothing in dlo */
348
0
    return LWS_SRET_OK;
349
350
0
  memset(&rs->st[0].co, 0, sizeof(rs->st[0].co));
351
0
  rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list);
352
353
0
  while (rs->sp || rs->st[0].dlo) {
354
0
    lws_dlo_t *dlo = rs->st[rs->sp].dlo;
355
0
    lws_box_t co;
356
0
    lws_fx_t t2;
357
358
0
    if (!dlo) {
359
0
      if (rs->sp > 0)
360
0
        rs->sp--;
361
0
      else
362
0
        break;
363
0
      continue;
364
0
    }
365
366
0
    lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
367
0
    lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
368
0
    co.w = dlo->box.w;
369
0
    co.h = dlo->box.h;
370
371
0
    lws_fx_add(&t2, &co.y, &dlo->box.h);
372
373
374
0
    if (dlo->id) {
375
0
      lws_display_id_t *id = dlo->id;
376
377
0
      if (id) {
378
0
        id->id[sizeof(id->id) - 1] = '\0';
379
0
        lwsl_debug("%s: set id box %s\n", __func__, id->id);
380
381
0
        id->box = co;
382
0
      }
383
0
      dlo->id = NULL; /* decouple us */
384
0
    }
385
386
387
0
    if (co.y.whole + co.h.whole > rs->lowest_id_y) {
388
0
      rs->lowest_id_y = (lws_display_scalar)(co.y.whole + co.h.whole);
389
0
      if (rs->lowest_id_y > rs->ic->wh_px[1].whole)
390
0
        rs->lowest_id_y = (lws_display_scalar)rs->ic->wh_px[1].whole;
391
0
    }
392
393
    /* next sibling at this level if any */
394
395
0
    d = dlo->list.next;
396
0
    if (d)
397
0
      rs->st[rs->sp].dlo = lws_container_of(d,
398
0
            lws_dlo_t, list);
399
0
    else
400
0
      rs->st[rs->sp].dlo = NULL;
401
402
    /* go into any children */
403
404
0
    if (dlo->children.head) {
405
0
      if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
406
0
        lwsl_err("%s: DLO stack overflow A\n",
407
0
            __func__);
408
0
        return LWS_SRET_FATAL;
409
0
      }
410
0
      rs->st[++rs->sp].dlo = lws_container_of(
411
0
        dlo->children.head, lws_dlo_t, list);
412
0
      rs->st[rs->sp].co = co;
413
0
      continue;
414
0
    }
415
0
  }
416
417
0
  lws_display_render_dump_ids(&rs->ids);
418
419
0
  return LWS_SRET_OK;
420
0
}
421
422
lws_stateful_ret_t
423
lws_display_list_render_line(lws_display_render_state_t *rs)
424
0
{
425
0
  lws_dll2_t *d;
426
427
0
  if (rs->html == 1) {
428
0
    lwsl_notice("%s: returning LWS_SRET_WANT_INPUT due to rs->html = 1\n", __func__);
429
0
    return LWS_SRET_WANT_INPUT;
430
0
  }
431
432
0
  if (!rs->sp && !rs->st[0].dlo) {
433
434
    /* starting a line */
435
436
0
    d = lws_dll2_get_head(&rs->displaylist.dl);
437
0
    if (!d)
438
      /* nothing in dlo */
439
0
      return LWS_SRET_OK;
440
441
  //  memset(rs->line, 0, (size_t)rs->ic->wh_px[0].whole *
442
  //        (rs->ic->greyscale ? 1 : 3));
443
0
    memset(&rs->st[0].co, 0, sizeof(rs->st[0].co));
444
0
    rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list);
445
0
  }
446
447
0
  while (rs->sp || rs->st[0].dlo) {
448
0
    lws_dlo_t *dlo = rs->st[rs->sp].dlo;
449
0
    lws_stateful_ret_t r;
450
0
    lws_box_t co;
451
0
    lws_fx_t t2;
452
453
0
    if (!dlo) {
454
0
      if (rs->sp > 0)
455
0
        rs->sp--;
456
0
      else
457
0
        break;
458
0
      continue;
459
0
    }
460
461
//    lwsl_notice("%s: curr %d: %d %d %d %d\n", __func__, (int)rs->curr, (int)dlo->box.x.whole, (int)dlo->box.y.whole, (int)dlo->box.w.whole, (int)dlo->box.h.whole);
462
463
0
    lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
464
0
    lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
465
466
0
    co.w = dlo->box.w;
467
0
    co.h = dlo->box.h;
468
469
0
    lws_fx_add(&t2, &co.y, &dlo->box.h);
470
471
0
    if (rs->curr > lws_fx_roundup(&t2) && dlo->box.h.whole > 3) {
472
0
      d = dlo->list.next;
473
0
      rs->st[rs->sp].dlo = d ? lws_container_of(d, lws_dlo_t,
474
0
                list) : NULL;
475
476
0
      lws_display_dlo_destroy(&dlo);
477
0
      continue;
478
0
    }
479
480
#if 0
481
    if (dlo->_destroy == lws_display_dlo_png_destroy)
482
      lwsl_err("png line %d %d %d %d\n", rs->curr, co.y.whole - 1,
483
          rs->st[rs->sp].co.y.whole, dlo->box.y.whole);
484
#endif
485
486
0
    if (rs->curr >= co.y.whole - 1) {
487
488
0
      r = dlo->render(rs);
489
490
      //rs->ic, dlo, &rs->st[rs->sp].co,
491
      //    rs->curr, rs->line, &dlo->nle[0]);
492
0
      if (r)
493
0
        return r;
494
495
      /* next sibling at this level if any */
496
497
0
      d = dlo->list.next;
498
499
0
      if (d)
500
0
        rs->st[rs->sp].dlo = lws_container_of(d,
501
0
              lws_dlo_t, list);
502
0
      else
503
0
        rs->st[rs->sp].dlo = NULL;
504
505
506
      /* go into any children */
507
508
0
      if (dlo->children.head) {
509
0
        if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
510
0
          lwsl_err("%s: DLO stack overflow B\n",
511
0
              __func__);
512
0
          return LWS_SRET_FATAL;
513
0
        }
514
0
        rs->st[++rs->sp].dlo = lws_container_of(
515
0
          dlo->children.head, lws_dlo_t, list);
516
0
        rs->st[rs->sp].co = co;
517
0
        continue;
518
0
      }
519
0
    } else {
520
      /* next sibling at this level if any */
521
522
0
      d = dlo->list.next;
523
0
      if (d)
524
0
        rs->st[rs->sp].dlo = lws_container_of(d,
525
0
              lws_dlo_t, list);
526
0
      else
527
0
        rs->st[rs->sp].dlo = NULL;
528
0
    }
529
530
531
0
  }
532
533
0
  return LWS_SRET_OK;
534
0
}
535
536
static int
537
dlo_clean_table_rows(lws_dll2_t *d, void *user)
538
0
{
539
0
  lhp_table_row_t *r = lws_container_of(d, lhp_table_row_t, list);
540
541
0
  lws_dll2_remove(d);
542
0
  lws_free(r);
543
544
0
  return 0;
545
0
}
546
547
static int
548
dlo_clean_table_cols(lws_dll2_t *d, void *user)
549
0
{
550
0
  lhp_table_col_t *c = lws_container_of(d, lhp_table_col_t, list);
551
552
0
  lws_dll2_remove(d);
553
0
  lws_free(c);
554
555
0
  return 0;
556
0
}
557
558
void
559
lws_display_dlo_destroy(lws_dlo_t **r)
560
0
{
561
0
  lws_dlo_t *rr = *r;
562
563
0
  if (!rr)
564
0
    return;
565
566
0
  lws_dll2_remove(&rr->list);
567
0
  lws_dll2_remove(&rr->col_list);
568
0
  lws_dll2_remove(&rr->row_list);
569
570
0
  while (rr->children.head) {
571
0
    lws_dlo_t *d = lws_container_of(rr->children.head,
572
0
              lws_dlo_t, list);
573
574
0
    lws_display_dlo_destroy(&d);
575
0
  }
576
577
0
  lws_dll2_foreach_safe(&rr->table_cols, NULL, dlo_clean_table_cols);
578
0
  lws_dll2_foreach_safe(&rr->table_rows, NULL, dlo_clean_table_rows);
579
580
0
  if (rr->_destroy)
581
0
    rr->_destroy(rr);
582
583
0
  lws_free_set_NULL(*r);
584
0
}
585
586
void
587
lws_display_list_destroy(struct lws_context *cx, lws_displaylist_t *dl)
588
0
{
589
0
  if (!dl)
590
0
    return;
591
592
  //lws_dlo_ss_stop_any_active(cx);
593
594
0
  while (dl->dl.head) {
595
0
    lws_dlo_t *d = lws_container_of(dl->dl.head, lws_dlo_t, list);
596
597
0
    lws_display_dlo_destroy(&d);
598
0
  }
599
0
}
600
601
lws_dlo_filesystem_t *
602
lws_dlo_file_register(struct lws_context *cx, const lws_dlo_filesystem_t *f)
603
0
{
604
0
  const lws_dlo_filesystem_t *b;
605
0
  lws_dlo_filesystem_t *a;
606
607
0
  b = lws_dlo_file_choose(cx, f->name);
608
609
0
  if (b) {
610
0
    lwsl_err("%s: dlo file %s already exists %p\n", __func__, b->name, b);
611
0
    lws_dlo_file_unregister((lws_dlo_filesystem_t **)&b);
612
0
  }
613
614
0
  a = lws_malloc(sizeof(*a), __func__);
615
0
  if (!a)
616
0
    return NULL;
617
618
0
  *a = *f;
619
0
  lws_dll2_clear(&a->list);
620
0
  lws_dll2_add_tail(&a->list, &cx->dlo_file);
621
622
0
  lwsl_err("%s: dlo file %s registered at %p\n", __func__, a->name, a);
623
624
0
  return a;
625
0
}
626
627
/*
628
 * Only needed with heap-alloc'd lws_dlo_filesystem_t
629
 */
630
631
void
632
lws_dlo_file_unregister(lws_dlo_filesystem_t **f)
633
0
{
634
0
  if (!*f)
635
0
    return;
636
637
0
  lws_dll2_remove(&(*f)->list);
638
0
  lws_free_set_NULL(*f);
639
0
}
640
641
void
642
lws_dlo_file_unregister_by_name(struct lws_context *cx, const char *name)
643
0
{
644
0
  lws_dlo_filesystem_t *a;
645
646
0
  a = (lws_dlo_filesystem_t *)lws_dlo_file_choose(cx, name);
647
0
  if (!a)
648
0
    return;
649
650
0
  lws_dll2_remove(&a->list);
651
0
  lws_free_set_NULL(a);
652
0
}
653
654
static int
655
_lws_dlo_file_destroy(struct lws_dll2 *d, void *user)
656
0
{
657
0
  lws_free(d);
658
0
  return 0;
659
0
}
660
661
void
662
lws_dlo_file_destroy(struct lws_context *cx)
663
0
{
664
0
  lws_dll2_foreach_safe(&cx->dlo_file, NULL, _lws_dlo_file_destroy);
665
0
}
666
667
const lws_dlo_filesystem_t *
668
lws_dlo_file_choose(struct lws_context *cx, const char *name)
669
0
{
670
0
  lws_start_foreach_dll(struct lws_dll2 *, p,
671
0
            lws_dll2_get_head(&cx->dlo_file)) {
672
0
    const lws_dlo_filesystem_t *pn = lws_container_of(p,
673
0
            lws_dlo_filesystem_t, list);
674
675
0
    if (!strcmp(name, pn->name))
676
0
      return pn;
677
678
0
  } lws_end_foreach_dll(p);
679
680
0
  return NULL;
681
0
}
682
683
static int
684
lws_display_id_destroy(struct lws_dll2 *d, void *user)
685
0
{
686
0
  lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
687
688
0
  lws_dll2_remove(&id->list);
689
0
  lws_free(id);
690
0
  return 0;
691
0
}
692
693
void
694
lws_display_render_free_ids(lws_display_render_state_t *rs)
695
0
{
696
0
  lws_dll2_foreach_safe(&rs->ids, NULL, lws_display_id_destroy);
697
0
}
698
699
lws_display_id_t *
700
lws_display_render_get_id(lws_display_render_state_t *rs, const char *_id)
701
0
{
702
0
  lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(&rs->ids)) {
703
0
    lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
704
705
0
    if (!strcmp(_id, id->id))
706
0
      return id;
707
708
0
  } lws_end_foreach_dll(d);
709
710
0
  return NULL;
711
0
}
712
713
lws_display_id_t *
714
lws_display_render_add_id(lws_display_render_state_t *rs, const char *_id, void *priv)
715
0
{
716
0
  lws_display_id_t *id;
717
718
0
  id = lws_display_render_get_id(rs, _id);
719
0
  if (id) {
720
0
    id->priv_user = priv;
721
0
    return id;
722
0
  }
723
724
0
  id = lws_zalloc(sizeof(*id), __func__);
725
726
0
  if (id) {
727
0
    lws_strncpy(id->id, _id, sizeof(id->id));
728
0
    id->priv_user = priv;
729
0
    lws_dll2_add_tail(&id->list, &rs->ids);
730
0
  }
731
732
0
  return id;
733
0
}
734
735
void
736
lws_display_render_dump_ids(lws_dll2_owner_t *ids)
737
0
{
738
0
  lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(ids)) {
739
0
    lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
740
741
0
    if (!id->exists)
742
0
      lwsl_notice("  id: '%s' (not present)\n", id->id);
743
0
    else
744
0
      lwsl_notice("  id: '%s', (%d,%d), %dx%d\n", id->id,
745
0
          (int)id->box.x.whole, (int)id->box.y.whole,
746
0
          (int)id->box.w.whole, (int)id->box.h.whole);
747
0
  } lws_end_foreach_dll(d);
748
0
}
749
750
#if defined (LWS_WITH_FILE_OPS)
751
752
int
753
dlo_filesystem_fops_close(lws_fop_fd_t *fop_fd)
754
0
{
755
0
  lws_free_set_NULL(*fop_fd);
756
0
  return 0;
757
0
}
758
759
lws_fileofs_t
760
dlo_filesystem_fops_seek_cur(lws_fop_fd_t fop_fd,
761
           lws_fileofs_t pos)
762
0
{
763
0
  if (pos < 0)
764
0
    fop_fd->pos = 0;
765
0
  else
766
0
    if (pos >= (long long)fop_fd->len)
767
0
      fop_fd->pos = fop_fd->len;
768
0
    else
769
0
      fop_fd->pos = (lws_filepos_t)pos;
770
771
0
  return (lws_fileofs_t)fop_fd->pos;
772
0
}
773
774
int
775
dlo_filesystem_fops_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
776
        uint8_t *buf, lws_filepos_t len)
777
0
{
778
0
  *amount = 0;
779
780
0
  return -1;
781
0
}
782
783
int
784
dlo_filesystem_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
785
        uint8_t *buf, lws_filepos_t len)
786
0
{
787
0
  const uint8_t *p = (uint8_t *)fop_fd->filesystem_priv;
788
0
  lws_filepos_t amt = *amount;
789
790
0
  *amount = 0;
791
0
  if (fop_fd->len <= fop_fd->pos)
792
0
    return 0;
793
794
0
  if (amt > fop_fd->len - fop_fd->pos)
795
0
    amt = fop_fd->len - fop_fd->pos;
796
797
0
  if (amt > len)
798
0
    amt = len;
799
800
0
  memcpy(buf, p + fop_fd->pos, (size_t)amt);
801
0
  fop_fd->pos += amt;
802
803
0
  *amount = amt;
804
805
0
  return 0;
806
0
}
807
808
lws_fop_fd_t
809
lws_dlo_filesystem_fops_open(const struct lws_plat_file_ops *fops_own,
810
           const struct lws_plat_file_ops *fops,
811
           const char *vfs_path, const char *vpath,
812
           lws_fop_flags_t *flags)
813
0
{
814
0
  const lws_dlo_filesystem_t *f = NULL;
815
0
  lws_fop_fd_t fop_fd;
816
817
  // lwsl_err("%s: %s\n", __func__, vpath);
818
819
0
  f = lws_dlo_file_choose(fops->cx, vpath);
820
0
  if (f) {
821
    /* we will handle it then */
822
0
    fop_fd = lws_zalloc(sizeof(*fop_fd), __func__);
823
0
    if (!fop_fd)
824
0
      return NULL;
825
826
0
    fop_fd->fops = fops_own;
827
0
    fop_fd->filesystem_priv = (void *)f->data;
828
0
    fop_fd->pos = 0;
829
0
    fop_fd->len = f->len;
830
831
    // lwsl_notice("%s: Opened %s\n", __func__, vpath);
832
833
0
    return fop_fd;
834
0
  } else
835
0
    lwsl_err("%s: failed to open %s\n", __func__, vpath);
836
837
0
  return NULL;
838
0
}
839
840
const struct lws_plat_file_ops lws_dlo_fops = {
841
  .LWS_FOP_OPEN   = lws_dlo_filesystem_fops_open,
842
  .LWS_FOP_CLOSE    = dlo_filesystem_fops_close,
843
  .LWS_FOP_SEEK_CUR = dlo_filesystem_fops_seek_cur,
844
  .LWS_FOP_READ   = dlo_filesystem_fops_read,
845
  .LWS_FOP_WRITE    = dlo_filesystem_fops_write,
846
  .fi = { { "dlofs/", 6 } },
847
};
848
849
#endif