Coverage Report

Created: 2026-02-14 07:00

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
      rs->sp--;
360
0
      continue;
361
0
    }
362
363
0
    lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
364
0
    lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
365
0
    co.w = dlo->box.w;
366
0
    co.h = dlo->box.h;
367
368
0
    lws_fx_add(&t2, &co.y, &dlo->box.h);
369
370
371
0
    if (dlo->id) {
372
0
      lws_display_id_t *id = dlo->id;
373
374
0
      if (id) {
375
0
        id->id[sizeof(id->id) - 1] = '\0';
376
0
        lwsl_debug("%s: set id box %s\n", __func__, id->id);
377
378
0
        id->box = co;
379
0
      }
380
0
      dlo->id = NULL; /* decouple us */
381
0
    }
382
383
384
0
    if (co.y.whole + co.h.whole > rs->lowest_id_y) {
385
0
      rs->lowest_id_y = (lws_display_scalar)(co.y.whole + co.h.whole);
386
0
      if (rs->lowest_id_y > rs->ic->wh_px[1].whole)
387
0
        rs->lowest_id_y = (lws_display_scalar)rs->ic->wh_px[1].whole;
388
0
    }
389
390
    /* next sibling at this level if any */
391
392
0
    d = dlo->list.next;
393
0
    if (d)
394
0
      rs->st[rs->sp].dlo = lws_container_of(d,
395
0
            lws_dlo_t, list);
396
0
    else
397
0
      rs->st[rs->sp].dlo = NULL;
398
399
    /* go into any children */
400
401
0
    if (dlo->children.head) {
402
0
      if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
403
0
        lwsl_err("%s: DLO stack overflow A\n",
404
0
            __func__);
405
0
        return LWS_SRET_FATAL;
406
0
      }
407
0
      rs->st[++rs->sp].dlo = lws_container_of(
408
0
        dlo->children.head, lws_dlo_t, list);
409
0
      rs->st[rs->sp].co = co;
410
0
      continue;
411
0
    }
412
0
  }
413
414
0
  lws_display_render_dump_ids(&rs->ids);
415
416
0
  return LWS_SRET_OK;
417
0
}
418
419
lws_stateful_ret_t
420
lws_display_list_render_line(lws_display_render_state_t *rs)
421
0
{
422
0
  lws_dll2_t *d;
423
424
0
  if (rs->html == 1) {
425
0
    lwsl_notice("%s: returning LWS_SRET_WANT_INPUT due to rs->html = 1\n", __func__);
426
0
    return LWS_SRET_WANT_INPUT;
427
0
  }
428
429
0
  if (!rs->sp && !rs->st[0].dlo) {
430
431
    /* starting a line */
432
433
0
    d = lws_dll2_get_head(&rs->displaylist.dl);
434
0
    if (!d)
435
      /* nothing in dlo */
436
0
      return LWS_SRET_OK;
437
438
  //  memset(rs->line, 0, (size_t)rs->ic->wh_px[0].whole *
439
  //        (rs->ic->greyscale ? 1 : 3));
440
0
    memset(&rs->st[0].co, 0, sizeof(rs->st[0].co));
441
0
    rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list);
442
0
  }
