virtual void onDraw(SkCanvas* canvas) { constexpr SkScalar kOffset = 35000.0f; constexpr SkScalar kExtents = 1000.0f; SkPictureRecorder recorder; // We record a picture of huge vertical extents in which we clear the canvas to red, create // a 'extents' by 'extents' round rect clip at a vertical offset of 'offset', then draw // green into that. SkCanvas* rec = recorder.beginRecording(kExtents, kOffset + kExtents, nullptr, 0); rec->drawColor(SK_ColorRED); rec->save(); SkRect r = SkRect::MakeXYWH(-kExtents, kOffset - kExtents, 2 * kExtents, 2 * kExtents); SkPath p; p.addRoundRect(r, 5, 5); rec->clipPath(p, true); rec->drawColor(SK_ColorGREEN); rec->restore(); sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture()); // Next we play that picture into another picture of the same size. pict->playback(recorder.beginRecording(pict->cullRect().width(), pict->cullRect().height(), nullptr, 0)); sk_sp<SkPicture> pict2(recorder.finishRecordingAsPicture()); // Finally we play the part of that second picture that should be green into the canvas. canvas->save(); canvas->translate(kExtents / 2, -(kOffset - kExtents / 2)); pict2->playback(canvas); canvas->restore(); // If the image is red, we erroneously decided the clipPath was empty and didn't record // the green drawColor, if it's green we're all good. }
virtual void onDrawContent(SkCanvas* canvas) { canvas->drawColor(SK_ColorWHITE); canvas->translate(SkIntToScalar(20), SkIntToScalar(20)); static const CanvasProc gProc[] = { show_text, show_thick, show_hair, show_fill }; SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) }; SkPath clipPath; r.inset(SK_Scalar1 / 4, SK_Scalar1 / 4); clipPath.addRoundRect(r, SkIntToScalar(20), SkIntToScalar(20)); // clipPath.toggleInverseFillType(); for (int aa = 0; aa <= 1; ++aa) { canvas->save(); for (size_t i = 0; i < SK_ARRAY_COUNT(gProc); ++i) { canvas->save(); canvas->clipPath(clipPath, SkRegion::kIntersect_Op, true); // canvas->drawColor(SK_ColorWHITE); gProc[i](canvas, SkToBool(aa)); canvas->restore(); canvas->translate(W * SK_Scalar1 * 8 / 7, 0); } canvas->restore(); canvas->translate(0, H * SK_Scalar1 * 8 / 7); } }
PathEffectView() { SkRandom rand; int steps = 20; SkScalar dist = SkIntToScalar(400); SkScalar x = SkIntToScalar(20); SkScalar y = SkIntToScalar(50); fPath.moveTo(x, y); for (int i = 0; i < steps; i++) { x += dist/steps; SkScalar tmpY = y + SkIntToScalar(rand.nextS() % 25); if (i == steps/2) { fPath.moveTo(x, tmpY); } else { fPath.lineTo(x, tmpY); } } { SkRect oval; oval.set(SkIntToScalar(20), SkIntToScalar(30), SkIntToScalar(100), SkIntToScalar(60)); oval.offset(x, 0); fPath.addRoundRect(oval, SkIntToScalar(8), SkIntToScalar(8)); } fClickPt.set(SkIntToScalar(200), SkIntToScalar(200)); }
void onOnceBeforeDraw() override { SkRandom rand; int steps = 20; SkScalar dist = SkIntToScalar(400); SkScalar x = SkIntToScalar(20); SkScalar y = SkIntToScalar(50); fPath.moveTo(x, y); for (int i = 0; i < steps; i++) { x += dist/steps; SkScalar tmpY = y + SkIntToScalar(rand.nextS() % 25); if (i == steps/2) { fPath.moveTo(x, tmpY); } else { fPath.lineTo(x, tmpY); } } { SkRect oval; oval.set(SkIntToScalar(20), SkIntToScalar(30), SkIntToScalar(100), SkIntToScalar(60)); oval.offset(x, 0); fPath.addRoundRect(oval, SkIntToScalar(8), SkIntToScalar(8)); } fClickPt.set(SkIntToScalar(200), SkIntToScalar(200)); this->setBGColor(0xFFDDDDDD); }
virtual void onDraw(int loops, SkCanvas* canvas) { SkPaint paint; this->setupPaint(&paint); for (int i = 0; i < loops; ++i) { // jostle the clip regions each time to prevent caching fClipRect.offset((i % 2) == 0 ? SkIntToScalar(10) : SkIntToScalar(-10), 0); fClipPath.reset(); fClipPath.addRoundRect(fClipRect, SkIntToScalar(5), SkIntToScalar(5)); SkASSERT(fClipPath.isConvex()); canvas->save(); #if 1 if (fDoPath) { canvas->clipPath(fClipPath, kReplace_SkClipOp, fDoAA); } else { canvas->clipRect(fClipRect, kReplace_SkClipOp, fDoAA); } canvas->drawRect(fDrawRect, paint); #else // this path tests out directly draw the clip primitive // use it to comparing just drawing the clip vs. drawing using // the clip if (fDoPath) { canvas->drawPath(fClipPath, paint); } else { canvas->drawRect(fClipRect, paint); } #endif canvas->restore(); } }
void onDraw(SkCanvas* canvas) override { SkPictureRecorder recorder; SkCanvas* rec = recorder.beginRecording(1200, 900, nullptr, 0); SkPath p; SkRect r = { SkIntToScalar(100), SkIntToScalar(200), SkIntToScalar(400), SkIntToScalar(700) }; p.addRoundRect(r, SkIntToScalar(50), SkIntToScalar(50)); rec->clipPath(p, SkRegion::kIntersect_Op, true); rec->translate(SkIntToScalar(250), SkIntToScalar(250)); rec->clipPath(p, SkRegion::kIntersect_Op, true); rec->drawColor(0xffff0000); sk_sp<SkPicture> pict(recorder.finishRecordingAsPicture()); canvas->setAllowSimplifyClip(true); canvas->save(); canvas->drawPicture(pict); canvas->restore(); canvas->setAllowSimplifyClip(false); canvas->save(); canvas->translate(SkIntToScalar(1200 / 2), 0); canvas->drawPicture(pict); canvas->restore(); }
static void setAAClip(SkAAClip* clip, const SkIRect& rect) { SkRect r; r.set(rect); SkPath path; path.addRoundRect(r, SkIntToScalar(5), SkIntToScalar(5)); clip->setPath(path); }
void onDraw(SkCanvas* canvas) override { canvas->translate(8.5f, 8.5f); const SkRect rect = { 0, 0, 80, 80 }; const SkScalar RAD = rect.width()/8; int i = 0; for (int insetFirst = 0; insetFirst <= 1; ++insetFirst) { for (int doEvenOdd = 0; doEvenOdd <= 1; ++doEvenOdd) { for (int outerRR = 0; outerRR <= 1; ++outerRR) { for (int innerRR = 0; innerRR <= 1; ++innerRR) { for (int outerCW = 0; outerCW <= 1; ++outerCW) { for (int innerCW = 0; innerCW <= 1; ++innerCW) { SkPath path; path.setFillType(doEvenOdd ? SkPath::kEvenOdd_FillType : SkPath::kWinding_FillType); SkPath::Direction outerDir = outerCW ? SkPath::kCW_Direction : SkPath::kCCW_Direction; SkPath::Direction innerDir = innerCW ? SkPath::kCW_Direction : SkPath::kCCW_Direction; SkRect r = insetFirst ? inset(rect) : rect; if (outerRR) { path.addRoundRect(r, RAD, RAD, outerDir); } else { path.addRect(r, outerDir); } r = insetFirst ? rect : inset(rect); if (innerRR) { path.addRoundRect(r, RAD, RAD, innerDir); } else { path.addRect(r, innerDir); } SkScalar dx = (i / 8) * rect.width() * 6 / 5; SkScalar dy = (i % 8) * rect.height() * 6 / 5; i++; path.offset(dx, dy); this->show(canvas, path); } } } } } } }
AAClipBuilderBench(void* param, bool doPath, bool doAA) : INHERITED(param) { fDoPath = doPath; fDoAA = doAA; fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect", doAA ? "AA" : "BW"); fRegion.setRect(0, 0, 640, 480); fRect.set(fRegion.getBounds()); fRect.inset(SK_Scalar1/4, SK_Scalar1/4); fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20)); }
virtual void onDraw(SkCanvas* canvas) { createShader(); createMaskFilter(); canvas->save(); // draw a letter "M" with a green & red striped texture and a // stipple mask with a round rect soft clip SkPaint paint; paint.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint); paint.setTextSize(72); paint.setShader(fShader.get()); paint.setMaskFilter(fMaskFilter.get()); SkRect temp; temp.set(SkIntToScalar(115), SkIntToScalar(75), SkIntToScalar(144), SkIntToScalar(110)); SkPath path; path.addRoundRect(temp, SkIntToScalar(5), SkIntToScalar(5)); canvas->clipPath(path, SkRegion::kReplace_Op, true); // AA is on canvas->drawText("M", 1, SkIntToScalar(100), SkIntToScalar(100), paint); canvas->restore(); // Now draw stroked versions of the "M" and the round rect so we can // see what is going on SkPaint paint2; paint2.setColor(SK_ColorBLACK); paint2.setAntiAlias(true); sk_tool_utils::set_portable_typeface(&paint2); paint2.setTextSize(72); paint2.setStyle(SkPaint::kStroke_Style); paint2.setStrokeWidth(1); canvas->drawText("M", 1, SkIntToScalar(100), SkIntToScalar(100), paint2); paint2.setColor(SK_ColorGRAY); canvas->drawPath(path, paint2); }
virtual void onDraw(SkCanvas* canvas) { this->drawBG(canvas); fSweep = SampleCode::GetAnimScalar(SkIntToScalar(360)/24, SkIntToScalar(360)); // fSweep = SkFloatToScalar(359.99f); SkRect r; SkPaint paint; paint.setAntiAlias(true); paint.setStrokeWidth(SkIntToScalar(2)); paint.setStyle(SkPaint::kStroke_Style); r.set(0, 0, SkIntToScalar(200), SkIntToScalar(200)); r.offset(SkIntToScalar(20), SkIntToScalar(20)); if (false) { const SkScalar d = SkIntToScalar(3); const SkScalar rad[] = { d, d, d, d, d, d, d, d }; SkPath path; path.addRoundRect(r, rad); canvas->drawPath(path, paint); return; } drawRectWithLines(canvas, r, paint); // printf("----- sweep %g %X\n", SkScalarToFloat(fSweep), SkDegreesToRadians(fSweep)); paint.setStyle(SkPaint::kFill_Style); paint.setColor(0x800000FF); canvas->drawArc(r, 0, fSweep, true, paint); paint.setColor(0x800FF000); canvas->drawArc(r, 0, fSweep, false, paint); paint.setStyle(SkPaint::kStroke_Style); paint.setColor(SK_ColorRED); canvas->drawArc(r, 0, fSweep, true, paint); paint.setStrokeWidth(0); paint.setColor(SK_ColorBLUE); canvas->drawArc(r, 0, fSweep, false, paint); drawArcs(canvas); this->inval(NULL); }
static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) { SkRect rect = SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height); float rx = description.shape.roundRect.rx; float ry = description.shape.roundRect.ry; if (description.style == SkPaint::kStrokeAndFill_Style) { float outset = description.strokeWidth / 2; rect.outset(outset, outset); rx += outset; ry += outset; } SkPath path; path.addRoundRect(rect, rx, ry); return tessellatePath(description, path); }
void draw(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); for (auto xradius : { 0, 7, 13, 20 } ) { for (auto yradius : { 0, 9, 18, 40 } ) { SkPath path; path.addRoundRect({10, 10, 36, 46}, xradius, yradius); paint.setColor(path.isRect(nullptr) ? SK_ColorRED : path.isOval(nullptr) ? SK_ColorBLUE : path.isConvex() ? SK_ColorGRAY : SK_ColorGREEN); canvas->drawPath(path, paint); canvas->translate(64, 0); } canvas->translate(-256, 64); } }
PathTexture* RoundRectShapeCache::getRoundRect(float width, float height, float rx, float ry, SkPaint* paint) { RoundRectShapeCacheEntry entry(width, height, rx, ry, paint); PathTexture* texture = get(entry); if (!texture) { SkPath path; SkRect r; r.set(0.0f, 0.0f, width, height); path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); texture = addTexture(entry, &path, paint); } return texture; }
AAClipBench(bool doPath, bool doAA) : fDoPath(doPath) , fDoAA(doAA) { fName.printf("aaclip_%s_%s", doPath ? "path" : "rect", doAA ? "AA" : "BW"); fClipRect.set(10.5f, 10.5f, 50.5f, 50.5f); fClipPath.addRoundRect(fClipRect, SkIntToScalar(10), SkIntToScalar(10)); fDrawRect.set(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(100), SkIntToScalar(100)); SkASSERT(fClipPath.isConvex()); }
virtual void onDrawContent(SkCanvas* canvas) { #if 1 SkAAClip aaclip; SkPath path; SkRect bounds; bounds.set(0, 0, 20, 20); bounds.inset(SK_ScalarHalf, SK_ScalarHalf); // path.addRect(bounds); // path.addOval(bounds); path.addRoundRect(bounds, 4, 4); aaclip.setPath(path); canvas->translate(30, 30); drawClip(canvas, aaclip); SkAAClip aaclip2; path.offset(10, 10); aaclip2.setPath(path); canvas->translate(30, 0); drawClip(canvas, aaclip2); SkAAClip aaclip3; aaclip3.op(aaclip, aaclip2, SkRegion::kIntersect_Op); canvas->translate(30, 0); drawClip(canvas, aaclip3); #endif #if 0 SkRect r; r.set(0, 0, this->width(), this->height()); r.inset(20, 20); canvas->clipRect(r); SkPath path; path.addRect(r); SkPaint paint; paint.setAntiAlias(true); paint.setColor(SK_ColorRED); canvas->drawPath(path, paint); #endif }
void recurse(SkCanvas* canvas, int depth, const SkPoint& offset) { canvas->save(); SkRect temp = SkRect::MakeLTRB(0, 0, fSizes[depth].fX, fSizes[depth].fY); temp.offset(offset); SkPath path; path.addRoundRect(temp, SkIntToScalar(3), SkIntToScalar(3)); SkASSERT(path.isConvex()); canvas->clipPath(path, 0 == depth ? SkRegion::kReplace_Op : SkRegion::kIntersect_Op, fDoAA); if (kNestingDepth == depth) { // we only draw the draw rect at the lowest nesting level SkPaint paint; paint.setColor(0xff000000 | fRandom.nextU()); canvas->drawRect(fDrawRect, paint); } else { SkPoint childOffset = offset; this->recurse(canvas, depth+1, childOffset); childOffset += fSizes[depth+1]; this->recurse(canvas, depth+1, childOffset); childOffset.fX = offset.fX + fSizes[depth+1].fX; childOffset.fY = offset.fY; this->recurse(canvas, depth+1, childOffset); childOffset.fX = offset.fX; childOffset.fY = offset.fY + fSizes[depth+1].fY; this->recurse(canvas, depth+1, childOffset); } canvas->restore(); }
PathTexture* PathCache::getRoundRect(float width, float height, float rx, float ry, const SkPaint* paint) { PathDescription entry(kShapeRoundRect, paint); entry.shape.roundRect.mWidth = width; entry.shape.roundRect.mHeight = height; entry.shape.roundRect.mRx = rx; entry.shape.roundRect.mRy = ry; PathTexture* texture = get(entry); if (!texture) { SkPath path; SkRect r; r.set(0.0f, 0.0f, width, height); path.addRoundRect(r, rx, ry, SkPath::kCW_Direction); texture = addTexture(entry, &path, paint); } return texture; }
static void TestParsePath(skiatest::Reporter* reporter) { for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); i++) { SkPath path; bool success = SkParsePath::FromSVGString(gRec[i].fStr, &path); REPORTER_ASSERT(reporter, success); const SkRect& expectedBounds = gRec[i].fBounds; const SkRect& pathBounds = path.getBounds(); REPORTER_ASSERT(reporter, expectedBounds == pathBounds); test_to_from(reporter, path); } SkRect r; r.set(0, 0, SkFloatToScalar(10), SkFloatToScalar(10.5f)); SkPath p; p.addRect(r); test_to_from(reporter, p); p.addOval(r); test_to_from(reporter, p); p.addRoundRect(r, SkFloatToScalar(4), SkFloatToScalar(4.5f)); test_to_from(reporter, p); }
virtual void onDraw(SkCanvas* canvas) { int offset = 35000; int extents = 1000; // We record a picture of huge vertical extents in which we clear the canvas to red, create // a 'extents' by 'extents' round rect clip at a vertical offset of 'offset', then draw // green into that. SkPicture pict; SkCanvas* rec = pict.beginRecording(100, offset + extents); rec->drawColor(0xffff0000); rec->save(); SkRect r = { SkIntToScalar(-extents), SkIntToScalar(offset - extents), SkIntToScalar(extents), SkIntToScalar(offset + extents) }; SkPath p; p.addRoundRect(r, 5, 5); rec->clipPath(p, SkRegion::kIntersect_Op, true); rec->drawColor(0xff00ff00); rec->restore(); pict.endRecording(); // Next we play that picture into another picture of the same size. SkPicture pict2; pict.draw(pict2.beginRecording(100, offset + extents)); pict2.endRecording(); // Finally we play the part of that second picture that should be green into the canvas. canvas->save(); canvas->translate(SkIntToScalar(extents / 2), SkIntToScalar(-(offset - extents / 2))); pict2.draw(canvas); canvas->restore(); // If the image is red, we erroneously decided the clipPath was empty and didn't record // the green drawColor, if it's green we're all good. }
SkPath makePath() { SkPath path; for (uint32_t cIndex = 0; cIndex < fPathContourCount; ++cIndex) { uint32_t segments = makeSegmentCount(); for (uint32_t sIndex = 0; sIndex < segments; ++sIndex) { RandomAddPath addPathType = makeAddPathType(); ++fAddCount; if (fPrintName) { SkDebugf("%.*s%s\n", fPathDepth * 3, fTab, gRandomAddPathNames[addPathType]); } switch (addPathType) { case kAddArc: { SkRect oval = makeRect(); SkScalar startAngle = makeAngle(); SkScalar sweepAngle = makeAngle(); path.addArc(oval, startAngle, sweepAngle); validate(path); } break; case kAddRoundRect1: { SkRect rect = makeRect(); SkScalar rx = makeScalar(), ry = makeScalar(); SkPath::Direction dir = makeDirection(); path.addRoundRect(rect, rx, ry, dir); validate(path); } break; case kAddRoundRect2: { SkRect rect = makeRect(); SkScalar radii[8]; makeScalarArray(SK_ARRAY_COUNT(radii), radii); SkPath::Direction dir = makeDirection(); path.addRoundRect(rect, radii, dir); validate(path); } break; case kAddRRect: { SkRRect rrect = makeRRect(); SkPath::Direction dir = makeDirection(); path.addRRect(rrect, dir); validate(path); } break; case kAddPoly: { SkTDArray<SkPoint> points; makePointArray(&points); bool close = makeBool(); path.addPoly(&points[0], points.count(), close); validate(path); } break; case kAddPath1: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkScalar dx = makeScalar(); SkScalar dy = makeScalar(); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, dx, dy, mode); --fPathDepth; validate(path); } break; case kAddPath2: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, mode); --fPathDepth; validate(path); } break; case kAddPath3: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); SkMatrix matrix = makeMatrix(); SkPath::AddPathMode mode = makeAddPathMode(); path.addPath(src, matrix, mode); --fPathDepth; validate(path); } break; case kReverseAddPath: if (fPathDepth < fPathDepthLimit) { ++fPathDepth; SkPath src = makePath(); validate(src); path.reverseAddPath(src); --fPathDepth; validate(path); } break; case kMoveToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.moveTo(x, y); validate(path); } break; case kRMoveToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.rMoveTo(x, y); validate(path); } break; case kLineToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.lineTo(x, y); validate(path); } break; case kRLineToPath: { SkScalar x = makeScalar(); SkScalar y = makeScalar(); path.rLineTo(x, y); validate(path); } break; case kQuadToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.quadTo(pt[0], pt[1]); validate(path); } break; case kRQuadToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.rQuadTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY); validate(path); } break; case kConicToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar weight = makeScalar(); path.conicTo(pt[0], pt[1], weight); validate(path); } break; case kRConicToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar weight = makeScalar(); path.rConicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, weight); validate(path); } break; case kCubicToPath: { SkPoint pt[3]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.cubicTo(pt[0], pt[1], pt[2]); validate(path); } break; case kRCubicToPath: { SkPoint pt[3]; makePointArray(SK_ARRAY_COUNT(pt), pt); path.rCubicTo(pt[0].fX, pt[0].fY, pt[1].fX, pt[1].fY, pt[2].fX, pt[2].fY); validate(path); } break; case kArcToPath: { SkPoint pt[2]; makePointArray(SK_ARRAY_COUNT(pt), pt); SkScalar radius = makeScalar(); path.arcTo(pt[0], pt[1], radius); validate(path); } break; case kArcTo2Path: { SkRect oval = makeRect(); SkScalar startAngle = makeAngle(); SkScalar sweepAngle = makeAngle(); bool forceMoveTo = makeBool(); path.arcTo(oval, startAngle, sweepAngle, forceMoveTo); validate(path); } break; case kClosePath: path.close(); validate(path); break; } } } return path; }