Lv_refr_area: Cannot refresh single line (Dev 6.1)

Description

Method lv_refr_area is unable to refresh areas which are 1 pixel height.

What MCU/Processor/Board and compiler are you using?

STM32F4xx on Keil uVision MDK 5.27 using ARMCC V5.06 update 6 toolchain.

What do you experience?

When refresh is called for an invalid area that has a height of only 1 pixel. The refresh method returns early and does not refresh the area.

What do you expect?

Refresh should occur for areas of all heights/widths.

Code to reproduce

Code of interest found in method static void lv_refr_area(const lv_area_t * area_p) in file lv_refr.c.
When using rounder callback refresh method attempts to

This code sets up the temp Y height. If the height is only 1, then y_tmp is 0.

lv_coord_t y_tmp = max_row - 1;

After this a loop is used to decrement y_tmp until it fits within the height. The loops exits on the break in the first iteration (indicating that a height of 1 did fit).

do {
    tmp.y2 = y_tmp;
    disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);

    /*If this height fits into `max_row` then fine*/
    if(lv_area_get_height(&tmp) <= max_row) break;

    /*Decrement the height of the area until it fits into `max_row` after rounding*/
    y_tmp--;
} while(y_tmp != 0);

Where the issue occurs is that there is a check that the size of the height is not zero. The problem is that for single pixel height objects y_tmp was already set to zero before the beginning of the loop and thus fails and does not redraw.

if(y_tmp == 0) {
    LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to "
                "small VDB)");
    return;
} else {
    max_row = tmp.y2 + 1;
}

Proposed Fix

I have resolved this problem on my end by changing the y_tmp var (renamed h_tmp to better represent that it is height) to equal max_row. I then have the internal tmp.y2 equal h_tmp -1. Also the checks for zero should be > for the while loop and <= for the h_tmp check at the end.

Code:

lv_coord_t h_tmp = max_row;
do {
    tmp.y2 = h_tmp - 1;
    disp_refr->driver.rounder_cb(&disp_refr->driver, &tmp);

    /*If this height fits into `max_row` then fine*/
    if(lv_area_get_height(&tmp) <= max_row) break;

    /*Decrement the height of the area until it fits into `max_row` after rounding*/
    h_tmp--;
} while(h_tmp > 0);

if(h_tmp <= 0) {
    LV_LOG_WARN("Can't set VDB height using the round function. (Wrong round_cb or to "
                "small VDB)");
    return;
} else {
    max_row = tmp.y2 + 1;
}

Hi,

Your fix seems correct!

Can you send a Pull request with these updates?

Will submit a pull request as soon as I have a few free minutes :slight_smile:

Pull request was sent and accepted, Thanks :slight_smile:

Thanks! :slight_smile: