自定义View继承自View类,需要重写onDraw方法,通过canvas和paint进行绘制
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawLine(); }
public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { super.drawLine(startX, startY, stopX, stopY, paint); }
framework/base/graphics/java/android/graphics/BaseCanvas.java
public void drawLine(float startX, float startY, float stopX, float stopY, @NonNull Paint paint) { throwIfHasHwFeaturesInSwMode(paint); nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance()); }
private static native void nDrawLine(long nativeCanvas, float startX, float startY, float stopX, float stopY, long nativePaint);
framework/base/libs/hwui/jni/android_graphics_Canvas.cpp
// If called from Canvas these are regular JNI // If called from DisplayListCanvas they are @FastNative static const JNINativeMethod gDrawMethods[] = { {"nDrawColor","(JII)V", (void*) CanvasJNI::drawColor}, {"nDrawColor","(JJJI)V", (void*) CanvasJNI::drawColorLong}, {"nDrawPaint","(JJ)V", (void*) CanvasJNI::drawPaint}, {"nDrawPoint", "(JFFJ)V", (void*) CanvasJNI::drawPoint}, {"nDrawPoints", "(J[FIIJ)V", (void*) CanvasJNI::drawPoints}, {"nDrawLine", "(JFFFFJ)V", (void*) CanvasJNI::drawLine},
static void drawLine(JNIEnv* env, jobject, jlong canvasHandle, jfloat startX, jfloat startY, jfloat stopX, jfloat stopY, jlong paintHandle) { Paint* paint = reinterpret_cast<Paint*>(paintHandle); get_canvas(canvasHandle)->drawLine(startX, startY, stopX, stopY, *paint); }
static Canvas* get_canvas(jlong canvasHandle) { return reinterpret_cast<Canvas*>(canvasHandle); }
framework/base/libs/hwui/hwui/Canvas.cpp
virtual void drawLine(float startX, float startY, float stopX, float stopY, const Paint& paint) = 0;
frameworks\base\libs\hwui\SkiaCanvas.cpp
void SkiaCanvas::drawLine(float startX, float startY, float stopX, float stopY, const Paint& paint) { applyLooper(&paint, [&](const SkPaint& p) { mCanvas->drawLine(startX, startY, stopX, stopY, p); }); }
void applyLooper(const Paint* paint, Proc proc, void (*preFilter)(SkPaint&) = nullptr) { BlurDrawLooper* looper = paint ? paint->getLooper() : nullptr; Paint pnt = paint ? *paint : Paint(); if (preFilter) { preFilter(pnt); } this->onFilterPaint(pnt); if (looper) { looper->apply(pnt, [&](SkPoint offset, const Paint& modifiedPaint) { mCanvas->save(); mCanvas->translate(offset.fX, offset.fY); proc(modifiedPaint); mCanvas->restore(); }); } else { proc(pnt); } }
external/skia/src/core/SkCanvas.cpp
void SkCanvas::drawLine(SkScalar x0, SkScalar y0, SkScalar x1, SkScalar y1, const SkPaint& paint) { SkPoint pts[2]; pts[0].set(x0, y0); pts[1].set(x1, y1); this->drawPoints(kLines_PointMode, 2, pts, paint); }
void SkCanvas::drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { TRACE_EVENT0("skia", TRACE_FUNC); this->onDrawPoints(mode, count, pts, paint); }
void SkCanvas::onDrawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { if ((long)count <= 0 || paint.nothingToDraw()) { return; } SkASSERT(pts != nullptr); SkRect bounds; // Compute bounds from points (common for drawing a single line) if (count == 2) { bounds.set(pts[0], pts[1]); } else { bounds.setBounds(pts, SkToInt(count)); } // Enforce paint style matches implicit behavior of drawPoints SkPaint strokePaint = paint; strokePaint.setStyle(SkPaint::kStroke_Style); if (this->internalQuickReject(bounds, strokePaint)) { return; } auto layer = this->aboutToDraw(this, strokePaint, &bounds); if (layer) { this->topDevice()->drawPoints(mode, count, pts, layer->paint()); } }
external\skia\src\core\SkDevice.h
virtual void drawPaint(const SkPaint& paint) = 0; virtual void drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint[], const SkPaint& paint) = 0;
external\skia\src\gpu\v1\Device.cpp
void Device::drawPaint(const SkPaint& paint) { ASSERT_SINGLE_OWNER GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPaint", fContext.get()); GrPaint grPaint; if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, this->asMatrixProvider(), &grPaint)) { return; } fSurfaceDrawContext->drawPaint(this->clip(), std::move(grPaint), this->localToDevice()); } void Device::drawPoints(SkCanvas::PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) { ASSERT_SINGLE_OWNER GR_CREATE_TRACE_MARKER_CONTEXT("skgpu::v1::Device", "drawPoints", fContext.get()); SkScalar width = paint.getStrokeWidth(); if (width < 0) { return; } GrAA aa = fSurfaceDrawContext->chooseAA(paint); if (count == 2 && mode == SkCanvas::kLines_PointMode) { if (paint.getPathEffect()) { // Probably a dashed line. Draw as a path. GrPaint grPaint; if (SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, this->asMatrixProvider(), &grPaint)) { SkPath path; path.setIsVolatile(true); path.moveTo(pts[0]); path.lineTo(pts[1]); fSurfaceDrawContext->drawPath(this->clip(), std::move(grPaint), aa, this->localToDevice(), path, GrStyle(paint, SkPaint::kStroke_Style)); } return; } if (!paint.getMaskFilter() && paint.getStrokeWidth() > 0 && // drawStrokedLine doesn't support hairlines. paint.getStrokeCap() != SkPaint::kRound_Cap) { // drawStrokedLine doesn't do round caps. // Simple stroked line. Bypass path rendering. GrPaint grPaint; if (SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, this->asMatrixProvider(), &grPaint)) { fSurfaceDrawContext->drawStrokedLine(this->clip(), std::move(grPaint), aa, this->localToDevice(), pts, SkStrokeRec(paint, SkPaint::kStroke_Style)); } return; } } SkScalar scales[2]; bool isHairline = (0 == width) || (1 == width && this->localToDevice().getMinMaxScales(scales) && SkScalarNearlyEqual(scales[0], 1.f) && SkScalarNearlyEqual(scales[1], 1.f)); // we only handle non-coverage-aa hairlines and paints without path effects or mask filters, // else we let the SkDraw call our drawPath() if (!isHairline || paint.getPathEffect() || paint.getMaskFilter() || fSurfaceDrawContext->chooseAAType(aa) == GrAAType::kCoverage) { SkRasterClip rc(this->devClipBounds()); SkDraw draw; draw.fDst = SkPixmap(SkImageInfo::MakeUnknown(this->width(), this->height()), nullptr, 0); draw.fMatrixProvider = this; draw.fRC = &rc; draw.drawPoints(mode, count, pts, paint, this); return; } GrPrimitiveType primitiveType = point_mode_to_primitive_type(mode); const SkMatrixProvider* matrixProvider = this; GrPaint grPaint; if (!SkPaintToGrPaint(this->recordingContext(), fSurfaceDrawContext->colorInfo(), paint, *matrixProvider, &grPaint)) { return; } static constexpr SkVertices::VertexMode kIgnoredMode = SkVertices::kTriangles_VertexMode; sk_sp<SkVertices> vertices = SkVertices::MakeCopy(kIgnoredMode, SkToS32(count), pts, nullptr, nullptr); fSurfaceDrawContext->drawVertices(this->clip(), std::move(grPaint), *matrixProvider, std::move(vertices), &primitiveType); }