void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) { SkPaint paint; this->setupSkeletonPaint(&paint); SkPath path; path.moveTo(pts[0]); path.lineTo(pts[1]); switch (fStyle) { case kHair_Style: if (fUseGPU) { SkPaint p; p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(SK_Scalar1 * fZoom); SkPath dst; p.getFillPath(path, &dst); path.addPath(dst); } break; case kStroke_Style: { SkPaint p; p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(SK_Scalar1 * fZoom); SkPath dst; p.getFillPath(path, &dst); path = dst; if (fUseGPU) { path.moveTo(dst.getPoint(0)); path.lineTo(dst.getPoint(2)); } } break; } max->drawPath(path, paint); }
bool PathSkia::StrokeContainsPoint(const StrokeOptions &aStrokeOptions, const Point &aPoint, const Matrix &aTransform) const { Matrix inverse = aTransform; inverse.Invert(); Point transformed = inverse * aPoint; SkPaint paint; StrokeOptionsToPaint(paint, aStrokeOptions); SkPath strokePath; paint.getFillPath(mPath, &strokePath); Rect bounds = aTransform.TransformBounds(SkRectToRect(strokePath.getBounds())); if (aPoint.x < bounds.x || aPoint.y < bounds.y || aPoint.x > bounds.XMost() || aPoint.y > bounds.YMost()) { return false; } SkRegion pointRect; pointRect.setRect(int32_t(SkFloatToScalar(transformed.x - 1.f)), int32_t(SkFloatToScalar(transformed.y - 1.f)), int32_t(SkFloatToScalar(transformed.x + 1.f)), int32_t(SkFloatToScalar(transformed.y + 1.f))); SkRegion pathRegion; return pathRegion.setPath(strokePath, pointRect); }
// found and fixed for webkit: mishandling when we hit recursion limit on // mostly degenerate cubic flatness test DEF_TEST(Paint_regression_cubic, reporter) { SkPath path, stroke; SkPaint paint; path.moveTo(460.2881309415525f, 303.250847066498f); path.cubicTo(463.36378422175284f, 302.1169735073363f, 456.32239330810046f, 304.720354932878f, 453.15255460013304f, 305.788586869862f); SkRect fillR, strokeR; fillR = path.getBounds(); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(2)); paint.getFillPath(path, &stroke); strokeR = stroke.getBounds(); SkRect maxR = fillR; SkScalar miter = SkMaxScalar(SK_Scalar1, paint.getStrokeMiter()); SkScalar inset = paint.getStrokeJoin() == SkPaint::kMiter_Join ? SkScalarMul(paint.getStrokeWidth(), miter) : paint.getStrokeWidth(); maxR.inset(-inset, -inset); // test that our stroke didn't explode REPORTER_ASSERT(reporter, maxR.contains(strokeR)); }
// Computes the bounding box for the stroke and style currently selected into // the given bounding box. This also takes into account the stroke width. static FloatRect boundingBoxForCurrentStroke(const GraphicsContext* context) { SkPaint paint; context->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath boundingPath; paint.getFillPath(context->platformContext()->currentPathInLocalCoordinates(), &boundingPath); return boundingPath.getBounds(); }
bool Path::strokeContains(const FloatPoint& point, const StrokeData& strokeData) const { SkPaint paint; strokeData.setupPaint(&paint); SkPath strokePath; paint.getFillPath(m_path, &strokePath); return SkPathContainsPoint(strokePath, point, SkPath::kWinding_FillType); }
FloatRect Path::strokeBoundingRect(const StrokeData& strokeData) const { SkPaint paint; strokeData.setupPaint(&paint); SkPath boundingPath; paint.getFillPath(m_path, &boundingPath); return boundingPath.getBounds(); }
static SkScalar make_frame(SkPath* path) { SkRect r = { 10, 10, 630, 470 }; path->addRoundRect(r, 15, 15); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(5); paint.getFillPath(*path, path); return 15; }
static void test_blur_drawing(skiatest::Reporter* reporter) { SkPaint paint; paint.setColor(SK_ColorGRAY); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(strokeWidth)); SkScalar sigma = SkBlurMask::ConvertRadiusToSigma(SkIntToScalar(5)); for (int style = 0; style <= kLastEnum_SkBlurStyle; ++style) { SkBlurStyle blurStyle = static_cast<SkBlurStyle>(style); const uint32_t flagPermutations = SkBlurMaskFilter::kAll_BlurFlag; for (uint32_t flags = 0; flags < flagPermutations; ++flags) { SkMaskFilter* filter; filter = SkBlurMaskFilter::Create(blurStyle, sigma, flags); paint.setMaskFilter(filter); filter->unref(); for (size_t test = 0; test < SK_ARRAY_COUNT(tests); ++test) { SkPath path; tests[test].addPath(&path); SkPath strokedPath; paint.getFillPath(path, &strokedPath); SkRect refBound = strokedPath.getBounds(); SkIRect iref; refBound.roundOut(&iref); iref.inset(-outset, -outset); SkBitmap refBitmap; create(&refBitmap, iref); SkCanvas refCanvas(refBitmap); refCanvas.translate(SkIntToScalar(-iref.fLeft), SkIntToScalar(-iref.fTop)); drawBG(&refCanvas); refCanvas.drawPath(path, paint); for (int view = 0; view < tests[test].viewLen; ++view) { SkIRect itest = tests[test].views[view]; SkBitmap testBitmap; create(&testBitmap, itest); SkCanvas testCanvas(testBitmap); testCanvas.translate(SkIntToScalar(-itest.fLeft), SkIntToScalar(-itest.fTop)); drawBG(&testCanvas); testCanvas.drawPath(path, paint); REPORTER_ASSERT(reporter, compare(refBitmap, iref, testBitmap, itest)); } } } } }
static SkScalar make_frame(SkPath* path) { SkRect r = { SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(630), SkIntToScalar(470) }; path->addRoundRect(r, SkIntToScalar(15), SkIntToScalar(15)); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SkIntToScalar(5)); paint.getFillPath(*path, path); return SkIntToScalar(15); }
static void stroke_cubic(const SkPoint pts[4]) { SkPath path; path.moveTo(pts[0]); path.cubicTo(pts[1], pts[2], pts[3]); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SK_Scalar1 * 2); SkPath fill; paint.getFillPath(path, &fill); }
// FIXME: this method ignores the CTM and may yield inaccurate results for large // scales. SkPath Path::strokePath(const StrokeData& strokeData) const { SkPaint paint; strokeData.setupPaint(&paint); // Skia stroke resolution scale. This is multiplied by 4 internally // (i.e. 1.0 corresponds to 1/4 pixel res). static const SkScalar kResScale = 0.3f; SkPath strokePath; paint.getFillPath(m_path, &strokePath, nullptr, kResScale); return strokePath; }
Rect PathSkia::GetStrokedBounds(const StrokeOptions &aStrokeOptions, const Matrix &aTransform) const { SkPaint paint; StrokeOptionsToPaint(paint, aStrokeOptions); SkPath result; paint.getFillPath(mPath, &result); Rect bounds = SkRectToRect(result.getBounds()); return aTransform.TransformBounds(bounds); }
void onDraw(SkCanvas* canvas) override { canvas->drawColor(SK_ColorWHITE); canvas->translate(STROKE_WIDTH*3/2, STROKE_WIDTH*3/2); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(STROKE_WIDTH); static const SkPaint::Join gJoins[] = { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join }; static const SkScalar W = 80; static const SkScalar H = 80; static const SkRect gRects[] = { { 0, 0, W, H }, { W, 0, 0, H }, { 0, H, W, 0 }, { 0, 0, STROKE_WIDTH, H }, { 0, 0, W, STROKE_WIDTH }, { 0, 0, STROKE_WIDTH/2, STROKE_WIDTH/2 }, { 0, 0, W, 0 }, { 0, 0, 0, H }, { 0, 0, 0, 0 }, { 0, 0, W, FLT_EPSILON }, { 0, 0, FLT_EPSILON, H }, { 0, 0, FLT_EPSILON, FLT_EPSILON }, }; for (int doFill = 0; doFill <= 1; ++doFill) { for (size_t i = 0; i < SK_ARRAY_COUNT(gJoins); ++i) { SkPaint::Join join = gJoins[i]; paint.setStrokeJoin(join); SkAutoCanvasRestore acr(canvas, true); for (size_t j = 0; j < SK_ARRAY_COUNT(gRects); ++j) { const SkRect& r = gRects[j]; SkPath path, fillPath; path.addRect(r); paint.getFillPath(path, &fillPath); draw_path(canvas, fillPath, r, join, doFill); canvas->translate(W + 2 * STROKE_WIDTH, 0); } acr.restore(); canvas->translate(0, H + 2 * STROKE_WIDTH); } paint.setStyle(SkPaint::kStrokeAndFill_Style); } }
// This used to cause SkDashImpl to walk off the end of the intervals array, due to underflow // trying to substract a smal value from a large one in floats. DEF_TEST(DashCrazy_crbug_875494, r) { SkScalar vals[] = { 98, 94, 2888458849.f, 227, 0, 197 }; const int N = SK_ARRAY_COUNT(vals); SkRect cull = SkRect::MakeXYWH(43,236,57,149); SkPath path; path.addRect(cull); SkPath path2; SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setPathEffect(SkDashPathEffect::Make(vals, N, 222)); paint.getFillPath(path, &path2, &cull); }
void onDrawContent(SkCanvas* canvas) override { const float SCALE = 1; canvas->translate(30, 40); canvas->scale(SCALE, SCALE); SkPoint p1 = SkPoint::Make(50, 50); SkPoint p2 = SkPoint::Make(80, 50); SkPath path; switch (fPathType) { case 0: path = quadPath(p1, p2); break; case 1: path = linSemicirclePath(p1, p2); break; case 2: path = rectPath(p1); break; default: path = quadPath(p1, p2); break; } if (fClosePath) { path.close(); } SkPaint p; p.setColor(SK_ColorRED); p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(fStroke); canvas->drawPath(path, p); if (fDrawFillPath) { SkPath fillpath; p.getFillPath(path, &fillpath); SkPaint fillp; fillp.setColor(SK_ColorBLACK); fillp.setAntiAlias(true); fillp.setStyle(SkPaint::kStroke_Style); canvas->drawPath(fillpath, fillp); } }
// Computes the bounding box for the stroke and style currently selected into // the given bounding box. This also takes into account the stroke width. static FloatRect boundingBoxForCurrentStroke(GraphicsContext* context) { const SkPath* path = context->getCurrPath(); if (NULL == path) { return FloatRect(); } SkPaint paint; context->setupStrokePaint(&paint); SkPath fillPath; paint.getFillPath(*path, &fillPath); const SkRect& r = fillPath.getBounds(); return FloatRect(SkScalarToFloat(r.fLeft), SkScalarToFloat(r.fTop), SkScalarToFloat(r.width()), SkScalarToFloat(r.height())); }
DEF_TEST(DashPath_bug4871, r) { SkPath path; path.moveTo(30, 24); path.cubicTo(30.002f, 24, 30, 24, 30, 24); path.close(); SkScalar intervals[2] = { 1, 1 }; sk_sp<SkPathEffect> dash(SkDashPathEffect::Make(intervals, 2, 0)); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setPathEffect(dash); SkPath fill; paint.getFillPath(path, &fill); }
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const { GraphicsContext* scratch = scratchContext(); scratch->save(); applier->strokeStyle(scratch); SkPaint paint; scratch->setupStrokePaint(&paint); SkPath strokePath; paint.getFillPath(*platformPath(), &strokePath); bool contains = SkPathContainsPoint(&strokePath, point, SkPath::kWinding_FillType); scratch->restore(); return contains; }
// Extremely large path_length/dash_length ratios may cause infinite looping // in SkDashPathEffect::filterPath() due to single precision rounding. // The test is quite expensive, but it should get much faster after the fix // for http://crbug.com/165432 goes in. static void test_infinite_dash(skiatest::Reporter* reporter) { SkPath path; path.moveTo(0, 0); path.lineTo(5000000, 0); SkScalar intervals[] = { 0.2f, 0.2f }; SkDashPathEffect dash(intervals, 2, 0); SkPath filteredPath; SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setPathEffect(&dash); paint.getFillPath(path, &filteredPath); // If we reach this, we passed. REPORTER_ASSERT(reporter, true); }
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { GraphicsContext* scratch = scratchContext(); scratch->save(); if (applier) applier->strokeStyle(scratch); SkPaint paint; scratch->setupStrokePaint(&paint); SkPath boundingPath; paint.getFillPath(*platformPath(), &boundingPath); FloatRect r = boundingPath.getBounds(); scratch->restore(); return r; }
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { // FIXME(crbug.com/229267): Rewrite this to not require a scratch context. GraphicsContext* scratch = scratchContext(); scratch->save(); if (applier) applier->strokeStyle(scratch); SkPaint paint; scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath boundingPath; paint.getFillPath(m_path, &boundingPath); FloatRect boundingRect = boundingPath.getBounds(); scratch->restore(); return boundingRect; }
void onDraw(SkCanvas* canvas) override { SkAutoTUnref<SkSurface> surface(new_surface(SMALL_W, SMALL_H)); canvas->scale(ZOOM, ZOOM); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(SK_Scalar1); for (int i = 0; i < REPEAT_LOOP; ++i) { SkPath line, path; line.moveTo(1, 2); line.lineTo(SkIntToScalar(4 + i), 1); paint.getFillPath(line, &path); draw_fatpath(canvas, surface, path); canvas->translate(0, SMALL_H); } }
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const { // FIXME(crbug.com/229267): Rewrite this to not require a scratch context. GraphicsContext* scratch = scratchContext(); scratch->save(); ASSERT(applier); applier->strokeStyle(scratch); SkPaint paint; scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath strokePath; paint.getFillPath(m_path, &strokePath); bool contains = SkPathContainsPoint(&strokePath, point, SkPath::kWinding_FillType); scratch->restore(); return contains; }
void SkPDFDevice::drawPath(const SkDraw& d, const SkPath& path, const SkPaint& paint, const SkMatrix* prePathMatrix, bool pathIsMutable) { NOT_IMPLEMENTED(prePathMatrix != NULL, true); if (paint.getPathEffect()) { // Apply the path effect to path and draw it that way. SkPath noEffectPath; paint.getFillPath(path, &noEffectPath); SkPaint noEffectPaint(paint); SkSafeUnref(noEffectPaint.setPathEffect(NULL)); drawPath(d, noEffectPath, noEffectPaint, NULL, true); return; } updateGSFromPaint(paint, false); SkPDFUtils::EmitPath(path, &fContent); SkPDFUtils::PaintPath(paint.getStyle(), path.getFillType(), &fContent); }
FloatRect Path::strokeBoundingRect(StrokeStyleApplier* applier) const { if (isNull()) return FloatRect(); GraphicsContext* scratch = scratchContext(); scratch->save(); if (applier) applier->strokeStyle(scratch); SkPaint paint; scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath boundingPath; paint.getFillPath(*platformPath(), &boundingPath); FloatRect r = boundingPath.getBounds(); scratch->restore(); return r; }
bool Path::strokeContains(StrokeStyleApplier* applier, const FloatPoint& point) const { if (isNull()) return false; ASSERT(applier); GraphicsContext* scratch = scratchContext(); scratch->save(); applier->strokeStyle(scratch); SkPaint paint; scratch->platformContext()->setupPaintForStroking(&paint, 0, 0); SkPath strokePath; paint.getFillPath(*platformPath(), &strokePath); bool contains = SkPathContainsPoint(&strokePath, point, SkPath::kWinding_FillType); scratch->restore(); return contains; }
void FatBits::drawLineSkeleton(SkCanvas* max, const SkPoint pts[]) { SkPaint paint; this->setupSkeletonPaint(&paint); SkPath path; path.moveTo(pts[0]); path.lineTo(pts[1]); if (fStyle == kStroke_Style) { SkPaint p; p.setStyle(SkPaint::kStroke_Style); p.setStrokeWidth(fStrokeWidth * fZoom); p.setStrokeCap(fStrokeCap); SkPath dst; p.getFillPath(path, &dst); path = dst; path.moveTo(pts[0]); path.lineTo(pts[1]); } max->drawPath(path, paint); }
void SkPDFDevice::drawRect(const SkDraw& d, const SkRect& r, const SkPaint& paint) { if (paint.getPathEffect()) { // Create a path for the rectangle and apply the path effect to it. SkPath path; path.addRect(r); paint.getFillPath(path, &path); SkPaint noEffectPaint(paint); SkSafeUnref(noEffectPaint.setPathEffect(NULL)); drawPath(d, path, noEffectPaint, NULL, true); return; } updateGSFromPaint(paint, false); // Skia has 0,0 at top left, pdf at bottom left. Do the right thing. SkScalar bottom = r.fBottom < r.fTop ? r.fBottom : r.fTop; SkPDFUtils::AppendRectangle(r.fLeft, bottom, r.width(), r.height(), &fContent); SkPDFUtils::PaintPath(paint.getStyle(), SkPath::kWinding_FillType, &fContent); }
void drawPath(SkCanvas* canvas, const SkPath& path, SkPaint::Join j) { SkPaint paint; paint.setAntiAlias(true); paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeJoin(j); paint.setStrokeWidth(SkIntToScalar(fStroke)); if (fShowHairline) { SkPath fill; paint.getFillPath(path, &fill); paint.setStrokeWidth(0); canvas->drawPath(fill, paint); } else { canvas->drawPath(path, paint); } paint.setColor(SK_ColorRED); paint.setStrokeWidth(0); canvas->drawPath(path, paint); }
static void test_strokerect(skiatest::Reporter* reporter) { const SkScalar width = SkIntToScalar(10); SkPaint paint; paint.setStyle(SkPaint::kStroke_Style); paint.setStrokeWidth(width); SkRect r = { 0, 0, SkIntToScalar(200), SkIntToScalar(100) }; SkRect outer(r); outer.outset(width/2, width/2); static const SkPaint::Join joins[] = { SkPaint::kMiter_Join, SkPaint::kRound_Join, SkPaint::kBevel_Join }; for (size_t i = 0; i < SK_ARRAY_COUNT(joins); ++i) { paint.setStrokeJoin(joins[i]); SkPath path, fillPath; path.addRect(r); paint.getFillPath(path, &fillPath); REPORTER_ASSERT(reporter, equal(outer, fillPath.getBounds())); bool isMiter = SkPaint::kMiter_Join == joins[i]; SkRect nested[2]; REPORTER_ASSERT(reporter, fillPath.isNestedRects(nested) == isMiter); if (isMiter) { SkRect inner(r); inner.inset(width/2, width/2); REPORTER_ASSERT(reporter, equal(nested[0], outer)); REPORTER_ASSERT(reporter, equal(nested[1], inner)); } } }