Samsung / rlottie

A platform independent standalone library that plays Lottie Animation.
Other
1.18k stars 226 forks source link

gray_render_line enters an infinite loop in certain situations #473

Open xspeed1989 opened 3 years ago

xspeed1989 commented 3 years ago

@smohantty Loading the json file in the attachment by rlottie will cause this function to enter an infinite loop

frame index:58

43721-keywords.zip

xspeed1989 commented 3 years ago

@smohantty

/*************************************************************************/
/*                                                                       */
/* Render a straight line across multiple cells in any direction.        */
/*                                                                       */
static void gray_render_line(RAS_ARG_ TPos to_x, TPos to_y)
{
    TPos   dx, dy, fx1, fy1, fx2, fy2;
    TCoord ex1, ex2, ey1, ey2;

    ex1 = TRUNC(ras.x);
    ex2 = TRUNC(to_x);
    ey1 = TRUNC(ras.y);
    ey2 = TRUNC(to_y);

    /* perform vertical clipping */
    if ((ey1 >= ras.max_ey && ey2 >= ras.max_ey) ||
        (ey1 < ras.min_ey && ey2 < ras.min_ey))
        goto End;

    dx = to_x - ras.x;
    dy = to_y - ras.y;

    fx1 = ras.x - SUBPIXELS(ex1);
    fy1 = ras.y - SUBPIXELS(ey1);

    if (ex1 == ex2 && ey1 == ey2) /* inside one cell */
        ;
    else if (dy == 0) /* ex1 != ex2 */ /* any horizontal line */
    {
        ex1 = ex2;
        gray_set_cell(RAS_VAR_ ex1, ey1);
    } else if (dx == 0) {
        if (dy > 0) /* vertical line up */
            do {
                fy2 = ONE_PIXEL;
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * fx1 * 2;
                fy1 = 0;
                ey1++;
                gray_set_cell(RAS_VAR_ ex1, ey1);
            } while (ey1 != ey2);
        else /* vertical line down */
            do {
                fy2 = 0;
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * fx1 * 2;
                fy1 = ONE_PIXEL;
                ey1--;
                gray_set_cell(RAS_VAR_ ex1, ey1);
            } while (ey1 != ey2);
    } else /* any other line */
    {
        TArea prod = dx * fy1 - dy * fx1;
        SW_FT_UDIVPREP(dx);
        SW_FT_UDIVPREP(dy);

        /* The fundamental value `prod' determines which side and the  */
        /* exact coordinate where the line exits current cell.  It is  */
        /* also easily updated when moving from one cell to the next.  */
        do {
            if (prod <= 0 && prod - dx * ONE_PIXEL > 0) /* left */
            {
                fx2 = 0;
                fy2 = (TPos)SW_FT_UDIV(-prod, -dx);
                prod -= dy * ONE_PIXEL;
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * (fx1 + fx2);
                fx1 = ONE_PIXEL;
                fy1 = fy2;
                ex1--;
            } else if (prod - dx * ONE_PIXEL <= 0 &&
                       prod - dx * ONE_PIXEL + dy * ONE_PIXEL > 0) /* up */
            {
                prod -= dx * ONE_PIXEL;
                fx2 = (TPos)SW_FT_UDIV(-prod, dy);
                fy2 = ONE_PIXEL;
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * (fx1 + fx2);
                fx1 = fx2;
                fy1 = 0;
                ey1++;
            } else if (prod - dx * ONE_PIXEL + dy * ONE_PIXEL <= 0 &&
                       prod + dy * ONE_PIXEL >= 0) /* right */
            {
                prod += dy * ONE_PIXEL;
                fx2 = ONE_PIXEL;
                fy2 = (TPos)SW_FT_UDIV(prod, dx);
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * (fx1 + fx2);
                fx1 = 0;
                fy1 = fy2;
                ex1++;
            } else /* ( prod                  + dy * ONE_PIXEL <  0 &&
                        prod                                   >  0 )    down */
            {
                fx2 = (TPos)SW_FT_UDIV(prod, -dy);
                fy2 = 0;
                prod += dx * ONE_PIXEL;
                ras.cover += (fy2 - fy1);
                ras.area += (fy2 - fy1) * (fx1 + fx2);
                fx1 = fx2;
                fy1 = ONE_PIXEL;
                ey1--;
            }

            gray_set_cell(RAS_VAR_ ex1, ey1);
       // the while never break out.
        } while (ex1 != ex2 || ey1 != ey2);
    }

    fx2 = to_x - SUBPIXELS(ex2);
    fy2 = to_y - SUBPIXELS(ey2);

    ras.cover += (fy2 - fy1);
    ras.area += (fy2 - fy1) * (fx1 + fx2);

End:
    ras.x = to_x;
    ras.y = to_y;
}