DEF_TEST(PathOpsBuilder, reporter) { SkOpBuilder builder; SkPath result; REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isEmpty()); builder.add(result, kDifference_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isEmpty()); builder.add(result, kUnion_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isEmpty()); SkPath rectPath; rectPath.setFillType(SkPath::kEvenOdd_FillType); rectPath.addRect(0, 1, 2, 3, SkPath::kCW_Direction); builder.add(rectPath, kUnion_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); bool closed; SkPath::Direction dir; REPORTER_ASSERT(reporter, result.isRect(nullptr, &closed, &dir)); REPORTER_ASSERT(reporter, closed); REPORTER_ASSERT(reporter, dir == SkPath::kCCW_Direction); int pixelDiff = comparePaths(reporter, __FUNCTION__, rectPath, result); REPORTER_ASSERT(reporter, pixelDiff == 0); rectPath.reset(); rectPath.setFillType(SkPath::kEvenOdd_FillType); rectPath.addRect(0, 1, 2, 3, SkPath::kCCW_Direction); builder.add(rectPath, kUnion_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isRect(nullptr, &closed, &dir)); REPORTER_ASSERT(reporter, closed); REPORTER_ASSERT(reporter, dir == SkPath::kCCW_Direction); REPORTER_ASSERT(reporter, rectPath == result); builder.add(rectPath, kDifference_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isEmpty()); SkPath rect2, rect3; rect2.addRect(2, 1, 4, 3, SkPath::kCW_Direction); rect3.addRect(4, 1, 5, 3, SkPath::kCCW_Direction); builder.add(rectPath, kUnion_SkPathOp); builder.add(rect2, kUnion_SkPathOp); builder.add(rect3, kUnion_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); REPORTER_ASSERT(reporter, result.isRect(nullptr, &closed, &dir)); REPORTER_ASSERT(reporter, closed); SkRect expected; expected.set(0, 1, 5, 3); REPORTER_ASSERT(reporter, result.getBounds() == expected); SkPath circle1, circle2, circle3; circle1.addCircle(5, 6, 4, SkPath::kCW_Direction); circle2.addCircle(7, 4, 8, SkPath::kCCW_Direction); circle3.addCircle(6, 5, 6, SkPath::kCW_Direction); SkPath opCompare; Op(circle1, circle2, kUnion_SkPathOp, &opCompare); Op(opCompare, circle3, kDifference_SkPathOp, &opCompare); builder.add(circle1, kUnion_SkPathOp); builder.add(circle2, kUnion_SkPathOp); builder.add(circle3, kDifference_SkPathOp); REPORTER_ASSERT(reporter, builder.resolve(&result)); pixelDiff = comparePaths(reporter, __FUNCTION__, opCompare, result); REPORTER_ASSERT(reporter, pixelDiff == 0); }
static SkPath TestPath() { SkPath path; path.addRect(SkRect::MakeXYWH(SkIntToScalar(0), SkIntToScalar(0), SkIntToScalar(2), SkIntToScalar(1))); return path; }
// Test out the normal blur style with a wide range of sigmas static void test_sigma_range(skiatest::Reporter* reporter, GrContextFactory* factory) { static const int kSize = 100; // The geometry is offset a smidge to trigger: // https://code.google.com/p/chromium/issues/detail?id=282418 SkPath rectPath; rectPath.addRect(0.3f, 0.3f, 100.3f, 100.3f); SkPoint polyPts[] = { { 0.3f, 0.3f }, { 100.3f, 0.3f }, { 100.3f, 100.3f }, { 0.3f, 100.3f }, { 2.3f, 50.3f } // a little divet to throw off the rect special case }; SkPath polyPath; polyPath.addPoly(polyPts, SK_ARRAY_COUNT(polyPts), true); int rectSpecialCaseResult[kSize]; int generalCaseResult[kSize]; int groundTruthResult[kSize]; int bruteForce1DResult[kSize]; SkScalar sigma = 10.0f; for (int i = 0; i < 4; ++i, sigma /= 10) { cpu_blur_path(rectPath, sigma, rectSpecialCaseResult, kSize); cpu_blur_path(polyPath, sigma, generalCaseResult, kSize); ground_truth_2d(100, 100, sigma, groundTruthResult, kSize); brute_force_1d(-50.0f, 50.0f, sigma, bruteForce1DResult, kSize); REPORTER_ASSERT(reporter, match(rectSpecialCaseResult, bruteForce1DResult, kSize, 5)); REPORTER_ASSERT(reporter, match(generalCaseResult, bruteForce1DResult, kSize, 15)); #if SK_SUPPORT_GPU #if 0 int gpuResult[kSize]; bool haveGPUResult = gpu_blur_path(factory, rectPath, sigma, gpuResult, kSize); // Disabling this test for now -- I don't think it's a legit comparison. // Will continue to investigate this. if (haveGPUResult) { // 1 works everywhere but: Ubuntu13 & Nexus4 REPORTER_ASSERT(reporter, match(gpuResult, bruteForce1DResult, kSize, 10)); } #endif #endif REPORTER_ASSERT(reporter, match(groundTruthResult, bruteForce1DResult, kSize, 1)); #if WRITE_CSV write_as_csv("RectSpecialCase", sigma, rectSpecialCaseResult, kSize); write_as_csv("GeneralCase", sigma, generalCaseResult, kSize); #if SK_SUPPORT_GPU write_as_csv("GPU", sigma, gpuResult, kSize); #endif write_as_csv("GroundTruth2D", sigma, groundTruthResult, kSize); write_as_csv("BruteForce1D", sigma, bruteForce1DResult, kSize); #endif } }
static SkPath generate_rect_line(SkScalar cx, SkScalar cy, SkScalar l) { SkRect rect = SkRect::MakeXYWH(cx - l / 2, cy, l, 0); SkPath path; path.addRect(rect); return path; }
DEF_TEST(Fuzz846, reporter) { /* <clipPath id="clip-circle"> <circle id="circle" cx="60" cy="60" r="50" /> </clipPath> <clipPath id="clip-rect"> <clipPath id="clip-rect"> <clipPath id="clip-rect"> <clipPath id="clip-rect"> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="32668" /> <rect x="10" y="30" width="100" height="18446744073709551615" /> <rect x="10" y="255" width="100" height="60" /> <rect width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="4294967236" /> <rect x="10" y="30" width="100" height="60" /> </clipPath> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="0" height="0.18093252719929986369568203" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="32668" height="60" /> <rect x="10" y="30" width="100" height="18446744073709551615" /> <rect x="10" y="255" width="100" height="60" /> <rect x="2147483649" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> </clipPath> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="32668" height="60" /> <rect x="10" y="30" width="100" height="18446744073709551615" /> <rect x="10" y="255" width="100" height="60" /> <rect x="2147483649" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="2879753595" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> </clipPath> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="0" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="32668" height="60" /> <rect x="10" y="30" width="100" height="18446744073709551615" /> <rect x="10" y="255" width="100" height="60" /> <rect x="2147483649" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="60" /> <rect x="10" y="30" width="100" height="4294967236" /> <rect x="10" y="30" width="100" height="4294967236" /> <rect x="10" y="30" width="100" height="4294967236" /> <rect x="10" y="30" width="100" height="4294967236" /> <rect x="10" y="30" width="100" height="60" /> <rect x="757798030" y="30" width="100" height="60" /> */ SkPath clipCircle, clipRect; SkPath inner; clipCircle.addCircle(60, 60, 50); // <circle id="circle" cx="60" cy="60" r="50" /> inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+32668, 30+0); // <rect x="10" y="30" width="32668" /> inner.addRect(10, 30, 10+100, 30+18446744073709551615.f); // <rect x="10" y="30" width="100" height="18446744073709551615" /> inner.addRect(10, 255, 10+100, 255+60); // <rect x="10" y="255" width="100" height="60" /> inner.addRect(0, 0, 0+100, 0+60); // <rect width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+4294967236.f); // <rect x="10" y="30" width="100" height="4294967236" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> clipRect.addPath(inner); inner.reset(); inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+0, 30+0.18093252719929986369568203f); // <rect x="10" y="30" width="0" height="0.18093252719929986369568203" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+32668, 30+60); // <rect x="10" y="30" width="32668" height="60" /> inner.addRect(10, 30, 10+100, 30+18446744073709551615.f); // <rect x="10" y="30" width="100" height="18446744073709551615" /> inner.addRect(10, 255, 10+100, 255+60); // <rect x="10" y="255" width="100" height="60" /> inner.addRect(2147483649.f, 30, 2147483649.f+100, 30+60); // <rect x="2147483649" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> clipRect.addPath(inner); inner.reset(); inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+32668, 30+60); // <rect x="10" y="30" width="32668" height="60" /> inner.addRect(10, 30, 10+100, 30+18446744073709551615.f); // <rect x="10" y="30" width="100" height="18446744073709551615" /> inner.addRect(10, 255, 10+100, 255+60); // <rect x="10" y="255" width="100" height="60" /> inner.addRect(2147483649.f, 30, 2147483649.f+100, 30+60); // <rect x="2147483649" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 2879753595.f, 10+100, 30+2879753595.f); // <rect x="10" y="2879753595" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> clipRect.addPath(inner); inner.reset(); inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+0, 30+60); // <rect x="10" y="30" width="0" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+32668, 30+60); // <rect x="10" y="30" width="32668" height="60" /> inner.addRect(10, 30, 10+100, 30+18446744073709551615.f); // <rect x="10" y="30" width="100" height="18446744073709551615" /> inner.addRect(10, 255, 10+100, 255+60); // <rect x="10" y="255" width="100" height="60" /> inner.addRect(2147483649.f, 30, 2147483649.f+100, 30+60); // <rect x="2147483649" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(10, 30, 10+100, 30+4294967236.f); // <rect x="10" y="30" width="100" height="4294967236" /> inner.addRect(10, 30, 10+100, 30+4294967236.f); // <rect x="10" y="30" width="100" height="4294967236" /> inner.addRect(10, 30, 10+100, 30+4294967236.f); // <rect x="10" y="30" width="100" height="4294967236" /> inner.addRect(10, 30, 10+100, 30+4294967236.f); // <rect x="10" y="30" width="100" height="4294967236" /> inner.addRect(10, 30, 10+100, 30+60); // <rect x="10" y="30" width="100" height="60" /> inner.addRect(757798030.f, 30, 757798030.f+100, 30+60); // <rect x="757798030" y="30" width="100" height="60" /> clipRect.addPath(inner); SkOpBuilder builder; builder.add(clipCircle, kUnion_SkPathOp); builder.add(clipRect, kDifference_SkPathOp); SkPath result; builder.resolve(&result); }
static void test_close(skiatest::Reporter* reporter) { SkPath closePt; closePt.moveTo(0, 0); closePt.close(); check_close(reporter, closePt); SkPath openPt; openPt.moveTo(0, 0); check_close(reporter, openPt); SkPath empty; check_close(reporter, empty); empty.close(); check_close(reporter, empty); SkPath rect; rect.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); check_close(reporter, rect); rect.close(); check_close(reporter, rect); SkPath quad; quad.quadTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); check_close(reporter, quad); quad.close(); check_close(reporter, quad); SkPath cubic; quad.cubicTo(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1, 20 * SK_Scalar1, 20*SK_Scalar1); check_close(reporter, cubic); cubic.close(); check_close(reporter, cubic); SkPath line; line.moveTo(SK_Scalar1, SK_Scalar1); line.lineTo(10 * SK_Scalar1, 10*SK_Scalar1); check_close(reporter, line); line.close(); check_close(reporter, line); SkPath rect2; rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); rect2.close(); rect2.addRect(SK_Scalar1, SK_Scalar1, 10 * SK_Scalar1, 10*SK_Scalar1); check_close(reporter, rect2); rect2.close(); check_close(reporter, rect2); SkPath oval3; oval3.addOval(SkRect::MakeWH(SK_Scalar1*100,SK_Scalar1*100)); oval3.close(); oval3.addOval(SkRect::MakeWH(SK_Scalar1*200,SK_Scalar1*200)); check_close(reporter, oval3); oval3.close(); check_close(reporter, oval3); SkPath moves; moves.moveTo(SK_Scalar1, SK_Scalar1); moves.moveTo(5 * SK_Scalar1, SK_Scalar1); moves.moveTo(SK_Scalar1, 10 * SK_Scalar1); moves.moveTo(10 *SK_Scalar1, SK_Scalar1); check_close(reporter, moves); stroke_tiny_cubic(); }
static void drawRectAsPath(SkCanvas* canvas, const SkRect& r, const SkPaint& p) { SkPath path; path.addRect(r); canvas->drawPath(path, p); }
static SkPath generate_square(SkScalar cx, SkScalar cy, SkScalar w) { SkRect rect = SkRect::MakeXYWH(cx - w / 2, cy - w / 2, w, w); SkPath path; path.addRect(rect); return path; }
SkPath Rect::onAsPath() const { SkPath path; path.addRect(fRect, this->getDirection(), this->getInitialPointIndex()); return path; }
void SkGpuDevice::drawTextureProducerImpl(GrTextureProducer* producer, const SkRect& clippedSrcRect, const SkRect& clippedDstRect, SkCanvas::SrcRectConstraint constraint, const SkMatrix& viewMatrix, const SkMatrix& srcToDstMatrix, const GrClip& clip, const SkPaint& paint) { // Specifying the texture coords as local coordinates is an attempt to enable more GrDrawOp // combining by not baking anything about the srcRect, dstRect, or viewMatrix, into the texture // FP. In the future this should be an opaque optimization enabled by the combination of // GrDrawOp/GP and FP. const SkMaskFilter* mf = paint.getMaskFilter(); // The shader expects proper local coords, so we can't replace local coords with texture coords // if the shader will be used. If we have a mask filter we will change the underlying geometry // that is rendered. bool canUseTextureCoordsAsLocalCoords = !use_shader(producer->isAlphaOnly(), paint) && !mf; bool doBicubic; GrSamplerParams::FilterMode fm = GrSkFilterQualityToGrFilterMode(paint.getFilterQuality(), viewMatrix, srcToDstMatrix, &doBicubic); const GrSamplerParams::FilterMode* filterMode = doBicubic ? nullptr : &fm; GrTextureProducer::FilterConstraint constraintMode; if (SkCanvas::kFast_SrcRectConstraint == constraint) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } else { constraintMode = GrTextureAdjuster::kYes_FilterConstraint; } // If we have to outset for AA then we will generate texture coords outside the src rect. The // same happens for any mask filter that extends the bounds rendered in the dst. // This is conservative as a mask filter does not have to expand the bounds rendered. bool coordsAllInsideSrcRect = !paint.isAntiAlias() && !mf; // Check for optimization to drop the src rect constraint when on bilerp. if (filterMode && GrSamplerParams::kBilerp_FilterMode == *filterMode && GrTextureAdjuster::kYes_FilterConstraint == constraintMode && coordsAllInsideSrcRect) { SkMatrix combinedMatrix; combinedMatrix.setConcat(viewMatrix, srcToDstMatrix); if (can_ignore_bilerp_constraint(*producer, clippedSrcRect, combinedMatrix, fRenderTargetContext->isUnifiedMultisampled())) { constraintMode = GrTextureAdjuster::kNo_FilterConstraint; } } const SkMatrix* textureMatrix; SkMatrix tempMatrix; if (canUseTextureCoordsAsLocalCoords) { textureMatrix = &SkMatrix::I(); } else { if (!srcToDstMatrix.invert(&tempMatrix)) { return; } textureMatrix = &tempMatrix; } sk_sp<GrFragmentProcessor> fp(producer->createFragmentProcessor( *textureMatrix, clippedSrcRect, constraintMode, coordsAllInsideSrcRect, filterMode, fRenderTargetContext->getColorSpace())); if (!fp) { return; } GrPaint grPaint; if (!SkPaintToGrPaintWithTexture(fContext.get(), fRenderTargetContext.get(), paint, viewMatrix, fp, producer->isAlphaOnly(), &grPaint)) { return; } GrAA aa = GrBoolToAA(paint.isAntiAlias()); if (canUseTextureCoordsAsLocalCoords) { fRenderTargetContext->fillRectToRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect, clippedSrcRect); return; } if (!mf) { fRenderTargetContext->drawRect(clip, std::move(grPaint), aa, viewMatrix, clippedDstRect); return; } // First see if we can do the draw + mask filter direct to the dst. if (viewMatrix.isScaleTranslate()) { SkRect devClippedDstRect; viewMatrix.mapRectScaleTranslate(&devClippedDstRect, clippedDstRect); SkStrokeRec rec(SkStrokeRec::kFill_InitStyle); if (mf->directFilterRRectMaskGPU(fContext.get(), fRenderTargetContext.get(), std::move(grPaint), clip, viewMatrix, rec, SkRRect::MakeRect(clippedDstRect), SkRRect::MakeRect(devClippedDstRect))) { return; } } SkPath rectPath; rectPath.addRect(clippedDstRect); rectPath.setIsVolatile(true); GrBlurUtils::drawPathWithMaskFilter(this->context(), fRenderTargetContext.get(), this->clip(), rectPath, std::move(grPaint), aa, viewMatrix, mf, GrStyle::SimpleFill(), true); }