static void draw_path_with_mask_filter(GrContext* context, GrDrawContext* drawContext, const GrClip& clip, GrPaint* paint, const SkMatrix& viewMatrix, const SkMaskFilter* maskFilter, const GrStyle& style, const SkPath* path, bool pathIsMutable) { SkASSERT(maskFilter); SkIRect clipBounds; clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds); SkTLazy<SkPath> tmpPath; SkStrokeRec::InitStyle fillOrHairline; // We just fully apply the style here. if (style.applies()) { if (!style.applyToPath(tmpPath.init(), &fillOrHairline, *path, GrStyle::MatrixToScaleFactor(viewMatrix))) { return; } pathIsMutable = true; path = tmpPath.get(); } else if (style.isSimpleHairline()) { fillOrHairline = SkStrokeRec::kHairline_InitStyle; } else { SkASSERT(style.isSimpleFill()); fillOrHairline = SkStrokeRec::kFill_InitStyle; } // transform the path into device space if (!viewMatrix.isIdentity()) { SkPath* result; if (pathIsMutable) { result = const_cast<SkPath*>(path); } else { if (!tmpPath.isValid()) { tmpPath.init(); } result = tmpPath.get(); } path->transform(viewMatrix, result); path = result; result->setIsVolatile(true); pathIsMutable = true; } SkRect maskRect; if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(path->getBounds()), clipBounds, viewMatrix, &maskRect)) { // This mask will ultimately be drawn as a non-AA rect (see draw_mask). // Non-AA rects have a bad habit of snapping arbitrarily. Integerize here // so the mask draws in a reproducible manner. SkIRect finalIRect; maskRect.roundOut(&finalIRect); if (clip_bounds_quick_reject(clipBounds, finalIRect)) { // clipped out return; } if (maskFilter->directFilterMaskGPU(context->textureProvider(), drawContext, paint, clip, viewMatrix, SkStrokeRec(fillOrHairline), *path)) { // the mask filter was able to draw itself directly, so there's nothing // left to do. return; } sk_sp<GrTexture> mask(create_mask_GPU(context, finalIRect, *path, fillOrHairline, paint->isAntiAlias(), drawContext->numColorSamples())); if (mask) { GrTexture* filtered; if (maskFilter->filterMaskGPU(mask.get(), viewMatrix, finalIRect, &filtered, true)) { // filterMaskGPU gives us ownership of a ref to the result SkAutoTUnref<GrTexture> atu(filtered); if (draw_mask(drawContext, clip, viewMatrix, finalIRect, paint, filtered)) { // This path is completely drawn return; } } } } sw_draw_with_mask_filter(drawContext, context->textureProvider(), clip, viewMatrix, *path, maskFilter, clipBounds, paint, fillOrHairline); }
static void draw_path_with_mask_filter(GrContext* context, GrDrawContext* drawContext, const GrClip& clip, GrPaint* paint, const SkMatrix& viewMatrix, const SkMaskFilter* maskFilter, const SkPathEffect* pathEffect, const GrStrokeInfo& origStrokeInfo, SkPath* pathPtr, bool pathIsMutable) { SkASSERT(maskFilter); SkIRect clipBounds; clip.getConservativeBounds(drawContext->width(), drawContext->height(), &clipBounds); SkTLazy<SkPath> tmpPath; GrStrokeInfo strokeInfo(origStrokeInfo); static const SkRect* cullRect = nullptr; // TODO: what is our bounds? SkASSERT(strokeInfo.isDashed() || !pathEffect); if (!strokeInfo.isHairlineStyle()) { SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init(); if (strokeInfo.isDashed()) { if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) { pathPtr = strokedPath; pathPtr->setIsVolatile(true); pathIsMutable = true; } strokeInfo.removeDash(); } if (strokeInfo.applyToPath(strokedPath, *pathPtr)) { // Apply the stroke to the path if there is one pathPtr = strokedPath; pathPtr->setIsVolatile(true); pathIsMutable = true; strokeInfo.setFillStyle(); } } // avoid possibly allocating a new path in transform if we can SkPath* devPathPtr = pathIsMutable ? pathPtr : tmpPath.init(); if (!pathIsMutable) { devPathPtr->setIsVolatile(true); } // transform the path into device space pathPtr->transform(viewMatrix, devPathPtr); SkRect maskRect; if (maskFilter->canFilterMaskGPU(SkRRect::MakeRect(devPathPtr->getBounds()), clipBounds, viewMatrix, &maskRect)) { SkIRect finalIRect; maskRect.roundOut(&finalIRect); if (clip_bounds_quick_reject(clipBounds, finalIRect)) { // clipped out return; } if (maskFilter->directFilterMaskGPU(context->textureProvider(), drawContext, paint, clip, viewMatrix, strokeInfo, *devPathPtr)) { // the mask filter was able to draw itself directly, so there's nothing // left to do. return; } SkAutoTUnref<GrTexture> mask(create_mask_GPU(context, &maskRect, *devPathPtr, strokeInfo, paint->isAntiAlias(), drawContext->numColorSamples())); if (mask) { GrTexture* filtered; if (maskFilter->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) { // filterMaskGPU gives us ownership of a ref to the result SkAutoTUnref<GrTexture> atu(filtered); if (draw_mask(drawContext, clip, viewMatrix, maskRect, paint, filtered)) { // This path is completely drawn return; } } } } // draw the mask on the CPU - this is a fallthrough path in case the // GPU path fails SkPaint::Style style = strokeInfo.isHairlineStyle() ? SkPaint::kStroke_Style : SkPaint::kFill_Style; sw_draw_with_mask_filter(drawContext, context->textureProvider(), clip, viewMatrix, *devPathPtr, maskFilter, clipBounds, paint, style); }