443
444
0
  while (rs->sp || rs->st[0].dlo) {
445
0
    lws_dlo_t *dlo = rs->st[rs->sp].dlo;
446
0
    lws_stateful_ret_t r;
447
0
    lws_box_t co;
448
0
    lws_fx_t t2;
449
450
0
    if (!dlo) {
451
0
      rs->sp--;
452
0
      continue;
453
0
    }
454
455
//    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);
456
457
0
    lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
458
0
    lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
459
460
0
    co.w = dlo->box.w;
461
0
    co.h = dlo->box.h;
462
463
0
    lws_fx_add(&t2, &co.y, &dlo->box.h);
464
465
0
    if (rs->curr > lws_fx_roundup(&t2) && dlo->box.h.whole > 3) {
466
0
      d = dlo->list.next;
467
0
      rs->st[rs->sp].dlo = d ? lws_container_of(d, lws_dlo_t,
468
0
                list) : NULL;
469
470
0
      lws_display_dlo_destroy(&dlo);
471
0
      continue;
472
0
    }
473
474
#if 0
475
    if (dlo->_destroy == lws_display_dlo_png_destroy)
476
      lwsl_err("png line %d %d %d %d\n", rs->curr, co.y.whole - 1,
477
          rs->st[rs->sp].co.y.whole, dlo->box.y.whole);
478
#endif
479
480
0
    if (rs->curr >= co.y.whole - 1) {
481
482
0
      r = dlo->render(rs);
483
484
      //rs->ic, dlo, &rs->st[rs->sp].co,
485
      //    rs->curr, rs->line, &dlo->nle[0]);
486
0
      if (r)
487
0
        return r;
488
489
      /* next sibling at this level if any */
490
491
0
      d = dlo->list.next;
492
493
0
      if (d)
494
0
        rs->st[rs->sp].dlo = lws_container_of(d,
495
0
              lws_dlo_t, list);
496
0
      else
497
0
        rs->st[rs->sp].dlo = NULL;
498
499
500
      /* go into any children */
501
502
0
      if (dlo->children.head) {
503
0
        if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
504
0
          lwsl_err("%s: DLO stack overflow B\n",
505
0
              __func__);
506
0
          return LWS_SRET_FATAL;
507
0
        }
508
0
        rs->st[++rs->sp].dlo = lws_container_of(
509
0
          dlo->children.head, lws_dlo_t, list);
510
0
        rs->st[rs->sp].co = co;
511
0
        continue;
512
0
      }
513
0
    } else {
514
      /* next sibling at this level if any */
515
516
0
      d = dlo->list.next;
517
0
      if (d)
518
0
        rs->st[rs->sp].dlo = lws_container_of(d,
519
0
              lws_dlo_t, list);
520
0
      else
521
0
        rs->st[rs->sp].dlo = NULL;
522
0
    }
523
524
525
0
  }
526
527
0
  return LWS_SRET_OK;
528
0
}
529
530
static int
531
dlo_clean_table_rows(lws_dll2_t *d, void *user)
532
0
{
533
0
  lhp_table_row_t *r = lws_container_of(d, lhp_table_row_t, list);
534
535
0
  lws_dll2_remove(d);
536
0
  lws_free(r);
537
538
0
  return 0;
539
0
}
540
541
static int
542
dlo_clean_table_cols(lws_dll2_t *d, void *user)
543
0
{
544
0
  lhp_table_col_t *c = lws_container_of(d, lhp_table_col_t, list);
545
546
0
  lws_dll2_remove(d);
547
0
  lws_free(c);
548
549
0
  return 0;
550
0
}
551
552
void
553
lws_display_dlo_destroy(lws_dlo_t **r)
554
0
{
555
0
  lws_dlo_t *rr = *r;
556
557
0
  if (!rr)
558
0
    return;
559
560
0
  lws_dll2_remove(&rr->list);
561
0
  lws_dll2_remove(&rr->col_list);
562
0
  lws_dll2_remove(&rr->row_list);
563
564
0
  while (rr->children.head) {
565
0
    lws_dlo_t *d = lws_container_of(rr->children.head,
566
0
              lws_dlo_t, list);
567
568
0
    lws_display_dlo_destroy(&d);
569
0
  }
570
571
0
  lws_dll2_foreach_safe(&rr->table_cols, NULL, dlo_clean_table_cols);
572
0
  lws_dll2_foreach_safe(&rr->table_rows, NULL, dlo_clean_table_rows);
573
574
0
  if (rr->_destroy)
575
0
    rr->_destroy(rr);
576
577
0
  lws_free_set_NULL(*r);
578
0
}
579
580
void
581
lws_display_list_destroy(struct lws_context *cx, lws_displaylist_t *dl)
582
0
{
583
0
  if (!dl)
584
0
    return;
585
586
  //lws_dlo_ss_stop_any_active(cx);
587
588
0
  while (dl->dl.head) {
589
0
    lws_dlo_t *d = lws_container_of(dl->dl.head, lws_dlo_t, list);
590
591
0
    lws_display_dlo_destroy(&d);
592
0
  }
593
0
}
594
595
lws_dlo_filesystem_t *
596
lws_dlo_file_register(struct lws_context *cx, const lws_dlo_filesystem_t *f)
597
0
{
598
0
  const lws_dlo_filesystem_t *b;
599
0
  lws_dlo_filesystem_t *a;
600
601
0
  b = lws_dlo_file_choose(cx, f->name);
602
603
0
  if (b) {
604
0
    lwsl_err("%s: dlo file %s already exists %p\n", __func__, b->name, b);
605
0
    lws_dlo_file_unregister((lws_dlo_filesystem_t **)&b);
606
0
  }
607
608
0
  a = lws_malloc(sizeof(*a), __func__);
609
0
  if (!a)
610
0
    return NULL;
611
612
0
  *a = *f;
613
0
  lws_dll2_clear(&a->list);
614
0
  lws_dll2_add_tail(&a->list, &cx->dlo_file);
615
616
0
  lwsl_err("%s: dlo file %s registered at %p\n", __func__, a->name, a);
617
618
0
  return a;
619
0
}
620
621
/*
622
 * Only needed with heap-alloc'd lws_dlo_filesystem_t
623
 */
