diff --git a/src/draw/nema_gfx/lv_draw_nema_gfx.c b/src/draw/nema_gfx/lv_draw_nema_gfx.c index 7c7c52b64..0968d4fae 100644 --- a/src/draw/nema_gfx/lv_draw_nema_gfx.c +++ b/src/draw/nema_gfx/lv_draw_nema_gfx.c @@ -93,6 +93,12 @@ void lv_draw_nema_gfx_init(void) lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = lv_draw_create_unit(sizeof(lv_draw_nema_gfx_unit_t)); /*Initiallize NemaGFX*/ nema_init(); + + draw_nema_gfx_unit->base_unit.dispatch_cb = nema_gfx_dispatch; + draw_nema_gfx_unit->base_unit.evaluate_cb = nema_gfx_evaluate; + draw_nema_gfx_unit->base_unit.delete_cb = nema_gfx_delete; + draw_nema_gfx_unit->base_unit.name = "NEMA_GFX"; + #if LV_USE_NEMA_VG /*Initiallize NemaVG */ nema_vg_init(LV_NEMA_GFX_MAX_RESX, LV_NEMA_GFX_MAX_RESY); @@ -100,11 +106,9 @@ void lv_draw_nema_gfx_init(void) draw_nema_gfx_unit->paint = nema_vg_paint_create(); draw_nema_gfx_unit->gradient = nema_vg_grad_create(); draw_nema_gfx_unit->path = nema_vg_path_create(); + /*Initialize Freetype Support*/ + lv_draw_nema_gfx_label_init(&(draw_nema_gfx_unit->base_unit)); #endif - draw_nema_gfx_unit->base_unit.dispatch_cb = nema_gfx_dispatch; - draw_nema_gfx_unit->base_unit.evaluate_cb = nema_gfx_evaluate; - draw_nema_gfx_unit->base_unit.delete_cb = nema_gfx_delete; - draw_nema_gfx_unit->base_unit.name = "NEMA_GFX"; /*Create GPU Command List*/ draw_nema_gfx_unit->cl = nema_cl_create(); /*Bind Command List*/ diff --git a/src/draw/nema_gfx/lv_draw_nema_gfx.h b/src/draw/nema_gfx/lv_draw_nema_gfx.h index 26a8fae94..3ac255d1d 100644 --- a/src/draw/nema_gfx/lv_draw_nema_gfx.h +++ b/src/draw/nema_gfx/lv_draw_nema_gfx.h @@ -97,6 +97,8 @@ void lv_draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t void lv_draw_nema_gfx_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords); +void lv_draw_nema_gfx_label_init(lv_draw_unit_t * draw_unit); + void lv_draw_nema_gfx_layer(lv_draw_unit_t * draw_unit, const lv_draw_image_dsc_t * draw_dsc, const lv_area_t * coords); diff --git a/src/draw/nema_gfx/lv_draw_nema_gfx_img.c b/src/draw/nema_gfx/lv_draw_nema_gfx_img.c index 482666b4b..846602d69 100644 --- a/src/draw/nema_gfx/lv_draw_nema_gfx_img.c +++ b/src/draw/nema_gfx/lv_draw_nema_gfx_img.c @@ -106,6 +106,8 @@ static void _draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_d lv_layer_t * layer = draw_unit->target_layer; const lv_image_dsc_t * img_dsc = dsc->src; + bool masked = dsc->bitmap_mask_src != NULL; + lv_area_t blend_area; /*Let's get the blend area which is the intersection of the area to fill and the clip area.*/ if(!lv_area_intersect(&blend_area, coords, draw_unit->clip_area)) @@ -143,8 +145,8 @@ static void _draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_d uint32_t src_nema_cf = lv_nemagfx_cf_to_nema(src_cf); /* the stride should be computed internally for NEMA_TSC images and images missing a stride value */ - uint32_t src_stride = (src_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && src_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) - || img_dsc->header.stride == 0 ? -1 : img_dsc->header.stride; + int32_t src_stride = (src_cf >= LV_COLOR_FORMAT_NEMA_TSC_START && src_cf <= LV_COLOR_FORMAT_NEMA_TSC_END) + || img_dsc->header.stride == 0 ? -1 : (int32_t)img_dsc->header.stride; nema_bind_dst_tex((uintptr_t)NEMA_VIRT2PHYS(layer->draw_buf->data), lv_area_get_width(&(layer->buf_area)), lv_area_get_height(&(layer->buf_area)), dst_nema_cf, @@ -170,13 +172,26 @@ static void _draw_nema_gfx_img(lv_draw_unit_t * draw_unit, const lv_draw_image_d blending_mode |= NEMA_BLOP_MODULATE_A; } - if(dsc->bitmap_mask_src != NULL) { - blending_mode |= NEMA_BLOP_STENCIL_TXTY; - const lv_image_dsc_t * mask = dsc->bitmap_mask_src; - const void * mask_buf = mask->data; - nema_bind_tex(NEMA_TEX3, (uintptr_t)NEMA_VIRT2PHYS(mask_buf), mask->header.w, mask->header.h, - lv_nemagfx_mask_cf_to_nema(mask->header.cf), - mask->header.stride, NEMA_FILTER_BL); + if(!has_transform && masked && !recolor) { + if(dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_A8 || dsc->bitmap_mask_src->header.cf == LV_COLOR_FORMAT_L8) { + blending_mode |= NEMA_BLOP_STENCIL_TXTY; + const lv_image_dsc_t * mask = dsc->bitmap_mask_src; + const void * mask_buf = mask->data; + + const lv_area_t * image_area; + lv_area_t mask_area; + if(lv_area_get_width(&dsc->image_area) < 0) image_area = coords; + else image_area = &dsc->image_area; + + lv_area_set(&mask_area, 0, 0, dsc->bitmap_mask_src->header.w - 1, dsc->bitmap_mask_src->header.h - 1); + lv_area_align(image_area, &mask_area, LV_ALIGN_CENTER, 0, 0); + + mask_buf += dsc->bitmap_mask_src->header.w * (coords->y1 - mask_area.y1) + (coords->x1 - mask_area.x1); + + nema_bind_tex(NEMA_TEX3, (uintptr_t)NEMA_VIRT2PHYS(mask_buf), mask->header.w, mask->header.h, + lv_nemagfx_mask_cf_to_nema(mask->header.cf), + mask->header.stride, NEMA_FILTER_BL); + } } nema_set_blend_blit(blending_mode); diff --git a/src/draw/nema_gfx/lv_draw_nema_gfx_label.c b/src/draw/nema_gfx/lv_draw_nema_gfx_label.c index dc7e05596..9497f787b 100644 --- a/src/draw/nema_gfx/lv_draw_nema_gfx_label.c +++ b/src/draw/nema_gfx/lv_draw_nema_gfx_label.c @@ -35,20 +35,40 @@ #include "lv_draw_nema_gfx.h" #if LV_USE_NEMA_GFX -#include "../../font/lv_font.h" -#include "../../font/lv_font_fmt_txt.h" #include "../../misc/lv_utils.h" #include "../../misc/lv_text_private.h" +#include "../../lvgl.h" +#include "../../libs/freetype/lv_freetype_private.h" +#include "../../core/lv_global.h" /********************* * DEFINES *********************/ +#define LABEL_RECOLOR_PAR_LENGTH 6 #define LV_LABEL_HINT_UPDATE_TH 1024 /*Update the "hint" if the label's y coordinates have changed more then this*/ +#define FT_F26DOT6_SHIFT 6 + +#define font_draw_buf_handlers &(LV_GLOBAL_DEFAULT()->font_draw_buf_handlers) + +/** After converting the font reference size, it is also necessary to scale the 26dot6 data + * in the path to the real physical size + */ +#define FT_F26DOT6_TO_PATH_SCALE(x) (LV_FREETYPE_F26DOT6_TO_FLOAT(x) / (1 << FT_F26DOT6_SHIFT)) /*Forward declarations*/ void nema_set_matrix(nema_matrix3x3_t m); void nema_raster_rect(int x, int y, int w, int h); +/********************** + * TYPEDEFS + **********************/ +enum { + RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER, + RECOLOR_CMD_STATE_PARAMETER, + RECOLOR_CMD_STATE_TEXT_INPUT, +}; +typedef unsigned char cmd_state_t; + /********************** * STATIC PROTOTYPES **********************/ @@ -64,18 +84,36 @@ static inline uint8_t _bpp_nema_gfx_format(lv_draw_glyph_dsc_t * glyph_draw_dsc) static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, const lv_point_t * pos, const lv_font_t * font, uint32_t letter); -static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter); +static uint8_t hex_char_to_num(char hex); -static int unicode_list_compare(const void * ref, const void * element) -{ - return ((int32_t)(*(uint16_t *)ref)) - ((int32_t)(*(uint16_t *)element)); -} +static bool is_raw_bitmap; -static bool raw_bitmap = false; +#if LV_USE_FREETYPE && LV_USE_NEMA_VG + + #include "lv_nema_gfx_path.h" + + static void _draw_nema_gfx_outline(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc); + + static void freetype_outline_event_cb(lv_event_t * e); + + static void lv_nema_gfx_outline_push(const lv_freetype_outline_event_param_t * param); + + static void lv_nema_outline_event_alloc(const lv_freetype_outline_event_param_t * param); +#endif /********************** * GLOBAL FUNCTIONS **********************/ +void lv_draw_nema_gfx_label_init(lv_draw_unit_t * draw_unit) +{ +#if LV_USE_FREETYPE + /*Set up the freetype outline event*/ + lv_freetype_outline_add_event(freetype_outline_event_cb, LV_EVENT_ALL, draw_unit); +#else + LV_UNUSED(draw_unit); +#endif /* LV_USE_FREETYPE */ +} + void lv_draw_nema_gfx_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_t * dsc, const lv_area_t * coords) { if(dsc->opa <= LV_OPA_MIN) return; @@ -105,17 +143,148 @@ void lv_draw_nema_gfx_label(lv_draw_unit_t * draw_unit, const lv_draw_label_dsc_ /********************** * STATIC FUNCTIONS **********************/ +#if LV_USE_FREETYPE && LV_USE_NEMA_VG + +static void _draw_nema_gfx_outline(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * glyph_draw_dsc) +{ + + lv_area_t blend_area; + if(!_lv_area_intersect(&blend_area, glyph_draw_dsc->letter_coords, draw_unit->clip_area)) + return; + + lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)draw_unit; + + lv_nema_gfx_path_t * nema_gfx_path = (lv_nema_gfx_path_t *)glyph_draw_dsc->glyph_data; + + lv_point_t pos = {glyph_draw_dsc->letter_coords->x1, glyph_draw_dsc->letter_coords->y1}; + + float scale = FT_F26DOT6_TO_PATH_SCALE(lv_freetype_outline_get_scale(glyph_draw_dsc->g->resolved_font)); + + /*Calculate Path Matrix*/ + nema_matrix3x3_t matrix; + nema_mat3x3_load_identity(matrix); + nema_mat3x3_scale(matrix, scale, -scale); + nema_mat3x3_translate(matrix, pos.x - glyph_draw_dsc->g->ofs_x, + pos.y + glyph_draw_dsc->g->box_h + glyph_draw_dsc->g->ofs_y); + + nema_vg_path_clear(nema_gfx_path->path); + nema_vg_paint_clear(nema_gfx_path->paint); + + nema_vg_set_fill_rule(NEMA_VG_FILL_EVEN_ODD); + + nema_vg_path_set_shape(nema_gfx_path->path, nema_gfx_path->seg_size, nema_gfx_path->seg, nema_gfx_path->data_size, + nema_gfx_path->data); + + nema_vg_paint_set_type(nema_gfx_path->paint, NEMA_VG_PAINT_COLOR); + + lv_color32_t dsc_col32 = lv_color_to_32(glyph_draw_dsc->color, glyph_draw_dsc->opa); + uint32_t nema_dsc_color = nema_rgba(dsc_col32.red, dsc_col32.green, dsc_col32.blue, dsc_col32.alpha); + + nema_vg_paint_set_paint_color(nema_gfx_path->paint, nema_dsc_color); + + nema_vg_path_set_matrix(nema_gfx_path->path, matrix); + nema_vg_draw_path(nema_gfx_path->path, nema_gfx_path->paint); + + return; +} + +static void freetype_outline_event_cb(lv_event_t * e) +{ + LV_PROFILER_DRAW_BEGIN; + lv_event_code_t code = lv_event_get_code(e); + lv_freetype_outline_event_param_t * param = lv_event_get_param(e); + + switch(code) { + case LV_EVENT_CREATE: + param->outline = lv_nema_gfx_path_create(); + lv_nema_outline_event_alloc(param); + break; + case LV_EVENT_DELETE: + lv_nema_gfx_path_destroy(param->outline); + break; + case LV_EVENT_INSERT: + lv_nema_gfx_outline_push(param); + break; + default: + LV_LOG_WARN("unknown event code: %d", code); + break; + } + LV_PROFILER_DRAW_END; +} + +static void lv_nema_gfx_outline_push(const lv_freetype_outline_event_param_t * param) +{ + LV_PROFILER_DRAW_BEGIN; + lv_nema_gfx_path_t * outline = param->outline; + LV_ASSERT_NULL(outline); + + lv_freetype_outline_type_t type = param->type; + switch(type) { + case LV_FREETYPE_OUTLINE_END: + lv_nema_gfx_path_end(outline); + break; + case LV_FREETYPE_OUTLINE_MOVE_TO: + lv_nema_gfx_path_move_to(outline, param->to.x, param->to.y); + break; + case LV_FREETYPE_OUTLINE_LINE_TO: + lv_nema_gfx_path_line_to(outline, param->to.x, param->to.y); + break; + case LV_FREETYPE_OUTLINE_CUBIC_TO: + lv_nema_gfx_path_cubic_to(outline, param->control1.x, param->control1.y, + param->control2.x, param->control2.y, + param->to.x, param->to.y); + break; + case LV_FREETYPE_OUTLINE_CONIC_TO: + lv_nema_gfx_path_quad_to(outline, param->control1.x, param->control1.y, + param->to.x, param->to.y); + break; + default: + LV_LOG_ERROR("unknown point type: %d", type); + LV_ASSERT(false); + break; + } + LV_PROFILER_DRAW_END; +} + +static void lv_nema_outline_event_alloc(const lv_freetype_outline_event_param_t * param) +{ + lv_nema_gfx_path_t * outline = param->outline; + outline->data_size = param->sizes.data_size; + outline->seg_size = param->sizes.segments_size; + lv_nema_gfx_path_alloc(outline); +} + +#endif /* LV_USE_FREETYPE && LV_USE_NEMA_VG */ + +/** + * Convert a hexadecimal characters to a number (0..15) + * @param hex Pointer to a hexadecimal character (0..9, A..F) + * @return the numerical value of `hex` or 0 on error + */ +static uint8_t hex_char_to_num(char hex) +{ + if(hex >= '0' && hex <= '9') return hex - '0'; + if(hex >= 'a') hex -= 'a' - 'A'; /*Convert to upper case*/ + return 'A' <= hex && hex <= 'F' ? hex - 'A' + 10 : 0; +} + + static inline uint8_t _bpp_nema_gfx_format(lv_draw_glyph_dsc_t * glyph_draw_dsc) { uint32_t format = glyph_draw_dsc->g->format; switch(format) { case LV_FONT_GLYPH_FORMAT_A1: + case LV_FONT_GLYPH_FORMAT_A1_ALIGNED: return NEMA_A1; case LV_FONT_GLYPH_FORMAT_A2: + case LV_FONT_GLYPH_FORMAT_A2_ALIGNED: return NEMA_A2; case LV_FONT_GLYPH_FORMAT_A4: + case LV_FONT_GLYPH_FORMAT_A4_ALIGNED: return NEMA_A4; + case LV_FONT_GLYPH_FORMAT_A8: + case LV_FONT_GLYPH_FORMAT_A8_ALIGNED: default: return NEMA_A8; } @@ -150,16 +319,21 @@ static void _draw_nema_gfx_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_ lv_area_move(&blend_area, -layer->buf_area.x1, -layer->buf_area.y1); const lv_draw_buf_t * draw_buf = glyph_draw_dsc->glyph_data; - const void * mask_buf = draw_buf->data; + const void * mask_buf; + if(is_raw_bitmap) { + mask_buf = glyph_draw_dsc->glyph_data; + } + else { + mask_buf = draw_buf->data; + } - glyph_draw_dsc->glyph_data = lv_font_get_glyph_bitmap(glyph_draw_dsc->g, glyph_draw_dsc->_draw_buf); int32_t x = glyph_draw_dsc->letter_coords->x1 - layer->buf_area.x1; int32_t y = glyph_draw_dsc->letter_coords->y1 - layer->buf_area.y1; int32_t w = glyph_draw_dsc->g->box_w; int32_t h = glyph_draw_dsc->g->box_h; - if(raw_bitmap) { + if(glyph_draw_dsc->format <= LV_FONT_GLYPH_FORMAT_A4) { nema_bind_src_tex((uintptr_t)(mask_buf), w * h, 1, _bpp_nema_gfx_format(glyph_draw_dsc), 0, NEMA_FILTER_PS); nema_matrix3x3_t m = { @@ -172,7 +346,8 @@ static void _draw_nema_gfx_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_ nema_raster_rect(x, y, w, h); } else { - nema_bind_src_tex((uintptr_t)(mask_buf), w, h, NEMA_A8, w, NEMA_FILTER_PS); + nema_bind_src_tex((uintptr_t)(mask_buf), w, h, _bpp_nema_gfx_format(glyph_draw_dsc), -1, + NEMA_FILTER_PS); nema_blit(x, y); } } @@ -187,6 +362,15 @@ static void _draw_nema_gfx_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_ lv_draw_nema_gfx_img(draw_unit, &img_dsc, glyph_draw_dsc->letter_coords); #endif } + +#if LV_USE_FREETYPE && LV_USE_NEMA_VG + else if(glyph_draw_dsc->format == LV_FONT_GLYPH_FORMAT_VECTOR) { + if(lv_freetype_is_outline_font(glyph_draw_dsc->g->resolved_font)) { + _draw_nema_gfx_outline(draw_unit, glyph_draw_dsc); + } + } +#endif + } if(fill_draw_dsc && fill_area) { @@ -267,14 +451,16 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ pos.y += dsc->hint->y; } - uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL, - dsc->flag); + uint32_t remaining_len = dsc->text_length; + + uint32_t line_end = line_start + lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, + w, NULL, dsc->flag); /*Go the first visible line*/ while(pos.y + line_height_font < draw_unit->clip_area->y1) { /*Go to next line*/ line_start = line_end; - line_end += lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL, dsc->flag); + line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag); pos.y += line_height; /*Save at the threshold coordinate*/ @@ -289,14 +475,16 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ /*Align to middle*/ if(align == LV_TEXT_ALIGN_CENTER) { - line_width = lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space); + line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, + dsc->flag); pos.x += (lv_area_get_width(coords) - line_width) / 2; } /*Align to the right*/ else if(align == LV_TEXT_ALIGN_RIGHT) { - line_width = lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space); + line_width = lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, + dsc->flag); pos.x += lv_area_get_width(coords) - line_width; } @@ -320,49 +508,133 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ fill_dsc.opa = dsc->opa; int32_t underline_width = font->underline_thickness ? font->underline_thickness : 1; int32_t line_start_x; - uint32_t i; + uint32_t next_char_offset; + uint32_t recolor_command_start_index = 0; int32_t letter_w; + cmd_state_t recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER; + lv_color_t recolor = lv_color_black(); /* Holds the selected color inside the recolor command */ + uint8_t is_first_space_after_cmd = 0; lv_color32_t dsc_col32 = lv_color_to_32(dsc->color, dsc->opa); uint32_t nema_dsc_color = nema_rgba(dsc_col32.red, dsc_col32.green, dsc_col32.blue, dsc_col32.alpha); lv_color32_t dsc_sel_col32 = lv_color_to_32(dsc->sel_color, dsc->opa); uint32_t nema_dsc_sel_color = nema_rgba(dsc_sel_col32.red, dsc_sel_col32.green, dsc_sel_col32.blue, dsc_sel_col32.alpha); + uint32_t blend_color; + uint8_t blend_alpha = 255; _set_color_blend(nema_dsc_color, dsc_col32.alpha); - uint32_t is_dsc_color_enabled = 1U; + uint8_t cur_state = 2; + uint8_t prev_state = 2; /*Write out all lines*/ - while(dsc->text[line_start] != '\0') { + while(remaining_len && dsc->text[line_start] != '\0') { pos.x += x_ofs; line_start_x = pos.x; /*Write all letter of a line*/ - i = 0; + recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER; + next_char_offset = 0; #if LV_USE_BIDI char * bidi_txt = lv_malloc(line_end - line_start + 1); LV_ASSERT_MALLOC(bidi_txt); - _lv_bidi_process_paragraph(dsc->text + line_start, bidi_txt, line_end - line_start, base_dir, NULL, 0); + lv_bidi_process_paragraph(dsc->text + line_start, bidi_txt, line_end - line_start, base_dir, NULL, 0); #else const char * bidi_txt = dsc->text + line_start; #endif - while(i < line_end - line_start) { + while(next_char_offset < remaining_len && next_char_offset < line_end - line_start) { uint32_t logical_char_pos = 0; - if(sel_start != 0xFFFF && sel_end != 0xFFFF) { + + /* Check if the text selection is enabled */ + if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL) { #if LV_USE_BIDI logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start); - uint32_t t = lv_text_encoded_get_char_id(bidi_txt, i); - logical_char_pos += _lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, t, NULL); + uint32_t t = lv_text_encoded_get_char_id(bidi_txt, next_char_offset); + logical_char_pos += lv_bidi_get_logical_pos(bidi_txt, NULL, line_end - line_start, base_dir, t, NULL); #else - logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + i); + logical_char_pos = lv_text_encoded_get_char_id(dsc->text, line_start + next_char_offset); #endif } uint32_t letter; uint32_t letter_next; - lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &i); + lv_text_encoded_letter_next_2(bidi_txt, &letter, &letter_next, &next_char_offset); + + /* If recolor is enabled */ + if((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) { + + if(letter == (uint32_t)LV_TXT_COLOR_CMD[0]) { + /* Handle the recolor command marker depending of the current recolor state */ + + if(recolor_cmd_state == RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER) { + recolor_command_start_index = next_char_offset; + recolor_cmd_state = RECOLOR_CMD_STATE_PARAMETER; + continue; + } + /*Other start char in parameter escaped cmd. char*/ + else if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) { + recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER; + } + /* If letter is LV_TXT_COLOR_CMD and we were in the CMD_STATE_IN then the recolor close marked has been found */ + else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) { + recolor_cmd_state = RECOLOR_CMD_STATE_WAIT_FOR_PARAMETER; + continue; + } + } + + /* Find the first space (aka ' ') after the recolor command parameter, we need to skip rendering it */ + if((recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) && (letter == ' ') && (is_first_space_after_cmd == 0)) { + is_first_space_after_cmd = 1; + } + else { + is_first_space_after_cmd = 0; + } + + /* Skip the color parameter and wait the space after it + * Once we have reach the space ' ', then we will extract the color information + * and store it into the recolor variable */ + if(recolor_cmd_state == RECOLOR_CMD_STATE_PARAMETER) { + /* Not an space? Continue with the next character */ + if(letter != ' ') { + continue; + } + + /*Get the recolor parameter*/ + if((next_char_offset - recolor_command_start_index) == LABEL_RECOLOR_PAR_LENGTH + 1) { + /* Temporary buffer to hold the recolor information */ + char buf[LABEL_RECOLOR_PAR_LENGTH + 1]; + lv_memcpy(buf, &bidi_txt[recolor_command_start_index], LABEL_RECOLOR_PAR_LENGTH); + buf[LABEL_RECOLOR_PAR_LENGTH] = '\0'; + + uint8_t r, g, b; + r = (hex_char_to_num(buf[0]) << 4) + hex_char_to_num(buf[1]); + g = (hex_char_to_num(buf[2]) << 4) + hex_char_to_num(buf[3]); + b = (hex_char_to_num(buf[4]) << 4) + hex_char_to_num(buf[5]); + + recolor = lv_color_make(r, g, b); + } + else { + recolor.red = dsc->color.red; + recolor.blue = dsc->color.blue; + recolor.green = dsc->color.green; + } + + /*After the parameter the text is in the command*/ + recolor_cmd_state = RECOLOR_CMD_STATE_TEXT_INPUT; + } + + /* Don't draw the first space after the recolor command */ + if(is_first_space_after_cmd) { + continue; + } + } + + /* If we're in the CMD_STATE_IN state then we need to subtract the recolor command length */ + if(((dsc->flag & LV_TEXT_FLAG_RECOLOR) != 0) && (recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT)) { + logical_char_pos -= (LABEL_RECOLOR_PAR_LENGTH + 1); + } letter_w = lv_font_get_glyph_width(font, letter, letter_next); @@ -372,7 +644,7 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ bg_coords.x2 = pos.x + letter_w - 1; bg_coords.y2 = pos.y + line_height - 1; - if(i >= line_end - line_start) { + if(next_char_offset >= line_end - line_start) { if(dsc->decor & LV_TEXT_DECOR_UNDERLINE) { lv_area_t fill_area; fill_area.x1 = line_start_x; @@ -395,22 +667,34 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ } } - if(sel_start != 0xFFFF && sel_end != 0xFFFF && logical_char_pos >= sel_start && logical_char_pos < sel_end) { + /* Handle text selection */ + if(sel_start != LV_DRAW_LABEL_NO_TXT_SEL && sel_end != LV_DRAW_LABEL_NO_TXT_SEL + && logical_char_pos >= sel_start && logical_char_pos < sel_end) { draw_letter_dsc.color = dsc->sel_color; fill_dsc.color = dsc->sel_bg_color; lv_draw_nema_gfx_fill(draw_unit, &fill_dsc, &bg_coords); - - if(is_dsc_color_enabled) { - _set_color_blend(nema_dsc_sel_color, dsc_sel_col32.alpha); - is_dsc_color_enabled = 0U; - } + cur_state = 0 ; + blend_alpha = dsc_sel_col32.alpha; + blend_color = nema_dsc_sel_color; + } + else if(recolor_cmd_state == RECOLOR_CMD_STATE_TEXT_INPUT) { + draw_letter_dsc.color = recolor; + cur_state = 1 ; + blend_alpha = dsc_col32.alpha; + lv_color32_t dsc_recolor_col32 = lv_color_to_32(recolor, dsc->opa); + blend_color = nema_rgba(dsc_recolor_col32.red, dsc_recolor_col32.green, dsc_recolor_col32.blue, + dsc_recolor_col32.alpha); } else { draw_letter_dsc.color = dsc->color; - if(!is_dsc_color_enabled) { - _set_color_blend(nema_dsc_color, dsc_col32.alpha); - is_dsc_color_enabled = 1U; - } + cur_state = 2; + blend_alpha = dsc_col32.alpha; + blend_color = nema_dsc_color; + } + + if(cur_state != prev_state) { + _set_color_blend(blend_color, blend_alpha); + prev_state = cur_state; } _draw_letter(draw_unit, &draw_letter_dsc, &pos, font, letter); @@ -425,21 +709,24 @@ static void _draw_label_iterate_characters(lv_draw_unit_t * draw_unit, const lv_ bidi_txt = NULL; #endif /*Go to next line*/ + remaining_len -= line_end - line_start; line_start = line_end; - line_end += lv_text_get_next_line(&dsc->text[line_start], font, dsc->letter_space, w, NULL, dsc->flag); + if(remaining_len) { + line_end += lv_text_get_next_line(&dsc->text[line_start], remaining_len, font, dsc->letter_space, w, NULL, dsc->flag); + } pos.x = coords->x1; /*Align to middle*/ if(align == LV_TEXT_ALIGN_CENTER) { line_width = - lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space); + lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += (lv_area_get_width(coords) - line_width) / 2; } /*Align to the right*/ else if(align == LV_TEXT_ALIGN_RIGHT) { line_width = - lv_text_get_width(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space); + lv_text_get_width_with_flags(&dsc->text[line_start], line_end - line_start, font, dsc->letter_space, dsc->flag); pos.x += lv_area_get_width(coords) - line_width; } @@ -462,7 +749,7 @@ static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, if(lv_text_is_marker(letter)) /*Markers are valid letters but should not be rendered.*/ return; - LV_PROFILER_BEGIN; + LV_PROFILER_DRAW_BEGIN; bool g_ret = lv_font_get_glyph_dsc(font, &g, letter, '\0'); if(g_ret == false) { /*Add warning if the dsc is not found*/ @@ -471,7 +758,7 @@ static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, /*Don't draw anything if the character is empty. E.g. space*/ if((g.box_h == 0) || (g.box_w == 0)) { - LV_PROFILER_END; + LV_PROFILER_DRAW_END; return; } @@ -484,7 +771,7 @@ static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, /*If the letter is completely out of mask don't draw it*/ if(lv_area_is_out(&letter_coords, draw_unit->clip_area, 0) && lv_area_is_out(dsc->bg_coords, draw_unit->clip_area, 0)) { - LV_PROFILER_END; + LV_PROFILER_DRAW_END; return; } @@ -498,45 +785,24 @@ static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, uint32_t h = g.box_h; if(h * g.box_w < 64) h *= 2; /*Alloc a slightly larger buffer*/ - draw_buf = lv_draw_buf_create(g.box_w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO); + draw_buf = lv_draw_buf_create_ex(font_draw_buf_handlers, g.box_w, h, LV_COLOR_FORMAT_A8, LV_STRIDE_AUTO); LV_ASSERT_MALLOC(draw_buf); draw_buf->header.h = g.box_h; dsc->_draw_buf = draw_buf; } } - raw_bitmap = false; - /* Performance Optimization for lv_font_fmt_txt_dsc_t fonts */ + + /* Performance Optimization for lv_font_fmt_txt_dsc_t fonts, always request raw bitmaps */ + g.req_raw_bitmap = 1; + is_raw_bitmap = false; if(font->get_glyph_bitmap == lv_font_get_bitmap_fmt_txt) { lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc; if(fdsc->bitmap_format == LV_FONT_FMT_TXT_PLAIN) { - const lv_font_t * font_p = g.resolved_font; - LV_ASSERT_NULL(font_p); - - if(letter == '\t') letter = ' '; - - lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc; - uint32_t gid = get_glyph_dsc_id(font, letter); - if(!gid) dsc->glyph_data = NULL; - - const lv_font_fmt_txt_glyph_dsc_t * gdsc = &fdsc->glyph_dsc[gid]; - - int32_t gsize = (int32_t) gdsc->box_w * gdsc->box_h; - if(gsize == 0) dsc->glyph_data = NULL; - /*NemaGFX can handle A1, A2, A4 and A8 formats, no need to allocate A8 buffers. - We will use the original font bitmap, by rewriting the data in draw_buf - */ - if(draw_buf != NULL) { - const uint8_t * bitmap_in = &fdsc->glyph_bitmap[gdsc->bitmap_index]; - draw_buf->data = (uint8_t *) bitmap_in; - } - dsc->glyph_data = (void *)draw_buf; - raw_bitmap = true; + is_raw_bitmap = true; } } - if(!raw_bitmap) { - dsc->glyph_data = (void *)lv_font_get_glyph_bitmap(&g, draw_buf); - } + dsc->glyph_data = (void *)lv_font_get_glyph_bitmap(&g, draw_buf); dsc->format = dsc->glyph_data ? g.format : LV_FONT_GLYPH_FORMAT_NONE; } @@ -548,62 +814,9 @@ static void _draw_letter(lv_draw_unit_t * draw_unit, lv_draw_glyph_dsc_t * dsc, dsc->g = &g; _draw_nema_gfx_letter(draw_unit, dsc, NULL, NULL); - if(g.resolved_font && font->release_glyph) { - lv_draw_nema_gfx_unit_t * draw_nema_gfx_unit = (lv_draw_nema_gfx_unit_t *)draw_unit; - nema_cl_submit(&(draw_nema_gfx_unit->cl)); - nema_cl_wait(&(draw_nema_gfx_unit->cl)); - font->release_glyph(font, &g); - } - LV_PROFILER_END; + lv_font_glyph_release_draw_data(&g); + + LV_PROFILER_DRAW_END; } -static uint32_t get_glyph_dsc_id(const lv_font_t * font, uint32_t letter) -{ - if(letter == '\0') return 0; - - lv_font_fmt_txt_dsc_t * fdsc = (lv_font_fmt_txt_dsc_t *)font->dsc; - - uint16_t i; - for(i = 0; i < fdsc->cmap_num; i++) { - - /*Relative code point*/ - uint32_t rcp = letter - fdsc->cmaps[i].range_start; - if(rcp >= fdsc->cmaps[i].range_length) continue; - uint32_t glyph_id = 0; - if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_TINY) { - glyph_id = fdsc->cmaps[i].glyph_id_start + rcp; - } - else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_FORMAT0_FULL) { - const uint8_t * gid_ofs_8 = fdsc->cmaps[i].glyph_id_ofs_list; - glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_8[rcp]; - } - else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_TINY) { - uint16_t key = rcp; - uint16_t * p = lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, - sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare); - - if(p) { - lv_uintptr_t ofs = p - fdsc->cmaps[i].unicode_list; - glyph_id = fdsc->cmaps[i].glyph_id_start + ofs; - } - } - else if(fdsc->cmaps[i].type == LV_FONT_FMT_TXT_CMAP_SPARSE_FULL) { - uint16_t key = rcp; - uint16_t * p = lv_utils_bsearch(&key, fdsc->cmaps[i].unicode_list, fdsc->cmaps[i].list_length, - sizeof(fdsc->cmaps[i].unicode_list[0]), unicode_list_compare); - - if(p) { - lv_uintptr_t ofs = p - fdsc->cmaps[i].unicode_list; - const uint16_t * gid_ofs_16 = fdsc->cmaps[i].glyph_id_ofs_list; - glyph_id = fdsc->cmaps[i].glyph_id_start + gid_ofs_16[ofs]; - } - } - - return glyph_id; - } - - return 0; - -} - -#endif /*LV_USE_NEMA_GFX*/ +#endif /*LV_USE_NEMA_GFX*/ \ No newline at end of file diff --git a/src/draw/nema_gfx/lv_nema_gfx_path.c b/src/draw/nema_gfx/lv_nema_gfx_path.c new file mode 100644 index 000000000..55a774b24 --- /dev/null +++ b/src/draw/nema_gfx/lv_nema_gfx_path.c @@ -0,0 +1,159 @@ +/** + * MIT License + * + * ----------------------------------------------------------------------------- + * Copyright (c) 2008-24 Think Silicon Single Member PC + * ----------------------------------------------------------------------------- + * + * 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 (including the next paragraph) + * 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. + * + */ + +/** + * @file lv_nema_gfx_path.c + * + */ + +/********************* + * INCLUDES + *********************/ +#include "../../core/lv_refr.h" + +#if LV_USE_NEMA_GFX +#if LV_USE_NEMA_VG + +#include "lv_nema_gfx_path.h" + +/********************** + * GLOBAL FUNCTIONS + **********************/ + +static int data_point = 0; +static int seg_point = 0; + +lv_nema_gfx_path_t * lv_nema_gfx_path_create(void) +{ + LV_PROFILER_DRAW_BEGIN; + lv_nema_gfx_path_t * nema_gfx_path = lv_malloc_zeroed(sizeof(lv_nema_gfx_path_t)); + LV_ASSERT_MALLOC(nema_gfx_path); + nema_gfx_path->seg = NULL; + nema_gfx_path->data = NULL; + nema_gfx_path->seg_size = 0; + nema_gfx_path->data_size = 0; + data_point = 0; + seg_point = 0; + LV_PROFILER_DRAW_END; + return nema_gfx_path; +} + +void lv_nema_gfx_path_alloc(lv_nema_gfx_path_t * nema_gfx_path) +{ + LV_PROFILER_DRAW_BEGIN; + nema_gfx_path->path = nema_vg_path_create(); + nema_gfx_path->paint = nema_vg_paint_create(); + nema_gfx_path->data = (float *) lv_malloc(nema_gfx_path->data_size * sizeof(float)); + LV_ASSERT_MALLOC(nema_gfx_path->data); + nema_gfx_path->seg = (uint8_t *) lv_malloc(nema_gfx_path->seg_size * sizeof(uint8_t)); + LV_ASSERT_MALLOC(nema_gfx_path->seg); + LV_PROFILER_DRAW_END; +} + +void lv_nema_gfx_path_destroy(lv_nema_gfx_path_t * nema_gfx_path) +{ + LV_PROFILER_DRAW_BEGIN; + LV_ASSERT_NULL(nema_gfx_path); + + if(nema_gfx_path->path != NULL) { + nema_vg_path_destroy(nema_gfx_path->path); + nema_gfx_path->path = NULL; + } + + if(nema_gfx_path->paint != NULL) { + nema_vg_paint_destroy(nema_gfx_path->paint); + nema_gfx_path->paint = NULL; + } + + if(nema_gfx_path->data != NULL) { + lv_free(nema_gfx_path->data); + nema_gfx_path->data = NULL; + } + if(nema_gfx_path->seg != NULL) { + lv_free(nema_gfx_path->seg); + nema_gfx_path->seg = NULL; + } + lv_free(nema_gfx_path); + LV_PROFILER_DRAW_END; +} + +void lv_nema_gfx_path_move_to(lv_nema_gfx_path_t * path, float x, float y) +{ + LV_ASSERT_NULL(path); + LV_ASSERT(path->data_size > data_point + 1); + LV_ASSERT(path->seg_size > seg_point); + path->seg[seg_point++] = NEMA_VG_PRIM_MOVE; + path->data[data_point++] = x; + path->data[data_point++] = y; +} + +void lv_nema_gfx_path_line_to(lv_nema_gfx_path_t * path, float x, float y) +{ + LV_ASSERT_NULL(path); + LV_ASSERT(path->data_size > data_point + 1); + LV_ASSERT(path->seg_size > seg_point); + path->seg[seg_point++] = NEMA_VG_PRIM_LINE; + path->data[data_point++] = x; + path->data[data_point++] = y; + +} + +void lv_nema_gfx_path_quad_to(lv_nema_gfx_path_t * path, float cx, float cy, float x, float y) +{ + LV_ASSERT_NULL(path); + LV_ASSERT(path->data_size > data_point + 3); + LV_ASSERT(path->seg_size > seg_point); + path->seg[seg_point++] = NEMA_VG_PRIM_BEZIER_QUAD; + path->data[data_point++] = cx; + path->data[data_point++] = cy; + path->data[data_point++] = x; + path->data[data_point++] = y; +} + +void lv_nema_gfx_path_cubic_to(lv_nema_gfx_path_t * path, float cx1, float cy1, float cx2, float cy2, float x, float y) +{ + LV_ASSERT_NULL(path); + LV_ASSERT(path->data_size > data_point + 5); + LV_ASSERT(path->seg_size > seg_point); + path->seg[seg_point++] = NEMA_VG_PRIM_BEZIER_CUBIC; + path->data[data_point++] = cx1; + path->data[data_point++] = cy1; + path->data[data_point++] = cx2; + path->data[data_point++] = cy2; + path->data[data_point++] = x; + path->data[data_point++] = y; +} + +void lv_nema_gfx_path_end(lv_nema_gfx_path_t * path) +{ + /* Do Path end jobs....whatever*/ + seg_point = 0; + data_point = 0; + +} + +#endif /*LV_USE_NEMA_VG*/ +#endif /*LV_USE_NEMA_GFX*/ diff --git a/src/draw/nema_gfx/lv_nema_gfx_path.h b/src/draw/nema_gfx/lv_nema_gfx_path.h new file mode 100644 index 000000000..0ff811833 --- /dev/null +++ b/src/draw/nema_gfx/lv_nema_gfx_path.h @@ -0,0 +1,97 @@ +/** + * MIT License + * + * ----------------------------------------------------------------------------- + * Copyright (c) 2008-24 Think Silicon Single Member PC + * ----------------------------------------------------------------------------- + * + * 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 (including the next paragraph) + * 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. + * + */ + +/** + * @file lv_nema_gfx_path.h + * + */ + +#ifndef LV_NEMA_GFX_PATH_H +#define LV_NEMA_GFX_PATH_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************* + * INCLUDES + *********************/ + +#include "lv_draw_nema_gfx.h" + +#if LV_USE_NEMA_GFX +#if LV_USE_NEMA_VG + +/********************** + * TYPEDEFS + **********************/ + +typedef struct { + NEMA_VG_PATH_HANDLE path; + NEMA_VG_PAINT_HANDLE paint; + float * data; + uint8_t * seg; + uint32_t data_size; + uint32_t seg_size; +} lv_nema_gfx_path_t; + +/********************** + * GLOBAL PROTOTYPES + **********************/ + +lv_nema_gfx_path_t * lv_nema_gfx_path_create(void); + +void lv_nema_gfx_path_alloc(lv_nema_gfx_path_t * nema_gfx_path); + +void lv_nema_gfx_path_destroy(lv_nema_gfx_path_t * nema_gfx_path); + +void lv_nema_gfx_path_move_to(lv_nema_gfx_path_t * nema_gfx_path, + float x, float y); + +void lv_nema_gfx_path_line_to(lv_nema_gfx_path_t * nema_gfx_path, + float x, float y); + +void lv_nema_gfx_path_quad_to(lv_nema_gfx_path_t * nema_gfx_path, + float cx, float cy, + float x, float y); + +void lv_nema_gfx_path_cubic_to(lv_nema_gfx_path_t * nema_gfx_path, + float cx1, float cy1, + float cx2, float cy2, + float x, float y); + +void lv_nema_gfx_path_end(lv_nema_gfx_path_t * nema_gfx_path); + + + +#endif /*LV_USE_NEMA_VG*/ +#endif /*LV_USE_NEMA_GFX*/ + +#ifdef __cplusplus +} /*extern "C"*/ +#endif + +#endif /*LV_NEMA_GFX_PATH_H*/ diff --git a/src/libs/freetype/lv_freetype_outline.c b/src/libs/freetype/lv_freetype_outline.c index e5bd2ce76..d5091dbb1 100755 --- a/src/libs/freetype/lv_freetype_outline.c +++ b/src/libs/freetype/lv_freetype_outline.c @@ -331,10 +331,48 @@ static lv_freetype_outline_t outline_create( } } + FT_Outline_Funcs outline_funcs = { + .move_to = outline_move_to_cb, + .line_to = outline_line_to_cb, + .conic_to = outline_conic_to_cb, + .cubic_to = outline_cubic_to_cb, + .shift = 0, + .delta = 0 + }; + + lv_result_t res; lv_freetype_outline_event_param_t param; - lv_memzero(¶m, sizeof(param)); + + /*Calculate Total Segmenets Before decompose */ + int32_t tag_size = face->glyph->outline.n_points; + int32_t segments = 0; + int32_t vectors = 0; + + for(int j = 0; j < tag_size; j++) { + if((face->glyph->outline.tags[j] & 0x1) == 0x1) { + segments++; + vectors++; + } + else { + int jj = j + 1 < tag_size ? j + 1 : 0; + if(face->glyph->outline.tags[jj] & 0x1) { + vectors++; + } + else { + segments++; + vectors += 2; + } + } + } + /*Also for every contour we may have a line for close*/ + segments += face->glyph->outline.n_contours; + vectors += face->glyph->outline.n_contours; + + param.sizes.data_size = vectors * 2; + param.sizes.segments_size = segments; + res = outline_send_event(ctx, LV_EVENT_CREATE, ¶m); lv_freetype_outline_t outline = param.outline; @@ -345,15 +383,6 @@ static lv_freetype_outline_t outline_create( return NULL; } - FT_Outline_Funcs outline_funcs = { - .move_to = outline_move_to_cb, - .line_to = outline_line_to_cb, - .conic_to = outline_conic_to_cb, - .cubic_to = outline_cubic_to_cb, - .shift = 0, - .delta = 0 - }; - /* Run outline decompose again to fill outline data */ error = FT_Outline_Decompose(&face->glyph->outline, &outline_funcs, outline); if(error) { diff --git a/src/libs/freetype/lv_freetype_private.h b/src/libs/freetype/lv_freetype_private.h index 86c870258..bb832d04c 100755 --- a/src/libs/freetype/lv_freetype_private.h +++ b/src/libs/freetype/lv_freetype_private.h @@ -65,12 +65,18 @@ struct _lv_freetype_outline_vector_t { int32_t y; }; +typedef struct { + int32_t segments_size; + int32_t data_size; +} lv_freetype_outline_sizes_t; + struct _lv_freetype_outline_event_param_t { lv_freetype_outline_t outline; lv_freetype_outline_type_t type; lv_freetype_outline_vector_t to; lv_freetype_outline_vector_t control1; lv_freetype_outline_vector_t control2; + lv_freetype_outline_sizes_t sizes; }; diff --git a/tests/src/test_cases/libs/test_freetype.c b/tests/src/test_cases/libs/test_freetype.c index c3396ce92..bd8da167d 100644 --- a/tests/src/test_cases/libs/test_freetype.c +++ b/tests/src/test_cases/libs/test_freetype.c @@ -29,359 +29,359 @@ static const char * UNIVERSAL_DECLARATION_OF_HUMAN_RIGHTS_JP = // Outline data for unicode '龘' (U+9F98) static const lv_freetype_outline_event_param_t outline_data_U9F98[] = { - {NULL, 1, {5888, 6889}, {0, 0}, {0, 0}}, - {NULL, 2, {6445, 6889}, {0, 0}, {0, 0}}, - {NULL, 2, {6238, 5915}, {0, 0}, {0, 0}}, - {NULL, 2, {5681, 5915}, {0, 0}, {0, 0}}, - {NULL, 2, {5888, 6889}, {0, 0}, {0, 0}}, - {NULL, 1, {2069, 5145}, {0, 0}, {0, 0}}, - {NULL, 2, {4576, 5145}, {0, 0}, {0, 0}}, - {NULL, 2, {4508, 4825}, {0, 0}, {0, 0}}, - {NULL, 2, {2525, 4825}, {0, 0}, {0, 0}}, - {NULL, 2, {2178, 3195}, {0, 0}, {0, 0}}, - {NULL, 2, {1654, 3195}, {0, 0}, {0, 0}}, - {NULL, 2, {2069, 5145}, {0, 0}, {0, 0}}, - {NULL, 1, {5714, 6070}, {0, 0}, {0, 0}}, - {NULL, 2, {8573, 6070}, {0, 0}, {0, 0}}, - {NULL, 2, {8401, 5259}, {0, 0}, {0, 0}}, - {NULL, 2, {5542, 5259}, {0, 0}, {0, 0}}, - {NULL, 2, {5606, 5562}, {0, 0}, {0, 0}}, - {NULL, 2, {7916, 5562}, {0, 0}, {0, 0}}, - {NULL, 2, {7962, 5775}, {0, 0}, {0, 0}}, - {NULL, 2, {5652, 5775}, {0, 0}, {0, 0}}, - {NULL, 2, {5714, 6070}, {0, 0}, {0, 0}}, - {NULL, 1, {5580, 5439}, {0, 0}, {0, 0}}, - {NULL, 2, {6137, 5439}, {0, 0}, {0, 0}}, - {NULL, 2, {5786, 3785}, {0, 0}, {0, 0}}, - {NULL, 4, {5832, 3600}, {5756, 3645}, {0, 0}}, - {NULL, 4, {6195, 3555}, {5909, 3555}, {0, 0}}, - {NULL, 4, {6461, 3555}, {6261, 3555}, {0, 0}}, - {NULL, 4, {6904, 3555}, {6662, 3555}, {0, 0}}, - {NULL, 4, {7359, 3555}, {7146, 3555}, {0, 0}}, - {NULL, 4, {7670, 3555}, {7572, 3555}, {0, 0}}, - {NULL, 4, {7880, 3579}, {7801, 3555}, {0, 0}}, - {NULL, 4, {8010, 3690}, {7959, 3604}, {0, 0}}, - {NULL, 4, {8107, 3957}, {8061, 3777}, {0, 0}}, - {NULL, 4, {8305, 3887}, {8188, 3916}, {0, 0}}, - {NULL, 4, {8526, 3842}, {8422, 3858}, {0, 0}}, - {NULL, 4, {8238, 3359}, {8416, 3482}, {0, 0}}, - {NULL, 4, {7668, 3236}, {8061, 3236}, {0, 0}}, - {NULL, 4, {7446, 3236}, {7610, 3236}, {0, 0}}, - {NULL, 4, {7074, 3236}, {7283, 3236}, {0, 0}}, - {NULL, 4, {6656, 3236}, {6865, 3236}, {0, 0}}, - {NULL, 4, {6287, 3236}, {6447, 3236}, {0, 0}}, - {NULL, 4, {6078, 3236}, {6127, 3236}, {0, 0}}, - {NULL, 4, {5345, 3334}, {5538, 3236}, {0, 0}}, - {NULL, 4, {5230, 3793}, {5153, 3432}, {0, 0}}, - {NULL, 2, {5580, 5439}, {0, 0}, {0, 0}}, - {NULL, 1, {4305, 6185}, {0, 0}, {0, 0}}, - {NULL, 2, {4756, 6038}, {0, 0}, {0, 0}}, - {NULL, 4, {4494, 5726}, {4616, 5874}, {0, 0}}, - {NULL, 4, {4258, 5464}, {4373, 5579}, {0, 0}}, - {NULL, 2, {3901, 5595}, {0, 0}, {0, 0}}, - {NULL, 4, {4120, 5894}, {4002, 5726}, {0, 0}}, - {NULL, 4, {4305, 6185}, {4238, 6062}, {0, 0}}, - {NULL, 1, {2506, 6046}, {0, 0}, {0, 0}}, - {NULL, 2, {2941, 6169}, {0, 0}, {0, 0}}, - {NULL, 4, {3051, 5894}, {3014, 6046}, {0, 0}}, - {NULL, 4, {3088, 5628}, {3089, 5743}, {0, 0}}, - {NULL, 2, {2610, 5497}, {0, 0}, {0, 0}}, - {NULL, 4, {2584, 5763}, {2616, 5603}, {0, 0}}, - {NULL, 4, {2506, 6046}, {2553, 5923}, {0, 0}}, - {NULL, 1, {4322, 5145}, {0, 0}, {0, 0}}, - {NULL, 2, {4846, 5145}, {0, 0}, {0, 0}}, - {NULL, 2, {4515, 3588}, {0, 0}, {0, 0}}, - {NULL, 4, {4421, 3362}, {4481, 3432}, {0, 0}}, - {NULL, 4, {4238, 3252}, {4362, 3293}, {0, 0}}, - {NULL, 4, {3912, 3203}, {4115, 3211}, {0, 0}}, - {NULL, 4, {3423, 3195}, {3710, 3195}, {0, 0}}, - {NULL, 4, {3409, 3359}, {3433, 3277}, {0, 0}}, - {NULL, 4, {3358, 3506}, {3385, 3441}, {0, 0}}, - {NULL, 4, {3677, 3506}, {3530, 3506}, {0, 0}}, - {NULL, 4, {3874, 3506}, {3825, 3506}, {0, 0}}, - {NULL, 4, {3956, 3522}, {3932, 3506}, {0, 0}}, - {NULL, 4, {3991, 3588}, {3980, 3539}, {0, 0}}, - {NULL, 2, {4322, 5145}, {0, 0}, {0, 0}}, - {NULL, 1, {6071, 6595}, {0, 0}, {0, 0}}, - {NULL, 2, {8988, 6595}, {0, 0}, {0, 0}}, - {NULL, 2, {8923, 6291}, {0, 0}, {0, 0}}, - {NULL, 2, {6006, 6291}, {0, 0}, {0, 0}}, - {NULL, 2, {6071, 6595}, {0, 0}, {0, 0}}, - {NULL, 1, {5732, 5038}, {0, 0}, {0, 0}}, - {NULL, 2, {8190, 5038}, {0, 0}, {0, 0}}, - {NULL, 2, {8132, 4768}, {0, 0}, {0, 0}}, - {NULL, 2, {5674, 4768}, {0, 0}, {0, 0}}, - {NULL, 2, {5732, 5038}, {0, 0}, {0, 0}}, - {NULL, 1, {5646, 4555}, {0, 0}, {0, 0}}, - {NULL, 2, {8046, 4555}, {0, 0}, {0, 0}}, - {NULL, 2, {7987, 4276}, {0, 0}, {0, 0}}, - {NULL, 2, {5587, 4276}, {0, 0}, {0, 0}}, - {NULL, 2, {5646, 4555}, {0, 0}, {0, 0}}, - {NULL, 1, {5523, 4055}, {0, 0}, {0, 0}}, - {NULL, 2, {8046, 4055}, {0, 0}, {0, 0}}, - {NULL, 2, {7989, 3785}, {0, 0}, {0, 0}}, - {NULL, 2, {5466, 3785}, {0, 0}, {0, 0}}, - {NULL, 2, {5523, 4055}, {0, 0}, {0, 0}}, - {NULL, 1, {2081, 4047}, {0, 0}, {0, 0}}, - {NULL, 2, {4350, 4047}, {0, 0}, {0, 0}}, - {NULL, 2, {4288, 3752}, {0, 0}, {0, 0}}, - {NULL, 2, {2019, 3752}, {0, 0}, {0, 0}}, - {NULL, 2, {2081, 4047}, {0, 0}, {0, 0}}, - {NULL, 1, {2196, 4588}, {0, 0}, {0, 0}}, - {NULL, 2, {4465, 4588}, {0, 0}, {0, 0}}, - {NULL, 2, {4402, 4293}, {0, 0}, {0, 0}}, - {NULL, 2, {2133, 4293}, {0, 0}, {0, 0}}, - {NULL, 2, {2196, 4588}, {0, 0}, {0, 0}}, - {NULL, 1, {2066, 6447}, {0, 0}, {0, 0}}, - {NULL, 2, {5351, 6447}, {0, 0}, {0, 0}}, - {NULL, 2, {5284, 6128}, {0, 0}, {0, 0}}, - {NULL, 2, {1999, 6128}, {0, 0}, {0, 0}}, - {NULL, 2, {2066, 6447}, {0, 0}, {0, 0}}, - {NULL, 1, {1689, 5710}, {0, 0}, {0, 0}}, - {NULL, 2, {5433, 5710}, {0, 0}, {0, 0}}, - {NULL, 2, {5365, 5390}, {0, 0}, {0, 0}}, - {NULL, 2, {1621, 5390}, {0, 0}, {0, 0}}, - {NULL, 2, {1689, 5710}, {0, 0}, {0, 0}}, - {NULL, 1, {3383, 6824}, {0, 0}, {0, 0}}, - {NULL, 2, {3903, 6914}, {0, 0}, {0, 0}}, - {NULL, 4, {4030, 6607}, {3973, 6783}, {0, 0}}, - {NULL, 4, {4110, 6308}, {4087, 6431}, {0, 0}}, - {NULL, 2, {3568, 6185}, {0, 0}, {0, 0}}, - {NULL, 4, {3507, 6500}, {3554, 6316}, {0, 0}}, - {NULL, 4, {3383, 6824}, {3461, 6685}, {0, 0}}, - {NULL, 1, {3008, 3129}, {0, 0}, {0, 0}}, - {NULL, 2, {3377, 3129}, {0, 0}, {0, 0}}, - {NULL, 2, {3168, 2146}, {0, 0}, {0, 0}}, - {NULL, 2, {2799, 2146}, {0, 0}, {0, 0}}, - {NULL, 2, {3008, 3129}, {0, 0}, {0, 0}}, - {NULL, 1, {860, 1425}, {0, 0}, {0, 0}}, - {NULL, 2, {2163, 1425}, {0, 0}, {0, 0}}, - {NULL, 2, {2095, 1106}, {0, 0}, {0, 0}}, - {NULL, 2, {1136, 1106}, {0, 0}, {0, 0}}, - {NULL, 2, {776, -590}, {0, 0}, {0, 0}}, - {NULL, 2, {432, -590}, {0, 0}, {0, 0}}, - {NULL, 2, {860, 1425}, {0, 0}, {0, 0}}, - {NULL, 1, {2834, 2310}, {0, 0}, {0, 0}}, - {NULL, 2, {4317, 2310}, {0, 0}, {0, 0}}, - {NULL, 2, {4143, 1491}, {0, 0}, {0, 0}}, - {NULL, 2, {2660, 1491}, {0, 0}, {0, 0}}, - {NULL, 2, {2723, 1786}, {0, 0}, {0, 0}}, - {NULL, 2, {3853, 1786}, {0, 0}, {0, 0}}, - {NULL, 2, {3901, 2015}, {0, 0}, {0, 0}}, - {NULL, 2, {2771, 2015}, {0, 0}, {0, 0}}, - {NULL, 2, {2834, 2310}, {0, 0}, {0, 0}}, - {NULL, 1, {2703, 1696}, {0, 0}, {0, 0}}, - {NULL, 2, {3063, 1696}, {0, 0}, {0, 0}}, - {NULL, 2, {2698, -25}, {0, 0}, {0, 0}}, - {NULL, 4, {2705, -184}, {2672, -147}, {0, 0}}, - {NULL, 4, {2869, -221}, {2738, -221}, {0, 0}}, - {NULL, 4, {3045, -221}, {2919, -221}, {0, 0}}, - {NULL, 4, {3311, -221}, {3172, -221}, {0, 0}}, - {NULL, 4, {3500, -221}, {3451, -221}, {0, 0}}, - {NULL, 4, {3659, -147}, {3607, -221}, {0, 0}}, - {NULL, 4, {3776, 188}, {3711, -74}, {0, 0}}, - {NULL, 4, {3899, 114}, {3824, 147}, {0, 0}}, - {NULL, 4, {4044, 66}, {3974, 82}, {0, 0}}, - {NULL, 4, {3826, -418}, {3951, -295}, {0, 0}}, - {NULL, 4, {3473, -541}, {3702, -541}, {0, 0}}, - {NULL, 4, {3346, -541}, {3449, -541}, {0, 0}}, - {NULL, 4, {3121, -541}, {3244, -541}, {0, 0}}, - {NULL, 4, {2899, -541}, {2998, -541}, {0, 0}}, - {NULL, 4, {2769, -541}, {2801, -541}, {0, 0}}, - {NULL, 4, {2366, -446}, {2465, -541}, {0, 0}}, - {NULL, 4, {2338, -25}, {2268, -352}, {0, 0}}, - {NULL, 2, {2703, 1696}, {0, 0}, {0, 0}}, - {NULL, 1, {2189, 2474}, {0, 0}, {0, 0}}, - {NULL, 2, {2462, 2335}, {0, 0}, {0, 0}}, - {NULL, 4, {2225, 2031}, {2337, 2171}, {0, 0}}, - {NULL, 4, {2019, 1794}, {2114, 1892}, {0, 0}}, - {NULL, 2, {1800, 1917}, {0, 0}, {0, 0}}, - {NULL, 4, {2003, 2199}, {1892, 2040}, {0, 0}}, - {NULL, 4, {2189, 2474}, {2115, 2359}, {0, 0}}, - {NULL, 1, {1134, 2367}, {0, 0}, {0, 0}}, - {NULL, 2, {1451, 2433}, {0, 0}, {0, 0}}, - {NULL, 4, {1517, 2166}, {1492, 2318}, {0, 0}}, - {NULL, 4, {1543, 1901}, {1542, 2015}, {0, 0}}, - {NULL, 2, {1204, 1810}, {0, 0}, {0, 0}}, - {NULL, 4, {1196, 2080}, {1212, 1925}, {0, 0}}, - {NULL, 4, {1134, 2367}, {1180, 2236}, {0, 0}}, - {NULL, 1, {2015, 1425}, {0, 0}, {0, 0}}, - {NULL, 2, {2367, 1425}, {0, 0}, {0, 0}}, - {NULL, 2, {2022, -197}, {0, 0}, {0, 0}}, - {NULL, 4, {1941, -426}, {1989, -352}, {0, 0}}, - {NULL, 4, {1794, -541}, {1893, -500}, {0, 0}}, - {NULL, 4, {1551, -586}, {1703, -582}, {0, 0}}, - {NULL, 4, {1169, -590}, {1399, -590}, {0, 0}}, - {NULL, 4, {1166, -430}, {1176, -516}, {0, 0}}, - {NULL, 4, {1139, -270}, {1156, -344}, {0, 0}}, - {NULL, 4, {1415, -279}, {1293, -279}, {0, 0}}, - {NULL, 4, {1579, -279}, {1538, -279}, {0, 0}}, - {NULL, 4, {1670, -197}, {1653, -279}, {0, 0}}, - {NULL, 2, {2015, 1425}, {0, 0}, {0, 0}}, - {NULL, 1, {3108, 2826}, {0, 0}, {0, 0}}, - {NULL, 2, {4492, 2826}, {0, 0}, {0, 0}}, - {NULL, 2, {4429, 2531}, {0, 0}, {0, 0}}, - {NULL, 2, {3045, 2531}, {0, 0}, {0, 0}}, - {NULL, 2, {3108, 2826}, {0, 0}, {0, 0}}, - {NULL, 1, {2779, 1278}, {0, 0}, {0, 0}}, - {NULL, 2, {4016, 1278}, {0, 0}, {0, 0}}, - {NULL, 2, {3958, 1008}, {0, 0}, {0, 0}}, - {NULL, 2, {2721, 1008}, {0, 0}, {0, 0}}, - {NULL, 2, {2779, 1278}, {0, 0}, {0, 0}}, - {NULL, 1, {2674, 786}, {0, 0}, {0, 0}}, - {NULL, 2, {3919, 786}, {0, 0}, {0, 0}}, - {NULL, 2, {3862, 516}, {0, 0}, {0, 0}}, - {NULL, 2, {2617, 516}, {0, 0}, {0, 0}}, - {NULL, 2, {2674, 786}, {0, 0}, {0, 0}}, - {NULL, 1, {2570, 295}, {0, 0}, {0, 0}}, - {NULL, 2, {3692, 295}, {0, 0}, {0, 0}}, - {NULL, 2, {3632, 16}, {0, 0}, {0, 0}}, - {NULL, 2, {2510, 16}, {0, 0}, {0, 0}}, - {NULL, 2, {2570, 295}, {0, 0}, {0, 0}}, - {NULL, 1, {791, 328}, {0, 0}, {0, 0}}, - {NULL, 2, {1946, 328}, {0, 0}, {0, 0}}, - {NULL, 2, {1883, 33}, {0, 0}, {0, 0}}, - {NULL, 2, {728, 33}, {0, 0}, {0, 0}}, - {NULL, 2, {791, 328}, {0, 0}, {0, 0}}, - {NULL, 1, {905, 868}, {0, 0}, {0, 0}}, - {NULL, 2, {2060, 868}, {0, 0}, {0, 0}}, - {NULL, 2, {1998, 573}, {0, 0}, {0, 0}}, - {NULL, 2, {843, 573}, {0, 0}, {0, 0}}, - {NULL, 2, {905, 868}, {0, 0}, {0, 0}}, - {NULL, 1, {1016, 2736}, {0, 0}, {0, 0}}, - {NULL, 2, {2769, 2736}, {0, 0}, {0, 0}}, - {NULL, 2, {2701, 2417}, {0, 0}, {0, 0}}, - {NULL, 2, {948, 2417}, {0, 0}, {0, 0}}, - {NULL, 2, {1016, 2736}, {0, 0}, {0, 0}}, - {NULL, 1, {739, 1974}, {0, 0}, {0, 0}}, - {NULL, 2, {2640, 1974}, {0, 0}, {0, 0}}, - {NULL, 2, {2570, 1647}, {0, 0}, {0, 0}}, - {NULL, 2, {669, 1647}, {0, 0}, {0, 0}}, - {NULL, 2, {739, 1974}, {0, 0}, {0, 0}}, - {NULL, 1, {1666, 3056}, {0, 0}, {0, 0}}, - {NULL, 2, {2019, 3138}, {0, 0}, {0, 0}}, - {NULL, 4, {2100, 2887}, {2069, 3031}, {0, 0}}, - {NULL, 4, {2142, 2638}, {2131, 2744}, {0, 0}}, - {NULL, 2, {1756, 2515}, {0, 0}, {0, 0}}, - {NULL, 4, {1729, 2777}, {1755, 2630}, {0, 0}}, - {NULL, 4, {1666, 3056}, {1703, 2925}, {0, 0}}, - {NULL, 1, {6779, 3105}, {0, 0}, {0, 0}}, - {NULL, 2, {7156, 3105}, {0, 0}, {0, 0}}, - {NULL, 2, {6949, 2130}, {0, 0}, {0, 0}}, - {NULL, 2, {6572, 2130}, {0, 0}, {0, 0}}, - {NULL, 2, {6779, 3105}, {0, 0}, {0, 0}}, - {NULL, 1, {4558, 1401}, {0, 0}, {0, 0}}, - {NULL, 2, {5901, 1401}, {0, 0}, {0, 0}}, - {NULL, 2, {5833, 1081}, {0, 0}, {0, 0}}, - {NULL, 2, {4842, 1081}, {0, 0}, {0, 0}}, - {NULL, 2, {4481, -614}, {0, 0}, {0, 0}}, - {NULL, 2, {4129, -614}, {0, 0}, {0, 0}}, - {NULL, 2, {4558, 1401}, {0, 0}, {0, 0}}, - {NULL, 1, {6605, 2286}, {0, 0}, {0, 0}}, - {NULL, 2, {8146, 2286}, {0, 0}, {0, 0}}, - {NULL, 2, {7974, 1475}, {0, 0}, {0, 0}}, - {NULL, 2, {6433, 1475}, {0, 0}, {0, 0}}, - {NULL, 2, {6495, 1769}, {0, 0}, {0, 0}}, - {NULL, 2, {7667, 1769}, {0, 0}, {0, 0}}, - {NULL, 2, {7716, 1999}, {0, 0}, {0, 0}}, - {NULL, 2, {6544, 1999}, {0, 0}, {0, 0}}, - {NULL, 2, {6605, 2286}, {0, 0}, {0, 0}}, - {NULL, 1, {6474, 1671}, {0, 0}, {0, 0}}, - {NULL, 2, {6851, 1671}, {0, 0}, {0, 0}}, - {NULL, 2, {6482, -66}, {0, 0}, {0, 0}}, - {NULL, 4, {6491, -217}, {6456, -188}, {0, 0}}, - {NULL, 4, {6665, -246}, {6526, -246}, {0, 0}}, - {NULL, 4, {6837, -246}, {6706, -246}, {0, 0}}, - {NULL, 4, {7112, -246}, {6969, -246}, {0, 0}}, - {NULL, 4, {7313, -246}, {7255, -246}, {0, 0}}, - {NULL, 4, {7474, -176}, {7419, -246}, {0, 0}}, - {NULL, 4, {7594, 156}, {7530, -106}, {0, 0}}, - {NULL, 4, {7723, 86}, {7643, 115}, {0, 0}}, - {NULL, 4, {7873, 41}, {7803, 57}, {0, 0}}, - {NULL, 4, {7653, -450}, {7778, -328}, {0, 0}}, - {NULL, 4, {7292, -573}, {7529, -573}, {0, 0}}, - {NULL, 4, {7152, -573}, {7259, -573}, {0, 0}}, - {NULL, 4, {6919, -573}, {7046, -573}, {0, 0}}, - {NULL, 4, {6689, -573}, {6792, -573}, {0, 0}}, - {NULL, 4, {6554, -573}, {6587, -573}, {0, 0}}, - {NULL, 4, {6144, -479}, {6251, -573}, {0, 0}}, - {NULL, 4, {6107, -57}, {6037, -385}, {0, 0}}, - {NULL, 2, {6474, 1671}, {0, 0}, {0, 0}}, - {NULL, 1, {5928, 2449}, {0, 0}, {0, 0}}, - {NULL, 2, {6217, 2310}, {0, 0}, {0, 0}}, - {NULL, 4, {5978, 2015}, {6094, 2154}, {0, 0}}, - {NULL, 4, {5758, 1769}, {5863, 1876}, {0, 0}}, - {NULL, 2, {5530, 1892}, {0, 0}, {0, 0}}, - {NULL, 4, {5742, 2175}, {5622, 2015}, {0, 0}}, - {NULL, 4, {5928, 2449}, {5862, 2335}, {0, 0}}, - {NULL, 1, {4834, 2351}, {0, 0}, {0, 0}}, - {NULL, 2, {5157, 2408}, {0, 0}, {0, 0}}, - {NULL, 4, {5232, 2146}, {5208, 2302}, {0, 0}}, - {NULL, 4, {5258, 1884}, {5256, 1991}, {0, 0}}, - {NULL, 2, {4910, 1786}, {0, 0}, {0, 0}}, - {NULL, 4, {4894, 2060}, {4910, 1901}, {0, 0}}, - {NULL, 4, {4834, 2351}, {4879, 2220}, {0, 0}}, - {NULL, 1, {5746, 1401}, {0, 0}, {0, 0}}, - {NULL, 2, {6106, 1401}, {0, 0}, {0, 0}}, - {NULL, 2, {5763, -213}, {0, 0}, {0, 0}}, - {NULL, 4, {5684, -446}, {5728, -377}, {0, 0}}, - {NULL, 4, {5541, -565}, {5641, -516}, {0, 0}}, - {NULL, 4, {5280, -610}, {5433, -606}, {0, 0}}, - {NULL, 4, {4891, -614}, {5128, -614}, {0, 0}}, - {NULL, 4, {4888, -455}, {4899, -541}, {0, 0}}, - {NULL, 4, {4852, -295}, {4878, -369}, {0, 0}}, - {NULL, 4, {5138, -303}, {5007, -303}, {0, 0}}, - {NULL, 4, {5311, -295}, {5269, -303}, {0, 0}}, - {NULL, 4, {5401, -221}, {5385, -295}, {0, 0}}, - {NULL, 2, {5746, 1401}, {0, 0}, {0, 0}}, - {NULL, 1, {6887, 2802}, {0, 0}, {0, 0}}, - {NULL, 2, {8313, 2802}, {0, 0}, {0, 0}}, - {NULL, 2, {8250, 2507}, {0, 0}, {0, 0}}, - {NULL, 2, {6824, 2507}, {0, 0}, {0, 0}}, - {NULL, 2, {6887, 2802}, {0, 0}, {0, 0}}, - {NULL, 1, {6549, 1253}, {0, 0}, {0, 0}}, - {NULL, 2, {7827, 1253}, {0, 0}, {0, 0}}, - {NULL, 2, {7770, 983}, {0, 0}, {0, 0}}, - {NULL, 2, {6492, 983}, {0, 0}, {0, 0}}, - {NULL, 2, {6549, 1253}, {0, 0}, {0, 0}}, - {NULL, 1, {6445, 762}, {0, 0}, {0, 0}}, - {NULL, 2, {7731, 762}, {0, 0}, {0, 0}}, - {NULL, 2, {7674, 492}, {0, 0}, {0, 0}}, - {NULL, 2, {6388, 492}, {0, 0}, {0, 0}}, - {NULL, 2, {6445, 762}, {0, 0}, {0, 0}}, - {NULL, 1, {6340, 270}, {0, 0}, {0, 0}}, - {NULL, 2, {7512, 270}, {0, 0}, {0, 0}}, - {NULL, 2, {7455, 0}, {0, 0}, {0, 0}}, - {NULL, 2, {6283, 0}, {0, 0}, {0, 0}}, - {NULL, 2, {6340, 270}, {0, 0}, {0, 0}}, - {NULL, 1, {4496, 303}, {0, 0}, {0, 0}}, - {NULL, 2, {5692, 303}, {0, 0}, {0, 0}}, - {NULL, 2, {5630, 8}, {0, 0}, {0, 0}}, - {NULL, 2, {4434, 8}, {0, 0}, {0, 0}}, - {NULL, 2, {4496, 303}, {0, 0}, {0, 0}}, - {NULL, 1, {4611, 844}, {0, 0}, {0, 0}}, - {NULL, 2, {5807, 844}, {0, 0}, {0, 0}}, - {NULL, 2, {5746, 557}, {0, 0}, {0, 0}}, - {NULL, 2, {4550, 557}, {0, 0}, {0, 0}}, - {NULL, 2, {4611, 844}, {0, 0}, {0, 0}}, - {NULL, 1, {4715, 2720}, {0, 0}, {0, 0}}, - {NULL, 2, {6517, 2720}, {0, 0}, {0, 0}}, - {NULL, 2, {6447, 2392}, {0, 0}, {0, 0}}, - {NULL, 2, {4645, 2392}, {0, 0}, {0, 0}}, - {NULL, 2, {4715, 2720}, {0, 0}, {0, 0}}, - {NULL, 1, {4428, 1950}, {0, 0}, {0, 0}}, - {NULL, 2, {6394, 1950}, {0, 0}, {0, 0}}, - {NULL, 2, {6326, 1630}, {0, 0}, {0, 0}}, - {NULL, 2, {4360, 1630}, {0, 0}, {0, 0}}, - {NULL, 2, {4428, 1950}, {0, 0}, {0, 0}}, - {NULL, 1, {5370, 3023}, {0, 0}, {0, 0}}, - {NULL, 2, {5739, 3105}, {0, 0}, {0, 0}}, - {NULL, 4, {5825, 2855}, {5790, 2998}, {0, 0}}, - {NULL, 4, {5872, 2613}, {5860, 2712}, {0, 0}}, - {NULL, 2, {5479, 2499}, {0, 0}, {0, 0}}, - {NULL, 4, {5434, 2752}, {5469, 2605}, {0, 0}}, - {NULL, 4, {5370, 3023}, {5400, 2900}, {0, 0}}, - {NULL, 0, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5888, 6889}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6445, 6889}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6238, 5915}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5681, 5915}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5888, 6889}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2069, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4576, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4508, 4825}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2525, 4825}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2178, 3195}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1654, 3195}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2069, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5714, 6070}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8573, 6070}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8401, 5259}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5542, 5259}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5606, 5562}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7916, 5562}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7962, 5775}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5652, 5775}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5714, 6070}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5580, 5439}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6137, 5439}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5786, 3785}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5832, 3600}, {5756, 3645}, {0, 0}, {0, 0}}, + {NULL, 4, {6195, 3555}, {5909, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {6461, 3555}, {6261, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {6904, 3555}, {6662, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {7359, 3555}, {7146, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {7670, 3555}, {7572, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {7880, 3579}, {7801, 3555}, {0, 0}, {0, 0}}, + {NULL, 4, {8010, 3690}, {7959, 3604}, {0, 0}, {0, 0}}, + {NULL, 4, {8107, 3957}, {8061, 3777}, {0, 0}, {0, 0}}, + {NULL, 4, {8305, 3887}, {8188, 3916}, {0, 0}, {0, 0}}, + {NULL, 4, {8526, 3842}, {8422, 3858}, {0, 0}, {0, 0}}, + {NULL, 4, {8238, 3359}, {8416, 3482}, {0, 0}, {0, 0}}, + {NULL, 4, {7668, 3236}, {8061, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {7446, 3236}, {7610, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {7074, 3236}, {7283, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {6656, 3236}, {6865, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {6287, 3236}, {6447, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {6078, 3236}, {6127, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {5345, 3334}, {5538, 3236}, {0, 0}, {0, 0}}, + {NULL, 4, {5230, 3793}, {5153, 3432}, {0, 0}, {0, 0}}, + {NULL, 2, {5580, 5439}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4305, 6185}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4756, 6038}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {4494, 5726}, {4616, 5874}, {0, 0}, {0, 0}}, + {NULL, 4, {4258, 5464}, {4373, 5579}, {0, 0}, {0, 0}}, + {NULL, 2, {3901, 5595}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {4120, 5894}, {4002, 5726}, {0, 0}, {0, 0}}, + {NULL, 4, {4305, 6185}, {4238, 6062}, {0, 0}, {0, 0}}, + {NULL, 1, {2506, 6046}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2941, 6169}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {3051, 5894}, {3014, 6046}, {0, 0}, {0, 0}}, + {NULL, 4, {3088, 5628}, {3089, 5743}, {0, 0}, {0, 0}}, + {NULL, 2, {2610, 5497}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {2584, 5763}, {2616, 5603}, {0, 0}, {0, 0}}, + {NULL, 4, {2506, 6046}, {2553, 5923}, {0, 0}, {0, 0}}, + {NULL, 1, {4322, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4846, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4515, 3588}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {4421, 3362}, {4481, 3432}, {0, 0}, {0, 0}}, + {NULL, 4, {4238, 3252}, {4362, 3293}, {0, 0}, {0, 0}}, + {NULL, 4, {3912, 3203}, {4115, 3211}, {0, 0}, {0, 0}}, + {NULL, 4, {3423, 3195}, {3710, 3195}, {0, 0}, {0, 0}}, + {NULL, 4, {3409, 3359}, {3433, 3277}, {0, 0}, {0, 0}}, + {NULL, 4, {3358, 3506}, {3385, 3441}, {0, 0}, {0, 0}}, + {NULL, 4, {3677, 3506}, {3530, 3506}, {0, 0}, {0, 0}}, + {NULL, 4, {3874, 3506}, {3825, 3506}, {0, 0}, {0, 0}}, + {NULL, 4, {3956, 3522}, {3932, 3506}, {0, 0}, {0, 0}}, + {NULL, 4, {3991, 3588}, {3980, 3539}, {0, 0}, {0, 0}}, + {NULL, 2, {4322, 5145}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6071, 6595}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8988, 6595}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8923, 6291}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6006, 6291}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6071, 6595}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5732, 5038}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8190, 5038}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8132, 4768}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5674, 4768}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5732, 5038}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5646, 4555}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8046, 4555}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7987, 4276}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5587, 4276}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5646, 4555}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5523, 4055}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8046, 4055}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7989, 3785}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5466, 3785}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5523, 4055}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2081, 4047}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4350, 4047}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4288, 3752}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2019, 3752}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2081, 4047}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2196, 4588}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4465, 4588}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4402, 4293}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2133, 4293}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2196, 4588}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2066, 6447}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5351, 6447}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5284, 6128}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1999, 6128}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2066, 6447}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {1689, 5710}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5433, 5710}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5365, 5390}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1621, 5390}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1689, 5710}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {3383, 6824}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3903, 6914}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {4030, 6607}, {3973, 6783}, {0, 0}, {0, 0}}, + {NULL, 4, {4110, 6308}, {4087, 6431}, {0, 0}, {0, 0}}, + {NULL, 2, {3568, 6185}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {3507, 6500}, {3554, 6316}, {0, 0}, {0, 0}}, + {NULL, 4, {3383, 6824}, {3461, 6685}, {0, 0}, {0, 0}}, + {NULL, 1, {3008, 3129}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3377, 3129}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3168, 2146}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2799, 2146}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3008, 3129}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {860, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2163, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2095, 1106}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1136, 1106}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {776, -590}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {432, -590}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {860, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2834, 2310}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4317, 2310}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4143, 1491}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2660, 1491}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2723, 1786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3853, 1786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3901, 2015}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2771, 2015}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2834, 2310}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2703, 1696}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3063, 1696}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2698, -25}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {2705, -184}, {2672, -147}, {0, 0}, {0, 0}}, + {NULL, 4, {2869, -221}, {2738, -221}, {0, 0}, {0, 0}}, + {NULL, 4, {3045, -221}, {2919, -221}, {0, 0}, {0, 0}}, + {NULL, 4, {3311, -221}, {3172, -221}, {0, 0}, {0, 0}}, + {NULL, 4, {3500, -221}, {3451, -221}, {0, 0}, {0, 0}}, + {NULL, 4, {3659, -147}, {3607, -221}, {0, 0}, {0, 0}}, + {NULL, 4, {3776, 188}, {3711, -74}, {0, 0}, {0, 0}}, + {NULL, 4, {3899, 114}, {3824, 147}, {0, 0}, {0, 0}}, + {NULL, 4, {4044, 66}, {3974, 82}, {0, 0}, {0, 0}}, + {NULL, 4, {3826, -418}, {3951, -295}, {0, 0}, {0, 0}}, + {NULL, 4, {3473, -541}, {3702, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {3346, -541}, {3449, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {3121, -541}, {3244, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {2899, -541}, {2998, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {2769, -541}, {2801, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {2366, -446}, {2465, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {2338, -25}, {2268, -352}, {0, 0}, {0, 0}}, + {NULL, 2, {2703, 1696}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2189, 2474}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2462, 2335}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {2225, 2031}, {2337, 2171}, {0, 0}, {0, 0}}, + {NULL, 4, {2019, 1794}, {2114, 1892}, {0, 0}, {0, 0}}, + {NULL, 2, {1800, 1917}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {2003, 2199}, {1892, 2040}, {0, 0}, {0, 0}}, + {NULL, 4, {2189, 2474}, {2115, 2359}, {0, 0}, {0, 0}}, + {NULL, 1, {1134, 2367}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1451, 2433}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {1517, 2166}, {1492, 2318}, {0, 0}, {0, 0}}, + {NULL, 4, {1543, 1901}, {1542, 2015}, {0, 0}, {0, 0}}, + {NULL, 2, {1204, 1810}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {1196, 2080}, {1212, 1925}, {0, 0}, {0, 0}}, + {NULL, 4, {1134, 2367}, {1180, 2236}, {0, 0}, {0, 0}}, + {NULL, 1, {2015, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2367, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2022, -197}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {1941, -426}, {1989, -352}, {0, 0}, {0, 0}}, + {NULL, 4, {1794, -541}, {1893, -500}, {0, 0}, {0, 0}}, + {NULL, 4, {1551, -586}, {1703, -582}, {0, 0}, {0, 0}}, + {NULL, 4, {1169, -590}, {1399, -590}, {0, 0}, {0, 0}}, + {NULL, 4, {1166, -430}, {1176, -516}, {0, 0}, {0, 0}}, + {NULL, 4, {1139, -270}, {1156, -344}, {0, 0}, {0, 0}}, + {NULL, 4, {1415, -279}, {1293, -279}, {0, 0}, {0, 0}}, + {NULL, 4, {1579, -279}, {1538, -279}, {0, 0}, {0, 0}}, + {NULL, 4, {1670, -197}, {1653, -279}, {0, 0}, {0, 0}}, + {NULL, 2, {2015, 1425}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {3108, 2826}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4492, 2826}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4429, 2531}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3045, 2531}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3108, 2826}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2779, 1278}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4016, 1278}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3958, 1008}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2721, 1008}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2779, 1278}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2674, 786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3919, 786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3862, 516}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2617, 516}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2674, 786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {2570, 295}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3692, 295}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {3632, 16}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2510, 16}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2570, 295}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {791, 328}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1946, 328}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1883, 33}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {728, 33}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {791, 328}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {905, 868}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2060, 868}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1998, 573}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {843, 573}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {905, 868}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {1016, 2736}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2769, 2736}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2701, 2417}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {948, 2417}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {1016, 2736}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {739, 1974}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2640, 1974}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2570, 1647}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {669, 1647}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {739, 1974}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {1666, 3056}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {2019, 3138}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {2100, 2887}, {2069, 3031}, {0, 0}, {0, 0}}, + {NULL, 4, {2142, 2638}, {2131, 2744}, {0, 0}, {0, 0}}, + {NULL, 2, {1756, 2515}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {1729, 2777}, {1755, 2630}, {0, 0}, {0, 0}}, + {NULL, 4, {1666, 3056}, {1703, 2925}, {0, 0}, {0, 0}}, + {NULL, 1, {6779, 3105}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7156, 3105}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6949, 2130}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6572, 2130}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6779, 3105}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4558, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5901, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5833, 1081}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4842, 1081}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4481, -614}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4129, -614}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4558, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6605, 2286}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8146, 2286}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7974, 1475}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6433, 1475}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6495, 1769}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7667, 1769}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7716, 1999}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6544, 1999}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6605, 2286}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6474, 1671}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6851, 1671}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6482, -66}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {6491, -217}, {6456, -188}, {0, 0}, {0, 0}}, + {NULL, 4, {6665, -246}, {6526, -246}, {0, 0}, {0, 0}}, + {NULL, 4, {6837, -246}, {6706, -246}, {0, 0}, {0, 0}}, + {NULL, 4, {7112, -246}, {6969, -246}, {0, 0}, {0, 0}}, + {NULL, 4, {7313, -246}, {7255, -246}, {0, 0}, {0, 0}}, + {NULL, 4, {7474, -176}, {7419, -246}, {0, 0}, {0, 0}}, + {NULL, 4, {7594, 156}, {7530, -106}, {0, 0}, {0, 0}}, + {NULL, 4, {7723, 86}, {7643, 115}, {0, 0}, {0, 0}}, + {NULL, 4, {7873, 41}, {7803, 57}, {0, 0}, {0, 0}}, + {NULL, 4, {7653, -450}, {7778, -328}, {0, 0}, {0, 0}}, + {NULL, 4, {7292, -573}, {7529, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {7152, -573}, {7259, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {6919, -573}, {7046, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {6689, -573}, {6792, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {6554, -573}, {6587, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {6144, -479}, {6251, -573}, {0, 0}, {0, 0}}, + {NULL, 4, {6107, -57}, {6037, -385}, {0, 0}, {0, 0}}, + {NULL, 2, {6474, 1671}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5928, 2449}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6217, 2310}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5978, 2015}, {6094, 2154}, {0, 0}, {0, 0}}, + {NULL, 4, {5758, 1769}, {5863, 1876}, {0, 0}, {0, 0}}, + {NULL, 2, {5530, 1892}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5742, 2175}, {5622, 2015}, {0, 0}, {0, 0}}, + {NULL, 4, {5928, 2449}, {5862, 2335}, {0, 0}, {0, 0}}, + {NULL, 1, {4834, 2351}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5157, 2408}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5232, 2146}, {5208, 2302}, {0, 0}, {0, 0}}, + {NULL, 4, {5258, 1884}, {5256, 1991}, {0, 0}, {0, 0}}, + {NULL, 2, {4910, 1786}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {4894, 2060}, {4910, 1901}, {0, 0}, {0, 0}}, + {NULL, 4, {4834, 2351}, {4879, 2220}, {0, 0}, {0, 0}}, + {NULL, 1, {5746, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6106, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5763, -213}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5684, -446}, {5728, -377}, {0, 0}, {0, 0}}, + {NULL, 4, {5541, -565}, {5641, -516}, {0, 0}, {0, 0}}, + {NULL, 4, {5280, -610}, {5433, -606}, {0, 0}, {0, 0}}, + {NULL, 4, {4891, -614}, {5128, -614}, {0, 0}, {0, 0}}, + {NULL, 4, {4888, -455}, {4899, -541}, {0, 0}, {0, 0}}, + {NULL, 4, {4852, -295}, {4878, -369}, {0, 0}, {0, 0}}, + {NULL, 4, {5138, -303}, {5007, -303}, {0, 0}, {0, 0}}, + {NULL, 4, {5311, -295}, {5269, -303}, {0, 0}, {0, 0}}, + {NULL, 4, {5401, -221}, {5385, -295}, {0, 0}, {0, 0}}, + {NULL, 2, {5746, 1401}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6887, 2802}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8313, 2802}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {8250, 2507}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6824, 2507}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6887, 2802}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6549, 1253}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7827, 1253}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7770, 983}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6492, 983}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6549, 1253}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6445, 762}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7731, 762}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7674, 492}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6388, 492}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6445, 762}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {6340, 270}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7512, 270}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {7455, 0}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6283, 0}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6340, 270}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4496, 303}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5692, 303}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5630, 8}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4434, 8}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4496, 303}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4611, 844}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5807, 844}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5746, 557}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4550, 557}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4611, 844}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4715, 2720}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6517, 2720}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6447, 2392}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4645, 2392}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4715, 2720}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {4428, 1950}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6394, 1950}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {6326, 1630}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4360, 1630}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {4428, 1950}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 1, {5370, 3023}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 2, {5739, 3105}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5825, 2855}, {5790, 2998}, {0, 0}, {0, 0}}, + {NULL, 4, {5872, 2613}, {5860, 2712}, {0, 0}, {0, 0}}, + {NULL, 2, {5479, 2499}, {0, 0}, {0, 0}, {0, 0}}, + {NULL, 4, {5434, 2752}, {5469, 2605}, {0, 0}, {0, 0}}, + {NULL, 4, {5370, 3023}, {5400, 2900}, {0, 0}, {0, 0}}, + {NULL, 0, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, }; static void freetype_outline_event_cb(lv_event_t * e);