void onDraw(SkCanvas* canvas) override { // Set up a gradient paint for a rect. // And non-gradient paint for other objects. canvas->drawColor(SK_ColorWHITE); SkPaint paint; paint.setStyle(SkPaint::kFill_Style); paint.setAntiAlias(true); paint.setStrokeWidth(4); paint.setColor(0xFFFE938C); SkRect rect = SkRect::MakeXYWH(10, 10, 100, 160); SkPoint points[2] = { SkPoint::Make(0.0f, 0.0f), SkPoint::Make(256.0f, 256.0f) }; SkColor colors[2] = {SK_ColorBLUE, SK_ColorYELLOW}; SkPaint newPaint(paint); newPaint.setShader(SkGradientShader::MakeLinear( points, colors, nullptr, 2, SkTileMode::kClamp)); canvas->drawRect(rect, newPaint); SkRRect oval; oval.setOval(rect); oval.offset(40, 80); paint.setColor(0xFFE6B89C); canvas->drawRRect(oval, paint); paint.setColor(0xFF9CAFB7); canvas->drawCircle(180, 50, 25, paint); rect.offset(80, 50); paint.setColor(0xFF4281A4); paint.setStyle(SkPaint::kStroke_Style); canvas->drawRoundRect(rect, 10, 10, paint); }
bool GrClipMaskManager::installClipEffects(const ElementList& elements, GrDrawState::AutoRestoreEffects* are, const SkVector& clipToRTOffset, const SkRect* drawBounds) { GrDrawState* drawState = fGpu->drawState(); SkRect boundsInClipSpace; if (NULL != drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } are->set(drawState); GrRenderTarget* rt = drawState->getRenderTarget(); ElementList::Iter iter(elements); bool setARE = false; bool failed = false; while (NULL != iter.get()) { SkRegion::Op op = iter.get()->getOp(); bool invert; bool skip = false; switch (op) { case SkRegion::kReplace_Op: SkASSERT(iter.get() == elements.head()); // Fallthrough, handled same as intersect. case SkRegion::kIntersect_Op: invert = false; if (NULL != drawBounds && iter.get()->contains(boundsInClipSpace)) { skip = true; } break; case SkRegion::kDifference_Op: invert = true; // We don't currently have a cheap test for whether a rect is fully outside an // element's primitive, so don't attempt to set skip. break; default: failed = true; break; } if (failed) { break; } if (!skip) { GrEffectEdgeType edgeType; if (GR_AA_CLIP && iter.get()->isAA()) { if (rt->isMultisampled()) { // Coverage based AA clips don't place nicely with MSAA. failed = true; break; } edgeType = invert ? kInverseFillAA_GrEffectEdgeType : kFillAA_GrEffectEdgeType; } else { edgeType = invert ? kInverseFillBW_GrEffectEdgeType : kFillBW_GrEffectEdgeType; } SkAutoTUnref<GrEffectRef> effect; switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: effect.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), &clipToRTOffset)); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); effect.reset(GrRRectEffect::Create(edgeType, rrect)); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); effect.reset(GrConvexPolyEffect::Create(edgeType, rect)); break; } default: break; } if (effect) { if (!setARE) { are->set(fGpu->drawState()); setARE = true; } fGpu->drawState()->addCoverageEffect(effect); } else { failed = true; break; } } iter.next(); } if (failed) { are->set(NULL); } return !failed; }
static bool get_analytic_clip_processor(const GrReducedClip::ElementList& elements, bool abortIfAA, SkVector& clipToRTOffset, const SkRect* drawBounds, sk_sp<GrFragmentProcessor>* resultFP) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } SkASSERT(elements.count() <= kMaxAnalyticElements); SkSTArray<kMaxAnalyticElements, sk_sp<GrFragmentProcessor>> fps; GrReducedClip::ElementList::Iter iter(elements); while (iter.get()) { SkRegion::Op op = iter.get()->getOp(); bool invert; bool skip = false; switch (op) { case SkRegion::kReplace_Op: SkASSERT(iter.get() == elements.head()); // Fallthrough, handled same as intersect. case SkRegion::kIntersect_Op: invert = false; if (drawBounds && iter.get()->contains(boundsInClipSpace)) { skip = true; } break; case SkRegion::kDifference_Op: invert = true; // We don't currently have a cheap test for whether a rect is fully outside an // element's primitive, so don't attempt to set skip. break; default: return false; } if (!skip) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { if (abortIfAA) { return false; } edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fps.emplace_back(GrConvexPolyEffect::Make(edgeType, iter.get()->getPath(), &clipToRTOffset)); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps.emplace_back(GrRRectEffect::Make(edgeType, rrect)); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps.emplace_back(GrConvexPolyEffect::Make(edgeType, rect)); break; } default: break; } if (!fps.back()) { return false; } } iter.next(); } *resultFP = nullptr; if (fps.count()) { *resultFP = GrFragmentProcessor::RunInSeries(fps.begin(), fps.count()); } return true; }
const GrFragmentProcessor* GrClipMaskManager::getAnalyticClipProcessor( const GrReducedClip::ElementList& elements, const SkVector& clipToRTOffset, const SkRect* drawBounds) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } SkASSERT(elements.count() <= kMaxAnalyticElements); const GrFragmentProcessor* fps[kMaxAnalyticElements]; for (int i = 0; i < kMaxAnalyticElements; ++i) { fps[i] = nullptr; } int fpCnt = 0; GrReducedClip::ElementList::Iter iter(elements); bool failed = false; while (iter.get()) { SkRegion::Op op = iter.get()->getOp(); bool invert; bool skip = false; switch (op) { case SkRegion::kReplace_Op: SkASSERT(iter.get() == elements.head()); // Fallthrough, handled same as intersect. case SkRegion::kIntersect_Op: invert = false; if (drawBounds && iter.get()->contains(boundsInClipSpace)) { skip = true; } break; case SkRegion::kDifference_Op: invert = true; // We don't currently have a cheap test for whether a rect is fully outside an // element's primitive, so don't attempt to set skip. break; default: failed = true; break; } if (failed) { break; } if (!skip) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), &clipToRTOffset); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps[fpCnt] = GrRRectEffect::Create(edgeType, rrect); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fps[fpCnt] = GrConvexPolyEffect::Create(edgeType, rect); break; } default: break; } if (!fps[fpCnt]) { failed = true; break; } fpCnt++; } iter.next(); } const GrFragmentProcessor* resultFP = nullptr; if (!failed) { resultFP = GrFragmentProcessor::RunInSeries(fps, fpCnt); } for (int i = 0; i < fpCnt; ++i) { fps[i]->unref(); } return resultFP; }
bool GrClipMaskManager::installClipEffects(GrPipelineBuilder* pipelineBuilder, GrPipelineBuilder::AutoRestoreFragmentProcessors* arfp, const GrReducedClip::ElementList& elements, const SkVector& clipToRTOffset, const SkRect* drawBounds) { SkRect boundsInClipSpace; if (drawBounds) { boundsInClipSpace = *drawBounds; boundsInClipSpace.offset(-clipToRTOffset.fX, -clipToRTOffset.fY); } arfp->set(pipelineBuilder); GrRenderTarget* rt = pipelineBuilder->getRenderTarget(); GrReducedClip::ElementList::Iter iter(elements); bool failed = false; while (iter.get()) { SkRegion::Op op = iter.get()->getOp(); bool invert; bool skip = false; switch (op) { case SkRegion::kReplace_Op: SkASSERT(iter.get() == elements.head()); // Fallthrough, handled same as intersect. case SkRegion::kIntersect_Op: invert = false; if (drawBounds && iter.get()->contains(boundsInClipSpace)) { skip = true; } break; case SkRegion::kDifference_Op: invert = true; // We don't currently have a cheap test for whether a rect is fully outside an // element's primitive, so don't attempt to set skip. break; default: failed = true; break; } if (failed) { break; } if (!skip) { GrPrimitiveEdgeType edgeType; if (iter.get()->isAA()) { if (rt->isMultisampled()) { // Coverage based AA clips don't place nicely with MSAA. failed = true; break; } edgeType = invert ? kInverseFillAA_GrProcessorEdgeType : kFillAA_GrProcessorEdgeType; } else { edgeType = invert ? kInverseFillBW_GrProcessorEdgeType : kFillBW_GrProcessorEdgeType; } SkAutoTUnref<GrFragmentProcessor> fp; switch (iter.get()->getType()) { case SkClipStack::Element::kPath_Type: fp.reset(GrConvexPolyEffect::Create(edgeType, iter.get()->getPath(), &clipToRTOffset)); break; case SkClipStack::Element::kRRect_Type: { SkRRect rrect = iter.get()->getRRect(); rrect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fp.reset(GrRRectEffect::Create(edgeType, rrect)); break; } case SkClipStack::Element::kRect_Type: { SkRect rect = iter.get()->getRect(); rect.offset(clipToRTOffset.fX, clipToRTOffset.fY); fp.reset(GrConvexPolyEffect::Create(edgeType, rect)); break; } default: break; } if (fp) { pipelineBuilder->addCoverageProcessor(fp); } else { failed = true; break; } } iter.next(); } if (failed) { arfp->set(NULL); } return !failed; }
static SkRRect make_offset(const SkRRect& src, SkScalar dx, SkScalar dy) { SkRRect dst = src; dst.offset(dx, dy); return dst; }