Workaround for a bug in software Canvas that incorrectly computed clip boundaries (fixes screenshot tests)

Summary: Software Canvas uses ints to represents boundaries (because it is backed by Bitmap that has scalar size), whereas Hardware Canvas uses floats to represent boundaries. This results in a bug in Software Canvas where clipping with floats close to or outside of int range results in int overflows and incorrect clipping. To fix the issue, compute the clip boundaries manually instead of using Canvas.clipRect() method (that contains the bug).

Reviewed By: sriramramani

Differential Revision: D2919509
This commit is contained in:
Denis Koroskin 2016-02-10 11:19:03 -08:00 committed by Ahmed El-Helw
parent 44c814c94d
commit 4bff818706

View File

@ -10,10 +10,12 @@
package com.facebook.react.flat;
import android.graphics.Canvas;
import android.graphics.Rect;
/* package */ final class DrawView implements DrawCommand {
/* package */ static DrawView INSTANCE = new DrawView(0, 0, 0, 0);
/* package */ static final DrawView INSTANCE = new DrawView(0, 0, 0, 0);
private static final Rect TMP_CLIP_RECT = new Rect();
private final float mClipLeft;
private final float mClipTop;
@ -34,8 +36,18 @@ import android.graphics.Canvas;
@Override
public void draw(FlatViewGroup parent, Canvas canvas) {
// This should not be required, except that there is a bug in Canvas that only shows up in
// screenshot tests where Canvas incorrectly applies clip rect caused by integer overflows
// because software Canvas is actually using ints for bounds, not floats.
canvas.getClipBounds(TMP_CLIP_RECT);
TMP_CLIP_RECT.intersect(
Math.round(mClipLeft),
Math.round(mClipTop),
Math.round(mClipRight),
Math.round(mClipBottom));
canvas.save();
canvas.clipRect(mClipLeft, mClipTop, mClipRight, mClipBottom);
canvas.clipRect(TMP_CLIP_RECT);
parent.drawNextChild(canvas);
canvas.restore();
}