Canvas的drawRect方法用于绘制区域,参数一为RectF一个区域,代码如下:
//frameworks/base/graphics/java/android/graphic/Canvas.java
public class Canvas extends BaseCanvas {
public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
super.drawRect(rect, paint);
}
}
调用Canvas的父类BaseCanvas的drawPath方法:
//frameworks/base/graphics/java/android/graphic/BaseCanvas.java
public abstract class BaseCanvas {}
public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
throwIfHasHwFeaturesInSwMode(paint);
nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
}
}
drawRect
调用nDrawRect方法,nDrawRect方法是Native方法,在android_graphics_Canvas.cpp中实现,下面分别进行分析:
//framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
static void drawRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
jfloat right, jfloat bottom, jlong paintHandle) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
get_canvas(canvasHandle)->drawRect(left, top, right, bottom, *paint);
}
调用get_canvas取得Canvas:
//framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
static Canvas* get_canvas(jlong canvasHandle) {
return reinterpret_cast<Canvas*>(canvasHandle);
}
SkiaCanvas drawRect
SkiaCanvas继承于Canvas,因此调用SkiaCanvas的drawRect方法,SkiaCanvas的drawRect方法用于在画布上绘制一个矩形
//frameworks/base/libs/hwui/SkiaCanvas.cpp
class SkiaCanvas : public Canvas {
SkCanvas* mCanvas;
void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
applyLooper(&paint, [&](const SkPaint& p) {
mCanvas->drawRect({left, top, right, bottom}, p);
});
}
}
SkCanvas drawRect
调用SkCanvas的drawRect方法:
//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::drawRect(const SkRect& r, const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
// To avoid redundant logic in our culling code and various backends, we always sort rects
// before passing them along.
this->onDrawRect(r.makeSorted(), paint);
}
}
调用SkCanvas的onDrawRect方法:
//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::onDrawRect(const SkRect& r, const SkPaint& paint) {
SkASSERT(r.isSorted());
if (this->internalQuickReject(r, paint)) {
return;
}
auto layer = this->aboutToDraw(this, paint, &r, CheckForOverwrite::kYes);
if (layer) {
this->topDevice()->drawRect(r, layer->paint());
}
}
}
调用SkCanvas的topDevice方法,返回SkBaseDevice对象:
//external/skia/include/core/SkCanvas.cpp
SkBaseDevice* SkCanvas::topDevice() const {
SkASSERT(fMCRec->fDevice);
return fMCRec->fDevice;
}
SkBitmapDevice drawRect
调用SkBaseDevice的drawPath,由SkBaseDevice的子类SkBitmapDevice实现drawRect方法:
//external/skia/src/core/SkBitmapDevice.cpp
class SkBitmapDevice : public SkBaseDevice {
void SkBitmapDevice::drawRect(const SkRect& r, const SkPaint& paint) {
LOOP_TILER( drawRect(r, paint), Bounder(r, paint))
}
}
SkDraw drawRect
调用SkDraw的drawRect方法:
//external/skia/src/core/SkDraw.cpp
class SkDraw : public SkGlyphRunListPainter::BitmapDevicePainter {
void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
SkDEBUGCODE(this->validate();)
// nothing to draw
if (fRC->isEmpty()) {
return;
}
const SkMatrixProvider* matrixProvider = fMatrixProvider;
SkTLazy<SkPreConcatMatrixProvider> preConcatMatrixProvider;
if (paintMatrix) {
SkASSERT(postPaintRect);
matrixProvider = preConcatMatrixProvider.init(*matrixProvider, *paintMatrix);
} else {
SkASSERT(!postPaintRect);
}
SkMatrix ctm = fMatrixProvider->localToDevice();
SkPoint strokeSize;
RectType rtype = ComputeRectType(prePaintRect, paint, ctm, &strokeSize);
if (kPath_RectType == rtype) {
draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
return;
}
SkRect devRect;
const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
// skip the paintMatrix when transforming the rect by the CTM
ctm.mapPoints(rect_points(devRect), rect_points(paintRect), 2);
devRect.sort();
// look for the quick exit, before we build a blitter
SkRect bbox = devRect;
if (paint.getStyle() != SkPaint::kFill_Style) {
// extra space for hairlines
if (paint.getStrokeWidth() == 0) {
bbox.outset(1, 1);
} else {
// For kStroke_RectType, strokeSize is already computed.
const SkPoint& ssize = (kStroke_RectType == rtype)
? strokeSize
: compute_stroke_size(paint, ctm);
bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
}
}
if (SkPathPriv::TooBigForMath(bbox)) {
return;
}
if (!SkRectPriv::FitsInFixed(bbox) && rtype != kHair_RectType) {
draw_rect_as_path(*this, prePaintRect, paint, matrixProvider);
return;
}
SkIRect ir = bbox.roundOut();
if (fRC->quickReject(ir)) {
return;
}
SkAutoBlitterChoose blitterStorage(*this, matrixProvider, paint);
const SkRasterClip& clip = *fRC;
SkBlitter* blitter = blitterStorage.get();
// we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
// case we are also hairline (if we've gotten to here), which devolves to
// effectively just kFill
switch (rtype) {
case kFill_RectType:
if (paint.isAntiAlias()) {
SkScan::AntiFillRect(devRect, clip, blitter);
} else {
SkScan::FillRect(devRect, clip, blitter);
}
break;
case kStroke_RectType:
if (paint.isAntiAlias()) {
SkScan::AntiFrameRect(devRect, strokeSize, clip, blitter);
} else {
SkScan::FrameRect(devRect, strokeSize, clip, blitter);
}
break;
case kHair_RectType:
if (paint.isAntiAlias()) {
SkScan::AntiHairRect(devRect, clip, blitter);
} else {
SkScan::HairRect(devRect, clip, blitter);
}
break;
default:
SkDEBUGFAIL("bad rtype");
}
}}
SkScan FillRect
根据不同的case设置不同的proc,然后运行这个proc,我们继续分析SkScan::FillRect处理:
//external/skia/src/core/SkScan.cpp
class SkScan {
void SkScan::FillRect(const SkRect& r, const SkRegion* clip,
SkBlitter* blitter) {
SkIRect ir;
r.round(&ir);
SkScan::FillIRect(ir, clip, blitter);
}
}
调用SkScan的FillIRect方法:
//external/skia/src/core/SkScan.cpp
class SkScan {
void SkScan::FillIRect(const SkIRect& r, const SkRegion* clip,
SkBlitter* blitter) {
if (!r.isEmpty()) {
if (clip) {
if (clip->isRect()) {
const SkIRect& clipBounds = clip->getBounds();
if (clipBounds.contains(r)) {
blitrect(blitter, r);
} else {
SkIRect rr = r;
if (rr.intersect(clipBounds)) {
blitrect(blitter, rr);
}
}
} else {
SkRegion::Cliperator cliper(*clip, r);
const SkIRect& rr = cliper.rect();
while (!cliper.done()) {
blitrect(blitter, rr);
cliper.next();
}
}
} else {
blitrect(blitter, r);
}
}
}
}
调用SkBlitter的blitRect方法:
//external/skia/src/core/SkBlitter.cpp
class SkBlitter {
void SkBlitter::blitRect(int x, int y, int width, int height) {
SkASSERT(width > 0);
while (--height >= 0) {
this->blitH(x, y++, width);
}
}
}