void draw_fill(SkCanvas* canvas, const SkRect& rect, SkScalar width) { if (rect.isEmpty()) { return; } SkPaint paint; paint.setColor(0x1f1f0f0f); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(width); SkPath path; SkScalar maxSide = SkTMax(rect.width(), rect.height()) / 2; SkPoint center = { rect.fLeft + maxSide, rect.fTop + maxSide }; path.addCircle(center.fX, center.fY, maxSide); canvas->drawPath(path, paint); paint.setStyle(SkPaint::kFill_Style); path.reset(); path.addCircle(center.fX, center.fY, maxSide - width / 2); paint.setColor(0x3f0f1f3f); canvas->drawPath(path, paint); path.reset(); path.setFillType(SkPath::kEvenOdd_FillType); path.addCircle(center.fX, center.fY, maxSide + width / 2); SkRect outside = SkRect::MakeXYWH(center.fX - maxSide - width, center.fY - maxSide - width, (maxSide + width) * 2, (maxSide + width) * 2); path.addRect(outside); canvas->drawPath(path, paint); }
virtual void onDraw(SkCanvas* canvas) { if (false) test_rev(canvas); // avoid bit rot, suppress warning SkRect r = { 10, 10, 100, 60 }; SkPath path; path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.offset(20, 20); path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.reset(); path.moveTo(10, 10); path.lineTo(30, 30); path.addOval(r); r.offset(50, 20); path.addOval(r); test_rev(canvas, path); SkPaint paint; paint.setTextSize(SkIntToScalar(100)); SkTypeface* hira = SkTypeface::CreateFromName("Hiragino Maru Gothic Pro", SkTypeface::kNormal); SkSafeUnref(paint.setTypeface(hira)); path.reset(); paint.getTextPath("e", 1, 50, 50, &path); canvas->translate(0, 100); test_rev(canvas, path); }
static void test_undetected_paths(skiatest::Reporter* reporter) { SkPath path; path.moveTo(0, 62.5f); path.lineTo(0, 3.5f); path.conicTo(0, 0, 3.5f, 0, 0.70710677f); path.lineTo(196.5f, 0); path.conicTo(200, 0, 200, 3.5f, 0.70710677f); path.lineTo(200, 62.5f); path.conicTo(200, 66, 196.5f, 66, 0.70710677f); path.lineTo(3.5f, 66); path.conicTo(0, 66, 0, 62.5, 0.70710677f); path.close(); force_path_contains_rrect(reporter, path); path.reset(); path.moveTo(0, 81.5f); path.lineTo(0, 3.5f); path.conicTo(0, 0, 3.5f, 0, 0.70710677f); path.lineTo(149.5, 0); path.conicTo(153, 0, 153, 3.5f, 0.70710677f); path.lineTo(153, 81.5f); path.conicTo(153, 85, 149.5f, 85, 0.70710677f); path.lineTo(3.5f, 85); path.conicTo(0, 85, 0, 81.5f, 0.70710677f); path.close(); force_path_contains_rrect(reporter, path); path.reset(); path.moveTo(14, 1189); path.lineTo(14, 21); path.conicTo(14, 14, 21, 14, 0.70710677f); path.lineTo(1363, 14); path.conicTo(1370, 14, 1370, 21, 0.70710677f); path.lineTo(1370, 1189); path.conicTo(1370, 1196, 1363, 1196, 0.70710677f); path.lineTo(21, 1196); path.conicTo(14, 1196, 14, 1189, 0.70710677f); path.close(); force_path_contains_rrect(reporter, path); path.reset(); path.moveTo(14, 1743); path.lineTo(14, 21); path.conicTo(14, 14, 21, 14, 0.70710677f); path.lineTo(1363, 14); path.conicTo(1370, 14, 1370, 21, 0.70710677f); path.lineTo(1370, 1743); path.conicTo(1370, 1750, 1363, 1750, 0.70710677f); path.lineTo(21, 1750); path.conicTo(14, 1750, 14, 1743, 0.70710677f); path.close(); force_path_contains_rrect(reporter, path); }
virtual void onDraw(SkCanvas* canvas) { // explicitly add spaces, to test a prev. bug const char* text = "Ham bur ge fons"; int len = SkToInt(strlen(text)); SkPath path; SkPaint paint; paint.setAntiAlias(true); paint.setTextSize(SkIntToScalar(48)); canvas->translate(SkIntToScalar(10), SkIntToScalar(64)); canvas->drawText(text, len, 0, 0, paint); paint.getTextPath(text, len, 0, 0, &path); strokePath(canvas, path); path.reset(); SkAutoTArray<SkPoint> pos(len); SkAutoTArray<SkScalar> widths(len); paint.getTextWidths(text, len, &widths[0]); SkLCGRandom rand; SkScalar x = SkIntToScalar(20); SkScalar y = SkIntToScalar(100); for (int i = 0; i < len; ++i) { pos[i].set(x, y + rand.nextSScalar1() * 24); x += widths[i]; } canvas->translate(0, SkIntToScalar(64)); canvas->drawPosText(text, len, &pos[0], paint); paint.getPosTextPath(text, len, &pos[0], &path); strokePath(canvas, path); }
// Need to exercise drawing an inverse-path whose bounds intersect the clip, // but whose edges do not (since its a quad which draws only in the bottom half // of its bounds). // In the debug build, we used to assert in this case, until it was fixed. // static void test_inversepathwithclip() { SkPath path; path.moveTo(0, 20); path.quadTo(10, 10, 20, 20); path.toggleInverseFillType(); SkPaint paint; auto surface(SkSurface::MakeRasterN32Premul(640, 480)); SkCanvas* canvas = surface->getCanvas(); canvas->save(); canvas->clipRect(SkRect::MakeWH(19, 11)); paint.setAntiAlias(false); canvas->drawPath(path, paint); paint.setAntiAlias(true); canvas->drawPath(path, paint); canvas->restore(); // Now do the test again, with the path flipped, so we only draw in the // top half of our bounds, and have the clip intersect our bounds at the // bottom. path.reset(); // preserves our filltype path.moveTo(0, 10); path.quadTo(10, 20, 20, 10); canvas->clipRect(SkRect::MakeXYWH(0, 19, 19, 11)); paint.setAntiAlias(false); canvas->drawPath(path, paint); paint.setAntiAlias(true); canvas->drawPath(path, paint); }
void operate(const SkPath& one, const SkPath& two, ShapeOp op, SkPath& result) { result.reset(); result.setFillType(SkPath::kEvenOdd_FillType); // turn path into list of segments SkTArray<Op::Contour> contours; // FIXME: add self-intersecting cubics' T values to segment Op::EdgeBuilder builder(one, contours); const int aXorMask = builder.xorMask(); builder.addOperand(two); const int bXorMask = builder.xorMask(); builder.finish(); SkTDArray<Op::Contour*> contourList; makeContourList(contours, contourList); Op::Contour** currentPtr = contourList.begin(); if (!currentPtr) { return; } Op::Contour** listEnd = contourList.end(); // find all intersections between segments do { Op::Contour** nextPtr = currentPtr; Op::Contour* current = *currentPtr++; Op::Contour* next; do { next = *nextPtr++; } while (addIntersectTs(current, next) && nextPtr != listEnd); } while (currentPtr != listEnd); // eat through coincident edges coincidenceCheck(contourList); fixOtherTIndex(contourList); // construct closed contours Op::PathWrapper wrapper(result); bridgeOp(contourList, op, aXorMask, bXorMask, wrapper); }
static void test_path_bounds(skiatest::Reporter* reporter) { SkPath path; SkAAClip clip; const int height = 40; const SkScalar sheight = SkIntToScalar(height); path.addOval(SkRect::MakeWH(sheight, sheight)); REPORTER_ASSERT(reporter, sheight == path.getBounds().height()); clip.setPath(path, nullptr, true); REPORTER_ASSERT(reporter, height == clip.getBounds().height()); // this is the trimmed height of this cubic (with aa). The critical thing // for this test is that it is less than height, which represents just // the bounds of the path's control-points. // // This used to fail until we tracked the MinY in the BuilderBlitter. // const int teardrop_height = 12; path.reset(); imoveTo(path, 0, 20); icubicTo(path, 40, 40, 40, 0, 0, 20); REPORTER_ASSERT(reporter, sheight == path.getBounds().height()); clip.setPath(path, nullptr, true); REPORTER_ASSERT(reporter, teardrop_height == clip.getBounds().height()); }
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 SkPathStroker::finishContour(bool close, bool currIsLine) { if (fSegmentCount > 0) { SkPoint pt; if (close) { fJoiner(&fOuter, &fInner, fPrevUnitNormal, fPrevPt, fFirstUnitNormal, fRadius, fInvMiterLimit, fPrevIsLine, currIsLine); fOuter.close(); // now add fInner as its own contour fInner.getLastPt(&pt); fOuter.moveTo(pt.fX, pt.fY); fOuter.reversePathTo(fInner); fOuter.close(); } else { // add caps to start and end // cap the end fInner.getLastPt(&pt); fCapper(&fOuter, fPrevPt, fPrevNormal, pt, currIsLine ? &fInner : NULL); fOuter.reversePathTo(fInner); // cap the start fCapper(&fOuter, fFirstPt, -fFirstNormal, fFirstOuterPt, fPrevIsLine ? &fInner : NULL); fOuter.close(); } } fInner.reset(); fSegmentCount = -1; }
static void patheffect_slide(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); SkPath path; path.moveTo(20, 20); path.lineTo(70, 120); path.lineTo(120, 30); path.lineTo(170, 80); path.lineTo(240, 50); size_t i; canvas->save(); for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) { gPE[i](&paint); canvas->drawPath(path, paint); canvas->translate(0, 75); } canvas->restore(); path.reset(); SkRect r = { 0, 0, 250, 120 }; path.addOval(r, SkPath::kCW_Direction); r.inset(50, 50); path.addRect(r, SkPath::kCCW_Direction); canvas->translate(320, 20); for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) { gPE2[i](&paint); canvas->drawPath(path, paint); canvas->translate(0, 160); } }
void SampleWindow::onSizeChange() { this->INHERITED::onSizeChange(); SkView::F2BIter iter(this); SkView* view = iter.next(); view->setSize(this->width(), this->height()); // rebuild our clippath { const SkScalar W = this->width(); const SkScalar H = this->height(); fClipPath.reset(); #if 0 for (SkScalar y = SK_Scalar1; y < H; y += SkIntToScalar(32)) { SkRect r; r.set(SK_Scalar1, y, SkIntToScalar(30), y + SkIntToScalar(30)); for (; r.fLeft < W; r.offset(SkIntToScalar(32), 0)) fClipPath.addRect(r); } #else SkRect r; r.set(0, 0, W, H); fClipPath.addRect(r, SkPath::kCCW_Direction); r.set(W/4, H/4, W*3/4, H*3/4); fClipPath.addRect(r, SkPath::kCW_Direction); #endif } this->updateTitle(); // to refresh our config }
DEF_TEST(contour_measure, reporter) { SkPath path; path.addCircle(0, 0, 100); path.addCircle(0, 0, 10); SkContourMeasureIter fact(path, false); path.reset(); // we should not need the path avert we created the factory auto cm0 = fact.next(); auto cm1 = fact.next(); REPORTER_ASSERT(reporter, cm0->isClosed()); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(cm0->length(), 200 * SK_ScalarPI, 1.5f)); test_90_degrees(cm0, 100, reporter); REPORTER_ASSERT(reporter, cm1->isClosed()); REPORTER_ASSERT(reporter, SkScalarNearlyEqual(cm1->length(), 20 * SK_ScalarPI, 0.5f)); test_90_degrees(cm1, 10, reporter); auto cm2 = fact.next(); REPORTER_ASSERT(reporter, !cm2); test_empty_contours(reporter); test_MLM_contours(reporter); }
void onDraw(SkCanvas* canvas) override { SkPaint p; p.setColor(SK_ColorRED); p.setAntiAlias(true); canvas->clear(0xFFFFFFFF); canvas->save(); canvas->rotate(1); const SkScalar R = 115.2f, C = 128.0f; SkPath path; path.moveTo(C + R, C); for (int i = 1; i < 8; ++i) { SkScalar a = 2.6927937f * i; SkScalar cosine; SkScalar sine = SkScalarSinCos(a, &cosine); path.lineTo(C + R * cosine, C + R * sine); } canvas->drawPath(path, p); canvas->restore(); canvas->save(); canvas->translate(200, 0); canvas->rotate(1); p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(5); canvas->drawPath(path, p); canvas->restore(); // The following two paths test if we correctly cumulates the alpha on the middle pixel // column where the left rect and the right rect abut. p.setStyle(SkPaint::kFill_Style); canvas->translate(0, 300); path.reset(); path.addRect({20, 20, 100.4999f, 100}); path.addRect({100.5001f, 20, 200, 100}); canvas->drawPath(path, p); canvas->translate(300, 0); path.reset(); path.addRect({20, 20, 100.1f, 100}); path.addRect({100.9f, 20, 200, 100}); canvas->drawPath(path, p); }
void skiaDrawLine(caskbench_context_t *ctx, shapes_t *args) { path.reset(); path.moveTo(args->x, args->y); path.lineTo(args->x + args->width, args->y + args->height); ctx->skia_canvas->drawPath(path, *(ctx->skia_paint)); }
void skiaDrawQuadraticCurve(caskbench_context_t *ctx, shapes_t *args) { path.reset(); path.moveTo(args->x, args->y); path.rQuadTo(args->dx1, args->dy1, args->width, args->height); ctx->skia_canvas->drawPath(path, *(ctx->skia_paint)); }
/** * Called on a background thread. Here we can only modify fBackPaths. */ void runAnimationTask(double t, double dt, int w, int h) override { const float tsec = static_cast<float>(t); this->INHERITED::runAnimationTask(t, 0.5 * dt, w, h); for (int i = 0; i < kNumPaths; ++i) { const Glyph& glyph = fGlyphs[i]; const SkMatrix& backMatrix = fBackMatrices[i]; const Sk2f matrix[3] = { Sk2f(backMatrix.getScaleX(), backMatrix.getSkewY()), Sk2f(backMatrix.getSkewX(), backMatrix.getScaleY()), Sk2f(backMatrix.getTranslateX(), backMatrix.getTranslateY()) }; SkPath* backpath = &fBackPaths[i]; backpath->reset(); backpath->setFillType(SkPath::kEvenOdd_FillType); SkPath::RawIter iter(glyph.fPath); SkPath::Verb verb; SkPoint pts[4]; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: { SkPoint pt = fWaves.apply(tsec, matrix, pts[0]); backpath->moveTo(pt.x(), pt.y()); break; } case SkPath::kLine_Verb: { SkPoint endpt = fWaves.apply(tsec, matrix, pts[1]); backpath->lineTo(endpt.x(), endpt.y()); break; } case SkPath::kQuad_Verb: { SkPoint controlPt = fWaves.apply(tsec, matrix, pts[1]); SkPoint endpt = fWaves.apply(tsec, matrix, pts[2]); backpath->quadTo(controlPt.x(), controlPt.y(), endpt.x(), endpt.y()); break; } case SkPath::kClose_Verb: { backpath->close(); break; } case SkPath::kCubic_Verb: case SkPath::kConic_Verb: case SkPath::kDone_Verb: SK_ABORT("Unexpected path verb"); break; } } } }
static void test_convexity(skiatest::Reporter* reporter) { static const SkPath::Convexity C = SkPath::kConcave_Convexity; static const SkPath::Convexity V = SkPath::kConvex_Convexity; SkPath path; REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); path.addCircle(0, 0, 10); REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); path.addCircle(0, 0, 10); // 2nd circle REPORTER_ASSERT(reporter, C == SkPath::ComputeConvexity(path)); path.reset(); path.addRect(0, 0, 10, 10, SkPath::kCCW_Direction); REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); path.reset(); path.addRect(0, 0, 10, 10, SkPath::kCW_Direction); REPORTER_ASSERT(reporter, V == SkPath::ComputeConvexity(path)); static const struct { const char* fPathStr; SkPath::Convexity fExpectedConvexity; } gRec[] = { { "", SkPath::kConvex_Convexity }, { "0 0", SkPath::kConvex_Convexity }, { "0 0 10 10", SkPath::kConvex_Convexity }, { "0 0 10 10 20 20 0 0 10 10", SkPath::kConcave_Convexity }, { "0 0 10 10 10 20", SkPath::kConvex_Convexity }, { "0 0 10 10 10 0", SkPath::kConvex_Convexity }, { "0 0 10 10 10 0 0 10", SkPath::kConcave_Convexity }, { "0 0 10 0 0 10 -10 -10", SkPath::kConcave_Convexity }, }; for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) { SkPath path; setFromString(&path, gRec[i].fPathStr); SkPath::Convexity c = SkPath::ComputeConvexity(path); REPORTER_ASSERT(reporter, c == gRec[i].fExpectedConvexity); } }
DEF_TEST(PathMeasureConic, reporter) { SkPoint stdP, hiP, pts[] = {{0,0}, {100,0}, {100,0}}; SkPath p; p.moveTo(0, 0); p.conicTo(pts[1], pts[2], 1); SkPathMeasure stdm(p, false); REPORTER_ASSERT(reporter, stdm.getPosTan(20, &stdP, nullptr)); p.reset(); p.moveTo(0, 0); p.conicTo(pts[1], pts[2], 10); stdm.setPath(&p, false); REPORTER_ASSERT(reporter, stdm.getPosTan(20, &hiP, nullptr)); REPORTER_ASSERT(reporter, 19.5f < stdP.fX && stdP.fX < 20.5f); REPORTER_ASSERT(reporter, 19.5f < hiP.fX && hiP.fX < 20.5f); }
void skiaDrawTriangle(caskbench_context_t *ctx, shapes_t *args) { // Temporarily disable anti-aliasing to work around crash in GlShader ctx->skia_paint->setAntiAlias(false); path.reset(); path.moveTo(args->x, args->y + 2*args->radius); path.rLineTo(2*args->radius, 0); path.rLineTo(-args->radius, -2*args->radius); path.close(); ctx->skia_canvas->drawPath(path, *(ctx->skia_paint)); ctx->skia_paint->setAntiAlias(true); }
void skiaDrawStar(caskbench_context_t *ctx, shapes_t *args) { int px = args->x + 2*args->radius * star_points[0][0]/200.0; int py = args->y + 2*args->radius * star_points[0][1]/200.0; path.reset(); path.moveTo(px, py); for (int p = 1; p < 10; p++ ) { px = args->x + 2*args->radius * star_points[p][0]/200.0; py = args->y + 2*args->radius * star_points[p][1]/200.0; path.lineTo(px, py); } path.close(); ctx->skia_canvas->drawPath(path, *(ctx->skia_paint)); }
virtual void onDraw(SkCanvas* canvas) { SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); SkPath path; path.moveTo(20, 20); path.lineTo(70, 120); path.lineTo(120, 30); path.lineTo(170, 80); path.lineTo(240, 50); size_t i; canvas->save(); for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) { gPE[i](&paint); canvas->drawPath(path, paint); canvas->translate(0, 75); } canvas->restore(); path.reset(); SkRect r = { 0, 0, 250, 120 }; path.addOval(r, SkPath::kCW_Direction); r.inset(50, 50); path.addRect(r, SkPath::kCCW_Direction); canvas->translate(320, 20); for (i = 0; i < SK_ARRAY_COUNT(gPE2); i++) { gPE2[i](&paint); canvas->drawPath(path, paint); canvas->translate(0, 160); } SkIRect rect = SkIRect::MakeXYWH(20, 20, 60, 60); for (i = 0; i < SK_ARRAY_COUNT(gPE); i++) { SkPaint p; p.setAntiAlias(true); p.setStyle(SkPaint::kFill_Style); gPE[i](&p); canvas->drawIRect(rect, p); canvas->translate(75, 0); } }
static void writePng(const SkConic& c, const SkConic ch[2], const char* name) { const int scale = 10; SkConic conic, chopped[2]; for (int index = 0; index < 3; ++index) { conic.fPts[index].fX = c.fPts[index].fX * scale; conic.fPts[index].fY = c.fPts[index].fY * scale; for (int chIndex = 0; chIndex < 2; ++chIndex) { chopped[chIndex].fPts[index].fX = ch[chIndex].fPts[index].fX * scale; chopped[chIndex].fPts[index].fY = ch[chIndex].fPts[index].fY * scale; } } conic.fW = c.fW; chopped[0].fW = ch[0].fW; chopped[1].fW = ch[1].fW; SkBitmap bitmap; SkRect bounds; conic.computeTightBounds(&bounds); bounds.outset(10, 10); bitmap.tryAllocPixels(SkImageInfo::MakeN32Premul( SkScalarRoundToInt(bounds.width()), SkScalarRoundToInt(bounds.height()))); SkCanvas canvas(bitmap); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); canvas.translate(-bounds.fLeft, -bounds.fTop); canvas.drawColor(SK_ColorWHITE); SkPath path; path.moveTo(conic.fPts[0]); path.conicTo(conic.fPts[1], conic.fPts[2], conic.fW); paint.setARGB(0x80, 0xFF, 0, 0); canvas.drawPath(path, paint); path.reset(); path.moveTo(chopped[0].fPts[0]); path.conicTo(chopped[0].fPts[1], chopped[0].fPts[2], chopped[0].fW); path.moveTo(chopped[1].fPts[0]); path.conicTo(chopped[1].fPts[1], chopped[1].fPts[2], chopped[1].fW); paint.setARGB(0x80, 0, 0, 0xFF); canvas.drawPath(path, paint); SkString filename("c:\\Users\\caryclark\\Documents\\"); filename.appendf("%s.png", name); SkImageEncoder::EncodeFile(filename.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); }
DEF_TEST(cubic_scan_error_crbug_844457_and_845489, reporter) { auto surface(SkSurface::MakeRasterN32Premul(100, 100)); SkCanvas* canvas = surface->getCanvas(); SkPaint p; SkPath path; path.moveTo(-30/64.0, -31/64.0); path.cubicTo(-31/64.0, -31/64,-31/64.0, -31/64,-31/64.0, 100); path.lineTo(100, 100); canvas->drawPath(path, p); // May need to define SK_RASTERIZE_EVEN_ROUNDING to trigger the need for this test path.reset(); path.moveTo(-30/64.0f, -31/64.0f + 1/256.0f); path.cubicTo(-31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f, -31/64.0f + 1/256.0f, 100); path.lineTo(100, 100); canvas->drawPath(path, p); }
static void writeDPng(const SkDConic& dC, const char* name) { const int scale = 5; SkDConic dConic = {{{ {dC.fPts[0].fX * scale, dC.fPts[0].fY * scale }, {dC.fPts[1].fX * scale, dC.fPts[1].fY * scale }, {dC.fPts[2].fX * scale, dC.fPts[2].fY * scale }}}, dC.fWeight }; SkBitmap bitmap; SkDRect bounds; bounds.setBounds(dConic); bounds.fLeft -= 10; bounds.fTop -= 10; bounds.fRight += 10; bounds.fBottom += 10; bitmap.tryAllocPixels(SkImageInfo::MakeN32Premul( SkScalarRoundToInt(SkDoubleToScalar(bounds.width())), SkScalarRoundToInt(SkDoubleToScalar(bounds.height())))); SkCanvas canvas(bitmap); SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); canvas.translate(SkDoubleToScalar(-bounds.fLeft), SkDoubleToScalar(-bounds.fTop)); canvas.drawColor(SK_ColorWHITE); SkPath path; path.moveTo(dConic.fPts[0].asSkPoint()); path.conicTo(dConic.fPts[1].asSkPoint(), dConic.fPts[2].asSkPoint(), dConic.fWeight); paint.setARGB(0x80, 0xFF, 0, 0); canvas.drawPath(path, paint); path.reset(); const int chops = 2; for (int tIndex = 0; tIndex < chops; ++tIndex) { SkDConic chopped = dConic.subDivide(tIndex / (double) chops, (tIndex + 1) / (double) chops); path.moveTo(chopped.fPts[0].asSkPoint()); path.conicTo(chopped.fPts[1].asSkPoint(), chopped.fPts[2].asSkPoint(), chopped.fWeight); } paint.setARGB(0x80, 0, 0, 0xFF); canvas.drawPath(path, paint); SkString filename("c:\\Users\\caryclark\\Documents\\"); filename.appendf("%s.png", name); SkImageEncoder::EncodeFile(filename.c_str(), bitmap, SkImageEncoder::kPNG_Type, 100); }
DEF_TEST(SkOpBuilderFuzz665, reporter) { SkPath path; path.setFillType(SkPath::kEvenOdd_FillType); path.moveTo(SkBits2Float(0xcc4264a7), SkBits2Float(0x4bb12e50)); // -5.0959e+07f, 2.32235e+07f path.lineTo(SkBits2Float(0xcc4264b0), SkBits2Float(0x4bb12e48)); // -5.0959e+07f, 2.32234e+07f path.lineTo(SkBits2Float(0xcc4264a7), SkBits2Float(0x4bb12e50)); // -5.0959e+07f, 2.32235e+07f path.close(); SkPath path1(path); path.reset(); path.setFillType(SkPath::kWinding_FillType); path.moveTo(SkBits2Float(0x43213333), SkBits2Float(0x43080000)); // 161.2f, 136 path.lineTo(SkBits2Float(0x43038000), SkBits2Float(0x43080000)); // 131.5f, 136 path.cubicTo(SkBits2Float(0x43038000), SkBits2Float(0x42f00000), SkBits2Float(0x42f16666), SkBits2Float(0x42d53333), SkBits2Float(0x42d3cccd), SkBits2Float(0x42cd6666)); // 131.5f, 120, 120.7f, 106.6f, 105.9f, 102.7f path.lineTo(SkBits2Float(0x42e33333), SkBits2Float(0x42940000)); // 113.6f, 74 SkPath path2(path); SkOpBuilder builder; builder.add(path1, kUnion_SkPathOp); builder.add(path2, kUnion_SkPathOp); SkPath result; builder.resolve(&result); }
static void draw_fins(SkCanvas* canvas, const SkPoint& offset, float angle, const SkPaint& paint) { SkScalar cos, sin; // first fin sin = SkScalarSinCos(angle + (SK_ScalarPI/4), &cos); sin *= kRadius / 2.0f; cos *= kRadius / 2.0f; SkPath p; p.moveTo(offset.fX, offset.fY); p.lineTo(offset.fX + cos, offset.fY + sin); canvas->drawPath(p, paint); // second fin sin = SkScalarSinCos(angle - (SK_ScalarPI/4), &cos); sin *= kRadius / 2.0f; cos *= kRadius / 2.0f; p.reset(); p.moveTo(offset.fX, offset.fY); p.lineTo(offset.fX + cos, offset.fY + sin); canvas->drawPath(p, paint); }
void onDraw(SkCanvas* canvas) override { SkRect r = { 10, 10, 100, 60 }; SkPath path; path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.offset(20, 20); path.addRect(r); test_rev(canvas, path); canvas->translate(0, 100); path.reset(); path.moveTo(10, 10); path.lineTo(30, 30); path.addOval(r); r.offset(50, 20); path.addOval(r); test_rev(canvas, path); path = hiragino_maru_goth_pro_e(); canvas->translate(0, 100); test_rev(canvas, path); }
// Need to exercise drawing an inverse-path whose bounds intersect the clip, // but whose edges do not (since its a quad which draws only in the bottom half // of its bounds). // In the debug build, we used to assert in this case, until it was fixed. // static void test_inversepathwithclip(skiatest::Reporter* reporter) { SkPath path; path.moveTo(0, SkIntToScalar(20)); path.quadTo(SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(20), SkIntToScalar(20)); path.toggleInverseFillType(); SkPaint paint; SkAutoTUnref<SkCanvas> canvas(new_canvas(640, 480)); canvas.get()->save(); canvas.get()->clipRect(SkRect::MakeWH(SkIntToScalar(19), SkIntToScalar(11))); paint.setAntiAlias(false); canvas.get()->drawPath(path, paint); paint.setAntiAlias(true); canvas.get()->drawPath(path, paint); canvas.get()->restore(); // Now do the test again, with the path flipped, so we only draw in the // top half of our bounds, and have the clip intersect our bounds at the // bottom. path.reset(); // preserves our filltype path.moveTo(0, SkIntToScalar(10)); path.quadTo(SkIntToScalar(10), SkIntToScalar(20), SkIntToScalar(20), SkIntToScalar(10)); canvas.get()->clipRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(19), SkIntToScalar(19), SkIntToScalar(11))); paint.setAntiAlias(false); canvas.get()->drawPath(path, paint); paint.setAntiAlias(true); canvas.get()->drawPath(path, paint); }
// aaclip.setRegion should create idential masks to the region static void test_rgn(skiatest::Reporter* reporter) { SkRandom rand; for (int i = 0; i < 1000; i++) { SkRegion rgn; make_rand_rgn(&rgn, rand); REPORTER_ASSERT(reporter, equalsAAClip(rgn)); } { SkRegion rgn; SkPath path; path.addCircle(0, 0, SkIntToScalar(30)); setRgnToPath(&rgn, path); REPORTER_ASSERT(reporter, equalsAAClip(rgn)); path.reset(); path.moveTo(0, 0); path.lineTo(SkIntToScalar(100), 0); path.lineTo(SkIntToScalar(100 - 20), SkIntToScalar(20)); path.lineTo(SkIntToScalar(20), SkIntToScalar(20)); setRgnToPath(&rgn, path); REPORTER_ASSERT(reporter, equalsAAClip(rgn)); } }
static void test_stroke(SkCanvas* canvas) { if (true) { SkPath path; dump(path); path.reset(); path.moveTo(0, 0); dump(path); path.reset(); path.moveTo(100, 100); dump(path); path.reset(); path.moveTo(0, 0); path.moveTo(100, 100); dump(path); path.reset(); path.moveTo(0, 0); path.lineTo(100, 100); dump(path); path.reset(); path.moveTo(0, 0); path.lineTo(100, 100); path.moveTo(200, 200); dump(path); } #if 0 // TEST 1 - The rectangle as it's expected to look var canvas = document.createElement('canvas'); document.body.appendChild(canvas); var ctx = canvas.getContext("2d"); #else SkJSCanvas ctx(canvas); #endif ctx.save(); ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(150, 100); ctx.lineTo(150, 15); ctx.lineTo(10, 15); ctx.closePath(); // no extra moveTo here // ctx.moveTo(175, 125); ctx.stroke(); ctx.restore(); ctx.fillText("As Expected", 10, 10); #if 0 // TEST 2 - Includes an extra moveTo call before stroke; the rectangle appears larger canvas = document.createElement('canvas'); document.body.appendChild(canvas); ctx = canvas.getContext("2d"); #else canvas->translate(200, 0); #endif ctx.save(); ctx.lineWidth = 2; ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(150, 100); ctx.lineTo(150, 15); ctx.lineTo(10, 15); ctx.closePath(); ctx.moveTo(175, 125); ctx.stroke(); ctx.restore(); ctx.fillText("Larger Rectangle", 10, 10); #if 0 // TEST 3 - Identical to test 2 except the line width is 1 canvas = document.createElement('canvas'); document.body.appendChild(canvas); ctx = canvas.getContext("2d"); #else canvas->translate(200, 0); #endif ctx.save(); ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(10, 100); ctx.lineTo(150, 100); ctx.lineTo(150, 15); ctx.lineTo(10, 15); ctx.closePath(); ctx.moveTo(175, 125); ctx.stroke(); ctx.restore(); ctx.fillText("As Expected - line width 1", 10, 10); }