624
625
void
626
lws_dlo_file_unregister(lws_dlo_filesystem_t **f)
627
0
{
628
0
  if (!*f)
629
0
    return;
630
631
0
  lws_dll2_remove(&(*f)->list);
632
0
  lws_free_set_NULL(*f);
633
0
}
634
635
void
636
lws_dlo_file_unregister_by_name(struct lws_context *cx, const char *name)
637
0
{
638
0
  lws_dlo_filesystem_t *a;
639
640
0
  a = (lws_dlo_filesystem_t *)lws_dlo_file_choose(cx, name);
641
0
  if (!a)
642
0
    return;
643
644
0
  lws_dll2_remove(&a->list);
645
0
  lws_free_set_NULL(a);
646
0
}
647
648
static int
649
_lws_dlo_file_destroy(struct lws_dll2 *d, void *user)
650
0
{
651
0
  lws_free(d);
652
0
  return 0;
653
0
}
654
655
void
656
lws_dlo_file_destroy(struct lws_context *cx)
657
0
{
658
0
  lws_dll2_foreach_safe(&cx->dlo_file, NULL, _lws_dlo_file_destroy);
659
0
}
660
661
const lws_dlo_filesystem_t *
662
lws_dlo_file_choose(struct lws_context *cx, const char *name)
663
0
{
664
0
  lws_start_foreach_dll(struct lws_dll2 *, p,
665
0
            lws_dll2_get_head(&cx->dlo_file)) {
666
0
    const lws_dlo_filesystem_t *pn = lws_container_of(p,
667
0
            lws_dlo_filesystem_t, list);
668
669
0
    if (!strcmp(name, pn->name))
670
0
      return pn;
671
672
0
  } lws_end_foreach_dll(p);
673
674
0
  return NULL;
675
0
}
676
677
static int
678
lws_display_id_destroy(struct lws_dll2 *d, void *user)
679
0
{
680
0
  lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
681
682
0
  lws_dll2_remove(&id->list);
683
0
  lws_free(id);
684
0
  return 0;
685
0
}
686
687
void
688
lws_display_render_free_ids(lws_display_render_state_t *rs)
689
0
{
690
0
  lws_dll2_foreach_safe(&rs->ids, NULL, lws_display_id_destroy);
691
0
}
692
693
lws_display_id_t *
694
lws_display_render_get_id(lws_display_render_state_t *rs, const char *_id)
695
0
{
696
0
  lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(&rs->ids)) {
697
0
    lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
698
699
0
    if (!strcmp(_id, id->id))
700
0
      return id;
701
702
0
  } lws_end_foreach_dll(d);
703
704
0
  return NULL;
705
0
}
706
707
lws_display_id_t *
708
lws_display_render_add_id(lws_display_render_state_t *rs, const char *_id, void *priv)
709
0
{
710
0
  lws_display_id_t *id;
711
712
0
  id = lws_display_render_get_id(rs, _id);
713
0
  if (id) {
714
0
    id->priv_user = priv;
715
0
    return id;
716
0
  }
717
718
0
  id = lws_zalloc(sizeof(*id), __func__);
719
720
0
  if (id) {
721
0
    lws_strncpy(id->id, _id, sizeof(id->id));
722
0
    id->priv_user = priv;
723
0
    lws_dll2_add_tail(&id->list, &rs->ids);
724
0
  }
725
726
0
  return id;
727
0
}
728
729
void
730
lws_display_render_dump_ids(lws_dll2_owner_t *ids)
731
0
{
732
0
  lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(ids)) {
733
0
    lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
734
735
0
    if (!id->exists)
736
0
      lwsl_notice("  id: '%s' (not present)\n", id->id);
737
0
    else
738
0
      lwsl_notice("  id: '%s', (%d,%d), %dx%d\n", id->id,
739
0
          (int)id->box.x.whole, (int)id->box.y.whole,
740
0
          (int)id->box.w.whole, (int)id->box.h.whole);
741
0
  } lws_end_foreach_dll(d);
