feat(libs): add SVG rendering support (#6845)

Signed-off-by: zhangjipeng <zhangjipeng@xiaomi.com>
Co-authored-by: zhangjipeng <zhangjipeng@xiaomi.com>
This commit is contained in:
Zhang Ji Peng 2024-10-15 21:33:27 +08:00 committed by GitHub
parent 58243733d8
commit bbe5f032e6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
106 changed files with 8212 additions and 1 deletions

View File

@ -1299,6 +1299,14 @@ menu "LVGL configuration"
bool "Decode whole image to RAM for bin decoder"
default n
config LV_USE_SVG
bool "SVG library"
depends on LV_USE_VECTOR_GRAPHIC
config LV_USE_SVG_ANIMATION
bool "SVG animation"
depends on LV_USE_SVG
config LV_USE_RLE
bool "LVGL's version of RLE compression method"

49
docs/libs/svg.rst Normal file
View File

@ -0,0 +1,49 @@
.. _svg:
==============
SVG support
==============
Scalable Vector Graphics (SVG) Tiny 1.2 support in LVGL.
Detailed introduction: https://www.w3.org/TR/SVGTiny12/
Usage
-----
Enable :c:macro:`LV_USE_SVG` in ``lv_conf.h``.
See the examples below.
If you need support SVG animation attribute parsing,
you can enable :c:macro:`LV_USE_SVG_ANIMATION` in ``lv_conf.h``.
.. _svg_example:
Example
-------
.. include:: ../examples/libs/svg/index.rst
.. code:: c
lv_svg_node_t * svg_doc;
const char* svg_data = "<svg><rect x=\"0\" y=\"0\" width=\"100\" height=\"100\"/></svg>";
/* Create an SVG DOM tree*/
svg_doc = lv_svg_load_data(svg_data, svg_len);
...
/* Draw SVG image*/
lv_draw_svg(layer, svg_doc);
...
/* Release the DOM tree*/
lv_svg_node_delete(svg_doc);
.. _svg_api:
API
---

View File

@ -25,6 +25,7 @@ extern "C" {
#include "tjpgd/lv_example_tjpgd.h"
#include "libjpeg_turbo/lv_example_libjpeg_turbo.h"
#include "tiny_ttf/lv_example_tiny_ttf.h"
#include "svg/lv_example_svg.h"
/*********************
* DEFINES

View File

@ -0,0 +1,6 @@
Load and render SVG data
---------------------------------------
.. lv_example:: libs/svg/lv_example_svg_1
:language: c

View File

@ -0,0 +1,38 @@
/**
* @file lv_example_svg.h
*
*/
#ifndef LV_EXAMPLE_SVG_H
#define LV_EXAMPLE_SVG_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_example_svg_1(void);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_EXAMPLE_SVG_H*/

View File

@ -0,0 +1,36 @@
#include "../../lv_examples.h"
#if LV_BUILD_EXAMPLES
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
/**
* Load an SVG data
*/
static void event_cb(lv_event_t * e)
{
static char svg_data[] = "<svg width=\"12cm\" height=\"4cm\" viewBox=\"0 0 1200 400\">"
"<circle cx=\"600\" cy=\"200\" r=\"100\" fill=\"red\" stroke=\"blue\" stroke-width=\"10\"/></svg>";
lv_layer_t * layer = lv_event_get_layer(e);
lv_svg_node_t * svg = lv_svg_load_data(svg_data, sizeof(svg_data) / sizeof(char));
lv_draw_svg(layer, svg);
lv_svg_node_delete(svg);
}
void lv_example_svg_1(void)
{
lv_obj_add_event_cb(lv_screen_active(), event_cb, LV_EVENT_DRAW_MAIN, NULL);
}
#else
void lv_example_svg_1(void)
{
/*TODO
*fallback for online examples*/
lv_obj_t * label = lv_label_create(lv_screen_active());
lv_label_set_text(label, "SVG is not enabled");
lv_obj_center(label);
}
#endif
#endif

View File

@ -907,6 +907,11 @@
/** Use external LZ4 library */
#define LV_USE_LZ4_EXTERNAL 0
/*SVG library*/
#define LV_USE_SVG 0
#define LV_USE_SVG_ANIMATION 0
#define LV_USE_SVG_DEBUG 0
/** FFmpeg library for image decoding and playing videos.
* Supports all major image formats so do not enable other image decoder with it. */
#define LV_USE_FFMPEG 0

5
lvgl.h
View File

@ -35,7 +35,8 @@ extern "C" {
#include "src/misc/lv_utils.h"
#include "src/misc/lv_iter.h"
#include "src/misc/lv_circle_buf.h"
#include "src/misc/lv_tree.h"
#include "src/tick/lv_tick.h"
#include "src/core/lv_obj.h"
@ -106,6 +107,8 @@ extern "C" {
#include "src/libs/rlottie/lv_rlottie.h"
#include "src/libs/ffmpeg/lv_ffmpeg.h"
#include "src/libs/tiny_ttf/lv_tiny_ttf.h"
#include "src/libs/svg/lv_svg.h"
#include "src/libs/svg/lv_svg_render.h"
#include "src/layouts/lv_layout.h"

125
src/libs/svg/lv_svg.c Normal file
View File

@ -0,0 +1,125 @@
/**
* @file lv_svg.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_svg.h"
#if LV_USE_SVG
#include "../../misc/lv_assert.h"
#include "../../misc/lv_log.h"
#include "../../stdlib/lv_mem.h"
#include "lv_svg_token.h"
#include "lv_svg_parser.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_svg_node_constructor(const lv_tree_class_t * class_p, lv_tree_node_t * node)
{
LV_UNUSED(class_p);
lv_svg_node_t * t = (lv_svg_node_t *)node;
t->xml_id = NULL;
t->type = LV_SVG_TAG_INVALID;
lv_array_init(&t->attrs, 4, sizeof(lv_svg_attr_t));
t->render_obj = NULL;
}
static void lv_svg_node_destructor(const lv_tree_class_t * class_p, lv_tree_node_t * node)
{
LV_UNUSED(class_p);
lv_svg_node_t * t = (lv_svg_node_t *)node;
if(t->xml_id) {
lv_free(t->xml_id);
}
for(uint32_t i = 0; i < lv_array_size(&t->attrs); i++) {
lv_svg_attr_t * attr = lv_array_at(&t->attrs, i);
if(attr->val_type == LV_SVG_ATTR_VALUE_PTR) {
lv_free(attr->value.val);
}
}
lv_array_deinit(&t->attrs);
}
static bool svg_token_process_cb(_lv_svg_token_t * token, void * data)
{
_lv_svg_parser_t * parser = (_lv_svg_parser_t *)data;
return _lv_svg_parser_token(parser, token);
}
/**********************
* STATIC VARIABLES
**********************/
const lv_tree_class_t lv_svg_node_class = {
.base_class = &lv_tree_node_class,
.instance_size = sizeof(lv_svg_node_t),
.constructor_cb = lv_svg_node_constructor,
.destructor_cb = lv_svg_node_destructor,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_svg_node_t * lv_svg_load_data(const char * svg_data, uint32_t data_len)
{
LV_ASSERT_NULL(svg_data);
LV_ASSERT(data_len > 0);
_lv_svg_parser_t parser;
_lv_svg_parser_init(&parser);
if(_lv_svg_tokenizer(svg_data, data_len, svg_token_process_cb, &parser)) {
if(_lv_svg_parser_is_finish(&parser)) {
lv_svg_node_t * doc = parser.doc_root;
parser.doc_root = NULL;
_lv_svg_parser_deinit(&parser);
#if LV_USE_SVG_DEBUG
_lv_svg_dump_tree(doc, 0);
#endif
return doc;
}
else {
_lv_svg_parser_deinit(&parser);
LV_LOG_ERROR("svg document parser raise errors!");
return NULL;
}
}
else {
_lv_svg_parser_deinit(&parser);
LV_LOG_ERROR("svg document tokenizer raise errors!");
return NULL;
}
}
lv_svg_node_t * lv_svg_node_create(lv_svg_node_t * parent)
{
lv_tree_node_t * node = lv_tree_node_create(&lv_svg_node_class, (lv_tree_node_t *)parent);
return (lv_svg_node_t *)node;
}
void lv_svg_node_delete(lv_svg_node_t * node)
{
LV_ASSERT_NULL(node);
lv_tree_node_delete((lv_tree_node_t *)node);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_SVG*/

334
src/libs/svg/lv_svg.h Normal file
View File

@ -0,0 +1,334 @@
/**
* @file lv_svg.h
*
*/
#ifndef LV_SVG_H
#define LV_SVG_H
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_SVG
#include "../../misc/lv_array.h"
#include "../../misc/lv_tree.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
enum {
LV_SVG_TAG_INVALID = -1,
LV_SVG_TAG_CONTENT,
LV_SVG_TAG_SVG,
LV_SVG_TAG_USE,
LV_SVG_TAG_G,
LV_SVG_TAG_PATH,
LV_SVG_TAG_RECT,
LV_SVG_TAG_CIRCLE,
LV_SVG_TAG_ELLIPSE,
LV_SVG_TAG_LINE,
LV_SVG_TAG_POLYLINE,
LV_SVG_TAG_POLYGON,
LV_SVG_TAG_SOLID_COLOR,
LV_SVG_TAG_LINEAR_GRADIENT,
LV_SVG_TAG_RADIAL_GRADIENT,
LV_SVG_TAG_STOP,
LV_SVG_TAG_DEFS,
LV_SVG_TAG_IMAGE,
#if LV_USE_SVG_ANIMATION
LV_SVG_TAG_MPATH,
LV_SVG_TAG_SET,
LV_SVG_TAG_ANIMATE,
LV_SVG_TAG_ANIMATE_COLOR,
LV_SVG_TAG_ANIMATE_TRANSFORM,
LV_SVG_TAG_ANIMATE_MOTION,
#endif
LV_SVG_TAG_TEXT,
LV_SVG_TAG_TSPAN,
LV_SVG_TAG_TEXT_AREA,
};
typedef int8_t lv_svg_tag_t;
enum {
LV_SVG_ATTR_INVALID = 0,
LV_SVG_ATTR_ID,
LV_SVG_ATTR_XML_ID,
LV_SVG_ATTR_VERSION,
LV_SVG_ATTR_BASE_PROFILE,
LV_SVG_ATTR_VIEWBOX,
LV_SVG_ATTR_PRESERVE_ASPECT_RATIO,
LV_SVG_ATTR_VIEWPORT_FILL,
LV_SVG_ATTR_VIEWPORT_FILL_OPACITY,
LV_SVG_ATTR_DISPLAY,
LV_SVG_ATTR_VISIBILITY,
LV_SVG_ATTR_X,
LV_SVG_ATTR_Y,
LV_SVG_ATTR_WIDTH,
LV_SVG_ATTR_HEIGHT,
LV_SVG_ATTR_RX,
LV_SVG_ATTR_RY,
LV_SVG_ATTR_CX,
LV_SVG_ATTR_CY,
LV_SVG_ATTR_R,
LV_SVG_ATTR_X1,
LV_SVG_ATTR_Y1,
LV_SVG_ATTR_X2,
LV_SVG_ATTR_Y2,
LV_SVG_ATTR_POINTS,
LV_SVG_ATTR_D,
LV_SVG_ATTR_PATH_LENGTH,
LV_SVG_ATTR_XLINK_HREF,
LV_SVG_ATTR_FILL,
LV_SVG_ATTR_FILL_RULE,
LV_SVG_ATTR_FILL_OPACITY,
LV_SVG_ATTR_STROKE,
LV_SVG_ATTR_STROKE_WIDTH,
LV_SVG_ATTR_STROKE_LINECAP,
LV_SVG_ATTR_STROKE_LINEJOIN,
LV_SVG_ATTR_STROKE_MITER_LIMIT,
LV_SVG_ATTR_STROKE_DASH_ARRAY,
LV_SVG_ATTR_STROKE_DASH_OFFSET,
LV_SVG_ATTR_STROKE_OPACITY,
LV_SVG_ATTR_OPACITY,
LV_SVG_ATTR_SOLID_COLOR,
LV_SVG_ATTR_SOLID_OPACITY,
LV_SVG_ATTR_GRADIENT_UNITS,
LV_SVG_ATTR_GRADIENT_STOP_OFFSET,
LV_SVG_ATTR_GRADIENT_STOP_COLOR,
LV_SVG_ATTR_GRADIENT_STOP_OPACITY,
LV_SVG_ATTR_FONT_FAMILY,
LV_SVG_ATTR_FONT_STYLE,
LV_SVG_ATTR_FONT_VARIANT,
LV_SVG_ATTR_FONT_WEIGHT,
LV_SVG_ATTR_FONT_SIZE,
LV_SVG_ATTR_TRANSFORM,
LV_SVG_ATTR_TEXT_ANCHOR,
#if LV_USE_SVG_ANIMATION
LV_SVG_ATTR_ATTRIBUTE_NAME,
LV_SVG_ATTR_ATTRIBUTE_TYPE,
LV_SVG_ATTR_BEGIN,
LV_SVG_ATTR_END,
LV_SVG_ATTR_DUR,
LV_SVG_ATTR_MIN,
LV_SVG_ATTR_MAX,
LV_SVG_ATTR_RESTART,
LV_SVG_ATTR_REPEAT_COUNT,
LV_SVG_ATTR_REPEAT_DUR,
LV_SVG_ATTR_CALC_MODE,
LV_SVG_ATTR_VALUES,
LV_SVG_ATTR_KEY_TIMES,
LV_SVG_ATTR_KEY_SPLINES,
LV_SVG_ATTR_KEY_POINTS,
LV_SVG_ATTR_FROM,
LV_SVG_ATTR_TO,
LV_SVG_ATTR_BY,
LV_SVG_ATTR_ADDITIVE,
LV_SVG_ATTR_ACCUMULATE,
LV_SVG_ATTR_PATH,
LV_SVG_ATTR_ROTATE,
LV_SVG_ATTR_TRANSFORM_TYPE,
#endif
};
typedef uint8_t lv_svg_attr_type_t;
enum {
LV_SVG_TRANSFORM_TYPE_MATRIX = 1,
LV_SVG_TRANSFORM_TYPE_TRANSLATE,
LV_SVG_TRANSFORM_TYPE_ROTATE,
LV_SVG_TRANSFORM_TYPE_SCALE,
LV_SVG_TRANSFORM_TYPE_SKEW_X,
LV_SVG_TRANSFORM_TYPE_SKEW_Y,
};
typedef uint8_t lv_svg_transform_type_t;
#if LV_USE_SVG_ANIMATION
enum {
LV_SVG_ANIM_REMOVE = 0,
LV_SVG_ANIM_FREEZE,
};
enum {
LV_SVG_ANIM_RESTART_ALWAYS = 0,
LV_SVG_ANIM_RESTART_WHEN_NOT_ACTIVE,
LV_SVG_ANIM_RESTART_NEVER,
};
enum {
LV_SVG_ANIM_CALC_MODE_LINEAR = 0,
LV_SVG_ANIM_CALC_MODE_PACED,
LV_SVG_ANIM_CALC_MODE_SPLINE,
LV_SVG_ANIM_CALC_MODE_DISCRETE,
};
enum {
LV_SVG_ANIM_ADDITIVE_REPLACE = 0,
LV_SVG_ANIM_ADDITIVE_SUM,
};
enum {
LV_SVG_ANIM_ACCUMULATE_NONE = 0,
LV_SVG_ANIM_ACCUMULATE_SUM,
};
#endif
enum {
LV_SVG_ASPECT_RATIO_NONE = 0,
LV_SVG_ASPECT_RATIO_XMIN_YMIN = (1 << 1),
LV_SVG_ASPECT_RATIO_XMID_YMIN = (2 << 1),
LV_SVG_ASPECT_RATIO_XMAX_YMIN = (3 << 1),
LV_SVG_ASPECT_RATIO_XMIN_YMID = (4 << 1),
LV_SVG_ASPECT_RATIO_XMID_YMID = (5 << 1),
LV_SVG_ASPECT_RATIO_XMAX_YMID = (6 << 1),
LV_SVG_ASPECT_RATIO_XMIN_YMAX = (7 << 1),
LV_SVG_ASPECT_RATIO_XMID_YMAX = (8 << 1),
LV_SVG_ASPECT_RATIO_XMAX_YMAX = (9 << 1),
};
enum {
LV_SVG_ASPECT_RATIO_OPT_MEET = 0,
LV_SVG_ASPECT_RATIO_OPT_SLICE,
};
typedef uint32_t lv_svg_aspect_ratio_t;
typedef struct {
float x;
float y;
} lv_svg_point_t;
typedef struct {
float m[3][3];
} lv_svg_matrix_t;
typedef uint32_t lv_svg_color_t;
enum {
LV_SVG_FILL_NONZERO = 0,
LV_SVG_FILL_EVENODD,
};
typedef uint8_t lv_svg_fill_rule_t;
enum {
LV_SVG_LINE_CAP_BUTT = 0,
LV_SVG_LINE_CAP_SQUARE,
LV_SVG_LINE_CAP_ROUND,
};
typedef uint8_t lv_svg_line_cap_t;
enum {
LV_SVG_LINE_JOIN_MITER = 0,
LV_SVG_LINE_JOIN_BEVEL,
LV_SVG_LINE_JOIN_ROUND,
};
typedef uint8_t lv_svg_line_join_t;
enum {
LV_SVG_GRADIENT_UNITS_OBJECT = 0,
LV_SVG_GRADIENT_UNITS_USER_SPACE,
};
typedef uint8_t lv_svg_gradient_units_t;
typedef union {
int32_t ival;
uint32_t uval;
float fval;
char * sval;
void * val;
} lv_svg_attr_value_t;
/*
* to simplify list buffer management, allocate enough memory for all data and length.
* | size | data[0] | data[1] | data[2] | ... |
*/
typedef struct {
uint32_t length;
uint8_t data[1];
} lv_svg_attr_values_list_t;
/* https://www.w3.org/TR/SVGTiny12/svgudomidl.html */
enum {
LV_SVG_PATH_CMD_MOVE_TO = 77,
LV_SVG_PATH_CMD_LINE_TO = 76,
LV_SVG_PATH_CMD_CURVE_TO = 67,
LV_SVG_PATH_CMD_QUAD_TO = 81,
LV_SVG_PATH_CMD_CLOSE = 90,
};
/*
* to simplify list buffer management, allocate enough memory for all path data and cmd.
* | cmd | data[0] | data[1] | data[2] | ... |
*/
typedef struct {
uint32_t cmd;
uint8_t data[1];
} lv_svg_attr_path_value_t;
enum {
LV_SVG_ATTR_VALUE_DATA = 0,
LV_SVG_ATTR_VALUE_PTR,
};
typedef uint8_t lv_svg_attr_value_type_t;
enum {
LV_SVG_ATTR_VALUE_NONE = 0,
LV_SVG_ATTR_VALUE_INITIAL,
LV_SVG_ATTR_VALUE_INHERIT,
};
typedef uint8_t lv_svg_attr_value_class_t;
typedef struct {
lv_svg_attr_type_t id;
lv_svg_attr_value_type_t val_type;
lv_svg_attr_value_class_t class_type;
lv_svg_attr_value_t value;
} lv_svg_attr_t;
struct _lv_svg_render_obj;
typedef struct {
lv_tree_node_t base;
char * xml_id; /* xml_id or content */
lv_svg_tag_t type;
lv_array_t attrs;
struct _lv_svg_render_obj * render_obj;
} lv_svg_node_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Loading SVG data and creating the DOM tree
* @param svg_data pointer to the SVG data
* @param data_len the SVG data length
*/
lv_svg_node_t * lv_svg_load_data(const char * svg_data, uint32_t data_len);
/**
* @brief Create an SVG DOM node
* @param parent pointer to the parent node
* @return true: an new SVG DOM node, false: NULL
*/
lv_svg_node_t * lv_svg_node_create(lv_svg_node_t * parent);
/**
* @brief Delete an SVG DOM subtree
* @param node pointer to an SVG DOM subtree
*/
void lv_svg_node_delete(lv_svg_node_t * node);
/**********************
* MACROS
**********************/
#define LV_SVG_NODE_CHILD(n, i) \
((lv_svg_node_t *)(LV_TREE_NODE((n))->children[i]))
#define LV_SVG_NODE(n) ((lv_svg_node_t*)(n))
#endif /*LV_USE_SVG*/
#endif /*LV_SVG_H*/

2309
src/libs/svg/lv_svg_parser.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,84 @@
/**
* @file lv_svg_parser.h
*
*/
#ifndef LV_SVG_PARSER_H
#define LV_SVG_PARSER_H
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_SVG
#include "lv_svg.h"
#include "lv_svg_token.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef enum {
LV_SVG_PARSER_PROCESS = 0,
LV_SVG_PARSER_IGNORE,
} _lv_svg_parser_state_t;
typedef struct {
uint16_t state;
char * ignore_name;
uint32_t ignore_len;
int32_t dpi;
lv_svg_node_t * doc_root;
lv_svg_node_t * cur_node;
} _lv_svg_parser_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Initialize the SVG parser
* @param parser pointer to a parser object
*/
void _lv_svg_parser_init(_lv_svg_parser_t * parser);
/**
* @brief Deinitialize the SVG parser
* @param parser pointer to a parser object
*/
void _lv_svg_parser_deinit(_lv_svg_parser_t * parser);
/**
* @brief Parse an SVG document
* @param parser pointer to a parser object
* @param token pointer to a token object
* @return true: the parsing is finished, false: the parsing is not finished yet.
*/
bool _lv_svg_parser_token(_lv_svg_parser_t * parser, const _lv_svg_token_t * token);
/**
* @brief Check if the parsing is finished
* @param parser pointer to a parser object
* @return true: the parsing is finished, false: the parsing is not finished yet.
*/
bool _lv_svg_parser_is_finish(_lv_svg_parser_t * parser);
/**
* @brief Dump the SVG tree
* @param root pointer to the root of the SVG tree
* @param depth the depth of the current node in the tree
*/
void _lv_svg_dump_tree(lv_svg_node_t * root, int depth);
/**********************
* MACROS
**********************/
#endif /*LV_USE_SVG*/
#endif /*LV_SVG_PARSER_H*/

2204
src/libs/svg/lv_svg_render.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,98 @@
/**
* @file lv_svg_render.h
*
*/
#ifndef LV_SVG_RENDER_H
#define LV_SVG_RENDER_H
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_SVG && LV_USE_VECTOR_GRAPHIC
#include "lv_svg.h"
#include "../../misc/lv_types.h"
#include "../../draw/lv_draw_vector_private.h"
/*********************
* DEFINES
*********************/
#define LV_SVG_RENDER_OBJ(n) ((lv_svg_render_obj_t*)(n))
/**********************
* TYPEDEFS
**********************/
typedef struct _lv_svg_render_obj {
struct _lv_svg_render_obj * next;
uint32_t flags;
char * id;
lv_vector_draw_dsc_t dsc;
lv_matrix_t matrix;
/* for url(XXX) reference */
struct _lv_svg_render_obj * head;
char * fill_ref;
char * stroke_ref;
void (*set_paint_ref)(struct _lv_svg_render_obj * obj, lv_vector_draw_dsc_t * dsc,
const struct _lv_svg_render_obj * target_obj, bool fill);
void (*init)(struct _lv_svg_render_obj * obj, const lv_svg_node_t * node);
void (*render)(const struct _lv_svg_render_obj * obj, lv_vector_dsc_t * dsc, const lv_matrix_t * matrix);
void (*set_attr)(struct _lv_svg_render_obj * obj, lv_vector_draw_dsc_t * dsc, const lv_svg_attr_t * attr);
void (*get_bounds)(const struct _lv_svg_render_obj * obj, lv_area_t * area);
void (*destroy)(struct _lv_svg_render_obj * obj);
} lv_svg_render_obj_t;
typedef struct _lv_svg_render_hal {
void (*load_image)(const char * image_url, lv_draw_image_dsc_t * img_dsc);
const char * (*get_font_path)(const char * font_family);
} lv_svg_render_hal_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Initialize the SVG render
* @param hal pointer to a structure with rendering functions
*/
void lv_svg_render_init(const lv_svg_render_hal_t * hal);
/**
* @brief Create a new SVG render from an SVG document
* @param svg_doc pointer to the SVG document
* @return pointer to the new SVG render object
*/
lv_svg_render_obj_t * lv_svg_render_create(const lv_svg_node_t * svg_doc);
/**
* @brief Delete an SVG render object
* @param render pointer to the SVG render object to delete
*/
void lv_svg_render_delete(lv_svg_render_obj_t * render);
/**
* @brief Render an SVG object to a vector graphics
* @param dsc pointer to the vector graphics descriptor
* @param render pointer to the SVG render object to render
*/
void lv_draw_svg_render(lv_vector_dsc_t * dsc, const lv_svg_render_obj_t * render);
/**
* @brief Draw an SVG document to a layer
* @param layer pointer to the target layer
* @param svg_doc pointer to the SVG document to draw
*/
void lv_draw_svg(lv_layer_t * layer, const lv_svg_node_t * svg_doc);
/**********************
* MACROS
**********************/
#endif /*LV_USE_SVG*/
#endif /*LV_SVG_RENDER_H*/

483
src/libs/svg/lv_svg_token.c Normal file
View File

@ -0,0 +1,483 @@
/**
* @file lv_svg_token.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_svg_token.h"
#if LV_USE_SVG
#include "../../../lvgl.h"
#include <ctype.h>
#include <string.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/*
* tag mask quote mask tag search comment doc type xml inst
* | 0 0 0 | 0 0 | 0 | 0 | 0 | 0 | 0 |
*/
enum {
SVG_TAG_MASK = (1 << 3) - 1,
SVG_QUOTE_MASK = (1 << 5) - (1 << 3),
SVG_TAG = 1 << 5,
SVG_SEARCH = 1 << 6,
SVG_COMMENT = 1 << 7,
SVG_DOCTYPE = 1 << 8,
SVG_XMLINST = 1 << 9,
};
typedef uint32_t _lv_svg_parser_bits_t;
enum {
SVG_NO_QUOTE = 0,
SVG_SINGLE_QUOTE = 1,
SVG_DOUBLE_QUOTE = 2,
};
typedef uint32_t _lv_svg_parser_quote_t;
enum {
SVG_NO_TAG = 0,
SVG_TAG_NAME = 1,
SVG_ATTR_START = 2,
SVG_ATTR_NAME = 3,
SVG_SEARCH_EQUAL = 4,
SVG_SEARCH_VALUE = 5,
SVG_QUOTE_VALUE = 6,
SVG_VALUE = 7,
};
typedef uint32_t _lv_svg_parser_tag_state_t;
typedef struct {
uint32_t flags;
const char * cur;
const char * end;
} _lv_svg_parser_state_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void _set_state(_lv_svg_parser_state_t * state, uint32_t bit)
{
state->flags |= bit;
}
static void _clear_state(_lv_svg_parser_state_t * state, uint32_t bit)
{
state->flags &= ~bit;
}
static bool _is_state(_lv_svg_parser_state_t * state, uint32_t bit)
{
return state->flags & bit;
}
static void _set_tag_state(_lv_svg_parser_state_t * state, uint32_t bit)
{
state->flags = (state->flags & ~SVG_TAG_MASK) | bit;
}
static void _set_quote_state(_lv_svg_parser_state_t * state, uint32_t bit)
{
state->flags = (state->flags & ~SVG_QUOTE_MASK) | (bit << 3);
}
static bool _special_handle(_lv_svg_parser_state_t * state)
{
return state->flags & (SVG_TAG | SVG_SEARCH | SVG_TAG_MASK | SVG_COMMENT | SVG_DOCTYPE | SVG_XMLINST);
}
static void _lv_svg_token_init(_lv_svg_token_t * token)
{
token->start = NULL;
token->end = NULL;
token->type = LV_SVG_TOKEN_CONTENT;
token->flat = false;
token->cur_attr = NULL;
lv_array_init(&token->attrs, LV_ARRAY_DEFAULT_CAPACITY, sizeof(_lv_svg_token_attr_t));
}
static void _lv_svg_token_reset(_lv_svg_token_t * token)
{
token->start = NULL;
token->end = NULL;
token->type = LV_SVG_TOKEN_CONTENT;
token->flat = false;
token->cur_attr = NULL;
lv_array_clear(&token->attrs);
}
static bool _lv_svg_token_process(_lv_svg_token_t * token, svg_token_process cb, void * data)
{
if(!token->start || SVG_TOKEN_LEN(token) == 0)
return true;
bool ret = cb(token, data);
_lv_svg_token_reset(token);
return ret;
}
static _lv_svg_token_attr_t * _new_svg_attr(_lv_svg_token_t * token)
{
if((lv_array_size(&token->attrs) + 1) > lv_array_capacity(&token->attrs)) {
lv_array_resize(&token->attrs, token->attrs.capacity << 1);
}
token->attrs.size++;
_lv_svg_token_attr_t * attr = lv_array_at(&token->attrs, token->attrs.size - 1);
lv_memset(attr, 0, sizeof(_lv_svg_token_attr_t));
return attr;
}
static void _svg_parser_xml_inst(_lv_svg_parser_state_t * state, _lv_svg_token_t * token)
{
LV_UNUSED(token);
while(state->cur <= state->end) {
char ch = *(state->cur);
if(ch == '>' && (*(state->cur - 1)) == '?') {
_clear_state(state, SVG_XMLINST);
state->cur++;
break;
}
state->cur++;
}
}
static void _svg_parser_comment(_lv_svg_parser_state_t * state, _lv_svg_token_t * token)
{
LV_UNUSED(token);
while(state->cur <= state->end) {
char ch = *(state->cur);
if(ch == '>' && (*(state->cur - 1)) == '-' && (*(state->cur - 2)) == '-') {
_clear_state(state, SVG_COMMENT);
state->cur++;
break;
}
state->cur++;
}
}
static void _svg_parser_doctype(_lv_svg_parser_state_t * state, _lv_svg_token_t * token)
{
LV_UNUSED(token);
//TODO: processing DTD type
while(state->cur <= state->end) {
char ch = *(state->cur);
if(ch == '>') {
_clear_state(state, SVG_DOCTYPE);
state->cur++;
break;
}
state->cur++;
}
}
static bool _svg_parser_tag(_lv_svg_parser_state_t * state, _lv_svg_token_t * token, svg_token_process cb, void * data)
{
while(state->cur <= state->end) {
switch(state->flags & SVG_TAG_MASK) {
case SVG_NO_TAG: {
if(!_lv_svg_token_process(token, cb, data)) {
return false;
}
state->cur++;
}
return true;
case SVG_TAG_NAME: {
char ch = *(state->cur);
if(ch == '/') {
token->type = LV_SVG_TOKEN_END;
state->cur++;
if(!token->start) {
token->start = state->cur;
}
continue;
}
else if(ch == '>' || isspace(ch)) {
token->end = state->cur;
_set_tag_state(state, SVG_ATTR_START);
continue;
}
else {
if(!token->start) {
token->type = LV_SVG_TOKEN_BEGIN;
token->start = state->cur;
}
state->cur++;
continue;
}
}
break;
case SVG_ATTR_START: {
char ch = *(state->cur);
if(!isspace(ch) && ch != '\'' && ch != '\"') {
if(ch == '/') {
token->flat = true;
state->cur++;
continue;
}
if(ch == '>') {
_set_tag_state(state, SVG_NO_TAG);
}
else {
token->cur_attr = NULL;
_set_tag_state(state, SVG_ATTR_NAME);
}
continue;
}
}
break;
case SVG_ATTR_NAME: {
if(!token->cur_attr) {
token->cur_attr = _new_svg_attr(token);
}
char ch = *(state->cur);
if(isspace(ch) || ch == '=' || ch == '/' || ch == '>') {
token->cur_attr->name_end = state->cur;
_set_tag_state(state, SVG_SEARCH_EQUAL);
continue;
}
else {
if(!token->cur_attr->name_start) {
token->cur_attr->name_start = state->cur;
}
state->cur++;
continue;
}
}
break;
case SVG_SEARCH_EQUAL: {
char ch = *(state->cur);
if(!isspace(ch) && ch != '/' && ch != '\'' && ch != '\"') {
if(ch == '=') {
_set_tag_state(state, SVG_SEARCH_VALUE);
}
else {
// attr name has empty value
token->cur_attr = NULL;
_set_tag_state(state, SVG_ATTR_START);
continue;
}
}
}
break;
case SVG_SEARCH_VALUE: {
char ch = *(state->cur);
if(!isspace(ch)) {
if(ch == '\'' || ch == '\"') {
if(ch == '\'') {
_set_quote_state(state, SVG_SINGLE_QUOTE);
}
else {
_set_quote_state(state, SVG_DOUBLE_QUOTE);
}
_set_tag_state(state, SVG_QUOTE_VALUE);
}
else {
_set_tag_state(state, SVG_VALUE);
continue;
}
}
}
break;
case SVG_QUOTE_VALUE: {
char ch = *(state->cur);
if((ch == '\'' && ((state->flags & SVG_QUOTE_MASK) >> 3) == SVG_SINGLE_QUOTE)
|| (ch == '\"' && ((state->flags & SVG_QUOTE_MASK) >> 3) == SVG_DOUBLE_QUOTE)) {
if(!token->cur_attr->value_start) {
token->cur_attr->value_start = state->cur;
}
token->cur_attr->value_end = state->cur;
_set_quote_state(state, SVG_NO_QUOTE);
_set_tag_state(state, SVG_ATTR_START);
continue;
}
else {
if(!token->cur_attr->value_start) {
token->cur_attr->value_start = state->cur;
}
state->cur++;
continue;
}
}
break;
case SVG_VALUE: {
char ch = *(state->cur);
if(isspace(ch) || ch == '>' || ch == '/') {
if(!token->cur_attr->value_start) {
token->cur_attr->value_start = state->cur;
}
token->cur_attr->value_end = state->cur;
_set_quote_state(state, SVG_NO_QUOTE);
_set_tag_state(state, SVG_ATTR_START);
continue;
}
else {
if(!token->cur_attr->value_start) {
token->cur_attr->value_start = state->cur;
}
state->cur++;
continue;
}
}
break;
}
state->cur++;
}
return true;
}
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
bool _lv_svg_tokenizer(const char * svg_data, uint32_t data_len, svg_token_process cb, void * data)
{
LV_ASSERT_NULL(svg_data);
LV_ASSERT(data_len > 0);
LV_ASSERT_NULL(cb);
LV_ASSERT_NULL(data);
_lv_svg_token_t token;
_lv_svg_token_init(&token);
_lv_svg_parser_state_t state = {
.flags = 0,
.cur = svg_data,
.end = svg_data + data_len,
};
while(state.cur <= state.end) {
char ch = *(state.cur);
if(ch == '\r' || ch == '\n') { // skip LR character
state.cur++;
continue;
}
else if(_special_handle(&state)) {
if(_is_state(&state, SVG_TAG)) {
_clear_state(&state, SVG_TAG);
switch(ch) {
case '/': // end tag
_set_tag_state(&state, SVG_TAG_NAME);
break;
case '!': {
// <!-- comment or <!DOCTYPE>
_set_state(&state, SVG_SEARCH); // get more character
state.cur++;
}
break;
case '?': {
// xml instruction
_set_state(&state, SVG_XMLINST);
state.cur++;
}
break;
default: {
if(isalpha(ch)) {
_set_tag_state(&state, SVG_TAG_NAME);
}
else {
LV_LOG_ERROR("svg document parser error!");
lv_array_deinit(&token.attrs);
return false;
}
}
}
// process token
if(!_lv_svg_token_process(&token, cb, data)) {
LV_LOG_ERROR("svg document parser error!");
lv_array_deinit(&token.attrs);
return false;
}
}
else if(_is_state(&state, SVG_SEARCH)) {
if(ch == '-' || isalpha(ch)) {
if(!token.start) {
token.start = state.cur;
}
token.end = state.cur;
}
else {
// processing as a normal tag name.
_clear_state(&state, SVG_SEARCH);
_set_tag_state(&state, SVG_TAG_NAME);
continue;
}
if(((token.end - token.start) == 1) && (token.start[0] == '-') && (token.start[1] == '-')) {
// is <!-- comment start
_clear_state(&state, SVG_SEARCH);
token.start = token.end = NULL;
_set_state(&state, SVG_COMMENT);
}
else if(((token.end - token.start) == 6) && (strncmp(token.start, "DOCTYPE", 7) == 0)) {
_clear_state(&state, SVG_SEARCH);
token.start = token.end = NULL;
_set_state(&state, SVG_DOCTYPE);
}
state.cur++;
}
else if(_is_state(&state, SVG_COMMENT)) {
_svg_parser_comment(&state, &token);
}
else if(_is_state(&state, SVG_DOCTYPE)) {
_svg_parser_doctype(&state, &token);
}
else if(_is_state(&state, SVG_TAG_MASK)) {
if(!_svg_parser_tag(&state, &token, cb, data)) {
LV_LOG_ERROR("svg document parser error!");
lv_array_deinit(&token.attrs);
return false;
}
}
else if(_is_state(&state, SVG_XMLINST)) {
_svg_parser_xml_inst(&state, &token);
}
}
else {
switch(ch) {
case '<': {
_set_state(&state, SVG_TAG); // start a new tag
state.cur++;
}
break;
default: {
if(!token.start) {
token.start = state.cur;
}
if(state.cur == state.end) {
goto finish;
}
token.end = ++state.cur;
}
}
}
}
finish:
lv_array_deinit(&token.attrs);
return true;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_SVG*/

View File

@ -0,0 +1,70 @@
/**
* @file lv_svg_token.h
*
*/
#ifndef LV_SVG_TOKEN_H
#define LV_SVG_TOKEN_H
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_SVG
#include "../../misc/lv_array.h"
/*********************
* DEFINES
*********************/
#define SVG_TOKEN_LEN(t) ((t)->end - (t)->start)
/**********************
* TYPEDEFS
**********************/
typedef enum {
LV_SVG_TOKEN_BEGIN = 0,
LV_SVG_TOKEN_END,
LV_SVG_TOKEN_CONTENT,
} _lv_svg_token_type_t;
typedef struct {
const char * name_start;
const char * name_end;
const char * value_start;
const char * value_end;
} _lv_svg_token_attr_t;
typedef struct {
const char * start;
const char * end;
_lv_svg_token_type_t type;
bool flat;
_lv_svg_token_attr_t * cur_attr;
lv_array_t attrs;
} _lv_svg_token_t;
typedef bool (*svg_token_process)(_lv_svg_token_t * token, void * user_data);
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* @brief Parse SVG data and call a callback for each token
* @param svg_data pointer to SVG data
* @param len length of the SVG data
* @param cb callback function to be called for each token
* @param user_data custom data to be passed to the callback function
* @return true: SVG data successfully parsed, false: error occurred
*/
bool _lv_svg_tokenizer(const char * svg_data, uint32_t len, svg_token_process cb, void * user_data);
/**********************
* MACROS
**********************/
#endif /*LV_USE_SVG*/
#endif /*LV_SVG_TOKEN_H*/

View File

@ -2900,6 +2900,29 @@
#endif
#endif
/*SVG library*/
#ifndef LV_USE_SVG
#ifdef CONFIG_LV_USE_SVG
#define LV_USE_SVG CONFIG_LV_USE_SVG
#else
#define LV_USE_SVG 0
#endif
#endif
#ifndef LV_USE_SVG_ANIMATION
#ifdef CONFIG_LV_USE_SVG_ANIMATION
#define LV_USE_SVG_ANIMATION CONFIG_LV_USE_SVG_ANIMATION
#else
#define LV_USE_SVG_ANIMATION 0
#endif
#endif
#ifndef LV_USE_SVG_DEBUG
#ifdef CONFIG_LV_USE_SVG_DEBUG
#define LV_USE_SVG_DEBUG CONFIG_LV_USE_SVG_DEBUG
#else
#define LV_USE_SVG_DEBUG 0
#endif
#endif
/** FFmpeg library for image decoding and playing videos.
* Supports all major image formats so do not enable other image decoder with it. */
#ifndef LV_USE_FFMPEG

187
src/misc/lv_tree.c Normal file
View File

@ -0,0 +1,187 @@
/**
* @file lv_tree.c
* Tree.
* The nodes are dynamically allocated by the 'lv_mem' module,
*/
/*********************
* INCLUDES
*********************/
#include "lv_tree.h"
#include "../stdlib/lv_mem.h"
#include "../stdlib/lv_string.h"
#include "lv_assert.h"
/*********************
* DEFINES
*********************/
#define INIT_CHILDREN_CAP 4
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
const lv_tree_class_t lv_tree_node_class = {
.base_class = NULL,
.instance_size = sizeof(lv_tree_node_t),
.constructor_cb = NULL,
.destructor_cb = NULL,
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
static void _lv_tree_node_construct(const lv_tree_class_t * class_p, lv_tree_node_t * node)
{
if(node->class_p->base_class) {
const lv_tree_class_t * original_class_p = node->class_p;
node->class_p = node->class_p->base_class;
_lv_tree_node_construct(class_p, node);
node->class_p = original_class_p;
}
if(node->class_p->constructor_cb) node->class_p->constructor_cb(class_p, node);
}
static void _lv_tree_node_destruct(lv_tree_node_t * node)
{
if(node->class_p->destructor_cb) node->class_p->destructor_cb(node->class_p, node);
if(node->class_p->base_class) {
node->class_p = node->class_p->base_class;
_lv_tree_node_destruct(node);
}
}
static uint32_t get_instance_size(const lv_tree_class_t * class_p)
{
const lv_tree_class_t * base = class_p;
while(base && base->instance_size == 0)
base = base->base_class;
return base->instance_size;
}
static lv_tree_node_t * _lv_tree_class_create_node(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
{
uint32_t s = get_instance_size(class_p);
lv_tree_node_t * node = lv_malloc(s);
if(node == NULL) return NULL;
lv_memzero(node, s);
node->class_p = class_p;
node->parent = parent;
node->child_cap = INIT_CHILDREN_CAP;
node->children = lv_malloc(sizeof(lv_tree_node_t *) * node->child_cap);
if(parent != NULL) {
parent->child_cnt++;
if(parent->child_cnt == parent->child_cap) {
parent->child_cap <<= 1;
parent->children = lv_realloc(parent->children, sizeof(lv_tree_node_t *) * parent->child_cap);
}
parent->children[parent->child_cnt - 1] = node;
}
return node;
}
lv_tree_node_t * lv_tree_node_create(const lv_tree_class_t * class_p, lv_tree_node_t * parent)
{
lv_tree_node_t * node = _lv_tree_class_create_node(class_p, parent);
LV_ASSERT_NULL(node);
_lv_tree_node_construct(node->class_p, node);
return node;
}
static bool _lv_tree_node_destructor_cb(const lv_tree_node_t * n, void * user_data)
{
LV_UNUSED(user_data);
if(n) {
lv_tree_node_t * node = (lv_tree_node_t *)n;
_lv_tree_node_destruct(node);
lv_free(node->children);
lv_free(node);
}
return true;
}
void lv_tree_node_delete(lv_tree_node_t * node)
{
if(node) {
if(node->parent) {
/* Remove from parent */
lv_tree_node_t * parent = node->parent;
for(uint32_t i = 0; i < parent->child_cnt; i++) {
if(parent->children[i] == node) {
parent->children[i] = NULL;
}
}
}
lv_tree_walk(node, LV_TREE_WALK_POST_ORDER, _lv_tree_node_destructor_cb, NULL, NULL, NULL);
}
}
bool lv_tree_walk(const lv_tree_node_t * node,
lv_tree_walk_mode_t mode,
lv_tree_traverse_cb_t cb,
lv_tree_before_cb_t bcb,
lv_tree_after_cb_t acb,
void * user_data)
{
if(node && cb) {
if(mode == LV_TREE_WALK_PRE_ORDER) {
if(bcb && !bcb(node, user_data)) {
return false;
}
if(!cb(node, user_data)) {
return false;
}
}
for(uint32_t i = 0; i < node->child_cnt; i++) {
if(!lv_tree_walk(node->children[i], mode, cb, bcb, acb, user_data)) {
return false;
}
}
if(mode == LV_TREE_WALK_PRE_ORDER) {
if(acb) {
acb(node, user_data);
}
}
if(mode == LV_TREE_WALK_POST_ORDER) {
if(bcb && !bcb(node, user_data)) {
return false;
}
if(!cb(node, user_data)) {
return false;
}
if(acb) {
acb(node, user_data);
}
return true;
}
else {
return true;
}
}
else {
return true;
}
}

105
src/misc/lv_tree.h Normal file
View File

@ -0,0 +1,105 @@
/**
* @file lv_tree.h
* Tree. The tree nodes are dynamically allocated by the 'lv_mem' module.
*/
#ifndef LV_TREE_H
#define LV_TREE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_types.h"
/*********************
* DEFINES
*********************/
#define LV_TREE_NODE(n) ((lv_tree_node_t*)(n))
/**********************
* TYPEDEFS
**********************/
struct _lv_tree_node_t;
/**
* Describe the common methods of every object.
* Similar to a C++ class.
*/
typedef struct _lv_tree_class_t {
const struct _lv_tree_class_t * base_class;
uint32_t instance_size;
void (*constructor_cb)(const struct _lv_tree_class_t * class_p, struct _lv_tree_node_t * node);
void (*destructor_cb)(const struct _lv_tree_class_t * class_p, struct _lv_tree_node_t * node);
} lv_tree_class_t;
/** Description of a tree node*/
typedef struct _lv_tree_node_t {
struct _lv_tree_node_t * parent;
struct _lv_tree_node_t ** children;
uint32_t child_cnt;
uint32_t child_cap;
const struct _lv_tree_class_t * class_p;
} lv_tree_node_t;
enum {
LV_TREE_WALK_PRE_ORDER = 0,
LV_TREE_WALK_POST_ORDER,
};
typedef uint8_t lv_tree_walk_mode_t;
typedef bool (*lv_tree_traverse_cb_t)(const lv_tree_node_t * node, void * user_data);
typedef bool (*lv_tree_before_cb_t)(const lv_tree_node_t * node, void * user_data);
typedef void (*lv_tree_after_cb_t)(const lv_tree_node_t * node, void * user_data);
/**********************
* GLOBAL PROTOTYPES
**********************/
extern const lv_tree_class_t lv_tree_node_class;
/**
* @brief Create a tree node
* @param class_p pointer to a class of the node
* @param parent pointer to the parent node (or NULL if it's the root node)
* @return pointer to the new node
*/
lv_tree_node_t * lv_tree_node_create(const lv_tree_class_t * class_p, lv_tree_node_t * parent);
/**
* @brief Delete a tree node and all its children recursively
* @param node pointer to the node to delete
*/
void lv_tree_node_delete(lv_tree_node_t * node);
/**
* @brief Walk the tree recursively and call a callback function on each node
* @param node pointer to the root node of the tree
* @param mode LV_TREE_WALK_PRE_ORDER or LV_TREE_WALK_POST_ORDER
* @param cb callback function to call on each node
* @param bcb callback function to call before visiting a node
* @param acb callback function to call after visiting a node
* @param user_data user data to pass to the callback functions
* @return true: traversal is finished; false: traversal breaked
*/
bool lv_tree_walk(const lv_tree_node_t * node,
lv_tree_walk_mode_t mode,
lv_tree_traverse_cb_t cb,
lv_tree_before_cb_t bcb,
lv_tree_after_cb_t acb,
void * user_data);
/**********************
* MACROS
**********************/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif

View File

@ -206,6 +206,7 @@ if(NOT (CMAKE_C_COMPILER_ID STREQUAL "MSVC"))
-Wno-double-promotion
-Wno-unreachable-code
-Wno-gnu-zero-variadic-macro-arguments
-Wno-overlength-strings
)
else()
list(APPEND COMPILE_OPTIONS

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Some files were not shown because too many files have changed in this diff Show More