fix(vg_lite): fix rotated vector font clipping error (#8739)
Signed-off-by: pengyiqiang <pengyiqiang@xiaomi.com> Co-authored-by: pengyiqiang <pengyiqiang@xiaomi.com>
@@ -20,6 +20,7 @@
|
||||
#include "../../misc/lv_area_private.h"
|
||||
#include "../../libs/freetype/lv_freetype_private.h"
|
||||
#include "../lv_draw_label_private.h"
|
||||
#include "../lv_draw_image_private.h"
|
||||
|
||||
|
||||
/*********************
|
||||
@@ -60,6 +61,7 @@ static void bitmap_cache_release_cb(void * entry, void * user_data);
|
||||
#if LV_USE_FREETYPE
|
||||
static void freetype_outline_event_cb(lv_event_t * e);
|
||||
static void draw_letter_outline(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * dsc);
|
||||
static void outline_iter_cb(void * user_data, uint8_t op_code, const float * data, uint32_t len);
|
||||
#endif /* LV_USE_FREETYPE */
|
||||
|
||||
/**********************
|
||||
@@ -244,53 +246,120 @@ static void draw_letter_cb(lv_draw_task_t * t, lv_draw_glyph_dsc_t * glyph_draw_
|
||||
}
|
||||
}
|
||||
|
||||
static void draw_letter_bitmap(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * dsc, vg_lite_buffer_t * src_buf)
|
||||
static inline void convert_letter_matrix(vg_lite_matrix_t * matrix, const lv_draw_glyph_dsc_t * dsc)
|
||||
{
|
||||
lv_area_t clip_area;
|
||||
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)t->draw_unit;
|
||||
if(!lv_area_intersect(&clip_area, &t->clip_area, dsc->letter_coords)) {
|
||||
vg_lite_translate(dsc->letter_coords->x1, dsc->letter_coords->y1, matrix);
|
||||
|
||||
if(!dsc->rotation) {
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_point_t pivot = {
|
||||
.x = dsc->pivot.x,
|
||||
.y = dsc->g->box_h + dsc->g->ofs_y
|
||||
};
|
||||
vg_lite_translate(pivot.x, pivot.y, matrix);
|
||||
vg_lite_rotate(dsc->rotation / 10.0f, matrix);
|
||||
vg_lite_translate(-pivot.x, -pivot.y, matrix);
|
||||
}
|
||||
|
||||
static bool draw_letter_clip_areas(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * dsc, lv_area_t * letter_area,
|
||||
lv_area_t * cliped_area)
|
||||
{
|
||||
*letter_area = *dsc->letter_coords;
|
||||
|
||||
if(dsc->rotation) {
|
||||
const lv_point_t pivot = {
|
||||
.x = dsc->pivot.x,
|
||||
.y = dsc->g->box_h + dsc->g->ofs_y
|
||||
};
|
||||
|
||||
lv_image_buf_get_transformed_area(
|
||||
letter_area,
|
||||
lv_area_get_width(dsc->letter_coords),
|
||||
lv_area_get_height(dsc->letter_coords),
|
||||
dsc->rotation,
|
||||
LV_SCALE_NONE,
|
||||
LV_SCALE_NONE,
|
||||
&pivot);
|
||||
lv_area_move(letter_area, dsc->letter_coords->x1, dsc->letter_coords->y1);
|
||||
}
|
||||
|
||||
if(!lv_area_intersect(cliped_area, &t->clip_area, letter_area)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void draw_letter_bitmap(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * dsc, vg_lite_buffer_t * src_buf)
|
||||
{
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
const lv_area_t image_area = *dsc->letter_coords;
|
||||
lv_area_t image_area;
|
||||
lv_area_t clip_area;
|
||||
if(!draw_letter_clip_areas(t, dsc, &image_area, &clip_area)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)t->draw_unit;
|
||||
|
||||
vg_lite_matrix_t matrix = u->global_matrix;
|
||||
|
||||
const bool is_rotated = dsc->rotation % 3600 != 0;
|
||||
|
||||
if(!is_rotated) {
|
||||
vg_lite_translate(image_area.x1, image_area.y1, &matrix);
|
||||
}
|
||||
else {
|
||||
vg_lite_translate(image_area.x1 + dsc->pivot.x, image_area.y1 + (dsc->g->box_h + dsc->g->ofs_y), &matrix);
|
||||
vg_lite_rotate(dsc->rotation / 10.0f, &matrix);
|
||||
vg_lite_translate(-dsc->pivot.x, -dsc->g->box_h - dsc->g->ofs_y, &matrix);
|
||||
}
|
||||
convert_letter_matrix(&matrix, dsc);
|
||||
|
||||
const vg_lite_color_t color = lv_vg_lite_color(dsc->color, dsc->opa, true);
|
||||
|
||||
vg_lite_rectangle_t rect = {
|
||||
.x = clip_area.x1 - image_area.x1,
|
||||
.y = clip_area.y1 - image_area.y1,
|
||||
.width = lv_area_get_width(&clip_area),
|
||||
.height = lv_area_get_height(&clip_area)
|
||||
};
|
||||
/* If rotation is not required, blit directly */
|
||||
if(!dsc->rotation) {
|
||||
vg_lite_rectangle_t rect = {
|
||||
.x = clip_area.x1 - image_area.x1,
|
||||
.y = clip_area.y1 - image_area.y1,
|
||||
.width = lv_area_get_width(&clip_area),
|
||||
.height = lv_area_get_height(&clip_area)
|
||||
};
|
||||
|
||||
/* add offset for clipped area */
|
||||
if(rect.x || rect.y) {
|
||||
vg_lite_translate(rect.x, rect.y, &matrix);
|
||||
/* add offset for clipped area */
|
||||
if(rect.x || rect.y) {
|
||||
vg_lite_translate(rect.x, rect.y, &matrix);
|
||||
}
|
||||
|
||||
lv_vg_lite_blit_rect(
|
||||
&u->target_buffer,
|
||||
src_buf,
|
||||
&rect,
|
||||
&matrix,
|
||||
VG_LITE_BLEND_SRC_OVER,
|
||||
color,
|
||||
VG_LITE_FILTER_LINEAR);
|
||||
}
|
||||
else {
|
||||
lv_vg_lite_path_t * path = lv_vg_lite_path_get(u, VG_LITE_S16);
|
||||
lv_vg_lite_path_append_rect(
|
||||
path,
|
||||
image_area.x1, image_area.y1,
|
||||
lv_area_get_width(&image_area), lv_area_get_height(&image_area),
|
||||
0);
|
||||
lv_vg_lite_path_end(path);
|
||||
lv_vg_lite_path_set_bounding_box_area(path, &clip_area);
|
||||
|
||||
lv_vg_lite_blit_rect(
|
||||
&u->target_buffer,
|
||||
src_buf,
|
||||
&rect,
|
||||
&matrix,
|
||||
VG_LITE_BLEND_SRC_OVER,
|
||||
color,
|
||||
VG_LITE_FILTER_LINEAR);
|
||||
vg_lite_matrix_t path_matrix = u->global_matrix;
|
||||
|
||||
lv_vg_lite_draw_pattern(
|
||||
&u->target_buffer,
|
||||
lv_vg_lite_path_get_path(path),
|
||||
VG_LITE_FILL_EVEN_ODD,
|
||||
&path_matrix,
|
||||
src_buf,
|
||||
&matrix,
|
||||
VG_LITE_BLEND_SRC_OVER,
|
||||
VG_LITE_PATTERN_COLOR,
|
||||
0,
|
||||
color,
|
||||
VG_LITE_FILTER_LINEAR);
|
||||
|
||||
lv_vg_lite_path_drop(u, path);
|
||||
}
|
||||
|
||||
/* Check if the data has cache and add it to the pending list */
|
||||
if(dsc->g->entry) {
|
||||
@@ -317,80 +386,118 @@ static void bitmap_cache_release_cb(void * entry, void * user_data)
|
||||
|
||||
static void draw_letter_outline(lv_draw_task_t * t, const lv_draw_glyph_dsc_t * dsc)
|
||||
{
|
||||
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)t->draw_unit;
|
||||
/* get clip area */
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
lv_area_t letter_area;
|
||||
lv_area_t path_clip_area;
|
||||
if(!lv_area_intersect(&path_clip_area, &t->clip_area, dsc->letter_coords)) {
|
||||
if(!draw_letter_clip_areas(t, dsc, &letter_area, &path_clip_area)) {
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
lv_draw_vg_lite_unit_t * u = (lv_draw_vg_lite_unit_t *)t->draw_unit;
|
||||
|
||||
/* vg-lite bounding_box will crop the pixels on the edge, so +1px is needed here */
|
||||
path_clip_area.x2++;
|
||||
path_clip_area.y2++;
|
||||
|
||||
lv_vg_lite_path_t * outline = (lv_vg_lite_path_t *)dsc->glyph_data;
|
||||
const lv_point_t pos = {dsc->letter_coords->x1, dsc->letter_coords->y1};
|
||||
const lv_point_t glyph_pos = {
|
||||
dsc->letter_coords->x1 - dsc->g->ofs_x,
|
||||
dsc->letter_coords->y1 + dsc->g->box_h + dsc->g->ofs_y
|
||||
};
|
||||
/* scale size */
|
||||
const float scale = FT_F26DOT6_TO_PATH_SCALE(lv_freetype_outline_get_scale(dsc->g->resolved_font));
|
||||
const bool is_rotated = dsc->rotation % 3600 != 0;
|
||||
|
||||
const bool has_rotation_with_cliped = dsc->rotation && !lv_area_is_in(&letter_area, &t->clip_area, false);
|
||||
|
||||
/* calc convert matrix */
|
||||
vg_lite_matrix_t matrix;
|
||||
vg_lite_identity(&matrix);
|
||||
|
||||
if(!is_rotated) {
|
||||
vg_lite_translate(pos.x - dsc->g->ofs_x, pos.y + dsc->g->box_h + dsc->g->ofs_y, &matrix);
|
||||
vg_lite_scale(scale, scale, &matrix);
|
||||
}
|
||||
else {
|
||||
vg_lite_translate(pos.x - dsc->g->ofs_x + dsc->pivot.x, pos.y + dsc->g->box_h + dsc->g->ofs_y, &matrix);
|
||||
if(!has_rotation_with_cliped && dsc->rotation) {
|
||||
vg_lite_translate(glyph_pos.x + dsc->pivot.x, glyph_pos.y, &matrix);
|
||||
vg_lite_rotate(dsc->rotation / 10.0f, &matrix);
|
||||
vg_lite_translate(-dsc->pivot.x, 0, &matrix);
|
||||
vg_lite_scale(scale, scale, &matrix);
|
||||
}
|
||||
|
||||
if(vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR)) {
|
||||
/* set scissor area */
|
||||
lv_vg_lite_set_scissor_area(u, &t->clip_area);
|
||||
|
||||
/* no bounding box */
|
||||
lv_vg_lite_path_set_bounding_box(outline,
|
||||
(float)PATH_COORD_MIN, (float)PATH_COORD_MIN,
|
||||
(float)PATH_COORD_MAX, (float)PATH_COORD_MAX);
|
||||
}
|
||||
else {
|
||||
if(is_rotated) {
|
||||
LV_LOG_WARN("clip may be incorrect when vg_lite_query_feature(gcFEATURE_BIT_VG_SCISSOR) is false");
|
||||
}
|
||||
|
||||
/* calc inverse matrix */
|
||||
vg_lite_matrix_t result;
|
||||
if(!lv_vg_lite_matrix_inverse(&result, &matrix)) {
|
||||
LV_LOG_ERROR("no inverse matrix");
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_point_precise_t p1 = { path_clip_area.x1, path_clip_area.y1 };
|
||||
const lv_point_precise_t p1_res = lv_vg_lite_matrix_transform_point(&result, &p1);
|
||||
|
||||
const lv_point_precise_t p2 = { path_clip_area.x2, path_clip_area.y2 };
|
||||
const lv_point_precise_t p2_res = lv_vg_lite_matrix_transform_point(&result, &p2);
|
||||
|
||||
/* Since the font uses Cartesian coordinates, the y coordinates need to be reversed */
|
||||
if(is_rotated)
|
||||
lv_vg_lite_path_set_bounding_box(outline,
|
||||
(float)PATH_COORD_MIN, (float)PATH_COORD_MIN,
|
||||
(float)PATH_COORD_MAX, (float)PATH_COORD_MAX);
|
||||
else lv_vg_lite_path_set_bounding_box(outline, p1_res.x, p2_res.y, p2_res.x, p1_res.y);
|
||||
vg_lite_translate(glyph_pos.x, glyph_pos.y, &matrix);
|
||||
}
|
||||
|
||||
vg_lite_scale(scale, scale, &matrix);
|
||||
|
||||
/* matrix for drawing, different from matrix for calculating the bounding box */
|
||||
vg_lite_matrix_t draw_matrix = u->global_matrix;
|
||||
lv_vg_lite_matrix_multiply(&draw_matrix, &matrix);
|
||||
|
||||
/* calc inverse matrix */
|
||||
vg_lite_matrix_t result;
|
||||
if(!lv_vg_lite_matrix_inverse(&result, &matrix)) {
|
||||
LV_LOG_ERROR("no inverse matrix");
|
||||
lv_vg_lite_matrix_dump_info(&matrix);
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
const lv_point_precise_t p1 = { path_clip_area.x1, path_clip_area.y1 };
|
||||
const lv_point_precise_t p1_res = lv_vg_lite_matrix_transform_point(&result, &p1);
|
||||
const lv_point_precise_t p2 = { path_clip_area.x2, path_clip_area.y2 };
|
||||
const lv_point_precise_t p2_res = lv_vg_lite_matrix_transform_point(&result, &p2);
|
||||
|
||||
if(has_rotation_with_cliped) {
|
||||
/**
|
||||
* When intersecting the clipping region,
|
||||
* rotate the path contents without rotating the bounding box for cropping
|
||||
*/
|
||||
vg_lite_matrix_t internal_matrix;
|
||||
vg_lite_identity(&internal_matrix);
|
||||
const float pivot_x = dsc->pivot.x / scale;
|
||||
const float pivot_y = dsc->g->box_h + dsc->g->ofs_y;
|
||||
vg_lite_translate(pivot_x, pivot_y, &internal_matrix);
|
||||
vg_lite_rotate(dsc->rotation / 10.0f, &internal_matrix);
|
||||
vg_lite_translate(-pivot_x, -pivot_y, &internal_matrix);
|
||||
|
||||
lv_vg_lite_path_t * outline_transformed = lv_vg_lite_path_get(u, VG_LITE_FP32);
|
||||
lv_vg_lite_path_set_transform(outline_transformed, &internal_matrix);
|
||||
lv_vg_lite_path_for_each_data(lv_vg_lite_path_get_path(outline), outline_iter_cb, outline_transformed);
|
||||
lv_vg_lite_path_set_bounding_box(outline_transformed, p1_res.x, p2_res.y, p2_res.x, p1_res.y);
|
||||
|
||||
lv_vg_lite_draw(
|
||||
&u->target_buffer,
|
||||
lv_vg_lite_path_get_path(outline_transformed),
|
||||
VG_LITE_FILL_NON_ZERO,
|
||||
&draw_matrix,
|
||||
VG_LITE_BLEND_SRC_OVER,
|
||||
lv_vg_lite_color(dsc->color, dsc->opa, true));
|
||||
|
||||
lv_vg_lite_path_drop(u, outline_transformed);
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
return;
|
||||
}
|
||||
|
||||
if(dsc->rotation) {
|
||||
/* The bounding rectangle before scaling relative to the original coordinates of the path */
|
||||
lv_area_t box_area;
|
||||
box_area.x1 = dsc->g->ofs_x;
|
||||
box_area.y1 = -dsc->g->box_h - dsc->g->ofs_y;
|
||||
lv_area_set_width(&box_area, dsc->g->box_w);
|
||||
lv_area_set_height(&box_area, dsc->g->box_h);
|
||||
|
||||
/* Workaround for loss of rotation precision */
|
||||
lv_area_increase(&box_area, 5, 5);
|
||||
|
||||
/* Scale the path area to fit the original path data */
|
||||
lv_vg_lite_path_set_bounding_box(outline,
|
||||
box_area.x1 / scale,
|
||||
box_area.y1 / scale,
|
||||
box_area.x2 / scale,
|
||||
box_area.y2 / scale);
|
||||
}
|
||||
else {
|
||||
lv_vg_lite_path_set_bounding_box(outline, p1_res.x, p2_res.y, p2_res.x, p1_res.y);
|
||||
}
|
||||
|
||||
lv_vg_lite_draw(
|
||||
&u->target_buffer,
|
||||
lv_vg_lite_path_get_path(outline),
|
||||
@@ -463,6 +570,42 @@ static void freetype_outline_event_cb(lv_event_t * e)
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
static void outline_iter_cb(void * user_data, uint8_t op_code, const float * data, uint32_t len)
|
||||
{
|
||||
LV_UNUSED(len);
|
||||
typedef struct {
|
||||
float x;
|
||||
float y;
|
||||
} point_t;
|
||||
|
||||
lv_vg_lite_path_t * path = user_data;
|
||||
const point_t * pt = (point_t *)data;
|
||||
|
||||
switch(op_code) {
|
||||
case VLC_OP_MOVE:
|
||||
lv_vg_lite_path_move_to(path, pt->x, pt->y);
|
||||
break;
|
||||
case VLC_OP_LINE:
|
||||
lv_vg_lite_path_line_to(path, pt->x, pt->y);
|
||||
break;
|
||||
case VLC_OP_QUAD:
|
||||
lv_vg_lite_path_quad_to(path, pt[0].x, pt[0].y, pt[1].x, pt[1].y);
|
||||
break;
|
||||
case VLC_OP_CUBIC:
|
||||
lv_vg_lite_path_cubic_to(path, pt[0].x, pt[0].y, pt[1].x, pt[1].y, pt[2].x, pt[2].y);
|
||||
break;
|
||||
case VLC_OP_CLOSE:
|
||||
lv_vg_lite_path_close(path);
|
||||
break;
|
||||
case VLC_OP_END:
|
||||
lv_vg_lite_path_end(path);
|
||||
break;
|
||||
default:
|
||||
LV_ASSERT_FORMAT_MSG(false, "unknown op_code: %d", op_code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* LV_USE_FREETYPE */
|
||||
|
||||
#endif /*LV_USE_DRAW_VG_LITE*/
|
||||
|
||||
@@ -647,6 +647,7 @@ void lv_vg_lite_path_for_each_data(const vg_lite_path_t * path, lv_vg_lite_path_
|
||||
{
|
||||
LV_ASSERT_NULL(path);
|
||||
LV_ASSERT_NULL(cb);
|
||||
LV_PROFILER_DRAW_BEGIN;
|
||||
|
||||
uint8_t fmt_len = lv_vg_lite_path_format_len(path->format);
|
||||
uint8_t * cur = path->path;
|
||||
@@ -688,6 +689,8 @@ void lv_vg_lite_path_for_each_data(const vg_lite_path_t * path, lv_vg_lite_path_
|
||||
|
||||
cb(user_data, op_code, tmp_data, arg_len);
|
||||
}
|
||||
|
||||
LV_PROFILER_DRAW_END;
|
||||
}
|
||||
|
||||
void lv_vg_lite_path_append_path(lv_vg_lite_path_t * dest, const lv_vg_lite_path_t * src)
|
||||
|
||||
@@ -23,20 +23,6 @@ extern "C" {
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
#if LV_USE_VG_LITE_THORVG
|
||||
/**
|
||||
* It is found that thorvg cannot handle large coordinates well.
|
||||
* When the coordinates are larger than 4096, the calculation of tvgSwRle module will overflow in 32-bit system.
|
||||
* So we use FLT_MAX and FLT_MIN to write the mark to bounding_box to tell vg_lite_tvg not to add clip path to the current path.
|
||||
*/
|
||||
#define PATH_COORD_MAX FLT_MAX
|
||||
#define PATH_COORD_MIN FLT_MIN
|
||||
#else
|
||||
/* 18 bits is enough to represent the coordinates of path bounding box */
|
||||
#define PATH_COORD_MAX (1 << 18)
|
||||
#define PATH_COORD_MIN (-PATH_COORD_MAX)
|
||||
#endif
|
||||
|
||||
#define LV_VG_LITE_PATH_SET_OP_CODE(PTR, TYPE, OP_CODE) (*((TYPE*)PTR) = (OP_CODE))
|
||||
#define LV_VG_LITE_PATH_GET_OP_CODE(PTR) (*((uint8_t*)PTR))
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 4.1 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
After Width: | Height: | Size: 398 B |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.7 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 3.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 3.5 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 57 KiB |
@@ -4,6 +4,12 @@
|
||||
|
||||
#include "unity/unity.h"
|
||||
|
||||
#ifndef NON_AMD64_BUILD
|
||||
#define TEST_ASSERT_EQUAL_LETTER_SCREENSHOT(path) TEST_ASSERT_EQUAL_SCREENSHOT(path)
|
||||
#else
|
||||
#define TEST_ASSERT_EQUAL_LETTER_SCREENSHOT(path) LV_UNUSED(path)
|
||||
#endif
|
||||
|
||||
void setUp(void)
|
||||
{
|
||||
/* Function run before every test */
|
||||
@@ -17,31 +23,34 @@ void tearDown(void)
|
||||
lv_obj_clean(lv_screen_active());
|
||||
}
|
||||
|
||||
static lv_obj_t * canvas_create(void)
|
||||
static void on_canvas_delete(lv_event_t * e)
|
||||
{
|
||||
lv_obj_t * canvas = lv_event_get_current_target(e);
|
||||
lv_draw_buf_t * draw_buf = lv_canvas_get_draw_buf(canvas);
|
||||
TEST_ASSERT_NOT_NULL(draw_buf);
|
||||
lv_draw_buf_destroy(draw_buf);
|
||||
}
|
||||
|
||||
static lv_obj_t * canvas_create(uint32_t w, uint32_t h)
|
||||
{
|
||||
lv_obj_t * canvas = lv_canvas_create(lv_screen_active());
|
||||
lv_obj_set_size(canvas, 500, 360);
|
||||
lv_obj_set_size(canvas, w, h);
|
||||
|
||||
lv_draw_buf_t * draw_buf = lv_draw_buf_create(500, 360, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO);
|
||||
lv_draw_buf_t * draw_buf = lv_draw_buf_create(w, h, LV_COLOR_FORMAT_ARGB8888, LV_STRIDE_AUTO);
|
||||
lv_draw_buf_clear(draw_buf, NULL);
|
||||
lv_canvas_set_draw_buf(canvas, draw_buf);
|
||||
|
||||
lv_obj_add_event_cb(canvas, on_canvas_delete, LV_EVENT_DELETE, NULL);
|
||||
return canvas;
|
||||
}
|
||||
|
||||
static void canvas_destroy(lv_obj_t * canvas)
|
||||
{
|
||||
lv_draw_buf_destroy(lv_canvas_get_draw_buf(canvas));
|
||||
lv_obj_delete(canvas);
|
||||
}
|
||||
|
||||
void test_draw_sin_wave(void)
|
||||
{
|
||||
const char * string = "lol~ I'm wavvvvvvving~";
|
||||
const uint32_t string_len = lv_strlen(string);
|
||||
|
||||
LV_FONT_DECLARE(test_font_montserrat_ascii_4bpp);
|
||||
lv_obj_t * canvas = canvas_create();
|
||||
lv_obj_t * canvas = canvas_create(500, 360);
|
||||
|
||||
lv_layer_t layer;
|
||||
lv_canvas_init_layer(canvas, &layer);
|
||||
@@ -97,11 +106,89 @@ void test_draw_sin_wave(void)
|
||||
|
||||
lv_canvas_finish_layer(canvas, &layer);
|
||||
|
||||
#ifndef NON_AMD64_BUILD
|
||||
TEST_ASSERT_EQUAL_SCREENSHOT("draw/letter_0.png");
|
||||
#endif
|
||||
TEST_ASSERT_EQUAL_LETTER_SCREENSHOT("draw/letter_0.png");
|
||||
|
||||
canvas_destroy(canvas);
|
||||
lv_obj_delete(canvas);
|
||||
}
|
||||
|
||||
static void draw_letter_with_rotation(lv_obj_t * canvas, lv_layer_t * layer, uint32_t unicode, int32_t rotation,
|
||||
int32_t x, int32_t y)
|
||||
{
|
||||
lv_draw_letter_dsc_t letter_dsc;
|
||||
lv_draw_letter_dsc_init(&letter_dsc);
|
||||
letter_dsc.color = lv_color_hex(0xff0000);
|
||||
letter_dsc.font = lv_obj_get_style_text_font(canvas, 0);
|
||||
letter_dsc.unicode = unicode;
|
||||
letter_dsc.rotation = rotation;
|
||||
lv_draw_letter(layer, &letter_dsc, &(lv_point_t) {
|
||||
.x = x, .y = y
|
||||
});
|
||||
}
|
||||
|
||||
static void test_draw_letter(lv_freetype_font_render_mode_t render_mode, uint32_t unicode, int32_t rotation,
|
||||
const char * ref_img_path)
|
||||
{
|
||||
lv_obj_t * canvas = canvas_create(240, 240);
|
||||
|
||||
lv_font_t * font_normal = lv_freetype_font_create("./src/test_files/fonts/noto/NotoSansSC-Regular.ttf",
|
||||
render_mode,
|
||||
80,
|
||||
LV_FREETYPE_FONT_STYLE_NORMAL);
|
||||
TEST_ASSERT_NOT_NULL(font_normal);
|
||||
lv_obj_set_style_text_font(canvas, font_normal, 0);
|
||||
|
||||
lv_layer_t layer;
|
||||
lv_canvas_init_layer(canvas, &layer);
|
||||
lv_canvas_fill_bg(canvas, lv_color_white(), LV_OPA_COVER);
|
||||
|
||||
/* drawing letter with clipping */
|
||||
lv_area_t clip_area;
|
||||
lv_area_set(&clip_area, 40, 40, 200 - 1, 200 - 1);
|
||||
layer._clip_area = clip_area;
|
||||
|
||||
const int32_t offset_x = 40;
|
||||
const int32_t offset_y = 70;
|
||||
|
||||
for(int i = 0; i < 9; i++) {
|
||||
draw_letter_with_rotation(canvas, &layer, unicode, rotation, (i % 3) * 80 + offset_x, (i / 3) * 80 + offset_y);
|
||||
}
|
||||
|
||||
lv_draw_border_dsc_t draw_border_dsc;
|
||||
lv_draw_border_dsc_init(&draw_border_dsc);
|
||||
draw_border_dsc.width = 1;
|
||||
draw_border_dsc.color = lv_color_black();
|
||||
lv_draw_border(&layer, &draw_border_dsc, &clip_area);
|
||||
|
||||
lv_canvas_finish_layer(canvas, &layer);
|
||||
|
||||
TEST_ASSERT_EQUAL_LETTER_SCREENSHOT(ref_img_path);
|
||||
|
||||
lv_obj_delete(canvas);
|
||||
lv_freetype_font_delete(font_normal);
|
||||
}
|
||||
|
||||
void test_draw_letter_bitmap(void)
|
||||
{
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'A', 0, "draw/letter_bitmap_A_rotated_0.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'A', 450, "draw/letter_bitmap_A_rotated_45.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'A', 900, "draw/letter_bitmap_A_rotated_90.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'A', 1800, "draw/letter_bitmap_A_rotated_180.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'g', 0, "draw/letter_bitmap_g_rotated_0.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'g', 450, "draw/letter_bitmap_g_rotated_45.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'g', 900, "draw/letter_bitmap_g_rotated_90.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_BITMAP, 'g', 1800, "draw/letter_bitmap_g_rotated_180.png");
|
||||
}
|
||||
|
||||
void test_draw_letter_outline(void)
|
||||
{
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'A', 0, "draw/letter_outline_A_rotated_0.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'A', 450, "draw/letter_outline_A_rotated_45.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'A', 900, "draw/letter_outline_A_rotated_90.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'A', 1800, "draw/letter_outline_A_rotated_180.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'g', 0, "draw/letter_outline_g_rotated_0.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'g', 450, "draw/letter_outline_g_rotated_45.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'g', 900, "draw/letter_outline_g_rotated_90.png");
|
||||
test_draw_letter(LV_FREETYPE_FONT_RENDER_MODE_OUTLINE, 'g', 1800, "draw/letter_outline_g_rotated_180.png");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||