/src/libwebsockets/lib/misc/dlo/dlo-font-mcufont.c
Line | Count | Source |
1 | | /* |
2 | | * lws abstract display |
3 | | * |
4 | | * Copyright (C) 2013 Petteri Aimonen |
5 | | * Copyright (C) 2019 - 2022 Andy Green <andy@warmcat.com> |
6 | | * |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to |
9 | | * deal in the Software without restriction, including without limitation the |
10 | | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
11 | | * sell copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in |
15 | | * all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
22 | | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
23 | | * IN THE SOFTWARE. |
24 | | * |
25 | | * Display List Object: mcufont font |
26 | | * |
27 | | * The mcu decoding is rewritten from the mcufont implementation at |
28 | | * https://github.com/mcufont/mcufont, which is licensed under MIT already, |
29 | | * to use a stateful decoder. |
30 | | * |
31 | | * The decoder only brings in new compression codes when needed to produce more |
32 | | * pixels on the line of the glyphs being decoded. |
33 | | */ |
34 | | |
35 | | #include <private-lib-core.h> |
36 | | #include "private-lib-drivers-display-dlo.h" |
37 | | |
38 | 0 | #define DICT_START 24 |
39 | 0 | #define REF_FILLZEROS 16 |
40 | | |
41 | 0 | #define RLE_CODEMASK 0xC0 |
42 | 0 | #define RLE_VALMASK 0x3F |
43 | 0 | #define RLE_ZEROS 0x00 |
44 | 0 | #define RLE_64ZEROS 0x40 |
45 | 0 | #define RLE_ONES 0x80 |
46 | 0 | #define RLE_SHADE 0xC0 |
47 | | |
48 | 0 | #define DICT_START7BIT 4 |
49 | 0 | #define DICT_START6BIT 132 |
50 | 0 | #define DICT_START5BIT 196 |
51 | 0 | #define DICT_START4BIT 228 |
52 | 0 | #define DICT_START3BIT 244 |
53 | 0 | #define DICT_START2BIT 252 |
54 | | |
55 | | enum { |
56 | | RS_IDLE, |
57 | | RS_SKIP_PX, |
58 | | RS_WRITE_PX, |
59 | | RS_ALLZERO, |
60 | | |
61 | | COMP = 0, |
62 | | DICT1, |
63 | | DICT1_CONT, |
64 | | DICT2, |
65 | | DICT3 |
66 | | }; |
67 | | |
68 | | typedef struct mcu_stack { |
69 | | const uint8_t *dict; |
70 | | int16_t dictlen; |
71 | | int16_t runlen; /* for accumilation on DICT1 */ |
72 | | uint8_t byte; |
73 | | uint8_t bitcount; |
74 | | uint8_t state; |
75 | | } mcu_stack_t; |
76 | | |
77 | | typedef struct mcu_glyph { |
78 | | lws_font_glyph_t fg; |
79 | | const uint8_t *comp; |
80 | | |
81 | | mcu_stack_t st[3]; |
82 | | int32_t runlen; |
83 | | |
84 | | int8_t sp; |
85 | | |
86 | | uint8_t runstate; |
87 | | uint8_t alpha; |
88 | | uint8_t code; |
89 | | } mcu_glyph_t; |
90 | | |
91 | | /* Get bit count for the "fill entries" */ |
92 | | static uint8_t |
93 | | fillentry_bitcount(uint8_t index) |
94 | 0 | { |
95 | 0 | if (index >= DICT_START2BIT) |
96 | 0 | return 2; |
97 | 0 | else if (index >= DICT_START3BIT) |
98 | 0 | return 3; |
99 | 0 | else if (index >= DICT_START4BIT) |
100 | 0 | return 4; |
101 | 0 | else if (index >= DICT_START5BIT) |
102 | 0 | return 5; |
103 | 0 | else if (index >= DICT_START6BIT) |
104 | 0 | return 6; |
105 | 0 | else |
106 | 0 | return 7; |
107 | 0 | } |
108 | | |
109 | | void |
110 | | draw_px(lws_dlo_text_t *t, mcu_glyph_t *g) |
111 | 0 | { |
112 | 0 | lws_display_colour_t c = (lws_display_colour_t)((lws_display_colour_t)(g->alpha << 24) | |
113 | 0 | (lws_display_colour_t)((lws_display_colour_t)t->dlo.dc & 0xffffffu)); |
114 | 0 | lws_fx_t t1, x; |
115 | 0 | int ex; |
116 | |
|
117 | 0 | t1.whole = g->fg.x; |
118 | |
|
119 | 0 | if (!g->alpha) |
120 | 0 | return; |
121 | | |
122 | 0 | t1.frac = 0; |
123 | 0 | lws_fx_add(&x, &g->fg.xpx, &t1); |
124 | |
|
125 | | #if 0 |
126 | | { char b1[22], b2[22], b3[22]; |
127 | | lwsl_err("fadj %s = %s + %s\n", |
128 | | lws_fx_string(&x, b1, sizeof(b1)), |
129 | | lws_fx_string(&g->fg.xpx, b2, sizeof(b2)), |
130 | | lws_fx_string(&g->fg.xorg, b3, sizeof(b3))); } |
131 | | #endif |
132 | |
|
133 | 0 | ex = x.whole;// - t->dlo.box.x.whole; |
134 | 0 | if (ex < 0 || ex >= t->dlo.box.w.whole) { |
135 | | //lwsl_err("%s: ex %d (lim %d)\n", __func__, ex, t->dlo.box.w.whole); |
136 | 0 | return; |
137 | 0 | } |
138 | 0 | lws_fx_add(&x, &x, &g->fg.xorg); |
139 | |
|
140 | 0 | lws_fx_add(&t1, &t->dlo.box.x, &x); |
141 | 0 | lws_surface_set_px(t->ic, t->line, t1.whole, &c); |
142 | 0 | } |
143 | | |
144 | | static void |
145 | | write_ref_codeword(mcu_glyph_t *g, const uint8_t *bf, uint8_t c) |
146 | 0 | { |
147 | 0 | uint32_t o, o1; |
148 | |
|
149 | 0 | if (!c) { |
150 | 0 | g->runlen = 1; |
151 | 0 | g->runstate = RS_SKIP_PX; |
152 | 0 | return; |
153 | 0 | } |
154 | 0 | if (c <= 15) { |
155 | 0 | g->alpha = (uint8_t)(0x11 * c); |
156 | 0 | g->runlen = 1; |
157 | 0 | g->runstate = RS_WRITE_PX; |
158 | 0 | return; |
159 | 0 | } |
160 | 0 | if (c == REF_FILLZEROS) { |
161 | | /* Fill with zeroes to end */ |
162 | 0 | g->alpha = 0; |
163 | 0 | g->runlen = 1000000; |
164 | 0 | g->runstate = RS_WRITE_PX; |
165 | 0 | return; |
166 | 0 | } |
167 | 0 | if (c < DICT_START) |
168 | 0 | return; |
169 | | |
170 | 0 | if (c < DICT_START + lws_ser_ru32be(bf + MCUFO_COUNT_RLE_DICT)) { |
171 | | /* write_rle_dictentry */ |
172 | 0 | o1 = lws_ser_ru32be(bf + MCUFO_FOFS_DICT_OFS); |
173 | 0 | o = lws_ser_ru16be(bf + o1 + ((c - DICT_START) * 2)); |
174 | 0 | g->st[(int)++g->sp].dictlen = (int16_t)(lws_ser_ru16be(bf + o1 + |
175 | 0 | ((c - DICT_START + 1) * 2)) - o); |
176 | |
|
177 | 0 | g->st[(int)g->sp].dict = bf + lws_ser_ru32be(bf + MCUFO_FOFS_DICT_DATA) + o; |
178 | 0 | g->st[(int)g->sp].state = DICT2; |
179 | 0 | return; |
180 | 0 | } |
181 | | |
182 | 0 | g->st[(int)++g->sp].bitcount = fillentry_bitcount(c); |
183 | 0 | g->st[(int)g->sp].byte = (uint8_t)(c - DICT_START7BIT); |
184 | 0 | g->st[(int)g->sp].state = DICT1; |
185 | 0 | g->runlen = 0; |
186 | 0 | } |
187 | | |
188 | | static void |
189 | | mcufont_next_code(mcu_glyph_t *g) |
190 | 0 | { |
191 | 0 | lws_dlo_text_t *t = lws_container_of(g->fg.list.owner, lws_dlo_text_t, |
192 | 0 | glyphs); |
193 | 0 | const uint8_t *bf = (const uint8_t *)t->font->data; |
194 | 0 | uint8_t c = *g->comp++; |
195 | 0 | uint32_t o, o1; |
196 | |
|
197 | 0 | if (c < DICT_START + lws_ser_ru32be(&bf[MCUFO_COUNT_RLE_DICT]) || |
198 | 0 | c >= DICT_START + lws_ser_ru32be(&bf[MCUFO_COUNT_REF_RLE_DICT])) { |
199 | 0 | write_ref_codeword(g, bf, c); |
200 | 0 | return; |
201 | 0 | } |
202 | | |
203 | | /* write_ref_dictentry() */ |
204 | | |
205 | 0 | o1 = lws_ser_ru32be(bf + MCUFO_FOFS_DICT_OFS); |
206 | 0 | o = lws_ser_ru16be(bf + o1 + ((c - DICT_START) * 2)); |
207 | 0 | g->st[(int)++g->sp].dictlen = (int16_t)(lws_ser_ru16be(bf + o1 + |
208 | 0 | ((c - DICT_START + 1) * 2)) - o); |
209 | |
|
210 | 0 | g->st[(int)g->sp].dict = bf + lws_ser_ru32be(bf + MCUFO_FOFS_DICT_DATA) + o; |
211 | 0 | g->st[(int)g->sp].state = DICT3; |
212 | 0 | } |
213 | | |
214 | | /* lookup and append a glyph for specific unicode to the text glyph list */ |
215 | | |
216 | | static uint32_t |
217 | | font_mcufont_uniglyph_lookup(lws_dlo_text_t *text, uint32_t unicode) |
218 | 0 | { |
219 | 0 | const uint8_t *bf = (const uint8_t *)text->font->data, |
220 | 0 | *r = bf + lws_ser_ru32be(&bf[MCUFO_FOFS_CHAR_RANGE_TABLES]); |
221 | 0 | uint32_t entries = lws_ser_ru32be(&bf[MCUFO_COUNT_CHAR_RANGE_TABLES]); |
222 | 0 | unsigned int n; |
223 | |
|
224 | 0 | if (entries > 8) /* coverity sanity */ |
225 | 0 | return 0; |
226 | | |
227 | 0 | do { |
228 | 0 | for (n = 0; n < entries; n++) { |
229 | 0 | uint32_t cs = lws_ser_ru32be(r + 0), ce = lws_ser_ru32be(r + 4); |
230 | |
|
231 | 0 | if (cs >= 0x100000 || !ce || ce > 0x10000) |
232 | 0 | return 0; |
233 | | |
234 | 0 | if (unicode >= cs && unicode < cs + ce) { |
235 | 0 | uint32_t cbo = lws_ser_ru32be(r + 0xc); |
236 | |
|
237 | 0 | if (cbo >= text->font->data_len) |
238 | 0 | return 0; |
239 | | |
240 | 0 | cbo += lws_ser_ru16be(bf + |
241 | 0 | lws_ser_ru32be(r + 8) + ((unicode - cs) * 2)); |
242 | |
|
243 | 0 | if (cbo >= text->font->data_len) |
244 | 0 | return 0; |
245 | | |
246 | 0 | return cbo; |
247 | 0 | } |
248 | | |
249 | 0 | r += 16; |
250 | 0 | } |
251 | | |
252 | 0 | if (unicode == lws_ser_ru32be(&bf[MCUFO_UNICODE_FALLBACK])) |
253 | 0 | return 0; |
254 | 0 | unicode = lws_ser_ru32be(&bf[MCUFO_UNICODE_FALLBACK]); |
255 | |
|
256 | 0 | } while (1); |
257 | 0 | } |
258 | | |
259 | | static mcu_glyph_t * |
260 | | font_mcufont_uniglyph(lws_dlo_text_t *text, uint32_t unicode) |
261 | 0 | { |
262 | 0 | const uint8_t *bf = (const uint8_t *)text->font->data; |
263 | 0 | uint32_t ofs; |
264 | 0 | mcu_glyph_t *g; |
265 | |
|
266 | 0 | ofs = font_mcufont_uniglyph_lookup(text, unicode); |
267 | 0 | if (!ofs) |
268 | 0 | return NULL; |
269 | | |
270 | | // lwsl_warn("%s: text->text_len %u: %c\n", __func__, text->text_len, (char)unicode); |
271 | 0 | g = lwsac_use_zero(&text->ac_glyphs, sizeof(*g), |
272 | 0 | (text->text_len + 1) * sizeof(*g)); |
273 | 0 | if (!g) |
274 | 0 | return NULL; |
275 | | |
276 | 0 | g->comp = bf + ofs; |
277 | 0 | g->fg.cwidth.whole = *g->comp++; |
278 | 0 | g->fg.cwidth.frac = 0; |
279 | |
|
280 | 0 | lws_dll2_add_tail(&g->fg.list, &text->glyphs); |
281 | |
|
282 | 0 | return g; |
283 | 0 | } |
284 | | |
285 | | int |
286 | | lws_display_font_mcufont_getcwidth(lws_dlo_text_t *text, uint32_t unicode, |
287 | | lws_fx_t *fx) |
288 | 0 | { |
289 | 0 | const uint8_t *bf = (const uint8_t *)text->font->data; |
290 | 0 | uint32_t ofs = font_mcufont_uniglyph_lookup(text, unicode); |
291 | |
|
292 | 0 | if (!ofs) |
293 | 0 | return 1; |
294 | | |
295 | 0 | fx->whole = bf[ofs]; |
296 | 0 | fx->frac = 0; |
297 | |
|
298 | 0 | return 0; |
299 | 0 | } |
300 | | |
301 | | lws_font_glyph_t * |
302 | | lws_display_font_mcufont_image_glyph(lws_dlo_text_t *text, uint32_t unicode, |
303 | | char attach) |
304 | 0 | { |
305 | 0 | const uint8_t *bf = (const uint8_t *)text->font->data; |
306 | 0 | mcu_glyph_t *g; |
307 | | |
308 | | /* one text dlo has glyphs from all the same fonts and attributes */ |
309 | 0 | if (!text->font_height) { |
310 | 0 | text->font_height = (int16_t)lws_ser_ru16be(&bf[MCUFO16_HEIGHT]); |
311 | 0 | text->font_y_baseline = (int16_t)(text->font_height - |
312 | 0 | lws_ser_ru16be(&bf[MCUFO16_BASELINE_Y])); |
313 | 0 | text->font_line_height = (int16_t)lws_ser_ru16be(&bf[MCUFO16_LINE_HEIGHT]); |
314 | 0 | } |
315 | |
|
316 | 0 | lws_display_font_mcufont_getcwidth(text, unicode, &text->_cwidth); |
317 | |
|
318 | 0 | if (!attach) |
319 | 0 | return NULL; |
320 | | |
321 | 0 | g = font_mcufont_uniglyph(text, unicode); |
322 | 0 | if (!g) |
323 | 0 | return NULL; |
324 | | |
325 | 0 | g->fg.height.whole = lws_ser_ru16be(bf + MCUFO16_HEIGHT); |
326 | 0 | g->fg.height.frac = 0; |
327 | |
|
328 | 0 | return &g->fg; |
329 | 0 | } |
330 | | |
331 | | lws_stateful_ret_t |
332 | | lws_display_font_mcufont_render(struct lws_display_render_state *rs) |
333 | 0 | { |
334 | 0 | lws_dlo_t *dlo = rs->st[rs->sp].dlo; |
335 | 0 | lws_dlo_text_t *text = lws_container_of(dlo, lws_dlo_text_t, dlo); |
336 | 0 | const uint8_t *bf = (const uint8_t *)text->font->data; |
337 | 0 | lws_fx_t ax, ay, t, t1, t2, t3; |
338 | 0 | mcu_glyph_t *g; |
339 | 0 | int s, e, yo; |
340 | 0 | uint8_t c, el; |
341 | |
|
342 | 0 | lws_fx_add(&ax, &rs->st[rs->sp].co.x, &dlo->box.x); |
343 | 0 | lws_fx_add(&t, &ax, &dlo->box.w); |
344 | 0 | lws_fx_add(&ay, &rs->st[rs->sp].co.y, &dlo->box.y); |
345 | 0 | lws_fx_add(&t1, &ay, &dlo->box.h); |
346 | |
|
347 | 0 | lws_fx_add(&t2, &ax, &text->bounding_box.w); |
348 | |
|
349 | 0 | text->curr = rs->curr; |
350 | 0 | text->ic = rs->ic; |
351 | 0 | text->line = rs->line; |
352 | |
|
353 | 0 | s = ax.whole; |
354 | 0 | e = lws_fx_roundup(&t2); |
355 | |
|
356 | 0 | if (e <= 0) |
357 | 0 | return LWS_SRET_OK; /* wholly off to the left */ |
358 | 0 | if (s >= rs->ic->wh_px[0].whole) |
359 | 0 | return LWS_SRET_OK; /* wholly off to the right */ |
360 | | |
361 | 0 | if (e >= rs->ic->wh_px[0].whole) |
362 | 0 | e = rs->ic->wh_px[0].whole; |
363 | | |
364 | | /* figure out our y position inside the glyph bounding box */ |
365 | 0 | yo = rs->curr - ay.whole; |
366 | |
|
367 | 0 | if (!yo) { |
368 | 0 | lws_display_dlo_text_attach_glyphs(text); |
369 | |
|
370 | 0 | t3.whole = lws_ser_ru16be(bf + MCUFO16_BASELINE_X); |
371 | 0 | t3.frac = 0; |
372 | 0 | lws_start_foreach_dll(struct lws_dll2 *, d, |
373 | 0 | lws_dll2_get_head(&text->glyphs)) { |
374 | 0 | lws_font_glyph_t *fg = lws_container_of(d, lws_font_glyph_t, list); |
375 | 0 | lws_fx_sub(&fg->xpx, &fg->xpx, &t3); |
376 | 0 | fg->xorg = rs->st[rs->sp].co.x; |
377 | 0 | } lws_end_foreach_dll(d); |
378 | 0 | } |
379 | |
|
380 | | #if 0 |
381 | | { |
382 | | uint32_t dc = 0xff0000ff; |
383 | | int s1 = s; |
384 | | /* from origin.x + dlo->box.x */ |
385 | | for (s1 = ax.whole; s1 < t2.whole; s1++) |
386 | | lws_surface_set_px(ic, line, s1, &dc); |
387 | | |
388 | | memset(&ce, 0, sizeof(ce)); |
389 | | } |
390 | | #endif |
391 | |
|
392 | 0 | lws_start_foreach_dll(struct lws_dll2 *, d, |
393 | 0 | lws_dll2_get_head(&text->glyphs)) { |
394 | 0 | lws_font_glyph_t *fg = lws_container_of(d, lws_font_glyph_t, list); |
395 | |
|
396 | 0 | g = (mcu_glyph_t *)fg; |
397 | 0 | fg->x = 0; |
398 | |
|
399 | 0 | while (yo < (int)fg->height.whole && |
400 | 0 | fg->x < lws_ser_ru16be(bf + MCUFO16_WIDTH)) { |
401 | 0 | switch (g->runstate) { |
402 | 0 | case RS_IDLE: |
403 | 0 | switch (g->st[(int)g->sp].state) { |
404 | 0 | case COMP: |
405 | 0 | mcufont_next_code(g); |
406 | 0 | break; |
407 | | |
408 | 0 | case DICT1_CONT: |
409 | 0 | --g->sp; /* back to DICT1 after doing the skip */ |
410 | 0 | g->runstate = RS_SKIP_PX; |
411 | 0 | g->runlen = 1; |
412 | 0 | continue; |
413 | | |
414 | 0 | case DICT1: |
415 | | /* write_bin_codeword() states */ |
416 | 0 | el = 0; |
417 | 0 | while (g->st[(int)g->sp].bitcount--) { |
418 | 0 | c = g->st[(int)g->sp].byte; |
419 | 0 | g->st[(int)g->sp].byte >>= 1; |
420 | 0 | if (c & 1) |
421 | 0 | g->st[(int)g->sp].runlen++; |
422 | 0 | else { |
423 | 0 | if (g->st[(int)g->sp].runlen) { |
424 | 0 | g->alpha = 255; |
425 | 0 | g->runstate = RS_WRITE_PX; |
426 | 0 | g->runlen = g->st[(int)g->sp].runlen; |
427 | 0 | g->st[(int)g->sp].runlen = 0; |
428 | 0 | g->st[(int)++g->sp].state = DICT1_CONT; |
429 | 0 | el = 1; |
430 | 0 | break; |
431 | 0 | } |
432 | 0 | g->runstate = RS_SKIP_PX; |
433 | 0 | g->runlen = 1; |
434 | 0 | el = 1; |
435 | 0 | break; |
436 | 0 | } |
437 | 0 | } |
438 | |
|
439 | 0 | if (el) |
440 | 0 | continue; |
441 | | |
442 | | /* back out of DICT1 */ |
443 | 0 | if (!g->sp) |
444 | 0 | assert(0); |
445 | 0 | g->sp--; |
446 | |
|
447 | 0 | if (g->st[(int)g->sp + 1].runlen) { |
448 | 0 | g->alpha = 255; |
449 | 0 | g->runstate = RS_WRITE_PX; |
450 | 0 | g->runlen = g->st[(int)g->sp + 1].runlen; |
451 | 0 | g->st[(int)g->sp + 1].runlen = 0; |
452 | 0 | continue; |
453 | 0 | } |
454 | 0 | break; |
455 | | |
456 | 0 | case DICT2: /* write_rle_dictentry */ |
457 | 0 | c = (*g->st[(int)g->sp].dict++); |
458 | 0 | if (!--g->st[(int)g->sp].dictlen) { |
459 | 0 | if (!g->sp) |
460 | 0 | assert(0); |
461 | 0 | g->sp--; |
462 | 0 | } |
463 | 0 | if ((c & RLE_CODEMASK) == RLE_ZEROS) { |
464 | 0 | g->runstate = RS_SKIP_PX; |
465 | 0 | g->runlen = c & RLE_VALMASK; |
466 | 0 | continue; |
467 | 0 | } |
468 | 0 | if ((c & RLE_CODEMASK) == RLE_64ZEROS) { |
469 | 0 | g->runstate = RS_SKIP_PX; |
470 | 0 | g->runlen = ((c & RLE_VALMASK) + 1) * 64; |
471 | 0 | continue; |
472 | 0 | } |
473 | 0 | if ((c & RLE_CODEMASK) == RLE_ONES) { |
474 | 0 | g->alpha = 255; |
475 | 0 | g->runstate = RS_WRITE_PX; |
476 | 0 | g->runlen = (c & RLE_VALMASK) + 1; |
477 | 0 | continue; |
478 | 0 | } |
479 | 0 | if ((c & RLE_CODEMASK) == RLE_SHADE) { |
480 | 0 | g->alpha = (uint8_t)(((c & RLE_VALMASK) & 0xf) * 0x11); |
481 | 0 | g->runstate = RS_WRITE_PX; |
482 | 0 | g->runlen = ((c & RLE_VALMASK) >> 4) + 1; |
483 | 0 | continue; |
484 | 0 | } |
485 | 0 | break; |
486 | | |
487 | 0 | case DICT3: |
488 | 0 | c = *g->st[(int)g->sp].dict++; |
489 | 0 | if (!--g->st[(int)g->sp].dictlen) { |
490 | 0 | if (!g->sp) |
491 | 0 | assert(0); |
492 | |
|
493 | 0 | g->sp--; |
494 | 0 | } |
495 | |
|
496 | 0 | write_ref_codeword(g, bf, c); |
497 | 0 | break; |
498 | 0 | } |
499 | 0 | break; |
500 | 0 | case RS_SKIP_PX: |
501 | 0 | fg->x++; |
502 | 0 | if (--g->runlen) |
503 | 0 | break; |
504 | 0 | g->runstate = RS_IDLE; |
505 | 0 | break; |
506 | | |
507 | 0 | case RS_WRITE_PX: |
508 | 0 | if (g->alpha) |
509 | 0 | draw_px(text, g); |
510 | 0 | g->fg.x++; |
511 | 0 | if (--g->runlen) |
512 | 0 | break; |
513 | 0 | g->runstate = RS_IDLE; |
514 | 0 | break; |
515 | | |
516 | 0 | case RS_ALLZERO: |
517 | 0 | fg->x++; |
518 | 0 | if (--g->runlen) |
519 | 0 | break; |
520 | 0 | g->runstate = RS_IDLE; |
521 | 0 | break; |
522 | 0 | } |
523 | 0 | } |
524 | |
|
525 | 0 | } lws_end_foreach_dll(d); |
526 | |
|
527 | 0 | return LWS_SRET_OK; |
528 | 0 | } |