Android13 Canvas clipRect流程分析

Android中Canvas的clipRect方法用于裁剪画布,将画布限制在指定的矩形区域内。裁剪后,只有在该区域内的绘制内容才会被显示出来,超出该区域的内容将被隐藏。裁剪画布的作用是可以控制绘制的范围,只绘制在指定区域内的内容,可以实现一些特殊的绘制效果,比如局部放大、镂空等,代码如下:

//frameworks/base/graphics/java/android/graphic/Canvas.java
public class Canvas extends BaseCanvas {
    public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
        checkValidClipOp(op);
        return nClipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
                op.nativeInt);
    }
}

clipRect

调用nClipRect方法,nClipRect方法是Native方法,在android_graphics_Canvas.cpp中实现,下面分别进行分析

//framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
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);
    bool nonEmptyClip;
    switch (rgnOp) {
        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;
        case SkRegion::Op::kReplace_Op:
            // Replace is emulated to support legacy apps older than P
            nonEmptyClip = get_canvas(canvasHandle)->replaceClipRect_deprecated(l, t, r, b);
            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;
    }
    return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}

调用get_canvas取得Canvas:

//framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
static Canvas* get_canvas(jlong canvasHandle) {
    return reinterpret_cast<Canvas*>(canvasHandle);
}

SkiaCanvas clipRect

SkiaCanvas继承于Canvas,因此调用SkiaCanvas的clipRect方法,SkiaCanvas的clipRect方法用于在画布上创建一个矩形剪裁区域,只有在该区域内的内容才会被绘制出来

//frameworks/base/libs/hwui/SkiaCanvas.cpp
class SkiaCanvas : public Canvas {
SkCanvas* mCanvas; 
bool SkiaCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
    SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
    this->recordClip(rect, op);
    mCanvas->clipRect(rect, op);
    return !mCanvas->isClipEmpty();
}
}

SkCanvas clipRect

调用SkCanvas的clipRect方法:

//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::clipRect(const SkRect& rect, SkClipOp op, bool doAA) {
    if (!rect.isFinite()) {
        return;
    }
    this->checkForDeferredSave();
    ClipEdgeStyle edgeStyle = doAA ? kSoft_ClipEdgeStyle : kHard_ClipEdgeStyle;
    this->onClipRect(rect.makeSorted(), op, edgeStyle);
}
}

调用SkCanvas的onClipRect方法:

//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle edgeStyle) {
    SkASSERT(rect.isSorted());
    const bool isAA = kSoft_ClipEdgeStyle == edgeStyle;


    AutoUpdateQRBounds aqr(this);
    this->topDevice()->clipRect(rect, op, isAA);
}
}

调用SkCanvas的topDevice方法,返回SkBaseDevice对象:

//external/skia/include/core/SkCanvas.cpp
SkBaseDevice* SkCanvas::topDevice() const {
    SkASSERT(fMCRec->fDevice);
    return fMCRec->fDevice;
}
SkBitmapDevice clipRect

调用SkBaseDevice的drawPath,由SkBaseDevice的子类SkBitmapDevice实现drawRect方法:

//external/skia/src/core/SkBitmapDevice.cpp
class SkBitmapDevice : public SkBaseDevice {
void SkBitmapDevice::onClipRect(const SkRect& rect, SkClipOp op, bool aa) {
    fRCStack.clipRect(this->localToDevice(), rect, op, aa);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值