fix(gradient): general cleanup and fix for alignment issues (#3036)

* Try to fix ASAN behavior

* improve alignments

* fix buffer overflow and various other fixes

* minor fixes

* formatting

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
X-Ryl669
2022-01-24 15:47:47 +01:00
committed by GitHub
parent ba083dfd6d
commit 923defd6b6
20 changed files with 314 additions and 193 deletions

View File

@@ -39,7 +39,7 @@ typedef struct {
union {
#endif
lv_color_t bg_color; /**< First element of a gradient is a color, so it maps well here*/
lv_gradient_t bg_grad;
lv_grad_dsc_t bg_grad;
#if __STDC_VERSION__ >= 201112L
};
#endif

View File

@@ -17,7 +17,7 @@
#if _DITHER_GRADIENT
LV_ATTRIBUTE_FAST_MEM void lv_dither_none(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_none(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(x);
LV_UNUSED(y);
@@ -40,7 +40,7 @@ static const uint8_t dither_ordered_threshold_matrix[8 * 8] = {
}; /* Shift by 6 to normalize */
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(x);
/* For vertical dithering, the error is spread on the next column (and not next line).
@@ -63,7 +63,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_hor(lv_gradient_cache_t * grad, lv_
grad->map[j] = lv_color_hex(t.full);
}
}
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_gradient_cache_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_grad_t * grad, lv_coord_t x, lv_coord_t y, lv_coord_t w)
{
/* For vertical dithering, the error is spread on the next column (and not next line).
Since the renderer is scanline based, it's not obvious what could be used to perform the rendering efficiently.
@@ -99,7 +99,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_ordered_ver(lv_gradient_cache_t * grad, lv_
#if LV_DITHER_ERROR_DIFFUSION == 1
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_grad_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
{
LV_UNUSED(xs);
LV_UNUSED(y);
@@ -153,7 +153,7 @@ LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_hor(lv_gradient_cache_t * grad, lv
grad->map[grad->size - 1] = lv_color_hex(grad->hmap[grad->size - 1].full);
}
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_ver(lv_gradient_cache_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
LV_ATTRIBUTE_FAST_MEM void lv_dither_err_diff_ver(lv_grad_t * grad, lv_coord_t xs, lv_coord_t y, lv_coord_t w)
{
/* Try to implement error diffusion on a vertical gradient and an horizontal map using those tricks:
Since the given hi-resolution gradient (in src) is vertical, the Floyd Steinberg algorithm pass need to be rotated,

View File

@@ -19,13 +19,12 @@ extern "C" {
/*********************
* DEFINES
*********************/
#if LV_COLOR_DEPTH < 32 && LV_DRAW_COMPLEX == 1 && LV_DITHER_GRADIENT == 1
#if LV_COLOR_DEPTH < 32 && LV_DITHER_GRADIENT == 1
#define _DITHER_GRADIENT 1
#else
#define _DITHER_GRADIENT 0
#endif
/**********************
* TYPEDEFS
**********************/

View File

@@ -8,6 +8,7 @@
*********************/
#include "lv_draw_sw_gradient.h"
#include "../../misc/lv_gc.h"
#include "../../misc/lv_types.h"
/*********************
* DEFINES
@@ -20,6 +21,12 @@
#define GRAD_CONV(t, x) t = x
#endif
#if defined(LV_ARCH_64)
#define ALIGN(X) (((X) + 7) & ~7)
#else
#define ALIGN(X) (((X) + 3) & ~3)
#endif
#define MAX_WIN_RES 1024 /**TODO: Find a way to get this information: max(horz_res, vert_res)*/
#if _DITHER_GRADIENT
@@ -35,17 +42,17 @@
/**********************
* STATIC PROTOTYPES
**********************/
static lv_gradient_cache_t * next_in_cache(lv_gradient_cache_t * first);
static lv_grad_t * next_in_cache(lv_grad_t * item);
typedef lv_res_t (*op_cache_t)(lv_gradient_cache_t * c, void * ctx);
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t ** out);
static size_t get_cache_item_size(lv_gradient_cache_t * c);
static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h);
static lv_res_t find_oldest_item_life(lv_gradient_cache_t * c, void * ctx);
static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx);
static lv_res_t find_item(lv_gradient_cache_t * c, void * ctx);
static void free_item(lv_gradient_cache_t * c);
static uint32_t compute_key(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h);
typedef lv_res_t (*op_cache_t)(lv_grad_t * c, void * ctx);
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_grad_t ** out);
static size_t get_cache_item_size(lv_grad_t * c);
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h);
static lv_res_t find_oldest_item_life(lv_grad_t * c, void * ctx);
static lv_res_t kill_oldest_item(lv_grad_t * c, void * ctx);
static lv_res_t find_item(lv_grad_t * c, void * ctx);
static void free_item(lv_grad_t * c);
static uint32_t compute_key(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h);
/**********************
@@ -62,45 +69,44 @@ union void_cast {
const uint32_t value;
};
static uint32_t compute_key(const lv_gradient_t * g, lv_coord_t size, lv_coord_t w)
static uint32_t compute_key(const lv_grad_dsc_t * g, lv_coord_t size, lv_coord_t w)
{
union void_cast v;
v.ptr = g;
return (v.value ^ size ^ (w >> 1)); /*Yes, this is correct, it's like a hash that changes if the width changes*/
}
static size_t get_cache_item_size(lv_gradient_cache_t * c)
static size_t get_cache_item_size(lv_grad_t * c)
{
size_t s = sizeof(*c) + c->alloc_size * sizeof(lv_color_t)
size_t s = ALIGN(sizeof(*c)) + ALIGN(c->alloc_size * sizeof(lv_color_t));
#if _DITHER_GRADIENT
+ c->size * sizeof(lv_color32_t)
s += ALIGN(c->size * sizeof(lv_color32_t));
#if LV_DITHER_ERROR_DIFFUSION == 1
+ c->w * sizeof(lv_scolor24_t)
s += ALIGN(c->w * sizeof(lv_scolor24_t));
#endif
#endif
;
return s; /* TODO: Should we align this ? */
return s;
}
static lv_gradient_cache_t * next_in_cache(lv_gradient_cache_t * first)
static lv_grad_t * next_in_cache(lv_grad_t * item)
{
if(first == NULL)
return (lv_gradient_cache_t *)LV_GC_ROOT(_lv_grad_cache_mem);
if(first == NULL)
if(grad_cache_size == 0) return NULL;
if(item == NULL)
return (lv_grad_t *)LV_GC_ROOT(_lv_grad_cache_mem);
if(item == NULL)
return NULL;
size_t s = get_cache_item_size(first);
size_t s = get_cache_item_size(item);
/*Compute the size for this cache item*/
if((uint8_t *)first + s > grad_cache_end)
return NULL;
return (lv_gradient_cache_t *)((uint8_t *)first + s);
if((uint8_t *)item + s >= grad_cache_end) return NULL;
else return (lv_grad_t *)((uint8_t *)item + s);
}
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t ** out)
static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_grad_t ** out)
{
lv_gradient_cache_t * first = next_in_cache(NULL);
while(first != NULL) {
lv_grad_t * first = next_in_cache(NULL);
while(first != NULL && first->life) {
if((*func)(first, ctx) == LV_RES_OK) {
if(out != NULL) *out = first;
return LV_RES_OK;
@@ -110,19 +116,20 @@ static lv_res_t iterate_cache(op_cache_t func, void * ctx, lv_gradient_cache_t *
return LV_RES_INV;
}
static lv_res_t find_oldest_item_life(lv_gradient_cache_t * c, void * ctx)
static lv_res_t find_oldest_item_life(lv_grad_t * c, void * ctx)
{
uint32_t * min_life = (uint32_t *)ctx;
if(c->life < *min_life) *min_life = c->life;
return LV_RES_INV;
}
static void free_item(lv_gradient_cache_t * c)
static void free_item(lv_grad_t * c)
{
size_t size = get_cache_item_size(c);
size_t next_items_size = (size_t)(grad_cache_end - (uint8_t *)c) - size;
grad_cache_end -= size;
if(next_items_size) {
uint8_t * old = (uint8_t *)c;
lv_memcpy(c, ((uint8_t *)c) + size, next_items_size);
/* Then need to fix all internal pointers too */
while((uint8_t *)c != grad_cache_end) {
@@ -133,12 +140,13 @@ static void free_item(lv_gradient_cache_t * c)
c->error_acc = (lv_scolor24_t *)(((uint8_t *)c->error_acc) - size);
#endif
#endif
c = (lv_gradient_cache_t *)(((uint8_t *)c) + get_cache_item_size(c));
c = (lv_grad_t *)(((uint8_t *)c) + get_cache_item_size(c));
}
lv_memset_00(old + next_items_size, size);
}
}
static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx)
static lv_res_t kill_oldest_item(lv_grad_t * c, void * ctx)
{
uint32_t * min_life = (uint32_t *)ctx;
if(c->life == *min_life) {
@@ -148,58 +156,84 @@ static lv_res_t kill_oldest_item(lv_gradient_cache_t * c, void * ctx)
}
return LV_RES_INV;
}
static lv_res_t find_item(lv_gradient_cache_t * c, void * ctx)
static lv_res_t find_item(lv_grad_t * c, void * ctx)
{
uint32_t * k = (uint32_t *)ctx;
if(c->key == *k) return LV_RES_OK;
return LV_RES_INV;
}
static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
static lv_grad_t * allocate_item(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h)
{
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
lv_coord_t map_size = LV_MAX(w, h); /* The map is being used horizontally (width) unless
no dithering is selected where it's used vertically */
size_t req_size = sizeof(lv_gradient_cache_t) + map_size * sizeof(lv_color_t)
size_t req_size = ALIGN(sizeof(lv_grad_t)) + ALIGN(map_size * sizeof(lv_color_t));
#if _DITHER_GRADIENT
+ size * sizeof(lv_color32_t)
req_size += ALIGN(size * sizeof(lv_color32_t));
#if LV_DITHER_ERROR_DIFFUSION == 1
+ w * sizeof(lv_scolor24_t)
req_size += ALIGN(w * sizeof(lv_scolor24_t));
#endif
#endif
;
size_t act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
if(req_size + act_size > grad_cache_size) {
/*Need to evict items from cache until we find enough space to allocate this one */
if(req_size > grad_cache_size) {
LV_LOG_WARN("Gradient cache too small, failed to allocate");
return NULL; /*No magic here, if the empty cache is still too small*/
}
while(act_size + req_size < grad_cache_size) {
uint32_t oldest_life = UINT32_MAX;
iterate_cache(&find_oldest_item_life, &oldest_life, NULL);
iterate_cache(&kill_oldest_item, &oldest_life, NULL);
act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
}
/*Ok, now we have space to allocate*/
lv_grad_t * item = NULL;
if(req_size + act_size < grad_cache_size) {
item = (lv_grad_t *)grad_cache_end;
item->not_cached = 0;
}
lv_gradient_cache_t * item = (lv_gradient_cache_t *)grad_cache_end;
else {
/*Need to evict items from cache until we find enough space to allocate this one */
if(req_size <= grad_cache_size) {
while(act_size + req_size > grad_cache_size) {
uint32_t oldest_life = UINT32_MAX;
iterate_cache(&find_oldest_item_life, &oldest_life, NULL);
iterate_cache(&kill_oldest_item, &oldest_life, NULL);
act_size = (size_t)(grad_cache_end - LV_GC_ROOT(_lv_grad_cache_mem));
}
item = (lv_grad_t *)grad_cache_end;
item->not_cached = 0;
}
else {
/*The cache is too small. Allocate the item manually and free it later.*/
item = lv_mem_alloc(req_size);
LV_ASSERT_MALLOC(item);
if(item == NULL) return NULL;
item->not_cached = 1;
}
}
item->key = compute_key(g, size, w);
item->life = 1;
item->filled = 0;
item->alloc_size = map_size;
item->size = size;
item->map = (lv_color_t *)(grad_cache_end + sizeof(*item));
if(item->not_cached) {
uint8_t * p = (uint8_t *)item;
item->map = (lv_color_t *)(p + ALIGN(sizeof(*item)));
#if _DITHER_GRADIENT
item->hmap = (lv_color32_t *)(grad_cache_end + sizeof(*item) + map_size * sizeof(lv_color_t));
item->hmap = (lv_color32_t *)(p + ALIGN(sizeof(*item)) + ALIGN(map_size * sizeof(lv_color_t)));
#if LV_DITHER_ERROR_DIFFUSION == 1
item->error_acc = (lv_scolor24_t *)(grad_cache_end + sizeof(*item) + size * sizeof(lv_grad_color_t) +
map_size * sizeof(lv_color_t));
item->w = w;
item->error_acc = (lv_scolor24_t *)(p + ALIGN(sizeof(*item)) + ALIGN(size * sizeof(lv_grad_color_t)) +
ALIGN(map_size * sizeof(lv_color_t)));
item->w = w;
#endif
#endif
grad_cache_end += req_size;
}
else {
item->map = (lv_color_t *)(grad_cache_end + ALIGN(sizeof(*item)));
#if _DITHER_GRADIENT
item->hmap = (lv_color32_t *)(grad_cache_end + ALIGN(sizeof(*item)) + ALIGN(map_size * sizeof(lv_color_t)));
#if LV_DITHER_ERROR_DIFFUSION == 1
item->error_acc = (lv_scolor24_t *)(grad_cache_end + ALIGN(sizeof(*item)) + ALIGN(size * sizeof(lv_grad_color_t)) +
ALIGN(map_size * sizeof(lv_color_t)));
item->w = w;
#endif
#endif
grad_cache_end += req_size;
}
return item;
}
@@ -207,35 +241,38 @@ static lv_gradient_cache_t * allocate_item(const lv_gradient_t * g, lv_coord_t w
/**********************
* FUNCTIONS
**********************/
void lv_grad_free_cache()
void lv_gradient_free_cache(void)
{
lv_mem_free(LV_GC_ROOT(_lv_grad_cache_mem));
LV_GC_ROOT(_lv_grad_cache_mem) = grad_cache_end = NULL;
grad_cache_size = 0;
}
void lv_grad_set_cache_size(size_t max_bytes)
void lv_gradient_set_cache_size(size_t max_bytes)
{
lv_mem_free(LV_GC_ROOT(_lv_grad_cache_mem));
grad_cache_end = LV_GC_ROOT(_lv_grad_cache_mem) = lv_mem_alloc(max_bytes);
LV_ASSERT_MALLOC(LV_GC_ROOT(_lv_grad_cache_mem));
lv_memset_00(LV_GC_ROOT(_lv_grad_cache_mem), max_bytes);
grad_cache_size = max_bytes;
}
lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * g, lv_coord_t w, lv_coord_t h)
{
/* No gradient, no cache */
if(g->dir == LV_GRAD_DIR_NONE) return NULL;
/* Step 0: Check if the cache exist (else create it) */
if(!grad_cache_size) {
lv_grad_set_cache_size(LV_DEFAULT_GRAD_CACHE_SIZE);
static bool inited = false;
if(!inited) {
lv_gradient_set_cache_size(LV_GRAD_CACHE_DEF_SIZE);
inited = true;
}
/* Step 1: Search cache for the given key */
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
uint32_t key = compute_key(g, size, w);
lv_gradient_cache_t * item = NULL;
lv_grad_t * item = NULL;
if(iterate_cache(&find_item, &key, &item) == LV_RES_OK) {
item->life++; /* Don't forget to bump the counter */
return item;
@@ -243,39 +280,30 @@ lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * g, lv_coord_t
/* Step 2: Need to allocate an item for it */
item = allocate_item(g, w, h);
if(item == NULL) return item;
if(item == NULL) {
LV_LOG_WARN("Faild to allcoate item for teh gradient");
return item;
}
/* Step 3: Fill it with the gradient, as expected */
#if _DITHER_GRADIENT
for(lv_coord_t i = 0; i < item->size; i++) {
item->hmap[i] = lv_grad_get(g, item->size, i);
item->hmap[i] = lv_gradient_calculate(g, item->size, i);
}
#if LV_DITHER_ERROR_DIFFUSION == 1
lv_memset_00(item->error_acc, w * sizeof(lv_scolor24_t));
#endif
#else
for(lv_coord_t i = 0; i < item->size; i++) {
item->map[i] = lv_grad_get(g, item->size, i);
item->map[i] = lv_gradient_calculate(g, item->size, i);
}
#endif
return item;
}
void lv_grad_pop_from_cache(const lv_gradient_t * g, lv_coord_t w, lv_coord_t h)
{
lv_coord_t size = g->dir == LV_GRAD_DIR_HOR ? w : h;
uint32_t key = compute_key(g, size, w);
lv_gradient_cache_t * item = NULL;
if(iterate_cache(&find_item, &key, &item) == LV_RES_OK) {
free_item(item);
}
}
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_coord_t range, lv_coord_t frac)
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_gradient_calculate(const lv_grad_dsc_t * dsc, lv_coord_t range,
lv_coord_t frac)
{
lv_grad_color_t tmp;
lv_color32_t one, two;
@@ -316,3 +344,10 @@ LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_
LV_UDIV255(two.ch.blue * mix + one.ch.blue * imix));
return r;
}
void lv_gradient_cleanup(lv_grad_t * grad)
{
if(grad->not_cached) {
lv_mem_free(grad);
}
}

View File

@@ -40,9 +40,10 @@ typedef lv_color_t lv_grad_color_t;
typedef struct _lv_gradient_cache_t {
uint32_t key; /**< A discriminating key that's built from the drawing operation.
* If the key does not match, the cache item is not used */
uint32_t life : 31; /**< A life counter that's incremented on usage. Higher counter is
uint32_t life : 30; /**< A life counter that's incremented on usage. Higher counter is
* less likely to be evicted from the cache */
uint32_t filled : 1; /**< Used to skip dithering in it if already done */
uint32_t not_cached: 1; /**< The cache was too small so this item is not managed by the cache*/
lv_color_t * map; /**< The computed gradient low bitdepth color map, points into the
* cache's buffer, no free needed */
lv_coord_t alloc_size; /**< The map allocated size in colors */
@@ -56,7 +57,7 @@ typedef struct _lv_gradient_cache_t {
lv_coord_t w; /**< The error array width in pixels */
#endif
#endif
} lv_gradient_cache_t;
} lv_grad_t;
/**********************
@@ -68,22 +69,26 @@ typedef struct _lv_gradient_cache_t {
* @param range The range to use in computation.
* @param frac The current part used in the range. frac is in [0; range]
*/
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_grad_get(const lv_gradient_t * dsc, lv_coord_t range, lv_coord_t frac);
LV_ATTRIBUTE_FAST_MEM lv_grad_color_t lv_gradient_calculate(const lv_grad_dsc_t * dsc, lv_coord_t range,
lv_coord_t frac);
/** Set the gradient cache size */
void lv_grad_set_cache_size(size_t max_bytes);
/** Get a gradient cache from the given parameters */
lv_gradient_cache_t * lv_grad_get_from_cache(const lv_gradient_t * gradient, lv_coord_t w, lv_coord_t h);
/** Evict item from the gradient cache (not used anymore).
* This bypass the life counter on the item to remove this item.
/**
* Set the gradient cache size
* @param max_bytes Max cahce size
*/
void lv_grad_pop_from_cache(const lv_gradient_t * gradient, lv_coord_t w, lv_coord_t h);
void lv_gradient_set_cache_size(size_t max_bytes);
/** Free the gradient cache */
void lv_grad_free_cache(void);
void lv_gradient_free_cache(void);
/** Get a gradient cache from the given parameters */
lv_grad_t * lv_gradient_get(const lv_grad_dsc_t * gradient, lv_coord_t w, lv_coord_t h);
/**
* Clean up the gradient item after it was get with `lv_grad_get_from_cache`.
* @param grad pointer to a gradient
*/
void lv_gradient_cleanup(lv_grad_t * grad);
#ifdef __cplusplus
} /*extern "C"*/

View File

@@ -169,7 +169,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
/*Get gradient if appropriate*/
lv_gradient_cache_t * grad = lv_grad_get_from_cache(&dsc->bg_grad, coords_bg_w, coords_bg_h);
lv_grad_t * grad = lv_gradient_get(&dsc->bg_grad, coords_bg_w, coords_bg_h);
if(grad && grad_dir == LV_GRAD_DIR_HOR) {
blend_dsc.src_buf = grad->map + clipped_coords.x1 - bg_coords.x1;
}
@@ -192,10 +192,29 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
#if LV_DITHER_ERROR_DIFFUSION
if(dither_mode == LV_DITHER_ORDERED)
#endif
dither_func = grad_dir == LV_GRAD_DIR_HOR ? &lv_dither_ordered_hor : &lv_dither_ordered_ver;
switch(grad_dir) {
case LV_GRAD_DIR_HOR:
dither_func = lv_dither_ordered_hor;
break;
case LV_GRAD_DIR_VER:
dither_func = lv_dither_ordered_ver;
break;
default:
dither_func = NULL;
}
#if LV_DITHER_ERROR_DIFFUSION
else if(dither_mode == LV_DITHER_ERR_DIFF)
dither_func = grad_dir == LV_GRAD_DIR_HOR ? &lv_dither_err_diff_hor : &lv_dither_err_diff_ver;
switch(grad_dir) {
case LV_GRAD_DIR_HOR:
dither_func = lv_dither_err_diff_hor;
break;
case LV_GRAD_DIR_VER:
dither_func = lv_dither_err_diff_ver;
break;
default:
dither_func = NULL;
}
#endif
#endif
@@ -212,7 +231,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
if(blend_dsc.mask_res == LV_DRAW_MASK_RES_FULL_COVER) blend_dsc.mask_res = LV_DRAW_MASK_RES_CHANGED;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[h - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -238,7 +257,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = top_y;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, top_y - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, top_y - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[top_y - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -249,7 +268,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = bottom_y;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, bottom_y - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, bottom_y - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[bottom_y - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -288,7 +307,7 @@ static void draw_bg(lv_draw_ctx_t * draw_ctx, const lv_draw_rect_dsc_t * dsc, co
blend_area.y2 = h;
#if _DITHER_GRADIENT
dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
if(dither_func) dither_func(grad, blend_area.x1, h - bg_coords.y1, grad_size);
#endif
if(grad_dir == LV_GRAD_DIR_VER) blend_dsc.color = grad->map[h - bg_coords.y1];
lv_draw_sw_blend(draw_ctx, &blend_dsc);
@@ -302,6 +321,9 @@ bg_clean_up:
lv_draw_mask_remove_id(mask_rout_id);
lv_draw_mask_free_param(&mask_rout_param);
}
if(grad) {
lv_gradient_cleanup(grad);
}
#endif
}