Update Files
This commit is contained in:
528
Kinc/Sources/kinc/libs/misc/dlo/dlo-font-mcufont.c
Normal file
528
Kinc/Sources/kinc/libs/misc/dlo/dlo-font-mcufont.c
Normal file
@ -0,0 +1,528 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2013 Petteri Aimonen
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object: mcufont font
|
||||
*
|
||||
* The mcu decoding is rewritten from the mcufont implementation at
|
||||
* https://github.com/mcufont/mcufont, which is licensed under MIT already,
|
||||
* to use a stateful decoder.
|
||||
*
|
||||
* The decoder only brings in new compression codes when needed to produce more
|
||||
* pixels on the line of the glyphs being decoded.
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
#define DICT_START 24
|
||||
#define REF_FILLZEROS 16
|
||||
|
||||
#define RLE_CODEMASK 0xC0
|
||||
#define RLE_VALMASK 0x3F
|
||||
#define RLE_ZEROS 0x00
|
||||
#define RLE_64ZEROS 0x40
|
||||
#define RLE_ONES 0x80
|
||||
#define RLE_SHADE 0xC0
|
||||
|
||||
#define DICT_START7BIT 4
|
||||
#define DICT_START6BIT 132
|
||||
#define DICT_START5BIT 196
|
||||
#define DICT_START4BIT 228
|
||||
#define DICT_START3BIT 244
|
||||
#define DICT_START2BIT 252
|
||||
|
||||
enum {
|
||||
RS_IDLE,
|
||||
RS_SKIP_PX,
|
||||
RS_WRITE_PX,
|
||||
RS_ALLZERO,
|
||||
|
||||
COMP = 0,
|
||||
DICT1,
|
||||
DICT1_CONT,
|
||||
DICT2,
|
||||
DICT3
|
||||
};
|
||||
|
||||
typedef struct mcu_stack {
|
||||
const uint8_t *dict;
|
||||
int16_t dictlen;
|
||||
int16_t runlen; /* for accumilation on DICT1 */
|
||||
uint8_t byte;
|
||||
uint8_t bitcount;
|
||||
uint8_t state;
|
||||
} mcu_stack_t;
|
||||
|
||||
typedef struct mcu_glyph {
|
||||
lws_font_glyph_t fg;
|
||||
const uint8_t *comp;
|
||||
|
||||
mcu_stack_t st[3];
|
||||
int32_t runlen;
|
||||
|
||||
int8_t sp;
|
||||
|
||||
uint8_t runstate;
|
||||
uint8_t alpha;
|
||||
uint8_t code;
|
||||
} mcu_glyph_t;
|
||||
|
||||
/* Get bit count for the "fill entries" */
|
||||
static uint8_t
|
||||
fillentry_bitcount(uint8_t index)
|
||||
{
|
||||
if (index >= DICT_START2BIT)
|
||||
return 2;
|
||||
else if (index >= DICT_START3BIT)
|
||||
return 3;
|
||||
else if (index >= DICT_START4BIT)
|
||||
return 4;
|
||||
else if (index >= DICT_START5BIT)
|
||||
return 5;
|
||||
else if (index >= DICT_START6BIT)
|
||||
return 6;
|
||||
else
|
||||
return 7;
|
||||
}
|
||||
|
||||
void
|
||||
draw_px(lws_dlo_text_t *t, mcu_glyph_t *g)
|
||||
{
|
||||
lws_display_colour_t c = (lws_display_colour_t)((lws_display_colour_t)(g->alpha << 24) |
|
||||
(lws_display_colour_t)((lws_display_colour_t)t->dlo.dc & 0xffffffu));
|
||||
lws_fx_t t1, x;
|
||||
int ex;
|
||||
|
||||
t1.whole = g->fg.x;
|
||||
|
||||
if (!g->alpha)
|
||||
return;
|
||||
|
||||
t1.frac = 0;
|
||||
lws_fx_add(&x, &g->fg.xpx, &t1);
|
||||
|
||||
#if 0
|
||||
{ char b1[22], b2[22], b3[22];
|
||||
lwsl_err("fadj %s = %s + %s\n",
|
||||
lws_fx_string(&x, b1, sizeof(b1)),
|
||||
lws_fx_string(&g->fg.xpx, b2, sizeof(b2)),
|
||||
lws_fx_string(&g->fg.xorg, b3, sizeof(b3))); }
|
||||
#endif
|
||||
|
||||
ex = x.whole;// - t->dlo.box.x.whole;
|
||||
if (ex < 0 || ex >= t->dlo.box.w.whole) {
|
||||
//lwsl_err("%s: ex %d (lim %d)\n", __func__, ex, t->dlo.box.w.whole);
|
||||
return;
|
||||
}
|
||||
lws_fx_add(&x, &x, &g->fg.xorg);
|
||||
|
||||
lws_fx_add(&t1, &t->dlo.box.x, &x);
|
||||
lws_surface_set_px(t->ic, t->line, t1.whole, &c);
|
||||
}
|
||||
|
||||
static void
|
||||
write_ref_codeword(mcu_glyph_t *g, const uint8_t *bf, uint8_t c)
|
||||
{
|
||||
uint32_t o, o1;
|
||||
|
||||
if (!c) {
|
||||
g->runlen = 1;
|
||||
g->runstate = RS_SKIP_PX;
|
||||
return;
|
||||
}
|
||||
if (c <= 15) {
|
||||
g->alpha = (uint8_t)(0x11 * c);
|
||||
g->runlen = 1;
|
||||
g->runstate = RS_WRITE_PX;
|
||||
return;
|
||||
}
|
||||
if (c == REF_FILLZEROS) {
|
||||
/* Fill with zeroes to end */
|
||||
g->alpha = 0;
|
||||
g->runlen = 1000000;
|
||||
g->runstate = RS_WRITE_PX;
|
||||
return;
|
||||
}
|
||||
if (c < DICT_START)
|
||||
return;
|
||||
|
||||
if (c < DICT_START + lws_ser_ru32be(bf + MCUFO_COUNT_RLE_DICT)) {
|
||||
/* write_rle_dictentry */
|
||||
o1 = lws_ser_ru32be(bf + MCUFO_FOFS_DICT_OFS);
|
||||
o = lws_ser_ru16be(bf + o1 + ((c - DICT_START) * 2));
|
||||
g->st[(int)++g->sp].dictlen = (int16_t)(lws_ser_ru16be(bf + o1 +
|
||||
((c - DICT_START + 1) * 2)) - o);
|
||||
|
||||
g->st[(int)g->sp].dict = bf + lws_ser_ru32be(bf + MCUFO_FOFS_DICT_DATA) + o;
|
||||
g->st[(int)g->sp].state = DICT2;
|
||||
return;
|
||||
}
|
||||
|
||||
g->st[(int)++g->sp].bitcount = fillentry_bitcount(c);
|
||||
g->st[(int)g->sp].byte = (uint8_t)(c - DICT_START7BIT);
|
||||
g->st[(int)g->sp].state = DICT1;
|
||||
g->runlen = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
mcufont_next_code(mcu_glyph_t *g)
|
||||
{
|
||||
lws_dlo_text_t *t = lws_container_of(g->fg.list.owner, lws_dlo_text_t,
|
||||
glyphs);
|
||||
const uint8_t *bf = (const uint8_t *)t->font->data;
|
||||
uint8_t c = *g->comp++;
|
||||
uint32_t o, o1;
|
||||
|
||||
if (c < DICT_START + lws_ser_ru32be(&bf[MCUFO_COUNT_RLE_DICT]) ||
|
||||
c >= DICT_START + lws_ser_ru32be(&bf[MCUFO_COUNT_REF_RLE_DICT])) {
|
||||
write_ref_codeword(g, bf, c);
|
||||
return;
|
||||
}
|
||||
|
||||
/* write_ref_dictentry() */
|
||||
|
||||
o1 = lws_ser_ru32be(bf + MCUFO_FOFS_DICT_OFS);
|
||||
o = lws_ser_ru16be(bf + o1 + ((c - DICT_START) * 2));
|
||||
g->st[(int)++g->sp].dictlen = (int16_t)(lws_ser_ru16be(bf + o1 +
|
||||
((c - DICT_START + 1) * 2)) - o);
|
||||
|
||||
g->st[(int)g->sp].dict = bf + lws_ser_ru32be(bf + MCUFO_FOFS_DICT_DATA) + o;
|
||||
g->st[(int)g->sp].state = DICT3;
|
||||
}
|
||||
|
||||
/* lookup and append a glyph for specific unicode to the text glyph list */
|
||||
|
||||
static uint32_t
|
||||
font_mcufont_uniglyph_lookup(lws_dlo_text_t *text, uint32_t unicode)
|
||||
{
|
||||
const uint8_t *bf = (const uint8_t *)text->font->data,
|
||||
*r = bf + lws_ser_ru32be(&bf[MCUFO_FOFS_CHAR_RANGE_TABLES]);
|
||||
uint32_t entries = lws_ser_ru32be(&bf[MCUFO_COUNT_CHAR_RANGE_TABLES]);
|
||||
unsigned int n;
|
||||
|
||||
if (entries > 8) /* coverity sanity */
|
||||
return 0;
|
||||
|
||||
do {
|
||||
for (n = 0; n < entries; n++) {
|
||||
uint32_t cs = lws_ser_ru32be(r + 0), ce = lws_ser_ru32be(r + 4);
|
||||
|
||||
if (cs >= 0x100000 || !ce || ce > 0x10000)
|
||||
return 0;
|
||||
|
||||
if (unicode >= cs && unicode < cs + ce) {
|
||||
uint32_t cbo = lws_ser_ru32be(r + 0xc);
|
||||
|
||||
if (cbo >= text->font->data_len)
|
||||
return 0;
|
||||
|
||||
cbo += lws_ser_ru16be(bf +
|
||||
lws_ser_ru32be(r + 8) + ((unicode - cs) * 2));
|
||||
|
||||
if (cbo >= text->font->data_len)
|
||||
return 0;
|
||||
|
||||
return cbo;
|
||||
}
|
||||
|
||||
r += 16;
|
||||
}
|
||||
|
||||
if (unicode == lws_ser_ru32be(&bf[MCUFO_UNICODE_FALLBACK]))
|
||||
return 0;
|
||||
unicode = lws_ser_ru32be(&bf[MCUFO_UNICODE_FALLBACK]);
|
||||
|
||||
} while (1);
|
||||
}
|
||||
|
||||
static mcu_glyph_t *
|
||||
font_mcufont_uniglyph(lws_dlo_text_t *text, uint32_t unicode)
|
||||
{
|
||||
const uint8_t *bf = (const uint8_t *)text->font->data;
|
||||
uint32_t ofs;
|
||||
mcu_glyph_t *g;
|
||||
|
||||
ofs = font_mcufont_uniglyph_lookup(text, unicode);
|
||||
if (!ofs)
|
||||
return NULL;
|
||||
|
||||
// lwsl_warn("%s: text->text_len %u: %c\n", __func__, text->text_len, (char)unicode);
|
||||
g = lwsac_use_zero(&text->ac_glyphs, sizeof(*g),
|
||||
(text->text_len + 1) * sizeof(*g));
|
||||
if (!g)
|
||||
return NULL;
|
||||
|
||||
g->comp = bf + ofs;
|
||||
g->fg.cwidth.whole = *g->comp++;
|
||||
g->fg.cwidth.frac = 0;
|
||||
|
||||
lws_dll2_add_tail(&g->fg.list, &text->glyphs);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
int
|
||||
lws_display_font_mcufont_getcwidth(lws_dlo_text_t *text, uint32_t unicode,
|
||||
lws_fx_t *fx)
|
||||
{
|
||||
const uint8_t *bf = (const uint8_t *)text->font->data;
|
||||
uint32_t ofs = font_mcufont_uniglyph_lookup(text, unicode);
|
||||
|
||||
if (!ofs)
|
||||
return 1;
|
||||
|
||||
fx->whole = bf[ofs];
|
||||
fx->frac = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_font_glyph_t *
|
||||
lws_display_font_mcufont_image_glyph(lws_dlo_text_t *text, uint32_t unicode,
|
||||
char attach)
|
||||
{
|
||||
const uint8_t *bf = (const uint8_t *)text->font->data;
|
||||
mcu_glyph_t *g;
|
||||
|
||||
/* one text dlo has glyphs from all the same fonts and attributes */
|
||||
if (!text->font_height) {
|
||||
text->font_height = (int16_t)lws_ser_ru16be(&bf[MCUFO16_HEIGHT]);
|
||||
text->font_y_baseline = (int16_t)(text->font_height -
|
||||
lws_ser_ru16be(&bf[MCUFO16_BASELINE_Y]));
|
||||
text->font_line_height = (int16_t)lws_ser_ru16be(&bf[MCUFO16_LINE_HEIGHT]);
|
||||
}
|
||||
|
||||
lws_display_font_mcufont_getcwidth(text, unicode, &text->_cwidth);
|
||||
|
||||
if (!attach)
|
||||
return NULL;
|
||||
|
||||
g = font_mcufont_uniglyph(text, unicode);
|
||||
if (!g)
|
||||
return NULL;
|
||||
|
||||
g->fg.height.whole = lws_ser_ru16be(bf + MCUFO16_HEIGHT);
|
||||
g->fg.height.frac = 0;
|
||||
|
||||
return &g->fg;
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_font_mcufont_render(struct lws_display_render_state *rs)
|
||||
{
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo);
|
||||
const uint8_t *bf = (const uint8_t *)text->font->data;
|
||||
lws_fx_t ax, ay, t, t1, t2, t3;
|
||||
mcu_glyph_t *g;
|
||||
int s, e, yo;
|
||||
uint8_t c, el;
|
||||
|
||||
lws_fx_add(&ax, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&t, &ax, &dlo->box.w);
|
||||
lws_fx_add(&ay, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
lws_fx_add(&t1, &ay, &dlo->box.h);
|
||||
|
||||
lws_fx_add(&t2, &ax, &text->bounding_box.w);
|
||||
|
||||
text->curr = rs->curr;
|
||||
text->ic = rs->ic;
|
||||
text->line = rs->line;
|
||||
|
||||
s = ax.whole;
|
||||
e = lws_fx_roundup(&t2);
|
||||
|
||||
if (e <= 0)
|
||||
return LWS_SRET_OK; /* wholly off to the left */
|
||||
if (s >= rs->ic->wh_px[0].whole)
|
||||
return LWS_SRET_OK; /* wholly off to the right */
|
||||
|
||||
if (e >= rs->ic->wh_px[0].whole)
|
||||
e = rs->ic->wh_px[0].whole;
|
||||
|
||||
/* figure out our y position inside the glyph bounding box */
|
||||
yo = rs->curr - ay.whole;
|
||||
|
||||
if (!yo) {
|
||||
lws_display_dlo_text_attach_glyphs(text);
|
||||
|
||||
t3.whole = lws_ser_ru16be(bf + MCUFO16_BASELINE_X);
|
||||
t3.frac = 0;
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d,
|
||||
lws_dll2_get_head(&text->glyphs)) {
|
||||
lws_font_glyph_t *fg = lws_container_of(d, lws_font_glyph_t, list);
|
||||
lws_fx_sub(&fg->xpx, &fg->xpx, &t3);
|
||||
fg->xorg = rs->st[rs->sp].co.x;
|
||||
} lws_end_foreach_dll(d);
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
uint32_t dc = 0xff0000ff;
|
||||
int s1 = s;
|
||||
/* from origin.x + dlo->box.x */
|
||||
for (s1 = ax.whole; s1 < t2.whole; s1++)
|
||||
lws_surface_set_px(ic, line, s1, &dc);
|
||||
|
||||
memset(&ce, 0, sizeof(ce));
|
||||
}
|
||||
#endif
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d,
|
||||
lws_dll2_get_head(&text->glyphs)) {
|
||||
lws_font_glyph_t *fg = lws_container_of(d, lws_font_glyph_t, list);
|
||||
|
||||
g = (mcu_glyph_t *)fg;
|
||||
fg->x = 0;
|
||||
|
||||
while (yo < (int)fg->height.whole &&
|
||||
fg->x < lws_ser_ru16be(bf + MCUFO16_WIDTH)) {
|
||||
switch (g->runstate) {
|
||||
case RS_IDLE:
|
||||
switch (g->st[(int)g->sp].state) {
|
||||
case COMP:
|
||||
mcufont_next_code(g);
|
||||
break;
|
||||
|
||||
case DICT1_CONT:
|
||||
--g->sp; /* back to DICT1 after doing the skip */
|
||||
g->runstate = RS_SKIP_PX;
|
||||
g->runlen = 1;
|
||||
continue;
|
||||
|
||||
case DICT1:
|
||||
/* write_bin_codeword() states */
|
||||
el = 0;
|
||||
while (g->st[(int)g->sp].bitcount--) {
|
||||
c = g->st[(int)g->sp].byte;
|
||||
g->st[(int)g->sp].byte >>= 1;
|
||||
if (c & 1)
|
||||
g->st[(int)g->sp].runlen++;
|
||||
else {
|
||||
if (g->st[(int)g->sp].runlen) {
|
||||
g->alpha = 255;
|
||||
g->runstate = RS_WRITE_PX;
|
||||
g->runlen = g->st[(int)g->sp].runlen;
|
||||
g->st[(int)g->sp].runlen = 0;
|
||||
g->st[(int)++g->sp].state = DICT1_CONT;
|
||||
el = 1;
|
||||
break;
|
||||
}
|
||||
g->runstate = RS_SKIP_PX;
|
||||
g->runlen = 1;
|
||||
el = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (el)
|
||||
continue;
|
||||
|
||||
/* back out of DICT1 */
|
||||
if (!g->sp)
|
||||
assert(0);
|
||||
g->sp--;
|
||||
|
||||
if (g->st[(int)g->sp + 1].runlen) {
|
||||
g->alpha = 255;
|
||||
g->runstate = RS_WRITE_PX;
|
||||
g->runlen = g->st[(int)g->sp + 1].runlen;
|
||||
g->st[(int)g->sp + 1].runlen = 0;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case DICT2: /* write_rle_dictentry */
|
||||
c = (*g->st[(int)g->sp].dict++);
|
||||
if (!--g->st[(int)g->sp].dictlen) {
|
||||
if (!g->sp)
|
||||
assert(0);
|
||||
g->sp--;
|
||||
}
|
||||
if ((c & RLE_CODEMASK) == RLE_ZEROS) {
|
||||
g->runstate = RS_SKIP_PX;
|
||||
g->runlen = c & RLE_VALMASK;
|
||||
continue;
|
||||
}
|
||||
if ((c & RLE_CODEMASK) == RLE_64ZEROS) {
|
||||
g->runstate = RS_SKIP_PX;
|
||||
g->runlen = ((c & RLE_VALMASK) + 1) * 64;
|
||||
continue;
|
||||
}
|
||||
if ((c & RLE_CODEMASK) == RLE_ONES) {
|
||||
g->alpha = 255;
|
||||
g->runstate = RS_WRITE_PX;
|
||||
g->runlen = (c & RLE_VALMASK) + 1;
|
||||
continue;
|
||||
}
|
||||
if ((c & RLE_CODEMASK) == RLE_SHADE) {
|
||||
g->alpha = (uint8_t)(((c & RLE_VALMASK) & 0xf) * 0x11);
|
||||
g->runstate = RS_WRITE_PX;
|
||||
g->runlen = ((c & RLE_VALMASK) >> 4) + 1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case DICT3:
|
||||
c = *g->st[(int)g->sp].dict++;
|
||||
if (!--g->st[(int)g->sp].dictlen) {
|
||||
if (!g->sp)
|
||||
assert(0);
|
||||
|
||||
g->sp--;
|
||||
}
|
||||
|
||||
write_ref_codeword(g, bf, c);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case RS_SKIP_PX:
|
||||
fg->x++;
|
||||
if (--g->runlen)
|
||||
break;
|
||||
g->runstate = RS_IDLE;
|
||||
break;
|
||||
|
||||
case RS_WRITE_PX:
|
||||
if (g->alpha)
|
||||
draw_px(text, g);
|
||||
g->fg.x++;
|
||||
if (--g->runlen)
|
||||
break;
|
||||
g->runstate = RS_IDLE;
|
||||
break;
|
||||
|
||||
case RS_ALLZERO:
|
||||
fg->x++;
|
||||
if (--g->runlen)
|
||||
break;
|
||||
g->runstate = RS_IDLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
195
Kinc/Sources/kinc/libs/misc/dlo/dlo-jpeg.c
Normal file
195
Kinc/Sources/kinc/libs/misc/dlo/dlo-jpeg.c
Normal file
@ -0,0 +1,195 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object: JPEG
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
void
|
||||
lws_display_dlo_jpeg_destroy(struct lws_dlo *dlo)
|
||||
{
|
||||
lws_dlo_jpeg_t *dlo_jpeg = lws_container_of(dlo, lws_dlo_jpeg_t, dlo);
|
||||
|
||||
#if defined(LWS_WITH_CLIENT) && defined(LWS_WITH_SECURE_STREAMS)
|
||||
lws_ss_destroy(&dlo_jpeg->flow.h);
|
||||
#endif
|
||||
lws_buflist_destroy_all_segments(&dlo_jpeg->flow.bl);
|
||||
|
||||
if (dlo_jpeg->j)
|
||||
lws_jpeg_free(&dlo_jpeg->j);
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_render_jpeg(struct lws_display_render_state *rs)
|
||||
{
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_dlo_jpeg_t *dlo_jpeg = lws_container_of(dlo, lws_dlo_jpeg_t, dlo);
|
||||
lws_display_colour_t pc;
|
||||
lws_fx_t ax, ay, t, t1;
|
||||
lws_stateful_ret_t r;
|
||||
const uint8_t *pix;
|
||||
int s, e;
|
||||
|
||||
lws_fx_add(&ax, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&t, &ax, &dlo->box.w);
|
||||
lws_fx_add(&ay, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
lws_fx_add(&t1, &ay, &dlo->box.h);
|
||||
|
||||
if (!lws_jpeg_get_height(dlo_jpeg->j)) {
|
||||
lwsl_info("%s: jpeg does not have dimensions yet\n", __func__);
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
}
|
||||
|
||||
s = ax.whole;
|
||||
e = lws_fx_roundup(&t);
|
||||
|
||||
if (rs->curr > lws_fx_roundup(&t1))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
if (rs->curr - lws_fx_roundup(&ay) >
|
||||
(int)lws_jpeg_get_height(dlo_jpeg->j))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
if (s > rs->ic->wh_px[0].whole)
|
||||
return LWS_SRET_OK; /* off to the right */
|
||||
if (e > rs->ic->wh_px[0].whole)
|
||||
e = rs->ic->wh_px[0].whole - 1;
|
||||
if (e <= 0)
|
||||
return LWS_SRET_OK; /* off to the left */
|
||||
|
||||
do {
|
||||
if (lws_flow_feed(&dlo_jpeg->flow))
|
||||
/* if he says WANT_INPUT, we have nothing in the buflist */
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
|
||||
pix = NULL;
|
||||
r = lws_jpeg_emit_next_line(dlo_jpeg->j, &pix, &dlo_jpeg->flow.data,
|
||||
&dlo_jpeg->flow.len, rs->html == 1);
|
||||
|
||||
if (r & LWS_SRET_NO_FURTHER_IN)
|
||||
dlo_jpeg->flow.state = LWSDLOFLOW_STATE_READ_COMPLETED;
|
||||
|
||||
if (r & LWS_SRET_FATAL || r == LWS_SRET_OK)
|
||||
return r;
|
||||
|
||||
r = lws_flow_req(&dlo_jpeg->flow);
|
||||
if (r & LWS_SRET_WANT_INPUT)
|
||||
return r;
|
||||
|
||||
} while (!pix);
|
||||
|
||||
/*
|
||||
* What's in pix is either 24-bit RGB 3 bytes/px, or 8-bit grayscale
|
||||
* 1 byte/px, we have to map it on to either 32-bit RGBA or 16-bit YA
|
||||
* composition buf
|
||||
*/
|
||||
|
||||
pix = pix + (( (unsigned int)(s - ax.whole) *
|
||||
(lws_jpeg_get_pixelsize(dlo_jpeg->j) / 8)));
|
||||
|
||||
while (s < e && s >= ax.whole && s < lws_fx_roundup(&t) &&
|
||||
(s - ax.whole) < (int)lws_jpeg_get_width(dlo_jpeg->j)) {
|
||||
|
||||
if (lws_jpeg_get_pixelsize(dlo_jpeg->j) == 8)
|
||||
pc = LWSDC_RGBA(pix[0], pix[0], pix[0], 255);
|
||||
else
|
||||
pc = LWSDC_RGBA(pix[0], pix[1], pix[2], 255);
|
||||
|
||||
lws_surface_set_px(rs->ic, rs->line, s, &pc);
|
||||
s++;
|
||||
pix += lws_jpeg_get_pixelsize(dlo_jpeg->j) / 8;
|
||||
}
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_dlo_jpeg_metadata_scan(lws_dlo_jpeg_t *dlo_jpeg)
|
||||
{
|
||||
lws_stateful_ret_t r;
|
||||
size_t l, l1;
|
||||
const uint8_t *pix;
|
||||
|
||||
/*
|
||||
* If we don't have the image metadata yet, provide small chunks of the
|
||||
* source data until we do have the image metadata, but small enough
|
||||
* we can't produce any decoded pixels too early.
|
||||
*/
|
||||
|
||||
while (!lws_jpeg_get_height(dlo_jpeg->j) && dlo_jpeg->flow.len) {
|
||||
l1 = l = dlo_jpeg->flow.len > 128 ? 128 : dlo_jpeg->flow.len;
|
||||
|
||||
r = lws_jpeg_emit_next_line(dlo_jpeg->j, &pix, &dlo_jpeg->flow.data, &l, 1);
|
||||
if (r >= LWS_SRET_FATAL) {
|
||||
lwsl_err("%s: hdr parse failed %d\n", __func__, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
dlo_jpeg->flow.len -= l1 - l;
|
||||
|
||||
if (lws_jpeg_get_height(dlo_jpeg->j)) {
|
||||
lwsl_info("jpeg: w %d, h %d\n",
|
||||
lws_jpeg_get_width(dlo_jpeg->j),
|
||||
lws_jpeg_get_height(dlo_jpeg->j));
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
}
|
||||
|
||||
lws_dlo_jpeg_t *
|
||||
lws_display_dlo_jpeg_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
|
||||
lws_box_t *box)
|
||||
{
|
||||
lws_dlo_jpeg_t *dlo_jpeg = lws_zalloc(sizeof(*dlo_jpeg), __func__);
|
||||
|
||||
if (!dlo_jpeg)
|
||||
return NULL;
|
||||
|
||||
dlo_jpeg->j = lws_jpeg_new();
|
||||
if (!dlo_jpeg->j)
|
||||
goto bail;
|
||||
|
||||
dlo_jpeg->dlo.box = *box;
|
||||
dlo_jpeg->dlo.render = lws_display_render_jpeg;
|
||||
dlo_jpeg->dlo._destroy = lws_display_dlo_jpeg_destroy;
|
||||
|
||||
lws_display_dlo_add(dl, dlo_parent, &dlo_jpeg->dlo);
|
||||
|
||||
return dlo_jpeg;
|
||||
|
||||
bail:
|
||||
lwsl_err("%s: bailed\n", __func__);
|
||||
if (dlo_jpeg->j)
|
||||
lws_jpeg_free(&dlo_jpeg->j);
|
||||
|
||||
lws_free(dlo_jpeg);
|
||||
|
||||
return NULL;
|
||||
}
|
982
Kinc/Sources/kinc/libs/misc/dlo/dlo-lhp.c
Normal file
982
Kinc/Sources/kinc/libs/misc/dlo/dlo-lhp.c
Normal file
@ -0,0 +1,982 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List LHP layout
|
||||
*
|
||||
* The basic flow is logical elements exist in a stack as they are parsed, the
|
||||
* job of lhp_displaylist_layout() is to translate these into a tree of DLOs,
|
||||
* having parent-child relationships with (x,y) of the DLO box being an offset
|
||||
* into a local origin formed from the DLO parent box (which in turn may be
|
||||
* a child with its origin defined by its parent, etc).
|
||||
*
|
||||
* The element stack only exists while it and its parent elements are being
|
||||
* parsed, it goes out of scope as the element ends. So we must create related
|
||||
* DLOs by stream-parsing, while we still have everything relevant to hand.
|
||||
*
|
||||
* This gets us out of having to run around fixing up DLO (x,y) as we do the
|
||||
* layout, since the DLO parent-child relationships are static even if their
|
||||
* content size isn't.
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
/*
|
||||
* HTML Elements we can deal with for layout
|
||||
*/
|
||||
|
||||
enum {
|
||||
/* 0 is no match */
|
||||
LHP_ELEM_BR = 1,
|
||||
LHP_ELEM_DIV,
|
||||
LHP_ELEM_TABLE,
|
||||
LHP_ELEM_TR,
|
||||
LHP_ELEM_TD,
|
||||
LHP_ELEM_IMG,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
const char *elem;
|
||||
uint8_t elem_len;
|
||||
} elems[] = {
|
||||
{ "br", 2 },
|
||||
{ "div", 3 },
|
||||
{ "table", 5 },
|
||||
{ "tr", 2 },
|
||||
{ "td", 2 },
|
||||
{ "img", 3 },
|
||||
};
|
||||
|
||||
/*
|
||||
* Newline moves the psb->cury to cover text that was already placed using the
|
||||
* old psb->cury as to top of it. So a final newline on the last line of text
|
||||
* does not create an extra blank line.
|
||||
*/
|
||||
|
||||
static const lws_fx_t two = { 2,0 };
|
||||
|
||||
static void
|
||||
newline(lhp_ctx_t *ctx, lhp_pstack_t *psb, lhp_pstack_t *ps,
|
||||
lws_displaylist_t *dl)
|
||||
{
|
||||
int16_t group_baseline = 9999, group_height = 0;
|
||||
lws_fx_t line_height = { 0, 0 }, w, add, ew, t1;
|
||||
const struct lcsp_atr *a;
|
||||
lws_dlo_t *dlo, *d, *d1;
|
||||
int t = 0;
|
||||
|
||||
if (!psb || !ps) {
|
||||
lwsl_err("%s: psb/ps NULL!\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
dlo = (lws_dlo_t *)psb->dlo;
|
||||
|
||||
lws_fx_add(&w, lws_csp_px(ps->css_padding[CCPAS_LEFT], ps),
|
||||
lws_csp_px(ps->css_padding[CCPAS_RIGHT], ps));
|
||||
|
||||
if (lws_fx_comp(&w, &psb->widest) > 0)
|
||||
psb->widest = w;
|
||||
|
||||
if (!dlo || !dlo->children.tail)
|
||||
return;
|
||||
|
||||
d = lws_container_of(dlo->children.tail, lws_dlo_t, list);
|
||||
|
||||
/*
|
||||
* We may be at the end of a line of text
|
||||
*
|
||||
* Figure out the biggest height on the line, and the total width
|
||||
*/
|
||||
|
||||
while (d) {
|
||||
t |= d->_destroy == lws_display_dlo_text_destroy;
|
||||
/* find the "worst" height on the line */
|
||||
if (lws_fx_comp(&d->box.h, &line_height) > 0)
|
||||
line_height = d->box.h;
|
||||
|
||||
if (d->_destroy == lws_display_dlo_text_destroy) {
|
||||
lws_dlo_text_t *text = lws_container_of(d,
|
||||
lws_dlo_text_t, dlo.list);
|
||||
|
||||
if (text->font_y_baseline < group_baseline)
|
||||
group_baseline = text->font_y_baseline;
|
||||
if (text->font_height > group_height)
|
||||
group_height = text->font_height;
|
||||
}
|
||||
|
||||
if (!d->flag_runon)
|
||||
break;
|
||||
d = lws_container_of(d->list.prev, lws_dlo_t, list);
|
||||
};
|
||||
|
||||
/* mark the related text dlos with information about group bl and h,
|
||||
* offset box y to align to group baseline if necessary */
|
||||
|
||||
d1 = d;
|
||||
while (d) {
|
||||
if (d->_destroy == lws_display_dlo_text_destroy) {
|
||||
lws_dlo_text_t *t1 = lws_container_of(d1,
|
||||
lws_dlo_text_t, dlo.list);
|
||||
lws_fx_t ft;
|
||||
|
||||
t1->group_height = group_height;
|
||||
t1->group_y_baseline = group_baseline;
|
||||
|
||||
ft.whole = (t1->font_height - t1->font_y_baseline) -
|
||||
(group_height - group_baseline);
|
||||
ft.frac = 0;
|
||||
|
||||
lws_fx_sub(&t1->dlo.box.y, &t1->dlo.box.y, &ft);
|
||||
}
|
||||
if (!d1->list.next)
|
||||
break;
|
||||
d1 = lws_container_of(d1->list.next, lws_dlo_t, list);
|
||||
};
|
||||
|
||||
w = psb->curx;
|
||||
ew = ctx->ic.wh_px[0];
|
||||
if (psb->css_width && psb->css_width->unit != LCSP_UNIT_NONE)
|
||||
ew = *lws_csp_px(psb->css_width, psb);
|
||||
lws_fx_sub(&ew, &ew, lws_csp_px(ps->css_margin[CCPAS_RIGHT], ps));
|
||||
lws_fx_sub(&ew, &ew, lws_csp_px(ps->css_padding[CCPAS_RIGHT], ps));
|
||||
|
||||
if (lws_fx_comp(&w, &psb->widest) > 0)
|
||||
psb->widest = w;
|
||||
|
||||
if (!t) /* no textual children to newline (eg, <div></div>) */
|
||||
return;
|
||||
|
||||
/*
|
||||
* now is our chance to fix up dlos that are part of the line for
|
||||
* text-align rule of the container.
|
||||
*/
|
||||
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_TEXT_ALIGN);
|
||||
if (a) {
|
||||
|
||||
switch (a->propval) {
|
||||
case LCSP_PROPVAL_CENTER:
|
||||
add = *lws_csp_px(ps->css_padding[CCPAS_LEFT], ps);
|
||||
lws_fx_sub(&t1, &ew, &w);
|
||||
lws_fx_div(&t1, &t1, &two);
|
||||
lws_fx_add(&add, &add, &t1);
|
||||
goto fixup;
|
||||
case LCSP_PROPVAL_RIGHT:
|
||||
lws_fx_sub(&add, &ew, &w);
|
||||
lws_fx_sub(&add, &add, &d->box.x);
|
||||
|
||||
fixup:
|
||||
lws_fx_add(&t1, &add, &w);
|
||||
if (lws_fx_comp(&t1, &psb->widest) > 0)
|
||||
psb->widest = t1;
|
||||
|
||||
do {
|
||||
lws_fx_add(&d->box.x, &d->box.x, &add);
|
||||
if (!d->list.next)
|
||||
break;
|
||||
d = lws_container_of(d->list.next, lws_dlo_t,
|
||||
list);
|
||||
} while (1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
lws_fx_add(&psb->cury, &psb->cury, &line_height);
|
||||
lws_fx_set(psb->curx, 0, 0);
|
||||
psb->dlo_set_curx = NULL;
|
||||
psb->dlo_set_cury = NULL;
|
||||
psb->runon = 0;
|
||||
}
|
||||
|
||||
void
|
||||
lhp_set_dlo_padding_margin(lhp_pstack_t *ps, lws_dlo_t *dlo)
|
||||
{
|
||||
int n;
|
||||
|
||||
for (n = 0; n < 4; n ++) {
|
||||
if (ps->css_margin[n])
|
||||
dlo->margin[n] = *lws_csp_px(ps->css_margin[n], ps);
|
||||
else
|
||||
lws_fx_set(dlo->margin[n], 0, 0);
|
||||
if (ps->css_padding[n])
|
||||
dlo->padding[n] = *lws_csp_px(ps->css_padding[n], ps);
|
||||
else
|
||||
lws_fx_set(dlo->padding[n], 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
lhp_set_dlo_adjust_to_contents(lhp_pstack_t *ps)
|
||||
{
|
||||
lhp_pstack_t *psb = lws_container_of(ps->list.prev, lhp_pstack_t, list);
|
||||
lws_dlo_dim_t dim;
|
||||
|
||||
lws_dlo_contents(ps->dlo, &dim);
|
||||
lws_display_dlo_adjust_dims(ps->dlo, &dim);
|
||||
|
||||
if (lws_fx_comp(&dim.w, &psb->widest) > 0)
|
||||
psb->widest = dim.w;
|
||||
|
||||
if (lws_fx_comp(&dim.h, &psb->deepest) > 0)
|
||||
psb->deepest = dim.h;
|
||||
}
|
||||
|
||||
static void
|
||||
runon(lhp_pstack_t *ps, lws_dlo_t *dlo)
|
||||
{
|
||||
dlo->flag_runon = (uint8_t)(ps->runon & 1);
|
||||
ps->runon = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle end-of-div, table, tr, td retrospective dlo dimension adjustment
|
||||
*/
|
||||
|
||||
int
|
||||
lws_lhp_dlo_adjust_div_type_element(lhp_ctx_t *ctx, lhp_pstack_t *psb,
|
||||
lhp_pstack_t *pst, lhp_pstack_t *ps,
|
||||
int elem_match)
|
||||
{
|
||||
lws_dlo_rect_t *rect = (lws_dlo_rect_t *)ps->dlo;
|
||||
lws_fx_t t1, w, wd;
|
||||
char rd = 0;
|
||||
|
||||
/* need this to get bottom clearance for next block */
|
||||
|
||||
lws_fx_add(&ps->cury, &ps->cury,
|
||||
lws_csp_px(ps->css_padding[CCPAS_BOTTOM], ps));
|
||||
|
||||
if (psb && ps->dlo &&
|
||||
ps->css_margin[CCPAS_LEFT]->propval == LCSP_PROPVAL_AUTO &&
|
||||
ps->css_margin[CCPAS_RIGHT]->propval == LCSP_PROPVAL_AUTO) {
|
||||
lws_dlo_rect_t *re = (lws_dlo_rect_t *)ps->dlo;
|
||||
|
||||
/* h-center a div... find the available h space first */
|
||||
w = ctx->ic.wh_px[LWS_LHPREF_WIDTH];
|
||||
if (psb->css_width &&
|
||||
psb->css_width->propval != LCSP_PROPVAL_AUTO)
|
||||
w = *lws_csp_px(psb->css_width, psb);
|
||||
|
||||
lws_fx_sub(&t1, &w, &re->dlo.box.w);
|
||||
lws_fx_div(&t1, &t1, &two);
|
||||
lws_fx_sub(&wd, &t1, &re->dlo.box.x);
|
||||
|
||||
lws_fx_add(&re->dlo.box.x, &re->dlo.box.x, &wd);
|
||||
}
|
||||
|
||||
/* fix up the dimensions of div rectangle */
|
||||
if (!rect) {
|
||||
lwsl_notice("%s: elem %d: NO RECT\n", __func__, elem_match);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lhp_set_dlo_adjust_to_contents(ps);
|
||||
|
||||
/* if a td, deal with columnar changes in width */
|
||||
|
||||
if (ps->dlo->col_list.owner) {
|
||||
lhp_table_col_t *tc = lws_container_of(
|
||||
ps->dlo->col_list.owner,
|
||||
lhp_table_col_t, col_dlos);
|
||||
lws_fx_t wdelta, ow;
|
||||
|
||||
ow = tc->width;
|
||||
lws_fx_set(tc->width, 0, 0);
|
||||
|
||||
/* discover the new width of column */
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, c1,
|
||||
lws_dll2_get_head(&tc->col_dlos)) {
|
||||
lws_dlo_t *dloc = lws_container_of(c1,
|
||||
lws_dlo_t, col_list);
|
||||
|
||||
if (lws_fx_comp(&dloc->box.w, &tc->width) > 0)
|
||||
tc->width = dloc->box.w;
|
||||
} lws_end_foreach_dll(c1);
|
||||
|
||||
/* new width - old column width */
|
||||
lws_fx_sub(&wdelta, &tc->width, &ow);
|
||||
|
||||
/*
|
||||
* Update all dlos in our column (except
|
||||
* ourselves) with the increased column width
|
||||
*/
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, cold,
|
||||
lws_dll2_get_head(&tc->col_dlos)) {
|
||||
lws_dlo_t *dloc = lws_container_of(cold,
|
||||
lws_dlo_t, col_list);
|
||||
|
||||
if (dloc != &rect->dlo)
|
||||
/* we already did this for the
|
||||
* affected dlo */
|
||||
lws_fx_add(&dloc->box.w,
|
||||
&dloc->box.w, &wdelta);
|
||||
|
||||
rd = 1;
|
||||
|
||||
/* ... and then all of their row-mates
|
||||
* to the right also need their
|
||||
* x adjusting then */
|
||||
|
||||
while (dloc->row_list.next) {
|
||||
dloc = lws_container_of(
|
||||
dloc->row_list.next,
|
||||
lws_dlo_t, row_list);
|
||||
|
||||
lws_fx_add(&dloc->box.x,
|
||||
&dloc->box.x, &wdelta);
|
||||
}
|
||||
} lws_end_foreach_dll(cold);
|
||||
}
|
||||
|
||||
/* if a td, deal with row changes in height */
|
||||
|
||||
if (ps->dlo->row_list.owner) {
|
||||
lhp_table_row_t *tr = lws_container_of(
|
||||
ps->dlo->row_list.owner,
|
||||
lhp_table_row_t, row_dlos);
|
||||
lws_fx_t hdelta, oh;
|
||||
|
||||
oh = tr->height;
|
||||
lws_fx_set(tr->height, 0, 0);
|
||||
|
||||
/* discover the new width of column */
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, r1,
|
||||
lws_dll2_get_head(&tr->row_dlos)) {
|
||||
lws_dlo_t *dlor = lws_container_of(r1,
|
||||
lws_dlo_t, row_list);
|
||||
|
||||
if (lws_fx_comp(&dlor->box.h, &tr->height) > 0)
|
||||
tr->height = dlor->box.h;
|
||||
} lws_end_foreach_dll(r1);
|
||||
|
||||
/* new height - old row height */
|
||||
lws_fx_sub(&hdelta, &tr->height, &oh);
|
||||
|
||||
/*
|
||||
* Update all dlos in our row (except
|
||||
* ourselves) with the increased row height
|
||||
*/
|
||||
|
||||
lws_start_foreach_dll(struct lws_dll2 *, rold,
|
||||
lws_dll2_get_head(&tr->row_dlos)) {
|
||||
lws_dlo_t *dlor = lws_container_of(rold,
|
||||
lws_dlo_t, row_list);
|
||||
|
||||
if (dlor != &rect->dlo)
|
||||
/* we already did this for the
|
||||
* affected dlo */
|
||||
lws_fx_add(&dlor->box.h,
|
||||
&dlor->box.h, &hdelta);
|
||||
|
||||
/* ... so all of their col-mates below
|
||||
* also need their y adjusting then */
|
||||
|
||||
while (dlor->col_list.next) {
|
||||
dlor = lws_container_of(
|
||||
dlor->col_list.next,
|
||||
lws_dlo_t, col_list);
|
||||
|
||||
lws_fx_add(&dlor->box.y,
|
||||
&dlor->box.y, &hdelta);
|
||||
}
|
||||
|
||||
rd = 1;
|
||||
|
||||
} lws_end_foreach_dll(rold);
|
||||
}
|
||||
|
||||
/*
|
||||
* Row dimensions have to be reassessed?
|
||||
*/
|
||||
|
||||
if (rd) {
|
||||
lws_start_foreach_dll(struct lws_dll2 *, ro,
|
||||
lws_dll2_get_head(&pst->dlo->children)) {
|
||||
lws_dlo_t *dlo = lws_container_of(ro, lws_dlo_t, list);
|
||||
lws_dlo_dim_t dim;
|
||||
|
||||
lws_dlo_contents(dlo, &dim);
|
||||
lws_display_dlo_adjust_dims(dlo, &dim);
|
||||
} lws_end_foreach_dll(ro);
|
||||
}
|
||||
|
||||
if (psb && ps->css_position->propval != LCSP_PROPVAL_ABSOLUTE) {
|
||||
/* parent should account for our margin */
|
||||
if (elem_match == LHP_ELEM_DIV) {
|
||||
lws_fx_add(&psb->curx, &psb->curx, &ps->widest);
|
||||
/* now we applied ps->widest, reset it */
|
||||
lws_fx_set(ps->widest, 0, 0);
|
||||
psb->dlo_set_curx = ps->dlo;
|
||||
} else {
|
||||
/* needed for margin between table cells */
|
||||
lws_fx_add(&psb->curx, &psb->curx, lws_csp_px(ps->css_margin[CCPAS_LEFT], ps));
|
||||
lws_fx_add(&psb->curx, &psb->curx, lws_csp_px(ps->css_margin[CCPAS_RIGHT], ps));
|
||||
}
|
||||
|
||||
if (elem_match != LHP_ELEM_TD) {
|
||||
if (ps->css_display->propval != LCSP_PROPVAL_INLINE_BLOCK) {
|
||||
lws_fx_add(&psb->cury, &psb->cury, &ps->dlo->box.h);
|
||||
psb->dlo_set_cury = ps->dlo;
|
||||
}
|
||||
// lws_fx_add(&psb->cury, &psb->cury, &ps->dlo->margin[CCPAS_BOTTOM]);
|
||||
} else
|
||||
ps->widest = ps->dlo->box.w;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic LHP displaylist object layout callback... converts html elements
|
||||
* into DLOs on the display list
|
||||
*/
|
||||
|
||||
lws_stateful_ret_t
|
||||
lhp_displaylist_layout(lhp_ctx_t *ctx, char reason)
|
||||
{
|
||||
lhp_pstack_t *psb = NULL, *pst = NULL, *psp = NULL,
|
||||
*ps = lws_container_of(ctx->stack.tail, lhp_pstack_t, list);
|
||||
struct lws_context *cx = (struct lws_context *)ctx->user1;
|
||||
lws_dl_rend_t *drt = (lws_dl_rend_t *)ctx->user;
|
||||
lws_fx_t br[4], t1, indent, ox, w, h;
|
||||
const lws_display_font_t *f = NULL;
|
||||
lhp_table_col_t *tcol = NULL;
|
||||
lhp_table_row_t *trow = NULL;
|
||||
lws_dlo_t *abut_x, *abut_y;
|
||||
uint32_t col = 0xff000000;
|
||||
lws_dlo_text_t *txt;
|
||||
const lcsp_atr_t *a;
|
||||
lws_dlo_image_t u;
|
||||
const char *pname;
|
||||
char lastm = 0;
|
||||
int elem_match;
|
||||
lws_box_t box;
|
||||
char url[128];
|
||||
int n, s = 0;
|
||||
|
||||
/* default font choice */
|
||||
lws_font_choice_t fc = {
|
||||
.family_name = "term, serif",
|
||||
.fixed_height = 16,
|
||||
.weight = 400,
|
||||
};
|
||||
|
||||
if (!ps->font) {
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_FONT_SIZE);
|
||||
if (a)
|
||||
fc.fixed_height = (uint16_t)a->u.i.whole;
|
||||
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_FONT_FAMILY);
|
||||
if (a)
|
||||
fc.family_name = (const char *)&a[1];
|
||||
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_FONT_WEIGHT);
|
||||
if (a) {
|
||||
switch (a->propval) {
|
||||
case LCSP_PROPVAL_BOLD:
|
||||
fc.weight = 700;
|
||||
break;
|
||||
case LCSP_PROPVAL_BOLDER:
|
||||
fc.weight = 800;
|
||||
break;
|
||||
default:
|
||||
if (a->u.i.whole)
|
||||
fc.weight = (uint16_t)a->u.i.whole;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ps->font = lws_font_choose(cx, &fc);
|
||||
}
|
||||
f = ps->font;
|
||||
|
||||
psb = lws_css_get_parent_block(ctx, ps);
|
||||
|
||||
elem_match = 0;
|
||||
for (n = 0; n < (int)LWS_ARRAY_SIZE(elems); n++)
|
||||
if (ctx->npos == elems[n].elem_len &&
|
||||
!memcmp(ctx->buf, elems[n].elem, elems[n].elem_len))
|
||||
elem_match = n + 1;
|
||||
|
||||
switch (reason) {
|
||||
case LHPCB_CONSTRUCTED:
|
||||
case LHPCB_DESTRUCTED:
|
||||
case LHPCB_COMPLETE:
|
||||
case LHPCB_FAILED:
|
||||
break;
|
||||
|
||||
case LHPCB_ELEMENT_START:
|
||||
|
||||
switch (elem_match) {
|
||||
case LHP_ELEM_BR:
|
||||
newline(ctx, psb, ps, drt->dl);
|
||||
break;
|
||||
|
||||
case LHP_ELEM_TR:
|
||||
if (!psb)
|
||||
break;
|
||||
|
||||
pst = ps;
|
||||
while (pst && !pst->is_table)
|
||||
pst = lws_css_get_parent_block(ctx, pst);
|
||||
if (!pst) {
|
||||
lwsl_err("%s: td: no table found\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
pst->curx.whole = 0;
|
||||
pst->curx.frac = 0;
|
||||
psb->dlo_set_curx = NULL;
|
||||
|
||||
trow = lws_zalloc(sizeof(*trow), __func__);
|
||||
if (!trow) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
return LWS_SRET_FATAL;
|
||||
}
|
||||
lws_dll2_add_tail(&trow->list, &pst->dlo->table_rows);
|
||||
trow = NULL;
|
||||
pst->td_idx = 0;
|
||||
|
||||
goto do_rect;
|
||||
|
||||
case LHP_ELEM_TD:
|
||||
if (!psb) {
|
||||
lwsl_err("%s: td: no psb found\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
pst = ps;
|
||||
while (pst && !pst->is_table)
|
||||
pst = lws_css_get_parent_block(ctx, pst);
|
||||
if (!pst) {
|
||||
lwsl_err("%s: td: no table found\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
if (pst->td_idx >= (int)pst->dlo->table_cols.count) {
|
||||
tcol = lws_zalloc(sizeof(*tcol), __func__);
|
||||
if (!tcol) {
|
||||
lwsl_err("%s: OOM\n", __func__);
|
||||
return LWS_SRET_FATAL;
|
||||
}
|
||||
lws_dll2_add_tail(&tcol->list, &pst->dlo->table_cols);
|
||||
} else {
|
||||
tcol = lws_container_of(pst->dlo->table_cols.head, lhp_table_col_t, list);
|
||||
n = pst->td_idx;
|
||||
while (n--)
|
||||
tcol = lws_container_of(tcol->list.next, lhp_table_col_t, list);
|
||||
}
|
||||
|
||||
if (pst->dlo->table_rows.tail)
|
||||
trow = lws_container_of(pst->dlo->table_rows.tail, lhp_table_row_t, list);
|
||||
|
||||
goto do_rect;
|
||||
|
||||
case LHP_ELEM_TABLE:
|
||||
ps->is_table = 1;
|
||||
/* fallthru */
|
||||
case LHP_ELEM_DIV:
|
||||
|
||||
do_rect:
|
||||
lws_fx_set(box.x, 0, 0);
|
||||
lws_fx_set(box.y, 0, 0);
|
||||
lws_fx_set(box.h, 0, 0);
|
||||
lws_fx_set(box.w, 0, 0);
|
||||
abut_x = NULL;
|
||||
abut_y = NULL;
|
||||
|
||||
if (ps->css_position->propval == LCSP_PROPVAL_ABSOLUTE) {
|
||||
box.x = *lws_csp_px(ps->css_pos[CCPAS_LEFT], ps);
|
||||
box.y = *lws_csp_px(ps->css_pos[CCPAS_TOP], ps);
|
||||
} else {
|
||||
if (psb) {
|
||||
|
||||
/* margin adjusts our child box origin */
|
||||
lws_fx_add(&box.x, &psb->curx,
|
||||
lws_csp_px(ps->css_margin[CCPAS_LEFT], ps));
|
||||
box.y = psb->cury;
|
||||
abut_x = psb->dlo_set_curx;
|
||||
abut_y = psb->dlo_set_cury;
|
||||
//lws_fx_add(&box.y, &psb->cury,
|
||||
// lws_csp_px(ps->css_margin[CCPAS_TOP], ps));
|
||||
}
|
||||
}
|
||||
|
||||
/* If there's an explicit width, try to go with that */
|
||||
|
||||
if (ps->css_width &&
|
||||
ps->css_width->unit != LCSP_UNIT_NONE &&
|
||||
lws_fx_comp(lws_csp_px(ps->css_width, ps), &box.w) < 0)
|
||||
box.w = *lws_csp_px(ps->css_width, ps);
|
||||
|
||||
/* !!! we rely on this being nonzero to not infinite loop at text layout */
|
||||
|
||||
lws_fx_add(&box.w, &box.w,
|
||||
lws_csp_px(ps->css_padding[CCPAS_LEFT], ps));
|
||||
lws_fx_add(&box.w, &box.w,
|
||||
lws_csp_px(ps->css_padding[CCPAS_RIGHT], ps));
|
||||
|
||||
ps->drt.w = box.w;
|
||||
ps->curx = *lws_csp_px(ps->css_padding[CCPAS_LEFT], ps);
|
||||
ps->cury = *lws_csp_px(ps->css_padding[CCPAS_TOP], ps);
|
||||
|
||||
memset(br, 0, sizeof(br));
|
||||
|
||||
if (ps->css_border_radius[0])
|
||||
br[0] = *lws_csp_px(ps->css_border_radius[0], ps);
|
||||
if (ps->css_border_radius[1])
|
||||
br[1] = *lws_csp_px(ps->css_border_radius[1], ps);
|
||||
if (ps->css_border_radius[2])
|
||||
br[2] = *lws_csp_px(ps->css_border_radius[2], ps);
|
||||
if (ps->css_border_radius[3])
|
||||
br[3] = *lws_csp_px(ps->css_border_radius[3], ps);
|
||||
|
||||
psp = lws_container_of(ps->list.prev, lhp_pstack_t, list);
|
||||
|
||||
ps->dlo = (lws_dlo_t *)lws_display_dlo_rect_new(drt->dl,
|
||||
ps->css_position->propval == LCSP_PROPVAL_ABSOLUTE ? NULL : psp->dlo,
|
||||
&box, br, ps->css_background_color ?
|
||||
ps->css_background_color->u.rgba : 0);
|
||||
if (!ps->dlo) {
|
||||
lwsl_err("%s: FAILED to create rect\n", __func__);
|
||||
return LWS_SRET_FATAL;
|
||||
}
|
||||
|
||||
ps->dlo->abut_x = abut_x;
|
||||
ps->dlo->abut_y = abut_y;
|
||||
|
||||
if (psb)
|
||||
lws_fx_add(&psb->curx, &psb->curx,
|
||||
lws_csp_px(ps->css_margin[CCPAS_RIGHT], ps));
|
||||
|
||||
if (tcol)
|
||||
lws_dll2_add_tail(&ps->dlo->col_list, &tcol->col_dlos);
|
||||
if (trow)
|
||||
lws_dll2_add_tail(&ps->dlo->row_list, &trow->row_dlos);
|
||||
|
||||
lws_lhp_tag_dlo_id(ctx, ps, ps->dlo);
|
||||
lhp_set_dlo_padding_margin(ps, ps->dlo);
|
||||
break;
|
||||
|
||||
case LHP_ELEM_IMG:
|
||||
pname = lws_html_get_atr(ps, "src", 3);
|
||||
|
||||
if (!psb)
|
||||
break;
|
||||
|
||||
if (ps->css_position->propval == LCSP_PROPVAL_ABSOLUTE) {
|
||||
box.x = *lws_csp_px(ps->css_pos[CCPAS_LEFT], ps);
|
||||
box.y = *lws_csp_px(ps->css_pos[CCPAS_TOP], ps);
|
||||
} else {
|
||||
box.x = psb->curx;
|
||||
box.y = psb->cury;
|
||||
}
|
||||
|
||||
lws_fx_set(box.x, 0, 0);
|
||||
lws_fx_set(box.y, 0, 0);
|
||||
|
||||
if (psb) {
|
||||
lws_fx_add(&box.x, &box.x,
|
||||
lws_csp_px(psb->css_margin[CCPAS_LEFT], psb));
|
||||
lws_fx_add(&box.y, &box.y,
|
||||
lws_csp_px(psb->css_margin[CCPAS_TOP], psb));
|
||||
}
|
||||
|
||||
box.h = ctx->ic.wh_px[1]; /* placeholder */
|
||||
lws_fx_sub(&box.w, &ctx->ic.wh_px[0], &box.x);
|
||||
|
||||
if (ps->css_width &&
|
||||
lws_fx_comp(lws_csp_px(ps->css_width, ps), &box.w) > 0)
|
||||
box.w = *lws_csp_px(ps->css_width, ps);
|
||||
|
||||
if (lws_http_rel_to_url(url, sizeof(url),
|
||||
ctx->base_url, pname))
|
||||
break;
|
||||
|
||||
if (lws_dlo_ss_find(cx, url, &u))
|
||||
break;
|
||||
|
||||
lws_lhp_tag_dlo_id(ctx, ps, (lws_dlo_t *)(u.u.dlo_jpeg));
|
||||
|
||||
w = *lws_csp_px(lws_css_cascade_get_prop_atr(ctx,
|
||||
LCSP_PROP_WIDTH), ps);
|
||||
h = *lws_csp_px(lws_css_cascade_get_prop_atr(ctx,
|
||||
LCSP_PROP_HEIGHT), ps);
|
||||
|
||||
if (!w.whole || !h.whole) {
|
||||
w = ((lws_dlo_t *)(u.u.dlo_jpeg))->box.w;
|
||||
h = ((lws_dlo_t *)(u.u.dlo_jpeg))->box.w;
|
||||
}
|
||||
|
||||
if (psb) {
|
||||
lws_fx_add(&psb->curx, &psb->curx, &w);
|
||||
lws_fx_add(&psb->cury, &psb->cury, &h);
|
||||
psb->dlo_set_curx = ps->dlo;
|
||||
psb->dlo_set_cury = ps->dlo;
|
||||
if (lws_fx_comp(&psb->curx, &psb->widest) > 0)
|
||||
psb->widest = psb->curx;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LHPCB_ELEMENT_END:
|
||||
|
||||
if (ctx->npos == 2 && ctx->buf[0] == 'h' &&
|
||||
ctx->buf[1] > '0' && ctx->buf[1] <= '6') {
|
||||
|
||||
if (!psb)
|
||||
break;
|
||||
|
||||
newline(ctx, psb, ps, drt->dl);
|
||||
lws_fx_add(&psb->cury, &psb->cury,
|
||||
lws_csp_px(ps->css_padding[CCPAS_BOTTOM], ps));
|
||||
lws_fx_add(&psb->cury, &psb->cury,
|
||||
lws_csp_px(ps->css_margin[CCPAS_BOTTOM], ps));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (elem_match) {
|
||||
|
||||
case LHP_ELEM_TR:
|
||||
pst = ps;
|
||||
while (pst && !pst->is_table)
|
||||
pst = lws_css_get_parent_block(ctx, pst);
|
||||
if (!pst) {
|
||||
lwsl_err("%s: /td: no table\n", __func__);
|
||||
break;
|
||||
}
|
||||
|
||||
pst->tr_idx++;
|
||||
pst->td_idx = 0;
|
||||
goto do_end_rect;
|
||||
|
||||
case LHP_ELEM_TD:
|
||||
pst = ps;
|
||||
while (pst && !pst->is_table)
|
||||
pst = lws_css_get_parent_block(ctx, pst);
|
||||
if (!pst) {
|
||||
lwsl_err("%s: /td: no table\n", __func__);
|
||||
break;
|
||||
}
|
||||
pst->td_idx++;
|
||||
goto do_end_rect;
|
||||
|
||||
|
||||
/* fallthru */
|
||||
|
||||
case LHP_ELEM_TABLE:
|
||||
case LHP_ELEM_DIV:
|
||||
do_end_rect:
|
||||
ox = ps->curx;
|
||||
|
||||
if (lws_fx_comp(&ox, &ps->widest) > 0)
|
||||
ps->widest = ox;
|
||||
|
||||
newline(ctx, ps, ps, drt->dl);
|
||||
|
||||
if (lws_lhp_dlo_adjust_div_type_element(ctx, psb, pst, ps, elem_match))
|
||||
break;
|
||||
|
||||
if (lws_fx_comp(&ps->curx, &ps->widest) > 0)
|
||||
ps->widest = ps->curx;
|
||||
|
||||
/* move parent on according to used area plus bottom margin */
|
||||
|
||||
if (psb && ps->css_position->propval != LCSP_PROPVAL_ABSOLUTE) {
|
||||
|
||||
switch (ps->css_display->propval) {
|
||||
case LCSP_PROPVAL_BLOCK:
|
||||
case LCSP_PROPVAL_TABLE:
|
||||
case LCSP_PROPVAL_TABLE_ROW:
|
||||
lws_fx_set(psb->curx, 0, 0);
|
||||
psb->dlo_set_curx = NULL;
|
||||
|
||||
if (ps->css_display->propval == LCSP_PROPVAL_TABLE_ROW)
|
||||
break;
|
||||
lws_fx_add(&psb->cury, &psb->cury, lws_csp_px(ps->css_margin[CCPAS_BOTTOM], ps));
|
||||
break;
|
||||
|
||||
case LCSP_PROPVAL_INLINE_BLOCK:
|
||||
//lws_fx_add(&psb->cury, &psb->cury, lws_csp_px(ps->css_margin[CCPAS_BOTTOM], ps));
|
||||
lws_fx_add(&psb->curx, &psb->curx, &ps->widest);
|
||||
lws_fx_add(&psb->curx, &psb->curx, lws_csp_px(ps->css_margin[CCPAS_RIGHT], ps));
|
||||
lws_fx_set(ps->widest, 0, 0);
|
||||
psb->dlo_set_curx = ps->dlo;
|
||||
psb->dlo_set_cury = ps->dlo;
|
||||
break;
|
||||
|
||||
default:
|
||||
lws_fx_add(&psb->curx, &psb->curx, &ps->widest);
|
||||
psb->dlo_set_curx = ps->dlo;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lws_fx_comp(&psb->curx, &psb->widest) > 0)
|
||||
psb->widest = psb->curx;
|
||||
}
|
||||
|
||||
ps->dlo = NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case LHPCB_CONTENT:
|
||||
|
||||
if (!ps->css_display ||
|
||||
ps->css_display->propval == LCSP_PROPVAL_NONE)
|
||||
break;
|
||||
|
||||
if (ps->css_color)
|
||||
col = ps->css_color->u.rgba;
|
||||
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_FONT_SIZE);
|
||||
if (a)
|
||||
fc.fixed_height = (uint16_t)a->u.i.whole;
|
||||
|
||||
a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_FONT_FAMILY);
|
||||
if (a)
|
||||
fc.family_name = (const char *)&a[1];
|
||||
|
||||
for (n = 0; n < ctx->npos; n++)
|
||||
if (ctx->buf[n] == '\n')
|
||||
s++;
|
||||
|
||||
if (s == ctx->npos)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Let's not deal with things off the bottom of the display
|
||||
* surface.
|
||||
*/
|
||||
|
||||
if (psb && psb->cury.whole > ctx->ic.wh_px[LWS_LHPREF_HEIGHT].whole)
|
||||
return 0;
|
||||
|
||||
if (!psb)
|
||||
return 0;
|
||||
|
||||
f = lws_font_choose(cx, &fc);
|
||||
|
||||
n = s;
|
||||
while (n < ctx->npos) {
|
||||
int m;
|
||||
|
||||
lws_fx_set(box.x, 0, 0);
|
||||
lws_fx_set(box.y, 0, 0);
|
||||
lws_fx_set(box.w, 0, 0);
|
||||
|
||||
if (n == s && !(psb->runon & 1)) {
|
||||
lws_fx_set(indent, 0, 0);
|
||||
} else
|
||||
indent = psb->curx;
|
||||
lws_fx_add(&box.x, &indent,
|
||||
lws_csp_px(ps->css_padding[CCPAS_LEFT], ps));
|
||||
lws_fx_add(&box.y, &box.y, &psb->cury);
|
||||
|
||||
box.h.whole = (int32_t)f->choice.fixed_height;
|
||||
box.h.frac = 0;
|
||||
|
||||
if (psb->css_width &&
|
||||
(psb->css_width->propval == LCSP_PROPVAL_AUTO ||
|
||||
ps->css_width->propval == LCSP_PROPVAL_AUTO)) {
|
||||
//lws_fx_sub(&box.w, &ctx->ic.wh_px[0], &box.x);
|
||||
box.w = ctx->ic.wh_px[0];
|
||||
} else {
|
||||
lws_fx_sub(&t1, &psb->drt.w,
|
||||
lws_csp_px(psb->css_padding[CCPAS_LEFT], psb));
|
||||
lws_fx_sub(&box.w, &t1,
|
||||
lws_csp_px(psb->css_padding[CCPAS_RIGHT], psb));
|
||||
}
|
||||
|
||||
if (!box.w.whole)
|
||||
lws_fx_sub(&box.w, &ctx->ic.wh_px[0], &box.x);
|
||||
assert(psb);
|
||||
|
||||
txt = lws_display_dlo_text_new(drt->dl,
|
||||
(lws_dlo_t *)psb->dlo, &box, f);
|
||||
if (!txt) {
|
||||
lwsl_err("%s: failed to alloc text\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
runon(psb, &txt->dlo);
|
||||
txt->flags |= LWSDLO_TEXT_FLAG_WRAP;
|
||||
|
||||
lhp_set_dlo_padding_margin(ps, &txt->dlo);
|
||||
|
||||
// a = lws_css_cascade_get_prop_atr(ctx, LCSP_PROP_TEXT_ALIGN);
|
||||
|
||||
//lwsl_hexdump_notice(ctx->buf + n, (size_t)(ctx->npos - n));
|
||||
m = lws_display_dlo_text_update(txt, col, indent,
|
||||
ctx->buf + n,
|
||||
(size_t)(ctx->npos - n));
|
||||
if (m < 0) {
|
||||
lwsl_err("text_update ret %d\n", m);
|
||||
break;
|
||||
}
|
||||
|
||||
if (m == 2 && lastm)
|
||||
return 0;
|
||||
|
||||
lastm = m == 2;
|
||||
|
||||
n = (int)((size_t)n + txt->text_len);
|
||||
txt->dlo.box.w = txt->bounding_box.w;
|
||||
txt->dlo.box.h = txt->bounding_box.h;
|
||||
|
||||
lws_fx_add(&psb->curx, &psb->curx, &txt->bounding_box.w);
|
||||
psb->dlo_set_curx = &txt->dlo;
|
||||
|
||||
//lwsl_user("%s: bounding width %d, m: %d, text %.*s\n",
|
||||
// __func__, txt->bounding_box.w.whole, m,
|
||||
// ctx->npos, ctx->buf);
|
||||
|
||||
if (m > 0) { /* wrapping */
|
||||
newline(ctx, psb, ps, drt->dl);
|
||||
lws_fx_set(ps->curx, 0, 0);
|
||||
lws_fx_set(psb->curx, 0, 0);
|
||||
psb->dlo_set_curx = NULL;
|
||||
lws_fx_add(&ps->cury, &ps->cury, &txt->bounding_box.h);
|
||||
psb->dlo_set_cury = &txt->dlo;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case LHPCB_COMMENT:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
184
Kinc/Sources/kinc/libs/misc/dlo/dlo-png.c
Normal file
184
Kinc/Sources/kinc/libs/misc/dlo/dlo-png.c
Normal file
@ -0,0 +1,184 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object: PNG
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
void
|
||||
lws_display_dlo_png_destroy(struct lws_dlo *dlo)
|
||||
{
|
||||
lws_dlo_png_t *dlo_png = lws_container_of(dlo, lws_dlo_png_t, dlo);
|
||||
|
||||
#if defined(LWS_WITH_CLIENT) && defined(LWS_WITH_SECURE_STREAMS)
|
||||
lws_ss_destroy(&dlo_png->flow.h);
|
||||
#endif
|
||||
lws_buflist_destroy_all_segments(&dlo_png->flow.bl);
|
||||
|
||||
if (dlo_png->png)
|
||||
lws_upng_free(&dlo_png->png);
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_render_png(struct lws_display_render_state *rs)
|
||||
{
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_dlo_png_t *dlo_png = lws_container_of(dlo, lws_dlo_png_t, dlo);
|
||||
lws_fx_t ax, ay, t, t1;
|
||||
lws_display_colour_t pc;
|
||||
lws_stateful_ret_t r;
|
||||
const uint8_t *pix;
|
||||
int s, e;
|
||||
|
||||
if (!lws_upng_get_height(dlo_png->png)) {
|
||||
lwsl_info("%s: png does not have dimensions yet\n", __func__);
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
}
|
||||
|
||||
lws_fx_add(&ax, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&t, &ax, &dlo->box.w);
|
||||
lws_fx_add(&ay, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
lws_fx_add(&t1, &ay, &dlo->box.h);
|
||||
|
||||
s = ax.whole;
|
||||
e = lws_fx_roundup(&t);
|
||||
|
||||
if (rs->curr > lws_fx_roundup(&t1))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
if (rs->curr - lws_fx_roundup(&ay) >
|
||||
(int)lws_upng_get_height(dlo_png->png))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
if (s < 0)
|
||||
s = 0;
|
||||
if (s > rs->ic->wh_px[0].whole)
|
||||
return LWS_SRET_OK; /* off to the right */
|
||||
if (e > rs->ic->wh_px[0].whole)
|
||||
e = rs->ic->wh_px[0].whole - 1;
|
||||
if (e <= 0)
|
||||
return LWS_SRET_OK; /* off to the left */
|
||||
|
||||
do {
|
||||
if (lws_flow_feed(&dlo_png->flow))
|
||||
/* if he says WANT_INPUT, we have nothing in the buflist */
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
|
||||
pix = NULL;
|
||||
r = lws_upng_emit_next_line(dlo_png->png, &pix, &dlo_png->flow.data,
|
||||
&dlo_png->flow.len, rs->html == 1 /* hold at metadata */);
|
||||
|
||||
if (r & LWS_SRET_NO_FURTHER_IN)
|
||||
dlo_png->flow.state = LWSDLOFLOW_STATE_READ_COMPLETED;
|
||||
|
||||
if (r & (LWS_SRET_FATAL | LWS_SRET_YIELD) || r == LWS_SRET_OK)
|
||||
return r;
|
||||
|
||||
r = lws_flow_req(&dlo_png->flow);
|
||||
if (r & LWS_SRET_WANT_INPUT)
|
||||
return r;
|
||||
|
||||
} while (!pix);
|
||||
|
||||
pix = pix + (( (unsigned int)(s - ax.whole) *
|
||||
(lws_upng_get_pixelsize(dlo_png->png) / 8)));
|
||||
|
||||
while (s < e && s >= ax.whole && s < lws_fx_roundup(&t) &&
|
||||
(s - ax.whole) < (int)lws_upng_get_width(dlo_png->png)) {
|
||||
|
||||
if (lws_upng_get_pixelsize(dlo_png->png))
|
||||
pc = LWSDC_RGBA(pix[0], pix[0], pix[0], pix[1]);
|
||||
|
||||
pc = LWSDC_RGBA(pix[0], pix[1], pix[2], pix[3]);
|
||||
|
||||
lws_surface_set_px(rs->ic, rs->line, s, &pc);
|
||||
|
||||
s++;
|
||||
pix += lws_upng_get_pixelsize(dlo_png->png) / 8;
|
||||
}
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_dlo_png_metadata_scan(lws_dlo_png_t *dlo_png)
|
||||
{
|
||||
lws_stateful_ret_t r;
|
||||
size_t l, l1;
|
||||
const uint8_t *pix;
|
||||
|
||||
/*
|
||||
* If we don't have the image metadata yet, provide small chunks of the
|
||||
* source data until we do have the image metadata, but small enough
|
||||
* we can't produce any decoded pixels too early.
|
||||
*/
|
||||
|
||||
while (!lws_upng_get_height(dlo_png->png) && dlo_png->flow.len) {
|
||||
l1 = l = dlo_png->flow.len > 33 ? 33 : dlo_png->flow.len;
|
||||
|
||||
r = lws_upng_emit_next_line(dlo_png->png, &pix, &dlo_png->flow.data, &l, 1);
|
||||
if (r & LWS_SRET_FATAL) {
|
||||
lwsl_err("%s: hdr parse failed\n", __func__);
|
||||
return r;
|
||||
}
|
||||
|
||||
dlo_png->flow.len -= l1 - l;
|
||||
|
||||
if (lws_upng_get_height(dlo_png->png)) {
|
||||
lwsl_info("png: w %d, h %d\n",
|
||||
lws_upng_get_width(dlo_png->png),
|
||||
lws_upng_get_height(dlo_png->png));
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
}
|
||||
|
||||
lws_dlo_png_t *
|
||||
lws_display_dlo_png_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
|
||||
lws_box_t *box)
|
||||
{
|
||||
lws_dlo_png_t *dlo_png = lws_zalloc(sizeof(*dlo_png), __func__);
|
||||
|
||||
dlo_png->png = lws_upng_new();
|
||||
if (!dlo_png->png)
|
||||
goto bail;
|
||||
|
||||
dlo_png->dlo.box = *box;
|
||||
dlo_png->dlo.render = lws_display_render_png;
|
||||
dlo_png->dlo._destroy = lws_display_dlo_png_destroy;
|
||||
|
||||
lws_display_dlo_add(dl, dlo_parent, &dlo_png->dlo);
|
||||
|
||||
return dlo_png;
|
||||
|
||||
bail:
|
||||
if (dlo_png->png)
|
||||
lws_upng_free(&dlo_png->png);
|
||||
lws_free(dlo_png);
|
||||
|
||||
return NULL;
|
||||
}
|
247
Kinc/Sources/kinc/libs/misc/dlo/dlo-rect.c
Normal file
247
Kinc/Sources/kinc/libs/misc/dlo/dlo-rect.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object: rect / rounded rect
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
/* returns where on the x axis we intercept ys (== (curr - ory) ^ 2 ) */
|
||||
|
||||
static void
|
||||
isect(lws_circle_t *c, lws_fx_t *f, lws_fx_t *axsq)
|
||||
{
|
||||
assert(axsq->whole >= 0);
|
||||
assert(c->rsq.whole >= 0);
|
||||
|
||||
lws_fx_sub(f, &c->rsq, axsq);
|
||||
|
||||
if (f->whole < 0) {
|
||||
f->whole = 0;
|
||||
f->frac = 0;
|
||||
} else
|
||||
lws_fx_sqrt(f, f);
|
||||
|
||||
lws_fx_sub(f, &c->r, f);
|
||||
}
|
||||
|
||||
/* give it absolute x, returns intersection point as absolute y*/
|
||||
|
||||
static void
|
||||
isect_y_from_x(lws_circle_t *c, lws_fx_t *x, lws_fx_t *y)
|
||||
{
|
||||
lws_fx_t t, t1;
|
||||
|
||||
lws_fx_sub(y, x, &c->orx);
|
||||
lws_fx_mul(&t, y, y);
|
||||
lws_fx_sub(&t1, &c->rsq, &t);
|
||||
lws_fx_sqrt(&t, &t1);
|
||||
lws_fx_add(y, &c->ory, &t);
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_render_rect(struct lws_display_render_state *rs)
|
||||
/* const lws_surface_info_t *ic, struct lws_dlo *dlo,
|
||||
const lws_box_t *origin, lws_display_scalar curr,
|
||||
uint8_t *line, lws_colour_error_t **nle) */
|
||||
{
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_dlo_rect_t *r = lws_container_of(dlo, lws_dlo_rect_t, dlo);
|
||||
lws_fx_t cf, y, w, trim, s, e, t2, sfy;
|
||||
lws_display_colour_t dc;
|
||||
int n, le, os;
|
||||
|
||||
if (!LWSDC_ALPHA(dlo->dc))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
if (!r->init) {
|
||||
lws_fx_add(&r->db.x, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&r->db.y, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
lws_fx_add(&r->right, &r->db.x, &dlo->box.w);
|
||||
lws_fx_add(&r->btm, &r->db.y, &dlo->box.h);
|
||||
lws_fx_add(&r->c[0].ory, &r->db.y, &r->c[0].r);
|
||||
lws_fx_add(&r->c[1].ory, &r->db.y, &r->c[1].r);
|
||||
lws_fx_sub(&r->c[2].ory, &r->btm, &r->c[2].r);
|
||||
lws_fx_sub(&r->c[3].ory, &r->btm, &r->c[3].r);
|
||||
lws_fx_add(&r->c[0].orx, &r->db.x, &r->c[0].r);
|
||||
lws_fx_sub(&r->c[1].orx, &r->right, &r->c[1].r);
|
||||
lws_fx_add(&r->c[2].orx, &r->db.x, &r->c[2].r);
|
||||
lws_fx_sub(&r->c[3].orx, &r->right, &r->c[3].r);
|
||||
|
||||
r->init = 1;
|
||||
}
|
||||
|
||||
if (lws_fx_comp(&r->db.x, &rs->ic->wh_px[0]) >= 0)
|
||||
return LWS_SRET_OK; /* off to the right */
|
||||
|
||||
if (rs->curr < r->db.y.whole - 1 || rs->curr > lws_fx_roundup(&r->btm))
|
||||
return LWS_SRET_OK;
|
||||
|
||||
s = r->db.x;
|
||||
lws_fx_add(&e, &s, &dlo->box.w);
|
||||
|
||||
cf.whole = rs->curr;
|
||||
cf.frac = 50000000;
|
||||
|
||||
/*
|
||||
* Account for four independently radiused corners
|
||||
*
|
||||
* Fractional pixel occupancy is represented by modulating alpha.
|
||||
*
|
||||
* We know that the subpixel intersection on the circle is at yo.frac +
|
||||
* radius.frac which usually won't align to any pixel boundary.
|
||||
*/
|
||||
|
||||
for (n = 0; n < 4; n++) {
|
||||
lws_fx_sub(&y, &cf, &r->c[n].ory);
|
||||
lws_fx_mul(&r->c[n].ys, &y, &y);
|
||||
}
|
||||
|
||||
/* For this y line, find out how many x pixels we can skip at start
|
||||
* and end before and after the first pixels that intersect */
|
||||
|
||||
if (rs->curr <= (r->c[0].ory.whole)) { /* top left trims s */
|
||||
isect(&r->c[0], &trim, &r->c[0].ys /* (cf - ory)^2 */);
|
||||
lws_fx_add(&s, &s, &trim);
|
||||
}
|
||||
|
||||
if (rs->curr <= (r->c[1].ory.whole)) { /* top right trims e */
|
||||
isect(&r->c[1], &trim, &r->c[1].ys);
|
||||
lws_fx_sub(&e, &e, &trim);
|
||||
}
|
||||
|
||||
if (rs->curr >= (r->c[2].ory.whole)) { /* bottom left trims s */
|
||||
isect(&r->c[2], &trim, &r->c[2].ys);
|
||||
lws_fx_add(&s, &s, &trim);
|
||||
}
|
||||
|
||||
if (rs->curr >= (r->c[3].ory.whole)) { /* bottom right trims e */
|
||||
isect(&r->c[3], &trim, &r->c[3].ys);
|
||||
lws_fx_sub(&e, &e, &trim);
|
||||
}
|
||||
|
||||
/* clips */
|
||||
|
||||
if (s.whole < 0)
|
||||
lws_fx_set(s, 0, 0);
|
||||
if (e.whole >= rs->ic->wh_px[0].whole)
|
||||
lws_fx_set(e, rs->ic->wh_px[0].whole - 1, 0);
|
||||
if (e.whole <= 0 || e.whole < s.whole)
|
||||
return LWS_SRET_OK; /* off to the left */
|
||||
|
||||
lws_fx_sub(&w, &e, &s);
|
||||
if (lws_fx_comp(&w, &dlo->box.w) > 0)
|
||||
lws_fx_add(&e, &s, &dlo->box.w);
|
||||
|
||||
/* render the part of the line occupied by the rect body */
|
||||
|
||||
sfy = s;
|
||||
os = s.whole;
|
||||
s.frac = 0;
|
||||
le = e.whole + 1;
|
||||
|
||||
while (s.whole <= le) {
|
||||
unsigned int alpha = dlo->dc >> 24;
|
||||
|
||||
if (rs->curr <= r->c[0].ory.whole - 1 && s.whole >= r->db.x.whole &&
|
||||
lws_fx_comp(&s, &r->c[0].orx) <= 0) {
|
||||
isect_y_from_x(&r->c[0], &s, &t2);
|
||||
lws_fx_sub(&t2, &t2, &r->c[0].r);
|
||||
lws_fx_sub(&t2, &t2, &r->c[0].r);
|
||||
if (t2.frac && lws_fx_rounddown(&t2) == rs->curr)
|
||||
alpha = (((uint64_t)t2.frac * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
}
|
||||
if (rs->curr <= (r->c[1].ory.whole - 1) &&
|
||||
s.whole >= r->c[1].orx.whole) {
|
||||
isect_y_from_x(&r->c[1], &s, &t2);
|
||||
lws_fx_sub(&t2, &t2, &r->c[1].r);
|
||||
lws_fx_sub(&t2, &t2, &r->c[1].r);
|
||||
if (t2.frac && lws_fx_rounddown(&t2) == rs->curr)
|
||||
alpha = (((uint64_t)t2.frac * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
}
|
||||
if (rs->curr >= (r->c[2].ory.whole + 1) &&
|
||||
s.whole < lws_fx_roundup(&r->c[2].orx)) {
|
||||
isect_y_from_x(&r->c[2], &s, &t2);
|
||||
if (t2.frac && lws_fx_rounddown(&t2) == rs->curr)
|
||||
alpha = (((uint64_t)t2.frac * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
}
|
||||
|
||||
if (rs->curr >= (r->c[3].ory.whole + 1) &&
|
||||
s.whole >= lws_fx_roundup(&r->c[3].orx)) {
|
||||
isect_y_from_x(&r->c[3], &s, &t2);
|
||||
if (t2.frac && lws_fx_rounddown(&t2) == rs->curr)
|
||||
alpha = (((uint64_t)t2.frac * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
}
|
||||
|
||||
if (s.whole == os && sfy.frac)
|
||||
alpha = (((uint64_t)(99999999 - sfy.frac) * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
if (s.whole == le)
|
||||
alpha = (((uint64_t)e.frac * alpha) /
|
||||
LWS_FX_FRACTION_MSD) & 0xff;
|
||||
|
||||
|
||||
dc = (lws_display_colour_t)(((dlo->dc & 0xffffff) |
|
||||
(uint32_t)(alpha << 24)));
|
||||
|
||||
lws_surface_set_px(rs->ic, rs->line, s.whole, &dc);
|
||||
|
||||
s.whole++;
|
||||
}
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
|
||||
lws_dlo_rect_t *
|
||||
lws_display_dlo_rect_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
|
||||
lws_box_t *box, const lws_fx_t *radii,
|
||||
lws_display_colour_t dc)
|
||||
{
|
||||
lws_dlo_rect_t *r = lws_zalloc(sizeof(*r), __func__);
|
||||
int n;
|
||||
|
||||
if (!r)
|
||||
return NULL;
|
||||
|
||||
r->dlo.render = lws_display_render_rect;
|
||||
r->dlo.box = *box;
|
||||
r->dlo.dc = dc;
|
||||
if (radii) {
|
||||
r->c[0].r = radii[0];
|
||||
r->c[1].r = radii[1];
|
||||
r->c[2].r = radii[2];
|
||||
r->c[3].r = radii[3];
|
||||
|
||||
for (n = 0; n < 4; n++)
|
||||
lws_fx_mul(&r->c[n].rsq, &r->c[n].r, &r->c[n].r);
|
||||
}
|
||||
|
||||
lws_display_dlo_add(dl, dlo_parent, &r->dlo);
|
||||
|
||||
return r;
|
||||
}
|
342
Kinc/Sources/kinc/libs/misc/dlo/dlo-ss.c
Normal file
342
Kinc/Sources/kinc/libs/misc/dlo/dlo-ss.c
Normal file
@ -0,0 +1,342 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Secure Streams as DLO transport
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
LWS_SS_USER_TYPEDEF
|
||||
sul_cb_t on_rx;
|
||||
lhp_ctx_t *lhp;
|
||||
lws_sorted_usec_list_t *ssevsul; /* sul to use to resume rz */
|
||||
lws_sorted_usec_list_t sul; /* used for initial metadata cb */
|
||||
lws_dlo_image_t u; /* we use the lws_flow_t in here */
|
||||
lws_dll2_t active_asset_list; /*cx->active_assets*/
|
||||
uint8_t type; /* LWSDLOSS_TYPE_ */
|
||||
char url[96];
|
||||
} dloss_t;
|
||||
|
||||
/*
|
||||
* dlo images call back here when they have their dimensions (or have failed)
|
||||
*/
|
||||
|
||||
void
|
||||
lws_lhp_image_dimensions_cb(lws_sorted_usec_list_t *sul)
|
||||
{
|
||||
dloss_t *m = lws_container_of(sul, dloss_t, sul);
|
||||
lws_display_render_state_t *rs = lws_container_of(m->ssevsul,
|
||||
lws_display_render_state_t, sul);
|
||||
lws_dlo_dim_t dim;
|
||||
lws_dlo_t *dlo = &m->u.u.dlo_png->dlo;
|
||||
|
||||
if (m->u.failed) {
|
||||
dlo->box.w.whole = -1;
|
||||
dlo->box.h.whole = -1;
|
||||
lwsl_notice("%s: Failing %s\n", __func__, m->url);
|
||||
} else {
|
||||
|
||||
dlo->box.w.whole = (int32_t)lws_dlo_image_width(&m->u);
|
||||
dlo->box.h.whole = (int32_t)lws_dlo_image_height(&m->u);
|
||||
|
||||
lwsl_err("%s: setting dlo box %d x %d\n", __func__,
|
||||
(int)dlo->box.w.whole, (int)dlo->box.h.whole);
|
||||
#if 1
|
||||
lws_dlo_contents(dlo, &dim);
|
||||
lws_display_dlo_adjust_dims(dlo, &dim);
|
||||
|
||||
if (dlo->list.owner) {
|
||||
dlo = lws_container_of(dlo->list.owner, lws_dlo_t, children);
|
||||
|
||||
lws_dlo_contents(dlo, &dim);
|
||||
lws_display_dlo_adjust_dims(dlo, &dim);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (rs->html != 1) {
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0, m->ssevsul, m->on_rx, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
/* we are resuming the html parsing */
|
||||
lws_lhp_ss_html_parse_from_lhp(m->lhp);
|
||||
}
|
||||
|
||||
/* secure streams payload interface */
|
||||
|
||||
static lws_ss_state_return_t
|
||||
dloss_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
|
||||
{
|
||||
dloss_t *m = (dloss_t *)userobj;
|
||||
lws_stateful_ret_t r;
|
||||
|
||||
lwsl_info("%s: %u\n", __func__, (unsigned int)len);
|
||||
|
||||
if (m->type == LWSDLOSS_TYPE_CSS) {
|
||||
m->lhp->finish_css = !!(flags & LWSSS_FLAG_EOM);
|
||||
m->lhp->is_css = 1;
|
||||
r = lws_lhp_parse(m->lhp, &buf, &len);
|
||||
m->lhp->is_css = 0;
|
||||
|
||||
if (flags & LWSSS_FLAG_EOM)
|
||||
lws_dll2_remove(&m->active_asset_list);
|
||||
|
||||
if (r & LWS_SRET_FATAL)
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
|
||||
if (r & LWS_SRET_AWAIT_RETRY) {
|
||||
lwsl_warn("%s: returning to await retry\n", __func__);
|
||||
if (!m->lhp->await_css_done)
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0,
|
||||
m->lhp->sshtmlevsul,
|
||||
m->lhp->sshtmlevcb, 1);
|
||||
}
|
||||
goto okie;
|
||||
}
|
||||
|
||||
/* .flow is at the same offset in both dlo_jpeg and dlo_png */
|
||||
|
||||
if (len &&
|
||||
lws_buflist_append_segment(&m->u.u.dlo_jpeg->flow.bl, buf, len) < 0) {
|
||||
m->u.failed = 1;
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0,
|
||||
&m->sul, lws_lhp_image_dimensions_cb, 1);
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
}
|
||||
|
||||
// lwsl_notice("%s: buflen size %d\n", __func__,
|
||||
// (int)lws_buflist_total_len(&m->u.u.dlo_jpeg->flow.bl));
|
||||
|
||||
if (flags & LWSSS_FLAG_EOM) {
|
||||
m->u.u.dlo_jpeg->flow.state = LWSDLOFLOW_STATE_READ_COMPLETED;
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
}
|
||||
|
||||
if (!lws_dlo_image_width(&m->u)) {
|
||||
lws_flow_feed(&m->u.u.dlo_jpeg->flow);
|
||||
r = lws_dlo_image_metadata_scan(&m->u);
|
||||
lws_flow_req(&m->u.u.dlo_jpeg->flow);
|
||||
|
||||
if (r & LWS_SRET_FATAL) {
|
||||
m->u.failed = 1;
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0,
|
||||
&m->sul, lws_lhp_image_dimensions_cb, 1);
|
||||
return LWSSSSRET_DISCONNECT_ME;
|
||||
}
|
||||
|
||||
if (r != LWS_SRET_WANT_INPUT) {
|
||||
lwsl_notice("%s: seen metadata\n", __func__);
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0,
|
||||
&m->sul, lws_lhp_image_dimensions_cb, 1);
|
||||
} //else
|
||||
//lwsl_err("%s: metadata scan no end yet\n", __func__);
|
||||
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
okie:
|
||||
lws_sul_schedule(lws_ss_get_context(m->ss), 0, m->ssevsul, m->on_rx, 1);
|
||||
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
static lws_ss_state_return_t
|
||||
dloss_state(void *userobj, void *sh, lws_ss_constate_t state,
|
||||
lws_ss_tx_ordinal_t ack)
|
||||
{
|
||||
dloss_t *m = (dloss_t *)userobj;
|
||||
|
||||
switch (state) {
|
||||
case LWSSSCS_CREATING:
|
||||
break;
|
||||
|
||||
case LWSSSCS_DESTROYING:
|
||||
lws_sul_cancel(&m->sul);
|
||||
lws_dll2_remove(&m->active_asset_list);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return LWSSSSRET_OK;
|
||||
}
|
||||
|
||||
static LWS_SS_INFO("__default", dloss_t)
|
||||
.rx = dloss_rx,
|
||||
.state = dloss_state
|
||||
};
|
||||
|
||||
/*
|
||||
* If we have an active image asset from this URL, return a pointer to its
|
||||
* dlo image (ie, dlo_jpeg or dlo_png)
|
||||
*/
|
||||
|
||||
int
|
||||
lws_dlo_ss_find(struct lws_context *cx, const char *url, lws_dlo_image_t *u)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d,
|
||||
lws_dll2_get_head(&cx->active_assets)) {
|
||||
dloss_t *ds = lws_container_of(d, dloss_t, active_asset_list);
|
||||
|
||||
if (!strcmp(url, ds->url)) {
|
||||
*u = ds->u;
|
||||
|
||||
return 0; /* found */
|
||||
}
|
||||
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
return 1; /* not found */
|
||||
}
|
||||
|
||||
int
|
||||
lws_dlo_ss_create(lws_dlo_ss_create_info_t *i, lws_dlo_t **pdlo)
|
||||
{
|
||||
lws_dlo_jpeg_t *dlo_jpeg = NULL;
|
||||
lws_dlo_png_t *dlo_png = NULL;
|
||||
size_t ul = strlen(i->url);
|
||||
struct lws_ss_handle *h;
|
||||
lws_dlo_t *dlo = NULL;
|
||||
lws_ss_info_t ssi;
|
||||
dloss_t *dloss;
|
||||
uint8_t type;
|
||||
|
||||
if (ul < 5)
|
||||
return 1;
|
||||
|
||||
if (!strcmp(i->url + ul - 4, ".png"))
|
||||
type = LWSDLOSS_TYPE_PNG;
|
||||
else
|
||||
if (!strcmp(i->url + ul - 4, ".jpg") ||
|
||||
!strcmp(i->url + ul - 5, ".jpeg"))
|
||||
type = LWSDLOSS_TYPE_JPEG;
|
||||
else
|
||||
if (!strcmp(i->url + ul - 4, ".css"))
|
||||
type = LWSDLOSS_TYPE_CSS;
|
||||
else {
|
||||
lwsl_err("%s: unknown file type %s\n", __func__, i->url);
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case LWSDLOSS_TYPE_PNG:
|
||||
dlo_png = lws_display_dlo_png_new(i->dl, i->dlo_parent, i->box);
|
||||
if (!dlo_png)
|
||||
return 1;
|
||||
|
||||
i->u->u.dlo_png = dlo_png;
|
||||
|
||||
dlo_png->dlo.box.w.whole = (int32_t)
|
||||
lws_upng_get_width(dlo_png->png);
|
||||
dlo_png->dlo.box.w.frac = 0;
|
||||
dlo_png->dlo.box.h.whole = (int32_t)
|
||||
lws_upng_get_height(dlo_png->png);
|
||||
dlo_png->dlo.box.h.frac = 0;
|
||||
|
||||
dlo = &dlo_png->dlo;
|
||||
break;
|
||||
|
||||
case LWSDLOSS_TYPE_JPEG:
|
||||
dlo_jpeg = lws_display_dlo_jpeg_new(i->dl, i->dlo_parent, i->box);
|
||||
if (!dlo_jpeg)
|
||||
return 1;
|
||||
|
||||
i->u->u.dlo_jpeg = dlo_jpeg;
|
||||
|
||||
dlo_jpeg->dlo.box.w.whole = (int32_t)
|
||||
lws_jpeg_get_width(dlo_jpeg->j);
|
||||
dlo_jpeg->dlo.box.w.frac = 0;
|
||||
dlo_jpeg->dlo.box.h.whole = (int32_t)
|
||||
lws_jpeg_get_height(dlo_jpeg->j);
|
||||
dlo_jpeg->dlo.box.h.frac = 0;
|
||||
|
||||
dlo = &dlo_jpeg->dlo;
|
||||
break;
|
||||
}
|
||||
|
||||
/* we adapt the initial tx credit also to the requested window */
|
||||
|
||||
ssi = ssi_dloss_t;
|
||||
ssi.manual_initial_tx_credit = i->window;
|
||||
|
||||
if (lws_ss_create(i->cx, 0, &ssi, (void *)dlo, &h, NULL, NULL)) {
|
||||
lwsl_notice("%s: unable to create ss\n", __func__);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dloss = (dloss_t *)lws_ss_to_user_object(h);
|
||||
dloss->u.type = (lws_dlo_image_type_t)type;
|
||||
dloss->on_rx = i->on_rx;
|
||||
dloss->ssevsul = i->on_rx_sul;
|
||||
dloss->lhp = i->lhp;
|
||||
dloss->type = type;
|
||||
|
||||
lws_strncpy(dloss->url, i->url, sizeof(dloss->url));
|
||||
|
||||
switch (type) {
|
||||
case LWSDLOSS_TYPE_PNG:
|
||||
dloss->u.u.dlo_png = dlo_png;
|
||||
dlo_png->flow.h = h;
|
||||
dlo_png->flow.window = i->window;
|
||||
break;
|
||||
case LWSDLOSS_TYPE_JPEG:
|
||||
dloss->u.u.dlo_jpeg = dlo_jpeg;
|
||||
dlo_jpeg->flow.h = h;
|
||||
dlo_jpeg->flow.window = i->window;
|
||||
break;
|
||||
}
|
||||
|
||||
if (lws_ss_alloc_set_metadata(h, "endpoint", i->url, ul)) {
|
||||
lwsl_err("%s: unable to set endpoint\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (lws_ss_client_connect(dloss->ss)) {
|
||||
lwsl_err("%s: unable to do client connection\n", __func__);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
lws_dll2_add_tail(&dloss->active_asset_list, &i->cx->active_assets);
|
||||
|
||||
lwsl_notice("%s: starting %s (dlo %p)\n", __func__, i->url, dlo);
|
||||
|
||||
*pdlo = dlo;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
lws_ss_destroy(&h);
|
||||
|
||||
switch (type) {
|
||||
case LWSDLOSS_TYPE_PNG:
|
||||
lws_display_dlo_png_destroy(&dlo_png->dlo);
|
||||
break;
|
||||
case LWSDLOSS_TYPE_JPEG:
|
||||
lws_display_dlo_jpeg_destroy(&dlo_jpeg->dlo);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
413
Kinc/Sources/kinc/libs/misc/dlo/dlo-text.c
Normal file
413
Kinc/Sources/kinc/libs/misc/dlo/dlo-text.c
Normal file
@ -0,0 +1,413 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object: text
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
size_t
|
||||
utf8_bytes(uint8_t u)
|
||||
{
|
||||
if ((u & 0x80) == 0)
|
||||
return 1;
|
||||
|
||||
if ((u & 0xe0) == 0xc0)
|
||||
return 2;
|
||||
|
||||
if ((u & 0xf0) == 0xe0)
|
||||
return 3;
|
||||
|
||||
if ((u & 0xf8) == 0xf0)
|
||||
return 4;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
utf8_unicode(const char *utf8, size_t *utf8_len, uint32_t *unicode)
|
||||
{
|
||||
size_t glyph_len = utf8_bytes((uint8_t)*utf8);
|
||||
size_t n;
|
||||
|
||||
if (!glyph_len || glyph_len > *utf8_len) {
|
||||
(*utf8_len)--;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (glyph_len == 1)
|
||||
*unicode = (uint32_t)*utf8++;
|
||||
else {
|
||||
*unicode = (uint32_t)((*utf8++) & (0x7f >> glyph_len));
|
||||
for (n = 1; n < glyph_len; n++)
|
||||
*unicode = (*unicode << 6) | ((*utf8++) & 0x3f);
|
||||
}
|
||||
|
||||
*utf8_len -= glyph_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_display_dlo_text_destroy(struct lws_dlo *dlo)
|
||||
{
|
||||
lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo);
|
||||
|
||||
lws_free_set_NULL(text->kern);
|
||||
lws_free_set_NULL(text->text);
|
||||
|
||||
lwsac_free(&text->ac_glyphs);
|
||||
}
|
||||
|
||||
int
|
||||
lws_display_dlo_text_update(lws_dlo_text_t *text, lws_display_colour_t dc,
|
||||
lws_fx_t indent, const char *utf8, size_t text_len)
|
||||
{
|
||||
const char *last_utf8 = utf8, *outf8 = utf8;
|
||||
size_t last_bp_n = 0, tlen = text_len;
|
||||
lws_fx_t t1, eff, last_bp_eff, t2;
|
||||
uint8_t r = 0;
|
||||
char uc;
|
||||
|
||||
if (text->kern)
|
||||
lws_free_set_NULL(text->kern);
|
||||
|
||||
if (text->text)
|
||||
lws_free_set_NULL(text->text);
|
||||
|
||||
lws_dll2_owner_clear(&text->glyphs);
|
||||
lwsac_free(&text->ac_glyphs);
|
||||
|
||||
text->indent = indent;
|
||||
text->dlo.dc = dc;
|
||||
|
||||
lws_fx_set(eff, 0, 0);
|
||||
|
||||
/*
|
||||
* Let's go through the new string glyph by glyph, we want to
|
||||
* calculate effective kerned widths, and optionally deal with wrapping.
|
||||
*
|
||||
* But we don't want to instantiate the glyph objects until we are
|
||||
* engaged with rendering them. Otherwise we will carry around the
|
||||
* whole page-worth's of glyphs at once needlessly, which won't scale
|
||||
* for text-heavy pages. lws_display_dlo_text_attach_glyphs() does the
|
||||
* same flow as this but to create the glyphs and is called later
|
||||
* as the text dlo becomes rasterized during rendering.
|
||||
*/
|
||||
|
||||
/* { char b1[22]; lwsl_err("eff %s\n", lws_fx_string(&eff, b1, sizeof(b1))); }
|
||||
{ char b1[22]; lwsl_err("indent %s\n", lws_fx_string(&indent, b1, sizeof(b1))); }
|
||||
{ char b1[22]; lwsl_err("boxw %s\n", lws_fx_string(&text->dlo.box.w, b1, sizeof(b1))); } */
|
||||
|
||||
while (tlen &&
|
||||
lws_fx_comp(lws_fx_add(&t1, &eff, &indent), &text->dlo.box.w) < 0) {
|
||||
size_t ot = tlen;
|
||||
uint32_t unicode;
|
||||
|
||||
if (!utf8_unicode(utf8, &tlen, &unicode)) {
|
||||
text->font->image_glyph(text, unicode, 0);
|
||||
|
||||
uc = *utf8;
|
||||
utf8 += (ot - tlen);
|
||||
|
||||
if (uc == ' ') { /* act to snip it if used */
|
||||
last_utf8 = utf8;
|
||||
last_bp_n = tlen;
|
||||
last_bp_eff = eff;
|
||||
}
|
||||
|
||||
if (!lws_display_font_mcufont_getcwidth(text, unicode, &t2))
|
||||
lws_fx_add(&eff, &eff, &t2);
|
||||
|
||||
if (uc == '-' || uc == ',' || uc == ';' || uc == ':') {
|
||||
/* act to leave it in */
|
||||
last_utf8 = utf8;
|
||||
last_bp_n = tlen;
|
||||
last_bp_eff = eff;
|
||||
}
|
||||
} else
|
||||
lwsl_err("%s: missing glyph\n", __func__);
|
||||
}
|
||||
|
||||
if (last_bp_n &&
|
||||
lws_fx_comp(lws_fx_add(&t1, &eff, &indent), &text->dlo.box.w) >= 0) {
|
||||
eff = last_bp_eff;
|
||||
utf8 = last_utf8;
|
||||
tlen = last_bp_n;
|
||||
r = 1;
|
||||
}
|
||||
|
||||
text->text_len = text_len - tlen;
|
||||
if (tlen == text_len) {
|
||||
lwsl_notice("we couldn't fit anything in there, newline\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
text->text = lws_malloc(text->text_len + 1, __func__);
|
||||
if (!text->text)
|
||||
return -1;
|
||||
|
||||
memcpy(text->text, outf8, text->text_len);
|
||||
text->text[text->text_len] = '\0';
|
||||
|
||||
memset(&text->bounding_box, 0, sizeof(text->bounding_box));
|
||||
text->bounding_box.w = eff;
|
||||
text->bounding_box.h.whole = text->font_height;
|
||||
text->bounding_box.h.frac = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int
|
||||
lws_display_dlo_text_attach_glyphs(lws_dlo_text_t *text)
|
||||
{
|
||||
const char *utf8 = text->text;
|
||||
size_t tlen = text->text_len;
|
||||
lws_font_glyph_t *g = NULL;
|
||||
uint32_t unicode;
|
||||
lws_fx_t eff;
|
||||
uint8_t r = 0;
|
||||
|
||||
lws_fx_set(eff, 0, 0);
|
||||
|
||||
while (tlen) {
|
||||
size_t ot = tlen;
|
||||
|
||||
g = NULL;
|
||||
if (!utf8_unicode(utf8, &tlen, &unicode))
|
||||
/* instantiate the glyphs this time */
|
||||
g = text->font->image_glyph(text, unicode, 1);
|
||||
if (g == NULL) {
|
||||
lwsl_warn("%s: no glyph for 0x%02X '%c'\n", __func__, (unsigned int)*utf8, *utf8);
|
||||
break;
|
||||
}
|
||||
|
||||
utf8 += (ot - tlen);
|
||||
g->xpx = eff;
|
||||
lws_fx_add(&eff, &eff, &g->cwidth);
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
lws_dlo_text_t *
|
||||
lws_display_dlo_text_new(lws_displaylist_t *dl, lws_dlo_t *dlo_parent,
|
||||
lws_box_t *box, const lws_display_font_t *font)
|
||||
{
|
||||
lws_dlo_text_t *text = lws_zalloc(sizeof(*text), __func__);
|
||||
|
||||
if (!text)
|
||||
return NULL;
|
||||
|
||||
text->dlo.render = font->renderer;
|
||||
text->dlo._destroy = lws_display_dlo_text_destroy;
|
||||
text->dlo.box = *box;
|
||||
text->font = font;
|
||||
|
||||
lws_display_dlo_add(dl, dlo_parent, &text->dlo);
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
static const char *
|
||||
castrstr(const char *haystack, const char *needle)
|
||||
{
|
||||
size_t sn = strlen(needle), h = strlen(haystack) - sn + 1, n;
|
||||
char c, c1;
|
||||
|
||||
while (1) {
|
||||
for (n = 0; n < sn; n++) {
|
||||
c = (char)((haystack[h + n] >= 'A' && haystack[h + n] <= 'Z') ?
|
||||
haystack[h + n] + ('a' - 'A') : haystack[h + n]);
|
||||
c1 = (char)((needle[n] >= 'A' && needle[n] <= 'Z') ?
|
||||
needle[n] + ('a' - 'A') : needle[n]);
|
||||
if (c != c1)
|
||||
break;
|
||||
}
|
||||
if (n == sn)
|
||||
return &haystack[h];
|
||||
|
||||
if (!h)
|
||||
break;
|
||||
h--;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
lws_font_register(struct lws_context *cx, const uint8_t *data, size_t data_len)
|
||||
{
|
||||
lws_display_font_t *a;
|
||||
|
||||
if (lws_ser_ru32be(data) != LWS_FOURCC('M', 'C', 'U', 'F'))
|
||||
return 1;
|
||||
|
||||
a = lws_zalloc(sizeof(*a), __func__);
|
||||
if (!a)
|
||||
return 1;
|
||||
|
||||
a->choice.family_name = (const char *)data +
|
||||
lws_ser_ru32be(data + MCUFO_FOFS_FULLNAME);
|
||||
|
||||
if (castrstr(a->choice.family_name, "serif") ||
|
||||
castrstr(a->choice.family_name, "roman"))
|
||||
a->choice.generic_name = "serif";
|
||||
else
|
||||
a->choice.generic_name = "sans";
|
||||
|
||||
if (castrstr(a->choice.family_name, "italic") ||
|
||||
castrstr(a->choice.family_name, "oblique"))
|
||||
a->choice.style = 1;
|
||||
|
||||
if (castrstr(a->choice.family_name, "extrabold") ||
|
||||
castrstr(a->choice.family_name, "extra bold"))
|
||||
a->choice.weight = 900;
|
||||
else
|
||||
if (castrstr(a->choice.family_name, "bold"))
|
||||
a->choice.weight = 700;
|
||||
else
|
||||
if (castrstr(a->choice.family_name, "extralight") ||
|
||||
castrstr(a->choice.family_name, "extra light"))
|
||||
a->choice.weight = 200;
|
||||
else
|
||||
if (castrstr(a->choice.family_name, "light"))
|
||||
a->choice.weight = 300;
|
||||
else
|
||||
a->choice.weight = 400;
|
||||
|
||||
a->choice.fixed_height = lws_ser_ru16be(data + MCUFO16_LINE_HEIGHT);
|
||||
|
||||
a->data = data;
|
||||
a->data_len = data_len;
|
||||
a->renderer = lws_display_font_mcufont_render;
|
||||
a->image_glyph = lws_display_font_mcufont_image_glyph;
|
||||
|
||||
{
|
||||
lws_dlo_text_t t;
|
||||
|
||||
memset(&t, 0, sizeof(t));
|
||||
t.font = a;
|
||||
|
||||
lws_display_font_mcufont_getcwidth(&t, 'm', &a->em);
|
||||
a->ex.whole = a->choice.fixed_height;
|
||||
a->ex.frac = 0;
|
||||
}
|
||||
|
||||
lws_dll2_clear(&a->list);
|
||||
lws_dll2_add_tail(&a->list, &cx->fonts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_font_destroy(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_fonts_destroy(struct lws_context *cx)
|
||||
{
|
||||
lws_dll2_foreach_safe(&cx->fonts, NULL, lws_font_destroy);
|
||||
}
|
||||
|
||||
struct track {
|
||||
const lws_font_choice_t *hints;
|
||||
const lws_display_font_t *best;
|
||||
int best_score;
|
||||
};
|
||||
|
||||
static int
|
||||
lws_fonts_score(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
const lws_display_font_t *f = lws_container_of(d, lws_display_font_t,
|
||||
list);
|
||||
struct track *t = (struct track *)user;
|
||||
struct lws_tokenize ts;
|
||||
int score = 1000;
|
||||
|
||||
if (t->hints->family_name) {
|
||||
memset(&ts, 0, sizeof(ts));
|
||||
ts.start = t->hints->family_name;
|
||||
ts.len = strlen(ts.start);
|
||||
ts.flags = LWS_TOKENIZE_F_COMMA_SEP_LIST;
|
||||
|
||||
do {
|
||||
ts.e = (int8_t)lws_tokenize(&ts);
|
||||
if (ts.e == LWS_TOKZE_TOKEN) {
|
||||
if (!strncmp(f->choice.family_name, ts.token,
|
||||
ts.token_len)) {
|
||||
score = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (f->choice.generic_name &&
|
||||
!strncmp(f->choice.generic_name, ts.token,
|
||||
ts.token_len)) {
|
||||
score -= 500;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} while (ts.e > 0);
|
||||
}
|
||||
|
||||
if (t->hints->weight)
|
||||
score += (t->hints->weight > f->choice.weight ?
|
||||
(t->hints->weight - f->choice.weight) :
|
||||
(f->choice.weight - t->hints->weight)) / 100;
|
||||
|
||||
if (t->hints->style != f->choice.style)
|
||||
score += 100;
|
||||
|
||||
if (t->hints->fixed_height)
|
||||
score += 10 * (t->hints->fixed_height > f->choice.fixed_height ?
|
||||
(t->hints->fixed_height - f->choice.fixed_height) :
|
||||
(f->choice.fixed_height - t->hints->fixed_height));
|
||||
|
||||
if (score < t->best_score) {
|
||||
t->best_score = score;
|
||||
t->best = f;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const lws_display_font_t *
|
||||
lws_font_choose(struct lws_context *cx, const lws_font_choice_t *hints)
|
||||
{
|
||||
struct track t;
|
||||
|
||||
t.hints = hints;
|
||||
t.best = (const lws_display_font_t *)cx->fonts.head;
|
||||
t.best_score = 99999999;
|
||||
|
||||
if (t.hints)
|
||||
lws_dll2_foreach_safe(&cx->fonts, &t, lws_fonts_score);
|
||||
|
||||
return t.best;
|
||||
}
|
890
Kinc/Sources/kinc/libs/misc/dlo/dlo.c
Normal file
890
Kinc/Sources/kinc/libs/misc/dlo/dlo.c
Normal file
@ -0,0 +1,890 @@
|
||||
/*
|
||||
* lws abstract display
|
||||
*
|
||||
* Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to
|
||||
* deal in the Software without restriction, including without limitation the
|
||||
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
* sell copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
* IN THE SOFTWARE.
|
||||
*
|
||||
* Display List Object handling
|
||||
*/
|
||||
|
||||
#include <private-lib-core.h>
|
||||
#include "private-lib-drivers-display-dlo.h"
|
||||
|
||||
#define dlodump_loglevel LLL_NOTICE
|
||||
#if (_LWS_ENABLED_LOGS & dlodump_loglevel)
|
||||
#define lwsl_dlodump(...) _lws_log(dlodump_loglevel, __VA_ARGS__)
|
||||
#else
|
||||
#define lwsl_dlodump(...)
|
||||
#endif
|
||||
|
||||
void
|
||||
lws_display_dl_init(lws_displaylist_t *dl, lws_display_state_t *ds)
|
||||
{
|
||||
lws_dll2_owner_clear(&dl->dl);
|
||||
dl->ds = ds;
|
||||
}
|
||||
|
||||
int
|
||||
lws_display_dlo_add(lws_displaylist_t *dl, lws_dlo_t *dlo_parent, lws_dlo_t *dlo)
|
||||
{
|
||||
if (!dlo_parent && !dl->dl.head) {
|
||||
lws_dll2_add_tail(&dlo->list, &dl->dl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dlo_parent) {
|
||||
if (!dl->dl.head)
|
||||
return 0;
|
||||
|
||||
dlo_parent = lws_container_of(dl->dl.head, lws_dlo_t, list);
|
||||
}
|
||||
|
||||
lws_dll2_add_tail(&dlo->list, &dlo_parent->children);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_surface_set_px(const lws_surface_info_t *ic, uint8_t *line, int x,
|
||||
const lws_display_colour_t *c)
|
||||
{
|
||||
unsigned int alpha, ialpha;
|
||||
lws_display_colour_t oc;
|
||||
lws_display_colour_t y;
|
||||
uint8_t rgb[3];
|
||||
|
||||
if (x < 0 || x >= ic->wh_px[0].whole)
|
||||
return;
|
||||
|
||||
/*
|
||||
* All alpha composition takes place at 8bpp grey or 24bpp
|
||||
*/
|
||||
|
||||
if (ic->greyscale) {
|
||||
|
||||
/* line composition buffer is 8-bit Y per pixel */
|
||||
|
||||
oc = line[x];
|
||||
alpha = LWSDC_ALPHA(*c);
|
||||
ialpha = 255 - alpha;
|
||||
|
||||
y = RGB_TO_Y(LWSDC_R(*c), LWSDC_G(*c), LWSDC_B(*c));
|
||||
|
||||
line[x] = (uint8_t)(((y * alpha) / 255) +
|
||||
((LWSDC_R(oc) * ialpha) / 255));
|
||||
return;
|
||||
}
|
||||
|
||||
/* line composition buffer is 24-bit RGB per pixel */
|
||||
|
||||
line += (ic->render_to_rgba ? 4 : 3) * x;
|
||||
|
||||
alpha = LWSDC_ALPHA(*c);
|
||||
ialpha = 255 - alpha;
|
||||
|
||||
rgb[0] = (uint8_t)(((LWSDC_R(*c) * alpha) / 255) +
|
||||
((line[0] * ialpha) / 255));
|
||||
rgb[1] = (uint8_t)(((LWSDC_G(*c) * alpha) / 255) +
|
||||
((line[1] * ialpha) / 255));
|
||||
rgb[2] = (uint8_t)(((LWSDC_B(*c) * alpha) / 255) +
|
||||
((line[2] * ialpha) / 255));
|
||||
|
||||
*line++ = rgb[0];
|
||||
*line++ = rgb[1];
|
||||
*line++ = rgb[2];
|
||||
|
||||
if (ic->render_to_rgba)
|
||||
*line = 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Recursively find out the total width and height of the contents of a DLO
|
||||
*/
|
||||
|
||||
void
|
||||
lws_dlo_contents(lws_dlo_t *parent, lws_dlo_dim_t *dim)
|
||||
{
|
||||
lws_display_render_stack_t st[12]; /* DLO child stack */
|
||||
lws_dll2_t *d;
|
||||
lws_fx_t t1;
|
||||
int sp = 0;
|
||||
|
||||
dim->w.whole = 0;
|
||||
dim->w.frac = 0;
|
||||
dim->h.whole = 0;
|
||||
dim->h.frac = 0;
|
||||
|
||||
if (!parent)
|
||||
return;
|
||||
|
||||
d = lws_dll2_get_head(&parent->children);
|
||||
if (!d)
|
||||
return;
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
st[0].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
st[0].co.w.whole = 0;
|
||||
st[0].co.w.frac = 0;
|
||||
st[0].co.h.whole = 0;
|
||||
st[0].co.h.frac = 0;
|
||||
|
||||
/* We are collecting worst dlo->box.x + dlo->box.w and .y + .h */
|
||||
|
||||
while (sp || st[0].dlo) {
|
||||
lws_dlo_t *dlo = st[sp].dlo;
|
||||
|
||||
if (!dlo) {
|
||||
if (!sp) {
|
||||
lwsl_err("%s: underflow\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lws_fx_comp(&st[sp].co.w, &st[sp - 1].co.w) > 0)
|
||||
st[sp - 1].co.w = st[sp].co.w;
|
||||
|
||||
if (lws_fx_comp(&st[sp].co.h, &st[sp - 1].co.h) > 0)
|
||||
st[sp - 1].co.h = st[sp].co.h;
|
||||
|
||||
// lwsl_notice("sp %d: passing back w: %d, h: %d\n", sp, st[sp - 1].co.w.whole, st[sp - 1].co.h.whole);
|
||||
|
||||
sp--;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
lws_fx_add(&t1, &dlo->box.w, &dlo->box.x);
|
||||
// lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_LEFT]);
|
||||
lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_LEFT]);
|
||||
// lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_RIGHT]);
|
||||
// lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_RIGHT]);
|
||||
if (lws_fx_comp(&t1, &st[sp].co.w) > 0)
|
||||
st[sp].co.w = t1;
|
||||
|
||||
lws_fx_add(&t1, &dlo->box.h, &dlo->box.y);
|
||||
// lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_TOP]);
|
||||
lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_TOP]);
|
||||
// lws_fx_add(&t1, &t1, &dlo->padding[CCPAS_BOTTOM]);
|
||||
// lws_fx_add(&t1, &t1, &dlo->margin[CCPAS_BOTTOM]);
|
||||
if (lws_fx_comp(&t1, &st[sp].co.h) > 0)
|
||||
st[sp].co.h = t1;
|
||||
|
||||
d = dlo->list.next;
|
||||
if (d)
|
||||
st[sp].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
else
|
||||
st[sp].dlo = NULL;
|
||||
|
||||
/* go into any children */
|
||||
|
||||
if (dlo->children.head) {
|
||||
if (++sp == LWS_ARRAY_SIZE(st)) {
|
||||
lwsl_err("%s: DLO stack overflow\n", __func__);
|
||||
return;
|
||||
}
|
||||
st[sp].dlo = lws_container_of(
|
||||
dlo->children.head, lws_dlo_t, list);
|
||||
st[sp].co.w.whole = 0;
|
||||
st[sp].co.h.whole = 0;
|
||||
st[sp].co.w.frac = 0;
|
||||
st[sp].co.h.frac = 0;
|
||||
}
|
||||
}
|
||||
|
||||
dim->w = st[0].co.w;
|
||||
dim->h = st[0].co.h;
|
||||
|
||||
if (parent->col_list.owner) {
|
||||
lhp_table_col_t *tc = lws_container_of(parent->col_list.owner,
|
||||
lhp_table_col_t, col_dlos);
|
||||
|
||||
if (lws_fx_comp(&dim->w, &tc->width) < 0) {
|
||||
// lws_fx_add(&t1, &tc->width, &parent->padding[CCPAS_LEFT]);
|
||||
// lws_fx_add(&dim->w, &tc->width, &parent->padding[CCPAS_RIGHT]);
|
||||
dim->w = tc->width;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent->row_list.owner) {
|
||||
lhp_table_row_t *tr = lws_container_of(parent->row_list.owner,
|
||||
lhp_table_row_t, row_dlos);
|
||||
|
||||
if (lws_fx_comp(&dim->h, &tr->height) < 0) {
|
||||
// lws_fx_add(&t1, &tr->height, &parent->padding[CCPAS_TOP]);
|
||||
lws_fx_add(&dim->h, &tr->height, &parent->padding[CCPAS_BOTTOM]);
|
||||
// dim->h = tr->height;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
lwsl_user("%s: dlo %p: FINAL w:%d -> %d h:%d -> %d\n", __func__, parent,
|
||||
parent->box.w.whole, dim->w.whole,
|
||||
parent->box.h.whole, dim->h.whole);
|
||||
*/
|
||||
}
|
||||
|
||||
/*
|
||||
* Some DLO is changing height, adjust its height, and that of everybody below.
|
||||
*/
|
||||
|
||||
void
|
||||
lws_display_dlo_adjust_dims(lws_dlo_t *dlo, lws_dlo_dim_t *dim)
|
||||
{
|
||||
lws_dlo_dim_t delta;
|
||||
|
||||
if (!dim->w.whole && !dim->h.whole)
|
||||
return;
|
||||
|
||||
/* adjust the target's width / height */
|
||||
|
||||
lws_fx_sub(&delta.w, &dim->w, &dlo->box.w);
|
||||
lws_fx_sub(&delta.h, &dim->h, &dlo->box.h);
|
||||
|
||||
dlo->box.w = dim->w;
|
||||
dlo->box.h = dim->h;
|
||||
|
||||
// lwsl_notice("%s: dlo %p: delta w:%d h:%d\n", __func__, dlo, delta.w.whole, delta.h.whole);
|
||||
|
||||
/* move peers below him accordingly */
|
||||
|
||||
do {
|
||||
lws_dlo_t *dp = lws_container_of(dlo->list.owner, lws_dlo_t, children);
|
||||
|
||||
if (!dlo->list.owner)
|
||||
break;
|
||||
|
||||
/*
|
||||
* Adjust y pos of siblings below us
|
||||
*/
|
||||
|
||||
do {
|
||||
dlo = lws_container_of(dlo->list.next, lws_dlo_t, list);
|
||||
if (dlo) {
|
||||
//lwsl_notice("%s: dlo %p: adj y %d -> %d\n", __func__, dlo, dlo->box.y.whole, dlo->box.y.whole + delta.h.whole);
|
||||
lws_fx_add(&dlo->box.y, &dlo->box.y, &delta.h);
|
||||
}
|
||||
} while (dlo);
|
||||
|
||||
|
||||
/* go up parent chain until toplevel adjusting height of
|
||||
* parent siblings below parent */
|
||||
|
||||
if (dp->flag_toplevel)
|
||||
break;
|
||||
|
||||
dlo = dp;
|
||||
//lwsl_notice("%s: dlo %p: adj h by %d\n", __func__, dlo, delta.h.whole);
|
||||
lws_fx_add(&dlo->box.h, &dlo->box.h, &delta.h);
|
||||
} while (1);
|
||||
}
|
||||
|
||||
//#if defined(_DEBUG)
|
||||
void
|
||||
lws_display_dl_dump(lws_displaylist_t *dl)
|
||||
{
|
||||
lws_display_render_stack_t st[12]; /* DLO child stack */
|
||||
int sp = 0;
|
||||
lws_dll2_t *d = lws_dll2_get_head(&dl->dl);
|
||||
#if (_LWS_ENABLED_LOGS & dlodump_loglevel)
|
||||
static const char * const ind = " ";
|
||||
#endif
|
||||
char b[4][22], b1[4][22], dt[96];
|
||||
|
||||
if (!d) {
|
||||
lwsl_notice("%s: empty dl\n", __func__);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
lwsl_notice("%s\n", __func__);
|
||||
|
||||
memset(&st, 0, sizeof(st));
|
||||
st[0].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
|
||||
while (sp || st[0].dlo) {
|
||||
lws_dlo_t *dlo = st[sp].dlo;
|
||||
lws_box_t co;
|
||||
//lws_fx_t t2;
|
||||
|
||||
if (!dlo) {
|
||||
if (!sp) {
|
||||
lwsl_err("%s: underflow\n", __func__);
|
||||
return;
|
||||
}
|
||||
sp--;
|
||||
continue;
|
||||
}
|
||||
|
||||
lws_fx_add(&co.x, &st[sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&co.y, &st[sp].co.y, &dlo->box.y);
|
||||
co.w = dlo->box.w;
|
||||
co.h = dlo->box.h;
|
||||
|
||||
lws_snprintf(dt, sizeof(dt), "rect: RGBA 0x%08X", (unsigned int)dlo->dc);
|
||||
if (dlo->_destroy == lws_display_dlo_text_destroy) {
|
||||
lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo);
|
||||
lws_snprintf(dt, sizeof(dt), "text: RGBA 0x%08X, chars: %u, %.*s",
|
||||
(unsigned int)dlo->dc, (unsigned int)text->text_len,
|
||||
(int)text->text_len, text->text ? text->text : "(empty)");
|
||||
}
|
||||
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_UPNG) && defined(LWS_WITH_CLIENT)
|
||||
else if (dlo->_destroy == lws_display_dlo_png_destroy)
|
||||
lws_snprintf(dt, sizeof(dt), "png");
|
||||
#endif
|
||||
#if defined(LWS_WITH_NETWORK) && defined(LWS_WITH_JPEG) && defined(LWS_WITH_CLIENT)
|
||||
else if (dlo->_destroy == lws_display_dlo_jpeg_destroy)
|
||||
lws_snprintf(dt, sizeof(dt), "jpeg");
|
||||
#endif
|
||||
|
||||
lws_fx_string(&dlo->box.x, b[0], sizeof(b[0]));
|
||||
lws_fx_string(&dlo->box.y, b[1], sizeof(b[1]));
|
||||
lws_fx_string(&dlo->box.w, b[2], sizeof(b[2]));
|
||||
lws_fx_string(&dlo->box.h, b[3], sizeof(b[3]));
|
||||
lws_fx_string(&co.x, b1[0], sizeof(b1[0]));
|
||||
lws_fx_string(&co.y, b1[1], sizeof(b1[1]));
|
||||
lws_fx_string(&co.w, b1[2], sizeof(b1[2]));
|
||||
lws_fx_string(&co.h, b1[3], sizeof(b1[3]));
|
||||
|
||||
lwsl_dlodump("%.*s %p box: (%s, %s) [%s x %s], co: (%s, %s) [%s x %s], %s\n",
|
||||
sp, ind, dlo, b[0], b[1], b[2], b[3],
|
||||
b1[0], b1[1], b1[2], b1[3], dt);
|
||||
|
||||
d = dlo->list.next;
|
||||
if (d)
|
||||
st[sp].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
else
|
||||
st[sp].dlo = NULL;
|
||||
|
||||
/* go into any children */
|
||||
|
||||
if (dlo->children.head) {
|
||||
if (sp + 1 == LWS_ARRAY_SIZE(st)) {
|
||||
lwsl_err("%s: DLO stack overflow\n", __func__);
|
||||
return;
|
||||
}
|
||||
st[++sp].dlo = lws_container_of(
|
||||
dlo->children.head, lws_dlo_t, list);
|
||||
st[sp].co = co;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//#endif
|
||||
|
||||
/*
|
||||
* Go through every DLO once, setting its id->box to the final layout for the
|
||||
* related dlo, if any
|
||||
*/
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_get_ids_boxes(lws_display_render_state_t *rs)
|
||||
{
|
||||
lws_dll2_t *d;
|
||||
|
||||
rs->lowest_id_y = 0;
|
||||
|
||||
d = lws_dll2_get_head(&rs->displaylist.dl);
|
||||
if (!d)
|
||||
/* nothing in dlo */
|
||||
return LWS_SRET_OK;
|
||||
|
||||
memset(&rs->st[0].co, 0, sizeof(rs->st[0].co));
|
||||
rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
|
||||
while (rs->sp || rs->st[0].dlo) {
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_box_t co;
|
||||
lws_fx_t t2;
|
||||
|
||||
if (!dlo) {
|
||||
rs->sp--;
|
||||
continue;
|
||||
}
|
||||
|
||||
lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
co.w = dlo->box.w;
|
||||
co.h = dlo->box.h;
|
||||
|
||||
lws_fx_add(&t2, &co.y, &dlo->box.h);
|
||||
|
||||
if (dlo->id) {
|
||||
lws_display_id_t *id = dlo->id;
|
||||
|
||||
lwsl_debug("%s: set id box %s\n", __func__, id->id);
|
||||
id->box = co;
|
||||
dlo->id = NULL; /* decouple us */
|
||||
}
|
||||
|
||||
if (co.y.whole + co.h.whole > rs->lowest_id_y) {
|
||||
rs->lowest_id_y = (lws_display_scalar)(co.y.whole + co.h.whole);
|
||||
if (rs->lowest_id_y > rs->ic->wh_px[1].whole)
|
||||
rs->lowest_id_y = (lws_display_scalar)rs->ic->wh_px[1].whole;
|
||||
}
|
||||
|
||||
/* next sibling at this level if any */
|
||||
|
||||
d = dlo->list.next;
|
||||
if (d)
|
||||
rs->st[rs->sp].dlo = lws_container_of(d,
|
||||
lws_dlo_t, list);
|
||||
else
|
||||
rs->st[rs->sp].dlo = NULL;
|
||||
|
||||
/* go into any children */
|
||||
|
||||
if (dlo->children.head) {
|
||||
if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
|
||||
lwsl_err("%s: DLO stack overflow\n",
|
||||
__func__);
|
||||
return LWS_SRET_FATAL;
|
||||
}
|
||||
rs->st[++rs->sp].dlo = lws_container_of(
|
||||
dlo->children.head, lws_dlo_t, list);
|
||||
rs->st[rs->sp].co = co;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
lws_display_render_dump_ids(&rs->ids);
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_list_render_line(lws_display_render_state_t *rs)
|
||||
{
|
||||
lws_dll2_t *d;
|
||||
|
||||
if (rs->html == 1)
|
||||
return LWS_SRET_WANT_INPUT;
|
||||
|
||||
if (!rs->sp && !rs->st[0].dlo) {
|
||||
|
||||
/* starting a line */
|
||||
|
||||
d = lws_dll2_get_head(&rs->displaylist.dl);
|
||||
if (!d)
|
||||
/* nothing in dlo */
|
||||
return LWS_SRET_OK;
|
||||
|
||||
// memset(rs->line, 0, (size_t)rs->ic->wh_px[0].whole *
|
||||
// (rs->ic->greyscale ? 1 : 3));
|
||||
memset(&rs->st[0].co, 0, sizeof(rs->st[0].co));
|
||||
rs->st[0].dlo = lws_container_of(d, lws_dlo_t, list);
|
||||
}
|
||||
|
||||
while (rs->sp || rs->st[0].dlo) {
|
||||
lws_dlo_t *dlo = rs->st[rs->sp].dlo;
|
||||
lws_stateful_ret_t r;
|
||||
lws_box_t co;
|
||||
lws_fx_t t2;
|
||||
|
||||
if (!dlo) {
|
||||
rs->sp--;
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
lws_fx_add(&co.x, &rs->st[rs->sp].co.x, &dlo->box.x);
|
||||
lws_fx_add(&co.y, &rs->st[rs->sp].co.y, &dlo->box.y);
|
||||
|
||||
co.w = dlo->box.w;
|
||||
co.h = dlo->box.h;
|
||||
|
||||
lws_fx_add(&t2, &co.y, &dlo->box.h);
|
||||
|
||||
if (rs->curr > lws_fx_roundup(&t2)) {
|
||||
d = dlo->list.next;
|
||||
rs->st[rs->sp].dlo = d ? lws_container_of(d, lws_dlo_t,
|
||||
list) : NULL;
|
||||
|
||||
lws_display_dlo_destroy(&dlo);
|
||||
continue;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (dlo->_destroy == lws_display_dlo_png_destroy)
|
||||
lwsl_err("png line %d %d %d %d\n", rs->curr, co.y.whole - 1,
|
||||
rs->st[rs->sp].co.y.whole, dlo->box.y.whole);
|
||||
#endif
|
||||
|
||||
if (rs->curr >= co.y.whole - 1) {
|
||||
|
||||
r = dlo->render(rs);
|
||||
|
||||
//rs->ic, dlo, &rs->st[rs->sp].co,
|
||||
// rs->curr, rs->line, &dlo->nle[0]);
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
/* next sibling at this level if any */
|
||||
|
||||
d = dlo->list.next;
|
||||
|
||||
if (d)
|
||||
rs->st[rs->sp].dlo = lws_container_of(d,
|
||||
lws_dlo_t, list);
|
||||
else
|
||||
rs->st[rs->sp].dlo = NULL;
|
||||
|
||||
|
||||
/* go into any children */
|
||||
|
||||
if (dlo->children.head) {
|
||||
if (rs->sp + 1 == LWS_ARRAY_SIZE(rs->st)) {
|
||||
lwsl_err("%s: DLO stack overflow\n",
|
||||
__func__);
|
||||
return LWS_SRET_FATAL;
|
||||
}
|
||||
rs->st[++rs->sp].dlo = lws_container_of(
|
||||
dlo->children.head, lws_dlo_t, list);
|
||||
rs->st[rs->sp].co = co;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
/* next sibling at this level if any */
|
||||
|
||||
d = dlo->list.next;
|
||||
if (d)
|
||||
rs->st[rs->sp].dlo = lws_container_of(d,
|
||||
lws_dlo_t, list);
|
||||
else
|
||||
rs->st[rs->sp].dlo = NULL;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return LWS_SRET_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
dlo_clean_table_rows(lws_dll2_t *d, void *user)
|
||||
{
|
||||
lhp_table_row_t *r = lws_container_of(d, lhp_table_row_t, list);
|
||||
|
||||
lws_dll2_remove(d);
|
||||
lws_free(r);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
dlo_clean_table_cols(lws_dll2_t *d, void *user)
|
||||
{
|
||||
lhp_table_col_t *c = lws_container_of(d, lhp_table_col_t, list);
|
||||
|
||||
lws_dll2_remove(d);
|
||||
lws_free(c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_display_dlo_destroy(lws_dlo_t **r)
|
||||
{
|
||||
if (!(*r))
|
||||
return;
|
||||
|
||||
lws_dll2_remove(&(*r)->list);
|
||||
lws_dll2_remove(&(*r)->col_list);
|
||||
lws_dll2_remove(&(*r)->row_list);
|
||||
|
||||
while ((*r)->children.head) {
|
||||
lws_dlo_t *d = lws_container_of((*r)->children.head,
|
||||
lws_dlo_t, list);
|
||||
|
||||
lws_display_dlo_destroy(&d);
|
||||
}
|
||||
|
||||
lws_dll2_foreach_safe(&(*r)->table_cols, NULL, dlo_clean_table_cols);
|
||||
lws_dll2_foreach_safe(&(*r)->table_rows, NULL, dlo_clean_table_rows);
|
||||
|
||||
if ((*r)->_destroy)
|
||||
(*r)->_destroy(*r);
|
||||
|
||||
lws_free_set_NULL(*r);
|
||||
*r = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
lws_display_list_destroy(lws_displaylist_t *dl)
|
||||
{
|
||||
if (!dl)
|
||||
return;
|
||||
|
||||
while (dl->dl.head) {
|
||||
lws_dlo_t *d = lws_container_of(dl->dl.head, lws_dlo_t, list);
|
||||
|
||||
lws_display_dlo_destroy(&d);
|
||||
}
|
||||
}
|
||||
|
||||
lws_dlo_filesystem_t *
|
||||
lws_dlo_file_register(struct lws_context *cx, const lws_dlo_filesystem_t *f)
|
||||
{
|
||||
const lws_dlo_filesystem_t *b;
|
||||
lws_dlo_filesystem_t *a;
|
||||
|
||||
b = lws_dlo_file_choose(cx, f->name);
|
||||
|
||||
if (b) {
|
||||
lwsl_err("%s: dlo file %s already exists %p\n", __func__, b->name, b);
|
||||
lws_dlo_file_unregister((lws_dlo_filesystem_t **)&b);
|
||||
}
|
||||
|
||||
a = lws_malloc(sizeof(*a), __func__);
|
||||
if (!a)
|
||||
return NULL;
|
||||
|
||||
*a = *f;
|
||||
lws_dll2_clear(&a->list);
|
||||
lws_dll2_add_tail(&a->list, &cx->dlo_file);
|
||||
|
||||
lwsl_err("%s: dlo file %s registered at %p\n", __func__, a->name, a);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
/*
|
||||
* Only needed with heap-alloc'd lws_dlo_filesystem_t
|
||||
*/
|
||||
|
||||
void
|
||||
lws_dlo_file_unregister(lws_dlo_filesystem_t **f)
|
||||
{
|
||||
if (!*f)
|
||||
return;
|
||||
|
||||
lws_dll2_remove(&(*f)->list);
|
||||
lws_free_set_NULL(*f);
|
||||
}
|
||||
|
||||
void
|
||||
lws_dlo_file_unregister_by_name(struct lws_context *cx, const char *name)
|
||||
{
|
||||
lws_dlo_filesystem_t *a;
|
||||
|
||||
a = (lws_dlo_filesystem_t *)lws_dlo_file_choose(cx, name);
|
||||
if (!a)
|
||||
return;
|
||||
|
||||
lws_dll2_remove(&a->list);
|
||||
lws_free_set_NULL(a);
|
||||
}
|
||||
|
||||
static int
|
||||
_lws_dlo_file_destroy(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_free(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_dlo_file_destroy(struct lws_context *cx)
|
||||
{
|
||||
lws_dll2_foreach_safe(&cx->dlo_file, NULL, _lws_dlo_file_destroy);
|
||||
}
|
||||
|
||||
const lws_dlo_filesystem_t *
|
||||
lws_dlo_file_choose(struct lws_context *cx, const char *name)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, p,
|
||||
lws_dll2_get_head(&cx->dlo_file)) {
|
||||
const lws_dlo_filesystem_t *pn = lws_container_of(p,
|
||||
lws_dlo_filesystem_t, list);
|
||||
|
||||
if (!strcmp(name, pn->name))
|
||||
return pn;
|
||||
|
||||
} lws_end_foreach_dll(p);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
lws_display_id_destroy(struct lws_dll2 *d, void *user)
|
||||
{
|
||||
lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
|
||||
|
||||
lws_dll2_remove(&id->list);
|
||||
lws_free(id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
lws_display_render_free_ids(lws_display_render_state_t *rs)
|
||||
{
|
||||
lws_dll2_foreach_safe(&rs->ids, NULL, lws_display_id_destroy);
|
||||
}
|
||||
|
||||
lws_display_id_t *
|
||||
lws_display_render_get_id(lws_display_render_state_t *rs, const char *_id)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(&rs->ids)) {
|
||||
lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
|
||||
|
||||
if (!strcmp(_id, id->id))
|
||||
return id;
|
||||
|
||||
} lws_end_foreach_dll(d);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lws_display_id_t *
|
||||
lws_display_render_add_id(lws_display_render_state_t *rs, const char *_id, void *priv)
|
||||
{
|
||||
lws_display_id_t *id;
|
||||
|
||||
id = lws_display_render_get_id(rs, _id);
|
||||
if (id) {
|
||||
id->priv_user = priv;
|
||||
return id;
|
||||
}
|
||||
|
||||
id = lws_zalloc(sizeof(*id), __func__);
|
||||
|
||||
if (id) {
|
||||
lws_strncpy(id->id, _id, sizeof(id->id));
|
||||
id->priv_user = priv;
|
||||
lws_dll2_add_tail(&id->list, &rs->ids);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
lws_display_render_dump_ids(lws_dll2_owner_t *ids)
|
||||
{
|
||||
lws_start_foreach_dll(struct lws_dll2 *, d, lws_dll2_get_head(ids)) {
|
||||
lws_display_id_t *id = lws_container_of(d, lws_display_id_t, list);
|
||||
|
||||
if (!id->exists)
|
||||
lwsl_notice(" id: '%s' (not present)\n", id->id);
|
||||
else
|
||||
lwsl_notice(" id: '%s', (%d,%d), %dx%d\n", id->id,
|
||||
(int)id->box.x.whole, (int)id->box.y.whole,
|
||||
(int)id->box.w.whole, (int)id->box.h.whole);
|
||||
} lws_end_foreach_dll(d);
|
||||
}
|
||||
|
||||
#if defined (LWS_WITH_FILE_OPS)
|
||||
|
||||
int
|
||||
dlo_filesystem_fops_close(lws_fop_fd_t *fop_fd)
|
||||
{
|
||||
lws_free_set_NULL(*fop_fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_fileofs_t
|
||||
dlo_filesystem_fops_seek_cur(lws_fop_fd_t fop_fd,
|
||||
lws_fileofs_t pos)
|
||||
{
|
||||
if (pos < 0)
|
||||
fop_fd->pos = 0;
|
||||
else
|
||||
if (pos >= (long long)fop_fd->len)
|
||||
fop_fd->pos = fop_fd->len;
|
||||
else
|
||||
fop_fd->pos = (lws_filepos_t)pos;
|
||||
|
||||
return (lws_fileofs_t)fop_fd->pos;
|
||||
}
|
||||
|
||||
int
|
||||
dlo_filesystem_fops_write(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len)
|
||||
{
|
||||
*amount = 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int
|
||||
dlo_filesystem_fops_read(lws_fop_fd_t fop_fd, lws_filepos_t *amount,
|
||||
uint8_t *buf, lws_filepos_t len)
|
||||
{
|
||||
const uint8_t *p = (uint8_t *)fop_fd->filesystem_priv;
|
||||
lws_filepos_t amt = *amount;
|
||||
|
||||
*amount = 0;
|
||||
if (fop_fd->len <= fop_fd->pos)
|
||||
return 0;
|
||||
|
||||
if (amt > fop_fd->len - fop_fd->pos)
|
||||
amt = fop_fd->len - fop_fd->pos;
|
||||
|
||||
if (amt > len)
|
||||
amt = len;
|
||||
|
||||
memcpy(buf, p + fop_fd->pos, (size_t)amt);
|
||||
fop_fd->pos += amt;
|
||||
|
||||
*amount = amt;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
lws_fop_fd_t
|
||||
lws_dlo_filesystem_fops_open(const struct lws_plat_file_ops *fops_own,
|
||||
const struct lws_plat_file_ops *fops,
|
||||
const char *vfs_path, const char *vpath,
|
||||
lws_fop_flags_t *flags)
|
||||
{
|
||||
const lws_dlo_filesystem_t *f = NULL;
|
||||
lws_fop_fd_t fop_fd;
|
||||
|
||||
// lwsl_err("%s: %s\n", __func__, vpath);
|
||||
|
||||
f = lws_dlo_file_choose(fops->cx, vpath);
|
||||
if (f) {
|
||||
/* we will handle it then */
|
||||
fop_fd = lws_zalloc(sizeof(*fop_fd), __func__);
|
||||
if (!fop_fd)
|
||||
return NULL;
|
||||
|
||||
fop_fd->fops = fops_own;
|
||||
fop_fd->filesystem_priv = (void *)f->data;
|
||||
fop_fd->pos = 0;
|
||||
fop_fd->len = f->len;
|
||||
|
||||
// lwsl_notice("%s: Opened %s\n", __func__, vpath);
|
||||
|
||||
return fop_fd;
|
||||
} else
|
||||
lwsl_err("%s: failed to open %s\n", __func__, vpath);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct lws_plat_file_ops lws_dlo_fops = {
|
||||
.LWS_FOP_OPEN = lws_dlo_filesystem_fops_open,
|
||||
.LWS_FOP_CLOSE = dlo_filesystem_fops_close,
|
||||
.LWS_FOP_SEEK_CUR = dlo_filesystem_fops_seek_cur,
|
||||
.LWS_FOP_READ = dlo_filesystem_fops_read,
|
||||
.LWS_FOP_WRITE = dlo_filesystem_fops_write,
|
||||
.fi = { { "dlofs/", 6 } },
|
||||
};
|
||||
|
||||
#endif
|
@ -0,0 +1,57 @@
|
||||
enum {
|
||||
MCUFO_MAGIC = 0,
|
||||
MCUFO_FLAGS_VER = 4,
|
||||
MCUFO_FOFS_FULLNAME = 8,
|
||||
MCUFO_FOFS_NAME = 0xc,
|
||||
MCUFO_FOFS_DICT_DATA = 0x10,
|
||||
MCUFO_SIZE_DICT_DATA = 0x14,
|
||||
MCUFO_FOFS_DICT_OFS = 0x18,
|
||||
MCUFO_COUNT_RLE_DICT = 0x1C,
|
||||
MCUFO_COUNT_REF_RLE_DICT = 0x20,
|
||||
MCUFO_FOFS_CHAR_RANGE_TABLES = 0x24,
|
||||
MCUFO_COUNT_CHAR_RANGE_TABLES = 0x28,
|
||||
MCUFO_UNICODE_FALLBACK = 0x2C,
|
||||
|
||||
MCUFO16_WIDTH = 0x30,
|
||||
MCUFO16_HEIGHT = 0x32,
|
||||
MCUFO16_MIN_X_ADV = 0x34,
|
||||
MCUFO16_MAX_X_ADV = 0x36,
|
||||
MCUFO16_BASELINE_X = 0x38,
|
||||
MCUFO16_BASELINE_Y = 0x3a,
|
||||
MCUFO16_LINE_HEIGHT = 0x3c,
|
||||
};
|
||||
|
||||
void
|
||||
dist_err_floyd_steinberg_grey(int n, int width, lws_greyscale_error_t *gedl_this,
|
||||
lws_greyscale_error_t *gedl_next);
|
||||
|
||||
void
|
||||
dist_err_floyd_steinberg_col(int n, int width, lws_colour_error_t *edl_this,
|
||||
lws_colour_error_t *edl_next);
|
||||
|
||||
int
|
||||
lws_display_alloc_diffusion(const lws_surface_info_t *ic, lws_surface_error_t **se);
|
||||
|
||||
size_t
|
||||
utf8_bytes(uint8_t u);
|
||||
|
||||
int
|
||||
lws_display_font_mcufont_getcwidth(lws_dlo_text_t *text, uint32_t unicode,
|
||||
lws_fx_t *fx);
|
||||
|
||||
int
|
||||
lws_display_dlo_text_attach_glyphs(lws_dlo_text_t *text);
|
||||
|
||||
lws_stateful_ret_t
|
||||
lws_display_font_mcufont_render(struct lws_display_render_state *rs);
|
||||
|
||||
lws_font_glyph_t *
|
||||
lws_display_font_mcufont_image_glyph(lws_dlo_text_t *text, uint32_t unicode,
|
||||
char attach);
|
||||
|
||||
void
|
||||
lws_lhp_ss_html_parse_from_lhp(lhp_ctx_t *lhp);
|
||||
|
||||
void
|
||||
lws_lhp_image_dimensions_cb(lws_sorted_usec_list_t *sul);
|
||||
|
Reference in New Issue
Block a user