Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33a9dbc2 authored by Michael Ludwig's avatar Michael Ludwig
Browse files

Skip applying expanding clip ops in native canvas

This is the behavioral change that precedes removing support for
expanding clip ops. Canvas.java still passes the Region.Op value
through JNI but then ops other than intersect, difference, and
replace log a warning and make no change to the native Canvas
state.

At the moment, the Skia build flags still allow for the deprecated
ops, so replace is used as before. In the future replace will be
emulated and the build flags will be updated to make SkClipOp
distinct from SkRegion::Op.

Test: Added new CTS tests for current API and API <= 27.
  See other CL in the topic.
Bug: b/151725198
Bug: b/143352151
Change-Id: I933a8d18258878761b6010330240ff1e0c678acd
parent cdacbd77
Loading
Loading
Loading
Loading
+39 −16
Original line number Diff line number Diff line
@@ -197,30 +197,53 @@ static_assert(SkRegion::kXOR_Op == static_cast<SkRegion::Op>(SkClipOp::kXOR_depr
static_assert(SkRegion::kReverseDifference_Op == static_cast<SkRegion::Op>(SkClipOp::kReverseDifference_deprecated), "");
static_assert(SkRegion::kReplace_Op == static_cast<SkRegion::Op>(SkClipOp::kReplace_deprecated), "");

static SkClipOp opHandleToClipOp(jint opHandle) {
static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
                         jfloat r, jfloat b, jint opHandle) {
    // The opHandle is defined in Canvas.java to be Region::Op
    SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);

    // In the future, when we no longer support the wide range of ops (e.g. Union, Xor)
    // this function can perform a range check and throw an unsupported-exception.
    // e.g. if (rgnOp != kIntersect && rgnOp != kDifference) throw...

    // Skia now takes a different type, SkClipOp, as the parameter to clipping calls
    // This type is binary compatible with SkRegion::Op, so a static_cast<> is safe.
    return static_cast<SkClipOp>(rgnOp);
    bool nonEmptyClip;
    switch (rgnOp) {
        case SkRegion::Op::kReplace_Op:
            // For now replace can still be handled as an SkClipOp but will be emulated in the
            // future
            [[fallthrough]];
        case SkRegion::Op::kIntersect_Op:
        case SkRegion::Op::kDifference_Op:
            // Intersect and difference are supported clip operations
            nonEmptyClip =
                    get_canvas(canvasHandle)->clipRect(l, t, r, b, static_cast<SkClipOp>(rgnOp));
            break;
        default:
            // All other operations would expand the clip and are no longer supported,
            // so log and skip (to avoid breaking legacy apps).
            ALOGW("Ignoring unsupported clip operation %d", opHandle);
            SkRect clipBounds;  // ignored
            nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
            break;
    }

static jboolean clipRect(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jfloat l, jfloat t,
                         jfloat r, jfloat b, jint opHandle) {
    bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
            opHandleToClipOp(opHandle));
    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}

static jboolean clipPath(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, jlong pathHandle,
                         jint opHandle) {
    SkRegion::Op rgnOp = static_cast<SkRegion::Op>(opHandle);
    SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
    bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
    bool nonEmptyClip;
    switch (rgnOp) {
        case SkRegion::Op::kReplace_Op:
            // For now replace can still be handled as an SkClipOp but will be emulated in the
            // future
            [[fallthrough]];
        case SkRegion::Op::kIntersect_Op:
        case SkRegion::Op::kDifference_Op:
            nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, static_cast<SkClipOp>(rgnOp));
            break;
        default:
            ALOGW("Ignoring unsupported clip operation %d", opHandle);
            SkRect clipBounds;  // ignored
            nonEmptyClip = get_canvas(canvasHandle)->getClipBounds(&clipBounds);
            break;
    }
    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}