742
0
}
743
744
#if defined (LWS_WITH_FILE_OPS)
745
746
int
747
dlo_filesystem_fops_close(lws_fop_fd_t *fop_fd)
748
0
{
749
0
  lws_free_set_NULL(*fop_fd);
750
0
  return 0;
751
0
}
752
753
lws_fileofs_t
754
dlo_filesystem_fops_seek_cur(lws_fop_fd_t fop_fd,
755
           lws_fileofs_t pos)
756
0
{
757
0
  if (pos < 0)
758
0
    fop_fd->pos = 0;
759
0
  else
760
0
    if (pos >= (long long)fop_fd->len)
761
0
      fop_fd->pos = fop_fd->len;
762
0
    else
763
0
      fop_fd->pos = (lws_filepos_t)pos;
764
765
0
  return (lws_fileofs_t)fop_fd->pos;
766
0
}
767
768
int
769
dlo_filesystem_fops_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
770
        uint8_t *buf, lws_filepos_t len)
771
0
{
772
0
  *amount = 0;
773
774
0
  return -1;
775
0
}
776
777
int
778
dlo_filesystem_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
779
        uint8_t *buf, lws_filepos_t len)
780
0
{
781
0
  const uint8_t *p = (uint8_t *)fop_fd->filesystem_priv;
782
0
  lws_filepos_t amt = *amount;
783
784
0
  *amount = 0;
785
0
  if (fop_fd->len <= fop_fd->pos)
786
0
    return 0;
787
788
0
  if (amt > fop_fd->len - fop_fd->pos)
789
0
    amt = fop_fd->len - fop_fd->pos;
790
791
0
  if (amt > len)
792
0
    amt = len;
793
794
0
  memcpy(buf, p + fop_fd->pos, (size_t)amt);
795
0
  fop_fd->pos += amt;
796
797
0
  *amount = amt;
798
799
0
  return 0;
800
0
}
801
802
lws_fop_fd_t
803
lws_dlo_filesystem_fops_open(const struct lws_plat_file_ops *fops_own,
804
           const struct lws_plat_file_ops *fops,
805
           const char *vfs_path, const char *vpath,
806
           lws_fop_flags_t *flags)
807
0
{
808
0
  const lws_dlo_filesystem_t *f = NULL;
809
0
  lws_fop_fd_t fop_fd;
810
811
  // lwsl_err("%s: %s\n", __func__, vpath);
812
813
0
  f = lws_dlo_file_choose(fops->cx, vpath);
814
0
  if (f) {
815
    /* we will handle it then */
816
0
    fop_fd = lws_zalloc(sizeof(*fop_fd), __func__);
817
0
    if (!fop_fd)
818
0
      return NULL;
819
820
0
    fop_fd->fops = fops_own;
821
0
    fop_fd->filesystem_priv = (void *)f->data;
822
0
    fop_fd->pos = 0;
823
0
    fop_fd->len = f->len;
824
825
    // lwsl_notice("%s: Opened %s\n", __func__, vpath);
826
827
0
    return fop_fd;
828
0
  } else
829
0
    lwsl_err("%s: failed to open %s\n", __func__, vpath);
830
831
0
  return NULL;
832
0
}
833
834
const struct lws_plat_file_ops lws_dlo_fops = {
835
  .LWS_FOP_OPEN   = lws_dlo_filesystem_fops_open,
836
  .LWS_FOP_CLOSE    = dlo_filesystem_fops_close,
837
  .LWS_FOP_SEEK_CUR = dlo_filesystem_fops_seek_cur,
838
  .LWS_FOP_READ   = dlo_filesystem_fops_read,
839
  .LWS_FOP_WRITE    = dlo_filesystem_fops_write,
840
  .fi = { { "dlofs/", 6 } },
841
};
842
843
#endif