feat(NemaGFX): add freetype vector font support (#7346)

This commit is contained in:
Ioannis Markopoulos
2024-12-10 16:23:06 +02:00
committed by GitHub
parent 2209e3a270
commit e53ada9605
9 changed files with 1031 additions and 506 deletions

View File

@@ -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*/

View File

@@ -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);

View File

@@ -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);

View File

@@ -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*/

View File

@@ -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*/

View File

@@ -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*/

View File

@@ -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(&param, 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, &param);
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) {

View File

@@ -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;
};

View File

@@ -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);