Canvas的drawRoundRect用于绘制指定的圆角矩形,代码如下:
//frameworks/base/graphics/java/android/graphic/Canvas.java
public class Canvas extends BaseCanvas {
public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
super.drawRoundRect(rect, rx, ry, paint);
}
}
调用Canvas的父类BaseCanvas的drawRoundRect方法:
//frameworks/base/graphics/java/android/graphic/BaseCanvas.java
public abstract class BaseCanvas {}
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
@NonNull Paint paint) {
throwIfHasHwFeaturesInSwMode(paint);
nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
paint.getNativeInstance());
}
}
drawRoundRect
调用nDrawRoundRect方法,nDrawRoundRect方法是Native方法,在android_graphics_Canvas.cpp中实现,下面分别进行分析:
//framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
static void drawRoundRect(JNIEnv* env, jobject, jlong canvasHandle, jfloat left, jfloat top,
jfloat right, jfloat bottom, jfloat rx, jfloat ry, jlong paintHandle) {
const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
get_canvas(canvasHandle)->drawRoundRect(left, top, right, bottom, rx, ry, *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 drawRoundRect
SkiaCanvas继承于Canvas,因此调用SkiaCanvas的drawRoundRect方法:
//frameworks/base/libs/hwui/SkiaCanvas.cpp
class SkiaCanvas : public Canvas {
SkCanvas* mCanvas;
void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
const Paint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawRoundRect(rect, rx, ry, p); });
}
}
SkCanvas drawRoundRect
调用mCanvas(SkCanvas)的drawRoundRect方法:
//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::drawRoundRect(const SkRect& r, SkScalar rx, SkScalar ry,
const SkPaint& paint) {
if (rx > 0 && ry > 0) {
SkRRect rrect;
rrect.setRectXY(r, rx, ry);
this->drawRRect(rrect, paint);
} else {
this->drawRect(r, paint);
}
}
}
根据条件调用SkCanvas的drawRRect或drawRect方法,下面分别进行分析:
SkCanvas drawRRect
调用SkCanvas的drawRRect方法:
//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
TRACE_EVENT0("skia", TRACE_FUNC);
this->onDrawRRect(rrect, paint);
}
}
调用SkCanvas的onDrawRRect方法:
//external/skia/include/core/SkCanvas.cpp
class SK_API SkCanvas {
void SkCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
const SkRect& bounds = rrect.getBounds();
// Delegating to simpler draw operations
if (rrect.isRect()) {
// call the non-virtual version
this->SkCanvas::drawRect(bounds, paint);
return;
} else if (rrect.isOval()) {
// call the non-virtual version
this->SkCanvas::drawOval(bounds, paint);
return;
}
if (this->internalQuickReject(bounds, paint)) {
return;
}
auto layer = this->aboutToDraw(this, paint, &bounds);
if (layer) {
this->topDevice()->drawRRect(rrect, layer->paint());
}
}
}
调用SkCanvas的topDevice方法,返回SkBaseDevice对象:
//external/skia/include/core/SkCanvas.cpp
SkBaseDevice* SkCanvas::topDevice() const {
SkASSERT(fMCRec->fDevice);
return fMCRec->fDevice;
}
SkBitmapDevice drawRRect
调用SkBaseDevice的drawRRect,由SkBaseDevice的子类SkBitmapDevice实现drawRRect方法:
//external/skia/src/core/SkBitmapDevice.cpp
class SkBitmapDevice : public SkBaseDevice {
void SkBitmapDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
#ifdef SK_IGNORE_BLURRED_RRECT_OPT
// call the VIRTUAL version, so any subclasses who do handle drawPath aren't
// required to override drawRRect.
this->drawPath(SkPath::RRect(rrect), paint, true);
#else
LOOP_TILER( drawRRect(rrect, paint), Bounder(rrect.getBounds(), paint))
#endif
}
}
SkDraw drawRRect
调用SkDraw的drawRRect方法:
//external/skia/src/core/SkDraw.cpp
class SkDraw : public SkGlyphRunListPainter::BitmapDevicePainter {
void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
SkDEBUGCODE(this->validate());
if (fRC->isEmpty()) {
return;
}
SkMatrix ctm = fMatrixProvider->localToDevice();
{
// TODO: Investigate optimizing these options. They are in the same
// order as SkDraw::drawPath, which handles each case. It may be
// that there is no way to optimize for these using the SkRRect path.
SkScalar coverage;
if (SkDrawTreatAsHairline(paint, ctm, &coverage)) {
goto DRAW_PATH;
}
if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
goto DRAW_PATH;
}
}
if (paint.getMaskFilter()) {
// Transform the rrect into device space.
SkRRect devRRect;
if (rrect.transform(ctm, &devRRect)) {
SkAutoBlitterChoose blitter(*this, nullptr, paint);
if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, ctm, *fRC, blitter.get())) {
return; // filterRRect() called the blitter, so we're done
}
}
}
DRAW_PATH:
// Now fall back to the default case of using a path.
SkPath path;
path.addRRect(rrect);
this->drawPath(path, paint, nullptr, true);
}
}
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的drawRect,由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的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);
}
}
}