aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar robertphillips <robertphillips@google.com>2015-05-27 11:02:55 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2015-05-27 11:02:55 -0700
commitccb1b5751075506b4615d2112889d01ee8ad6436 (patch)
tree84bac0d48ad26f2f3bdb8c4b2ddeb95bb3459750
parent24a366a03756d7a8755f940d3160698cf9122cc0 (diff)
Move SkGpuDevice::internalDrawPath to GrBlurUtils::drawPathWithMaskFilter
This CL is ugly but it: removes the stored SkGpuDevice back pointer from GrTextContext (at the cost of passing more parameters) moves SkGpuDevice::internalDrawPath to GrDrawContext::drawPathFull Unfortunately, the GrTextContext-derived classes still need the SkGpuDevice for filterTextFlags calls but I will try removing that in a separate CL. Review URL: https://codereview.chromium.org/1157773003
-rw-r--r--gyp/gpu.gypi2
-rw-r--r--include/gpu/GrContext.h4
-rw-r--r--src/gpu/GrAtlasTextContext.cpp72
-rw-r--r--src/gpu/GrAtlasTextContext.h30
-rw-r--r--src/gpu/GrBlurUtils.cpp295
-rw-r--r--src/gpu/GrBlurUtils.h40
-rwxr-xr-xsrc/gpu/GrContext.cpp5
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.cpp41
-rw-r--r--src/gpu/GrStencilAndCoverTextContext.h15
-rw-r--r--src/gpu/GrTextContext.cpp52
-rw-r--r--src/gpu/GrTextContext.h26
-rw-r--r--src/gpu/SkGpuDevice.cpp290
-rw-r--r--src/gpu/SkGpuDevice.h4
13 files changed, 477 insertions, 399 deletions
diff --git a/gyp/gpu.gypi b/gyp/gpu.gypi
index c4ca5ed7f3..8a93bf8264 100644
--- a/gyp/gpu.gypi
+++ b/gyp/gpu.gypi
@@ -83,6 +83,8 @@
'<(skia_src_path)/gpu/GrBatchTest.h',
'<(skia_src_path)/gpu/GrBlend.cpp',
'<(skia_src_path)/gpu/GrBlend.h',
+ '<(skia_src_path)/gpu/GrBlurUtils.cpp',
+ '<(skia_src_path)/gpu/GrBlurUtils.h',
'<(skia_src_path)/gpu/GrBufferAllocPool.cpp',
'<(skia_src_path)/gpu/GrBufferAllocPool.h',
'<(skia_src_path)/gpu/GrCaps.cpp',
diff --git a/include/gpu/GrContext.h b/include/gpu/GrContext.h
index 2167513d2e..56ba262b86 100644
--- a/include/gpu/GrContext.h
+++ b/include/gpu/GrContext.h
@@ -480,11 +480,9 @@ private:
* render target and the context. Caller assumes the ownership
* of the returned object. The returned object must be deleted
* before the context is destroyed.
- * TODO we can possibly bury this behind context, but we need to be able to use the
- * drawText_asPaths logic on SkGpuDevice
+ * TODO bury this behind context!
*/
GrTextContext* createTextContext(GrRenderTarget*,
- SkGpuDevice*,
const SkDeviceProperties&,
bool enableDistanceFieldFonts);
diff --git a/src/gpu/GrAtlasTextContext.cpp b/src/gpu/GrAtlasTextContext.cpp
index 750cb13fc0..14f8ef7106 100644
--- a/src/gpu/GrAtlasTextContext.cpp
+++ b/src/gpu/GrAtlasTextContext.cpp
@@ -10,6 +10,7 @@
#include "GrBatchFontCache.h"
#include "GrBatchTarget.h"
#include "GrBatchTest.h"
+#include "GrBlurUtils.h"
#include "GrDefaultGeoProcFactory.h"
#include "GrDrawContext.h"
#include "GrFontScaler.h"
@@ -94,10 +95,9 @@ static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
// Distance field text in textblobs
GrAtlasTextContext::GrAtlasTextContext(GrContext* context,
- SkGpuDevice* gpuDevice,
const SkDeviceProperties& properties,
bool enableDistanceFields)
- : INHERITED(context, gpuDevice, properties)
+ : INHERITED(context, properties)
, fDistanceAdjustTable(SkNEW_ARGS(DistanceAdjustTable, (properties.gamma()))) {
// We overallocate vertices in our textblobs based on the assumption that A8 has the greatest
// vertexStride
@@ -196,10 +196,9 @@ void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable(float gam
}
GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context,
- SkGpuDevice* gpuDevice,
const SkDeviceProperties& props,
bool enableDistanceFields) {
- return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props, enableDistanceFields));
+ return SkNEW_ARGS(GrAtlasTextContext, (context, props, enableDistanceFields));
}
bool GrAtlasTextContext::canDraw(const GrRenderTarget*,
@@ -345,9 +344,10 @@ inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc());
}
-void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
- const SkPaint& skPaint, const SkMatrix& viewMatrix,
- const SkTextBlob* blob, SkScalar x, SkScalar y,
+void GrAtlasTextContext::drawTextBlob(SkGpuDevice* gpuDevice, GrRenderTarget* rt,
+ const GrClip& clip, const SkPaint& skPaint,
+ const SkMatrix& viewMatrix, const SkTextBlob* blob,
+ SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
// If we have been abandoned, then don't draw
if (fContext->abandoned()) {
@@ -411,8 +411,8 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
fCache->remove(cacheBlob);
cacheBlob.reset(SkRef(fCache->createCachedBlob(blob, key, blurRec, skPaint,
kGrayTextVASize)));
- this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y,
- drawFilter, clipRect, rt, clip, grPaint);
+ this->regenerateTextBlob(gpuDevice, cacheBlob, skPaint, grPaint.getColor(), viewMatrix,
+ blob, x, y, drawFilter, clipRect, rt, clip, grPaint);
} else {
// If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y
// offsets
@@ -428,12 +428,12 @@ void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
} else {
cacheBlob.reset(fCache->createBlob(blob, kGrayTextVASize));
}
- this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMatrix, blob, x, y,
- drawFilter, clipRect, rt, clip, grPaint);
+ this->regenerateTextBlob(gpuDevice, cacheBlob, skPaint, grPaint.getColor(), viewMatrix,
+ blob, x, y, drawFilter, clipRect, rt, clip, grPaint);
}
cacheBlob->fPaintColor = skPaint.getColor();
- this->flush(drawContext, blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
+ this->flush(gpuDevice, drawContext, blob, cacheBlob, rt, skPaint, grPaint, drawFilter,
clip, viewMatrix, clipBounds, x, y, transX, transY);
}
@@ -472,7 +472,7 @@ inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint,
return true;
}
-void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
+void GrAtlasTextContext::regenerateTextBlob(SkGpuDevice* gpuDevice, BitmapTextBlob* cacheBlob,
const SkPaint& skPaint, GrColor color,
const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,
@@ -500,7 +500,7 @@ void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
continue;
}
- runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
+ runPaint.setFlags(gpuDevice->filterTextFlags(runPaint));
// setup vertex / glyphIndex for the new run
if (run > 0) {
@@ -775,12 +775,12 @@ GrAtlasTextContext::createDrawPosTextBlob(GrRenderTarget* rt, const GrClip& clip
return blob;
}
-void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
+void GrAtlasTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt,
+ const GrClip& clip,
const GrPaint& paint, const SkPaint& skPaint,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
- GrDrawContext* drawContext = fContext->drawContext();
if (drawContext) {
SkAutoTUnref<BitmapTextBlob> blob(
this->createDrawTextBlob(rt, clip, paint, skPaint, viewMatrix,
@@ -789,13 +789,13 @@ void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
}
}
-void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
+void GrAtlasTextContext::onDrawPosText(GrDrawContext* drawContext, GrRenderTarget* rt,
+ const GrClip& clip,
const GrPaint& paint, const SkPaint& skPaint,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& regionClipBounds) {
- GrDrawContext* drawContext = fContext->drawContext();
if (drawContext) {
SkAutoTUnref<BitmapTextBlob> blob(
this->createDrawPosTextBlob(rt, clip, paint, skPaint, viewMatrix,
@@ -2043,7 +2043,9 @@ private:
float fGamma;
};
-void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, const SkPaint& skPaint,
+void GrAtlasTextContext::flushRunAsPaths(SkGpuDevice* gpuDevice, GrDrawContext* drawContext,
+ GrRenderTarget* rt, const SkTextBlob::RunIterator& it,
+ const GrClip& clip, const SkPaint& skPaint,
SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
const SkIRect& clipBounds, SkScalar x, SkScalar y) {
SkPaint runPaint = skPaint;
@@ -2057,20 +2059,23 @@ void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons
return;
}
- runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
+ runPaint.setFlags(gpuDevice->filterTextFlags(runPaint));
switch (it.positioning()) {
case SkTextBlob::kDefault_Positioning:
- this->drawTextAsPath(runPaint, viewMatrix, (const char *)it.glyphs(),
+ this->drawTextAsPath(drawContext, rt, clip, runPaint, viewMatrix,
+ (const char *)it.glyphs(),
textLen, x + offset.x(), y + offset.y(), clipBounds);
break;
case SkTextBlob::kHorizontal_Positioning:
- this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(),
+ this->drawPosTextAsPath(drawContext, rt, clip, runPaint, viewMatrix,
+ (const char*)it.glyphs(),
textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()),
clipBounds);
break;
case SkTextBlob::kFull_Positioning:
- this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs(),
+ this->drawPosTextAsPath(drawContext, rt, clip, runPaint, viewMatrix,
+ (const char*)it.glyphs(),
textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds);
break;
}
@@ -2140,8 +2145,9 @@ inline void GrAtlasTextContext::flushRun(GrDrawContext* drawContext,
}
}
-inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
- const SkPaint& skPaint,
+inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob,
+ GrDrawContext* drawContext, GrRenderTarget* rt,
+ const GrClip& clip, const SkPaint& skPaint,
SkScalar transX, SkScalar transY,
const SkIRect& clipBounds) {
if (!cacheBlob->fBigGlyphs.count()) {
@@ -2161,12 +2167,13 @@ inline void GrAtlasTextContext::flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRend
SkMatrix translate = cacheBlob->fViewMatrix;
translate.postTranslate(bigGlyph.fVx, bigGlyph.fVy);
- fGpuDevice->internalDrawPath(bigGlyph.fPath, skPaint, translate, &pathMatrix, clipBounds,
- false);
+ GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, bigGlyph.fPath,
+ skPaint, translate, &pathMatrix, clipBounds, false);
}
}
-void GrAtlasTextContext::flush(GrDrawContext* drawContext,
+void GrAtlasTextContext::flush(SkGpuDevice* gpuDevice,
+ GrDrawContext* drawContext,
const SkTextBlob* blob,
BitmapTextBlob* cacheBlob,
GrRenderTarget* rt,
@@ -2188,7 +2195,8 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext,
SkTextBlob::RunIterator it(blob);
for (int run = 0; !it.done(); it.next(), run++) {
if (cacheBlob->fRuns[run].fDrawAsPaths) {
- this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBounds, x, y);
+ this->flushRunAsPaths(gpuDevice, drawContext, rt, it, clip, skPaint,
+ drawFilter, viewMatrix, clipBounds, x, y);
continue;
}
cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
@@ -2197,7 +2205,7 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext,
}
// Now flush big glyphs
- this->flushBigGlyphs(cacheBlob, rt, skPaint, transX, transY, clipBounds);
+ this->flushBigGlyphs(cacheBlob, drawContext, rt, clip, skPaint, transX, transY, clipBounds);
}
void GrAtlasTextContext::flush(GrDrawContext* drawContext,
@@ -2216,7 +2224,7 @@ void GrAtlasTextContext::flush(GrDrawContext* drawContext,
}
// Now flush big glyphs
- this->flushBigGlyphs(cacheBlob, rt, skPaint, 0, 0, clipBounds);
+ this->flushBigGlyphs(cacheBlob, drawContext, rt, clip, skPaint, 0, 0, clipBounds);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
@@ -2234,7 +2242,7 @@ BATCH_TEST_DEFINE(TextBlobBatch) {
// We don't yet test the fall back to paths in the GrTextContext base class. This is mostly
// because we don't really want to have a gpu device here.
// We enable distance fields by twiddling a knob on the paint
- gTextContext = GrAtlasTextContext::Create(context, NULL, gDeviceProperties, false);
+ gTextContext = GrAtlasTextContext::Create(context, gDeviceProperties, false);
}
// create dummy render target
diff --git a/src/gpu/GrAtlasTextContext.h b/src/gpu/GrAtlasTextContext.h
index ad0f765f4c..3a8c37e1fd 100644
--- a/src/gpu/GrAtlasTextContext.h
+++ b/src/gpu/GrAtlasTextContext.h
@@ -34,26 +34,25 @@ class GrTextBlobCache;
*/
class GrAtlasTextContext : public GrTextContext {
public:
- static GrAtlasTextContext* Create(GrContext*, SkGpuDevice*, const SkDeviceProperties&,
+ static GrAtlasTextContext* Create(GrContext*, const SkDeviceProperties&,
bool enableDistanceFields);
private:
- GrAtlasTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&,
- bool enableDistanceFields);
+ GrAtlasTextContext(GrContext*, const SkDeviceProperties&, bool enableDistanceFields);
~GrAtlasTextContext() override {}
bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&,
const SkPaint&, const SkMatrix& viewMatrix) override;
- void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
+ void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override;
- void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
- const SkMatrix& viewMatrix,
+ void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&,
+ const SkPaint&, const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& regionClipBounds) override;
- void drawTextBlob(GrRenderTarget*, const GrClip&, const SkPaint&,
+ void drawTextBlob(SkGpuDevice*, GrRenderTarget*, const GrClip&, const SkPaint&,
const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y,
SkDrawFilter*, const SkIRect& clipBounds) override;
@@ -272,7 +271,9 @@ private:
size_t vertexStride, bool useVertexColor,
GrGlyph*);
- inline void flushRunAsPaths(const SkTextBlob::RunIterator&, const SkPaint&, SkDrawFilter*,
+ inline void flushRunAsPaths(SkGpuDevice*, GrDrawContext*, GrRenderTarget*,
+ const SkTextBlob::RunIterator&, const GrClip& clip,
+ const SkPaint&, SkDrawFilter*,
const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x,
SkScalar y);
inline BitmapTextBatch* createBatch(BitmapTextBlob*, const PerSubRunInfo&,
@@ -281,14 +282,15 @@ private:
const SkPaint&);
inline void flushRun(GrDrawContext*, GrPipelineBuilder*, BitmapTextBlob*, int run, GrColor,
SkScalar transX, SkScalar transY, const SkPaint&);
- inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrRenderTarget* rt,
- const SkPaint& skPaint,
+ inline void flushBigGlyphs(BitmapTextBlob* cacheBlob, GrDrawContext*, GrRenderTarget*,
+ const GrClip& clip, const SkPaint& skPaint,
SkScalar transX, SkScalar transY, const SkIRect& clipBounds);
// We have to flush SkTextBlobs differently from drawText / drawPosText
- void flush(GrDrawContext*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
- const GrPaint&, SkDrawFilter*, const GrClip&, const SkMatrix& viewMatrix,
- const SkIRect& clipBounds, SkScalar x, SkScalar y, SkScalar transX, SkScalar transY);
+ void flush(SkGpuDevice*, GrDrawContext*, const SkTextBlob*, BitmapTextBlob*, GrRenderTarget*,
+ const SkPaint&, const GrPaint&, SkDrawFilter*, const GrClip&,
+ const SkMatrix& viewMatrix, const SkIRect& clipBounds, SkScalar x, SkScalar y,
+ SkScalar transX, SkScalar transY);
void flush(GrDrawContext*, BitmapTextBlob*, GrRenderTarget*, const SkPaint&,
const GrPaint&, const GrClip&, const SkIRect& clipBounds);
@@ -337,7 +339,7 @@ private:
const BitmapTextBlob&, const SkPaint&,
const SkMaskFilter::BlurRec&,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
- void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor,
+ void regenerateTextBlob(SkGpuDevice*, BitmapTextBlob* bmp, const SkPaint& skPaint, GrColor,
const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipRect, GrRenderTarget*,
diff --git a/src/gpu/GrBlurUtils.cpp b/src/gpu/GrBlurUtils.cpp
new file mode 100644
index 0000000000..a757a4aed4
--- /dev/null
+++ b/src/gpu/GrBlurUtils.cpp
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "GrBlurUtils.h"
+#include "GrDrawContext.h"
+#include "GrContext.h"
+#include "effects/GrSimpleTextureEffect.h"
+#include "GrStrokeInfo.h"
+#include "GrTexture.h"
+#include "GrTextureProvider.h"
+#include "SkDraw.h"
+#include "SkGr.h"
+#include "SkMaskFilter.h"
+#include "SkPaint.h"
+
+static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
+ return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
+}
+
+// Draw a mask using the supplied paint. Since the coverage/geometry
+// is already burnt into the mask this boils down to a rect draw.
+// Return true if the mask was successfully drawn.
+static bool draw_mask(GrDrawContext* drawContext,
+ GrRenderTarget* rt,
+ const GrClip& clip,
+ const SkMatrix& viewMatrix,
+ const SkRect& maskRect,
+ GrPaint* grp,
+ GrTexture* mask) {
+ SkMatrix matrix;
+ matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
+ matrix.postIDiv(mask->width(), mask->height());
+
+ grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix,
+ kDevice_GrCoordSet))->unref();
+
+ SkMatrix inverse;
+ if (!viewMatrix.invert(&inverse)) {
+ return false;
+ }
+ drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
+ return true;
+}
+
+static bool draw_with_mask_filter(GrDrawContext* drawContext,
+ GrTextureProvider* textureProvider,
+ GrRenderTarget* rt,
+ const GrClip& clipData,
+ const SkMatrix& viewMatrix,
+ const SkPath& devPath,
+ SkMaskFilter* filter,
+ const SkIRect& clipBounds,
+ GrPaint* grp,
+ SkPaint::Style style) {
+ SkMask srcM, dstM;
+
+ if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
+ SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
+ return false;
+ }
+ SkAutoMaskFreeImage autoSrc(srcM.fImage);
+
+ if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) {
+ return false;
+ }
+ // this will free-up dstM when we're done (allocated in filterMask())
+ SkAutoMaskFreeImage autoDst(dstM.fImage);
+
+ if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
+ return false;
+ }
+
+ // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
+ // the current clip (and identity matrix) and GrPaint settings
+ GrSurfaceDesc desc;
+ desc.fWidth = dstM.fBounds.width();
+ desc.fHeight = dstM.fBounds.height();
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+
+ SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture(
+ desc, GrTextureProvider::kApprox_ScratchTexMatch));
+ if (!texture) {
+ return false;
+ }
+ texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
+ dstM.fImage, dstM.fRowBytes);
+
+ SkRect maskRect = SkRect::Make(dstM.fBounds);
+
+ return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, texture);
+}
+
+// Create a mask of 'devPath' and place the result in 'mask'.
+static GrTexture* create_mask_GPU(GrContext* context,
+ const SkRect& maskRect,
+ const SkPath& devPath,
+ const GrStrokeInfo& strokeInfo,
+ bool doAA,
+ int sampleCnt) {
+ GrSurfaceDesc desc;
+ desc.fFlags = kRenderTarget_GrSurfaceFlag;
+ desc.fWidth = SkScalarCeilToInt(maskRect.width());
+ desc.fHeight = SkScalarCeilToInt(maskRect.height());
+ desc.fSampleCnt = doAA ? sampleCnt : 0;
+ // We actually only need A8, but it often isn't supported as a
+ // render target so default to RGBA_8888
+ desc.fConfig = kRGBA_8888_GrPixelConfig;
+
+ if (context->isConfigRenderable(kAlpha_8_GrPixelConfig, desc.fSampleCnt > 0)) {
+ desc.fConfig = kAlpha_8_GrPixelConfig;
+ }
+
+ GrTexture* mask = context->textureProvider()->refScratchTexture(
+ desc, GrTextureProvider::kApprox_ScratchTexMatch);
+ if (NULL == mask) {
+ return NULL;
+ }
+
+ SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
+
+ GrDrawContext* drawContext = context->drawContext();
+ if (!drawContext) {
+ return NULL;
+ }
+
+ drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true);
+
+ GrPaint tempPaint;
+ tempPaint.setAntiAlias(doAA);
+ tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
+
+ // setup new clip
+ GrClip clip(clipRect);
+
+ // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
+ SkMatrix translate;
+ translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
+ drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
+ return mask;
+}
+
+void GrBlurUtils::drawPathWithMaskFilter(GrContext* context,
+ GrDrawContext* drawContext,
+ GrRenderTarget* renderTarget,
+ const GrClip& clip,
+ const SkPath& origSrcPath,
+ const SkPaint& paint,
+ const SkMatrix& origViewMatrix,
+ const SkMatrix* prePathMatrix,
+ const SkIRect& clipBounds,
+ bool pathIsMutable) {
+ SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
+
+ GrStrokeInfo strokeInfo(paint);
+
+ // If we have a prematrix, apply it to the path, optimizing for the case
+ // where the original path can in fact be modified in place (even though
+ // its parameter type is const).
+ SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
+ SkTLazy<SkPath> tmpPath;
+ SkTLazy<SkPath> effectPath;
+ SkPathEffect* pathEffect = paint.getPathEffect();
+
+ SkMatrix viewMatrix = origViewMatrix;
+
+ if (prePathMatrix) {
+ // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix.
+ // The pre-path-matrix also should not affect shading.
+ if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint.getShader() &&
+ (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) {
+ viewMatrix.preConcat(*prePathMatrix);
+ } else {
+ SkPath* result = pathPtr;
+
+ if (!pathIsMutable) {
+ result = tmpPath.init();
+ result->setIsVolatile(true);
+ pathIsMutable = true;
+ }
+ // should I push prePathMatrix on our MV stack temporarily, instead
+ // of applying it here? See SkDraw.cpp
+ pathPtr->transform(*prePathMatrix, result);
+ pathPtr = result;
+ }
+ }
+ // at this point we're done with prePathMatrix
+ SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
+
+ GrPaint grPaint;
+ if (!SkPaint2GrPaint(context, renderTarget, paint, viewMatrix, true, &grPaint)) {
+ return;
+ }
+
+ const SkRect* cullRect = NULL; // TODO: what is our bounds?
+ if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr,
+ &strokeInfo, cullRect)) {
+ pathPtr = effectPath.get();
+ pathIsMutable = true;
+ }
+
+ if (paint.getMaskFilter()) {
+ if (!strokeInfo.isHairlineStyle()) {
+ SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
+ if (strokeInfo.isDashed()) {
+ if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) {
+ pathPtr = strokedPath;
+ pathIsMutable = true;
+ }
+ strokeInfo.removeDash();
+ }
+ if (strokeInfo.applyToPath(strokedPath, *pathPtr)) {
+ pathPtr = strokedPath;
+ 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 (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
+ clipBounds,
+ viewMatrix,
+ &maskRect)) {
+ SkIRect finalIRect;
+ maskRect.roundOut(&finalIRect);
+ if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
+ // clipped out
+ return;
+ }
+
+ if (paint.getMaskFilter()->directFilterMaskGPU(context,
+ renderTarget,
+ &grPaint,
+ 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,
+ grPaint.isAntiAlias(),
+ renderTarget->numSamples()));
+ if (mask) {
+ GrTexture* filtered;
+
+ if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect,
+ &filtered, true)) {
+ // filterMaskGPU gives us ownership of a ref to the result
+ SkAutoTUnref<GrTexture> atu(filtered);
+ if (draw_mask(drawContext,
+ renderTarget,
+ clip,
+ viewMatrix,
+ maskRect,
+ &grPaint,
+ 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;
+ draw_with_mask_filter(drawContext, context->textureProvider(), renderTarget,
+ clip, viewMatrix, *devPathPtr,
+ paint.getMaskFilter(), clipBounds, &grPaint, style);
+ return;
+ }
+
+ drawContext->drawPath(renderTarget, clip, grPaint, viewMatrix, *pathPtr, strokeInfo);
+}
+
diff --git a/src/gpu/GrBlurUtils.h b/src/gpu/GrBlurUtils.h
new file mode 100644
index 0000000000..0fc77266b0
--- /dev/null
+++ b/src/gpu/GrBlurUtils.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef GrBlurUtils_DEFINED
+#define GrBlurUtils_DEFINED
+
+class GrClip;
+class GrContext;
+class GrDrawContext;
+class GrRenderTarget;
+struct SkIRect;
+class SkMatrix;
+class SkPaint;
+class SkPath;
+
+
+/**
+ * Blur utilities.
+ */
+namespace GrBlurUtils {
+ /**
+ * Draw a path handling the mask filter if present.
+ */
+ void drawPathWithMaskFilter(GrContext* context,
+ GrDrawContext* drawContext,
+ GrRenderTarget* rt,
+ const GrClip& clip,
+ const SkPath& origSrcPath,
+ const SkPaint& paint,
+ const SkMatrix& origViewMatrix,
+ const SkMatrix* prePathMatrix,
+ const SkIRect& clipBounds,
+ bool pathIsMutable);
+};
+
+#endif
diff --git a/src/gpu/GrContext.cpp b/src/gpu/GrContext.cpp
index a9beabb537..cc7e6c2b6f 100755
--- a/src/gpu/GrContext.cpp
+++ b/src/gpu/GrContext.cpp
@@ -244,18 +244,17 @@ void GrContext::getResourceCacheUsage(int* resourceCount, size_t* resourceBytes)
}
GrTextContext* GrContext::createTextContext(GrRenderTarget* renderTarget,
- SkGpuDevice* gpuDevice,
const SkDeviceProperties&
leakyProperties,
bool enableDistanceFieldFonts) {
if (fGpu->caps()->shaderCaps()->pathRenderingSupport() && renderTarget->isMultisampled()) {
GrStencilAttachment* sb = renderTarget->renderTargetPriv().attachStencilAttachment();
if (sb) {
- return GrStencilAndCoverTextContext::Create(this, gpuDevice, leakyProperties);
+ return GrStencilAndCoverTextContext::Create(this, leakyProperties);
}
}
- return GrAtlasTextContext::Create(this, gpuDevice, leakyProperties, enableDistanceFieldFonts);
+ return GrAtlasTextContext::Create(this, leakyProperties, enableDistanceFieldFonts);
}
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/GrStencilAndCoverTextContext.cpp b/src/gpu/GrStencilAndCoverTextContext.cpp
index 539d731743..4d34cf47ba 100644
--- a/src/gpu/GrStencilAndCoverTextContext.cpp
+++ b/src/gpu/GrStencilAndCoverTextContext.cpp
@@ -22,21 +22,18 @@
#include "SkTextFormatParams.h"
GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context,
- SkGpuDevice* gpuDevice,
const SkDeviceProperties& properties)
- : GrTextContext(context, gpuDevice, properties)
+ : GrTextContext(context, properties)
, fStroke(SkStrokeRec::kFill_InitStyle)
, fQueuedGlyphCount(0)
, fFallbackGlyphsIdx(kGlyphBufferSize) {
}
GrStencilAndCoverTextContext*
-GrStencilAndCoverTextContext::Create(GrContext* context, SkGpuDevice* gpuDevice,
- const SkDeviceProperties& props) {
+GrStencilAndCoverTextContext::Create(GrContext* context, const SkDeviceProperties& props) {
GrStencilAndCoverTextContext* textContext = SkNEW_ARGS(GrStencilAndCoverTextContext,
- (context, gpuDevice, props));
- textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, gpuDevice, props,
- false);
+ (context, props));
+ textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, props, false);
return textContext;
}
@@ -74,7 +71,7 @@ bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt,
return rec.getFormat() != SkMask::kARGB32_Format;
}
-void GrStencilAndCoverTextContext::onDrawText(GrRenderTarget* rt,
+void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt,
const GrClip& clip,
const GrPaint& paint,
const SkPaint& skPaint,
@@ -157,17 +154,19 @@ void GrStencilAndCoverTextContext::onDrawText(GrRenderTarget* rt,
const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
if (glyph.fWidth) {
- this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
+ this->appendGlyph(drawContext, glyph,
+ SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
}
fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
}
- this->finish();
+ this->finish(drawContext);
}
-void GrStencilAndCoverTextContext::onDrawPosText(GrRenderTarget* rt,
+void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* drawContext,
+ GrRenderTarget* rt,
const GrClip& clip,
const GrPaint& paint,
const SkPaint& skPaint,
@@ -211,12 +210,12 @@ void GrStencilAndCoverTextContext::onDrawPosText(GrRenderTarget* rt,
SkPoint loc;
alignProc(tmsLoc, glyph, &loc);
- this->appendGlyph(glyph, loc);
+ this->appendGlyph(drawContext, glyph, loc);
}
pos += scalarsPerPosition;
}
- this->finish();
+ this->finish(drawContext);
}
static GrPathRange* get_gr_glyphs(GrContext* ctx,
@@ -409,10 +408,11 @@ bool GrStencilAndCoverTextContext::mapToFallbackContext(SkMatrix* inverse) {
return true;
}
-inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, const SkPoint& pos) {
+inline void GrStencilAndCoverTextContext::appendGlyph(GrDrawContext* drawContext,
+ const SkGlyph& glyph, const SkPoint& pos) {
if (fQueuedGlyphCount >= fFallbackGlyphsIdx) {
SkASSERT(fQueuedGlyphCount == fFallbackGlyphsIdx);
- this->flush();
+ this->flush(drawContext);
}
// Stick the glyphs we can't draw at the end of the buffer, growing backwards.
@@ -430,17 +430,12 @@ static const SkScalar* get_xy_scalar_array(const SkPoint* pointArray) {
return &pointArray[0].fX;
}
-void GrStencilAndCoverTextContext::flush() {
+void GrStencilAndCoverTextContext::flush(GrDrawContext* drawContext) {
if (fQueuedGlyphCount > 0) {
SkAutoTUnref<GrPathProcessor> pp(GrPathProcessor::Create(fPaint.getColor(),
fViewMatrix,
fLocalMatrix));
- GrDrawContext* drawContext = fContext->drawContext();
- if (!drawContext) {
- return;
- }
-
drawContext->drawPaths(&fPipelineBuilder, pp, fGlyphs,
fGlyphIndices, GrPathRange::kU16_PathIndexType,
get_xy_scalar_array(fGlyphPositions),
@@ -477,8 +472,8 @@ void GrStencilAndCoverTextContext::flush() {
}
}
-void GrStencilAndCoverTextContext::finish() {
- this->flush();
+void GrStencilAndCoverTextContext::finish(GrDrawContext* drawContext) {
+ this->flush(drawContext);
fGlyphs->unref();
fGlyphs = NULL;
diff --git a/src/gpu/GrStencilAndCoverTextContext.h b/src/gpu/GrStencilAndCoverTextContext.h
index 0cb55535c2..d36b60f11c 100644
--- a/src/gpu/GrStencilAndCoverTextContext.h
+++ b/src/gpu/GrStencilAndCoverTextContext.h
@@ -23,8 +23,7 @@ class GrPathRange;
*/
class GrStencilAndCoverTextContext : public GrTextContext {
public:
- static GrStencilAndCoverTextContext* Create(GrContext*, SkGpuDevice*,
- const SkDeviceProperties&);
+ static GrStencilAndCoverTextContext* Create(GrContext*, const SkDeviceProperties&);
virtual ~GrStencilAndCoverTextContext();
@@ -68,16 +67,16 @@ private:
SkMatrix fLocalMatrix;
bool fUsingDeviceSpaceGlyphs;
- GrStencilAndCoverTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&);
+ GrStencilAndCoverTextContext(GrContext*, const SkDeviceProperties&);
bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&,
const SkPaint&, const SkMatrix& viewMatrix) override;
- void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
+ void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) override;
- void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
+ void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
@@ -87,9 +86,9 @@ private:
size_t textByteLength, RenderMode, const SkMatrix& viewMatrix,
const SkIRect& regionClipBounds);
bool mapToFallbackContext(SkMatrix* inverse);
- void appendGlyph(const SkGlyph&, const SkPoint&);
- void flush();
- void finish();
+ void appendGlyph(GrDrawContext*, const SkGlyph&, const SkPoint&);
+ void flush(GrDrawContext*);
+ void finish(GrDrawContext*);
};
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp
index 4b8bc68e33..1edacfc06e 100644
--- a/src/gpu/GrTextContext.cpp
+++ b/src/gpu/GrTextContext.cpp
@@ -6,8 +6,9 @@
*/
#include "GrTextContext.h"
+#include "GrBlurUtils.h"
#include "GrContext.h"
-#include "GrDrawTarget.h"
+#include "GrDrawContext.h"
#include "GrFontScaler.h"
#include "SkAutoKern.h"
@@ -19,11 +20,9 @@
#include "SkTextMapStateProc.h"
#include "SkTextToPathIter.h"
-GrTextContext::GrTextContext(GrContext* context, SkGpuDevice* gpuDevice,
- const SkDeviceProperties& properties)
+GrTextContext::GrTextContext(GrContext* context, const SkDeviceProperties& properties)
: fFallbackTextContext(NULL)
, fContext(context)
- , fGpuDevice(gpuDevice)
, fDeviceProperties(properties) {
}
@@ -52,19 +51,24 @@ void GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPai
return;
}
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (!drawContext) {
+ return;
+ }
+
GrTextContext* textContext = this;
do {
if (textContext->canDraw(rt, clip, paint, skPaint, viewMatrix)) {
- textContext->onDrawText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y,
- clipBounds);
+ textContext->onDrawText(drawContext, rt, clip, paint, skPaint, viewMatrix,
+ text, byteLength, x, y, clipBounds);
return;
}
textContext = textContext->fFallbackTextContext;
} while (textContext);
// fall back to drawing as a path
- SkASSERT(fGpuDevice);
- this->drawTextAsPath(skPaint, viewMatrix, text, byteLength, x, y, clipBounds);
+ this->drawTextAsPath(drawContext, rt, clip, skPaint, viewMatrix,
+ text, byteLength, x, y, clipBounds);
}
void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint,
@@ -76,10 +80,16 @@ void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const Gr
return;
}
+ GrDrawContext* drawContext = fContext->drawContext();
+ if (!drawContext) {
+ return;
+ }
+
GrTextContext* textContext = this;
do {
if (textContext->canDraw(rt, clip, paint, skPaint, viewMatrix)) {
- textContext->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, pos,
+ textContext->onDrawPosText(drawContext, rt, clip, paint, skPaint, viewMatrix,
+ text, byteLength, pos,
scalarsPerPosition, offset, clipBounds);
return;
}
@@ -87,12 +97,12 @@ void GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const Gr
} while (textContext);
// fall back to drawing as a path
- SkASSERT(fGpuDevice);
- this->drawPosTextAsPath(skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset,
- clipBounds);
+ this->drawPosTextAsPath(drawContext, rt, clip, skPaint, viewMatrix, text, byteLength, pos,
+ scalarsPerPosition, offset, clipBounds);
}
-void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const SkPaint& skPaint,
+void GrTextContext::drawTextBlob(SkGpuDevice* gpuDevice, GrRenderTarget* rt,
+ const GrClip& clip, const SkPaint& skPaint,
const SkMatrix& viewMatrix, const SkTextBlob* blob,
SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
@@ -112,7 +122,7 @@ void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const S
continue;
}
- runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
+ runPaint.setFlags(gpuDevice->filterTextFlags(runPaint));
GrPaint grPaint;
if (!SkPaint2GrPaint(fContext, fRenderTarget, runPaint, viewMatrix, true, &grPaint)) {
@@ -143,7 +153,9 @@ void GrTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, const S
}
}
-void GrTextContext::drawTextAsPath(const SkPaint& skPaint, const SkMatrix& viewMatrix,
+void GrTextContext::drawTextAsPath(GrDrawContext* drawContext, GrRenderTarget* rt,
+ const GrClip& clip,
+ const SkPaint& skPaint, const SkMatrix& viewMatrix,
const char text[], size_t byteLength, SkScalar x, SkScalar y,
const SkIRect& clipBounds) {
SkTextToPathIter iter(text, byteLength, skPaint, true);
@@ -159,13 +171,16 @@ void GrTextContext::drawTextAsPath(const SkPaint& skPaint, const SkMatrix& viewM
matrix.postTranslate(xpos - prevXPos, 0);
if (iterPath) {
const SkPaint& pnt = iter.getPaint();
- fGpuDevice->internalDrawPath(*iterPath, pnt, viewMatrix, &matrix, clipBounds, false);
+ GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, *iterPath,
+ pnt, viewMatrix, &matrix, clipBounds, false);
}
prevXPos = xpos;
}
}
-void GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix,
+void GrTextContext::drawPosTextAsPath(GrDrawContext* drawContext, GrRenderTarget* rt,
+ const GrClip& clip,
+ const SkPaint& origPaint, const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipBounds) {
@@ -204,7 +219,8 @@ void GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix&
matrix[SkMatrix::kMTransX] = loc.fX;
matrix[SkMatrix::kMTransY] = loc.fY;
- fGpuDevice->internalDrawPath(*path, paint, viewMatrix, &matrix, clipBounds, false);
+ GrBlurUtils::drawPathWithMaskFilter(fContext, drawContext, rt, clip, *path, paint,
+ viewMatrix, &matrix, clipBounds, false);
}
}
pos += scalarsPerPosition;
diff --git a/src/gpu/GrTextContext.h b/src/gpu/GrTextContext.h
index 242ae3abe4..07485f4d17 100644
--- a/src/gpu/GrTextContext.h
+++ b/src/gpu/GrTextContext.h
@@ -16,7 +16,7 @@
class GrClip;
class GrContext;
-class GrDrawTarget;
+class GrDrawContext;
class GrFontScaler;
class SkDrawFilter;
class SkGpuDevice;
@@ -37,18 +37,14 @@ public:
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipBounds);
- virtual void drawTextBlob(GrRenderTarget*, const GrClip&, const SkPaint&,
- const SkMatrix& viewMatrix, const SkTextBlob*, SkScalar x, SkScalar y,
+ virtual void drawTextBlob(SkGpuDevice*, GrRenderTarget*, const GrClip&, const SkPaint&,
+ const SkMatrix& viewMatrix, const SkTextBlob*,
+ SkScalar x, SkScalar y,
SkDrawFilter*, const SkIRect& clipBounds);
protected:
GrTextContext* fFallbackTextContext;
GrContext* fContext;
- // TODO we probably don't really need to store a back pointer to the owning SkGpuDevice, except
- // we need to be able to call drawPath on it in the event no other text context can draw the
- // text. We might be able to move this logic to context though. This is unreffed because
- // GrTextContext is completely owned by SkGpuDevice
- SkGpuDevice* fGpuDevice;
SkDeviceProperties fDeviceProperties;
SkAutoTUnref<GrRenderTarget> fRenderTarget;
@@ -58,24 +54,28 @@ protected:
GrPaint fPaint;
SkPaint fSkPaint;
- GrTextContext(GrContext*, SkGpuDevice*, const SkDeviceProperties&);
+ GrTextContext(GrContext*, const SkDeviceProperties&);
virtual bool canDraw(const GrRenderTarget*, const GrClip&, const GrPaint&,
const SkPaint&, const SkMatrix& viewMatrix) = 0;
- virtual void onDrawText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
+ virtual void onDrawText(GrDrawContext*, GrRenderTarget*, const GrClip&,
+ const GrPaint&, const SkPaint&,
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& clipBounds) = 0;
- virtual void onDrawPosText(GrRenderTarget*, const GrClip&, const GrPaint&, const SkPaint&,
+ virtual void onDrawPosText(GrDrawContext*, GrRenderTarget*, const GrClip&,
+ const GrPaint&, const SkPaint&,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipBounds) = 0;
- void drawTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix,
+ void drawTextAsPath(GrDrawContext*, GrRenderTarget*, const GrClip& clip,
+ const SkPaint& origPaint, const SkMatrix& viewMatrix,
const char text[], size_t byteLength, SkScalar x, SkScalar y,
const SkIRect& clipBounds);
- void drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix,
+ void drawPosTextAsPath(GrDrawContext*, GrRenderTarget*, const GrClip& clip,
+ const SkPaint& origPaint, const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipBounds);
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 94ded8de98..0008540cb5 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -7,6 +7,7 @@
#include "SkGpuDevice.h"
+#include "GrBlurUtils.h"
#include "GrContext.h"
#include "GrDrawContext.h"
#include "GrGpu.h"
@@ -167,8 +168,7 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, int width, int height,
fLegacyBitmap.setPixelRef(pr)->unref();
bool useDFT = fSurfaceProps.isUseDistanceFieldFonts();
- fTextContext = fContext->createTextContext(fRenderTarget, this, this->getLeakyProperties(),
- useDFT);
+ fTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProperties(), useDFT);
fDrawContext.reset(SkRef(fContext->drawContext()));
}
@@ -626,145 +626,13 @@ void SkGpuDevice::drawOval(const SkDraw& draw, const SkRect& oval,
///////////////////////////////////////////////////////////////////////////////
-// helpers for applying mask filters
-namespace {
-
-// Draw a mask using the supplied paint. Since the coverage/geometry
-// is already burnt into the mask this boils down to a rect draw.
-// Return true if the mask was successfully drawn.
-bool draw_mask(GrDrawContext* drawContext,
- GrRenderTarget* rt,
- const GrClip& clip,
- const SkMatrix& viewMatrix,
- const SkRect& maskRect,
- GrPaint* grp,
- GrTexture* mask) {
- SkMatrix matrix;
- matrix.setTranslate(-maskRect.fLeft, -maskRect.fTop);
- matrix.postIDiv(mask->width(), mask->height());
-
- grp->addCoverageProcessor(GrSimpleTextureEffect::Create(mask, matrix,
- kDevice_GrCoordSet))->unref();
-
- SkMatrix inverse;
- if (!viewMatrix.invert(&inverse)) {
- return false;
- }
- drawContext->drawNonAARectWithLocalMatrix(rt, clip, *grp, SkMatrix::I(), maskRect, inverse);
- return true;
-}
-
-static bool clip_bounds_quick_reject(const SkIRect& clipBounds, const SkIRect& rect) {
- return clipBounds.isEmpty() || rect.isEmpty() || !SkIRect::Intersects(clipBounds, rect);
-}
-
-bool draw_with_mask_filter(GrDrawContext* drawContext,
- GrTextureProvider* textureProvider,
- GrRenderTarget* rt,
- const GrClip& clipData,
- const SkMatrix& viewMatrix,
- const SkPath& devPath,
- SkMaskFilter* filter,
- const SkIRect& clipBounds,
- GrPaint* grp,
- SkPaint::Style style) {
- SkMask srcM, dstM;
-
- if (!SkDraw::DrawToMask(devPath, &clipBounds, filter, &viewMatrix, &srcM,
- SkMask::kComputeBoundsAndRenderImage_CreateMode, style)) {
- return false;
- }
- SkAutoMaskFreeImage autoSrc(srcM.fImage);
-
- if (!filter->filterMask(&dstM, srcM, viewMatrix, NULL)) {
- return false;
- }
- // this will free-up dstM when we're done (allocated in filterMask())
- SkAutoMaskFreeImage autoDst(dstM.fImage);
-
- if (clip_bounds_quick_reject(clipBounds, dstM.fBounds)) {
- return false;
- }
-
- // we now have a device-aligned 8bit mask in dstM, ready to be drawn using
- // the current clip (and identity matrix) and GrPaint settings
- GrSurfaceDesc desc;
- desc.fWidth = dstM.fBounds.width();
- desc.fHeight = dstM.fBounds.height();
- desc.fConfig = kAlpha_8_GrPixelConfig;
-
- SkAutoTUnref<GrTexture> texture(textureProvider->refScratchTexture(
- desc, GrTextureProvider::kApprox_ScratchTexMatch));
- if (!texture) {
- return false;
- }
- texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
- dstM.fImage, dstM.fRowBytes);
-
- SkRect maskRect = SkRect::Make(dstM.fBounds);
-
- return draw_mask(drawContext, rt, clipData, viewMatrix, maskRect, grp, texture);
-}
-
-// Create a mask of 'devPath' and place the result in 'mask'.
-GrTexture* create_mask_GPU(GrContext* context,
- const SkRect& maskRect,
- const SkPath& devPath,
- const GrStrokeInfo& strokeInfo,
- bool doAA,
- int sampleCnt) {
- GrSurfaceDesc desc;
- desc.fFlags = kRenderTarget_GrSurfaceFlag;
- desc.fWidth = SkScalarCeilToInt(maskRect.width());
- desc.fHeight = SkScalarCeilToInt(maskRect.height());
- desc.fSampleCnt = doAA ? sampleCnt : 0;
- // We actually only need A8, but it often isn't supported as a
- // render target so default to RGBA_8888
- desc.fConfig = kRGBA_8888_GrPixelConfig;
-
- if (context->isConfigRenderable(kAlpha_8_GrPixelConfig,
- desc.fSampleCnt > 0)) {
- desc.fConfig = kAlpha_8_GrPixelConfig;
- }
-
- GrTexture* mask = context->textureProvider()->refScratchTexture(
- desc, GrTextureProvider::kApprox_ScratchTexMatch);
- if (NULL == mask) {
- return NULL;
- }
-
- SkRect clipRect = SkRect::MakeWH(maskRect.width(), maskRect.height());
-
- GrDrawContext* drawContext = context->drawContext();
- if (!drawContext) {
- return NULL;
- }
-
- drawContext->clear(mask->asRenderTarget(), NULL, 0x0, true);
-
- GrPaint tempPaint;
- tempPaint.setAntiAlias(doAA);
- tempPaint.setCoverageSetOpXPFactory(SkRegion::kReplace_Op);
-
- // setup new clip
- GrClip clip(clipRect);
-
- // Draw the mask into maskTexture with the path's top-left at the origin using tempPaint.
- SkMatrix translate;
- translate.setTranslate(-maskRect.fLeft, -maskRect.fTop);
- drawContext->drawPath(mask->asRenderTarget(), clip, tempPaint, translate, devPath, strokeInfo);
- return mask;
-}
-
-SkBitmap wrap_texture(GrTexture* texture, int width, int height) {
+static SkBitmap wrap_texture(GrTexture* texture, int width, int height) {
SkBitmap result;
result.setInfo(SkImageInfo::MakeN32Premul(width, height));
result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (result.info(), texture)))->unref();
return result;
}
-};
-
void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
const SkPaint& paint, const SkMatrix* prePathMatrix,
bool pathIsMutable) {
@@ -772,150 +640,10 @@ void SkGpuDevice::drawPath(const SkDraw& draw, const SkPath& origSrcPath,
CHECK_SHOULD_DRAW(draw);
GR_CREATE_TRACE_MARKER_CONTEXT("SkGpuDevice::drawPath", fContext);
- return this->internalDrawPath(origSrcPath, paint, *draw.fMatrix, prePathMatrix,
- draw.fClip->getBounds(), pathIsMutable);
-}
-
-void SkGpuDevice::internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint,
- const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix,
- const SkIRect& clipBounds, bool pathIsMutable) {
- SkASSERT(!pathIsMutable || origSrcPath.isVolatile());
-
- GrStrokeInfo strokeInfo(paint);
-
- // If we have a prematrix, apply it to the path, optimizing for the case
- // where the original path can in fact be modified in place (even though
- // its parameter type is const).
- SkPath* pathPtr = const_cast<SkPath*>(&origSrcPath);
- SkTLazy<SkPath> tmpPath;
- SkTLazy<SkPath> effectPath;
- SkPathEffect* pathEffect = paint.getPathEffect();
-
- SkMatrix viewMatrix = origViewMatrix;
-
- if (prePathMatrix) {
- // stroking, path effects, and blurs are supposed to be applied *after* the prePathMatrix.
- // The pre-path-matrix also should not affect shading.
- if (NULL == paint.getMaskFilter() && NULL == pathEffect && NULL == paint.getShader() &&
- (strokeInfo.isFillStyle() || strokeInfo.isHairlineStyle())) {
- viewMatrix.preConcat(*prePathMatrix);
- } else {
- SkPath* result = pathPtr;
-
- if (!pathIsMutable) {
- result = tmpPath.init();
- result->setIsVolatile(true);
- pathIsMutable = true;
- }
- // should I push prePathMatrix on our MV stack temporarily, instead
- // of applying it here? See SkDraw.cpp
- pathPtr->transform(*prePathMatrix, result);
- pathPtr = result;
- }
- }
- // at this point we're done with prePathMatrix
- SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
-
- GrPaint grPaint;
- if (!SkPaint2GrPaint(this->context(), fRenderTarget, paint, viewMatrix, true, &grPaint)) {
- return;
- }
-
- const SkRect* cullRect = NULL; // TODO: what is our bounds?
- if (!strokeInfo.isDashed() && pathEffect && pathEffect->filterPath(effectPath.init(), *pathPtr,
- &strokeInfo, cullRect)) {
- pathPtr = effectPath.get();
- pathIsMutable = true;
- }
-
- if (paint.getMaskFilter()) {
- if (!strokeInfo.isHairlineStyle()) {
- SkPath* strokedPath = pathIsMutable ? pathPtr : tmpPath.init();
- if (strokeInfo.isDashed()) {
- if (pathEffect->filterPath(strokedPath, *pathPtr, &strokeInfo, cullRect)) {
- pathPtr = strokedPath;
- pathIsMutable = true;
- }
- strokeInfo.removeDash();
- }
- if (strokeInfo.applyToPath(strokedPath, *pathPtr)) {
- pathPtr = strokedPath;
- 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 (paint.getMaskFilter()->canFilterMaskGPU(devPathPtr->getBounds(),
- clipBounds,
- viewMatrix,
- &maskRect)) {
- SkIRect finalIRect;
- maskRect.roundOut(&finalIRect);
- if (clip_bounds_quick_reject(clipBounds, finalIRect)) {
- // clipped out
- return;
- }
-
- if (paint.getMaskFilter()->directFilterMaskGPU(fContext,
- fRenderTarget,
- &grPaint,
- fClip,
- 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(fContext,
- maskRect,
- *devPathPtr,
- strokeInfo,
- grPaint.isAntiAlias(),
- fRenderTarget->numSamples()));
- if (mask) {
- GrTexture* filtered;
-
- if (paint.getMaskFilter()->filterMaskGPU(mask, viewMatrix, maskRect, &filtered, true)) {
- // filterMaskGPU gives us ownership of a ref to the result
- SkAutoTUnref<GrTexture> atu(filtered);
- if (draw_mask(fDrawContext,
- fRenderTarget,
- fClip,
- viewMatrix,
- maskRect,
- &grPaint,
- 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;
- draw_with_mask_filter(fDrawContext, fContext->textureProvider(), fRenderTarget,
- fClip, viewMatrix, *devPathPtr,
- paint.getMaskFilter(), clipBounds, &grPaint, style);
- return;
- }
-
- fDrawContext->drawPath(fRenderTarget, fClip, grPaint, viewMatrix, *pathPtr, strokeInfo);
+ GrBlurUtils::drawPathWithMaskFilter(fContext, fDrawContext, fRenderTarget,
+ fClip, origSrcPath, paint,
+ *draw.fMatrix, prePathMatrix,
+ draw.fClip->getBounds(), pathIsMutable);
}
static const int kBmpSmallTileSize = 1 << 10;
@@ -1931,8 +1659,8 @@ void SkGpuDevice::drawTextBlob(const SkDraw& draw, const SkTextBlob* blob, SkSca
SkDEBUGCODE(this->validate();)
- fTextContext->drawTextBlob(fRenderTarget, fClip, paint, *draw.fMatrix, blob, x, y, drawFilter,
- draw.fClip->getBounds());
+ fTextContext->drawTextBlob(this, fRenderTarget, fClip, paint, *draw.fMatrix,
+ blob, x, y, drawFilter, draw.fClip->getBounds());
}
///////////////////////////////////////////////////////////////////////////////
diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h
index 1356a6f0fb..d7dceed89d 100644
--- a/src/gpu/SkGpuDevice.h
+++ b/src/gpu/SkGpuDevice.h
@@ -212,10 +212,6 @@ private:
int tileSize,
bool bicubic);
- void internalDrawPath(const SkPath& origSrcPath, const SkPaint& paint,
- const SkMatrix& origViewMatrix, const SkMatrix* prePathMatrix,
- const SkIRect& clipBounds, bool pathIsMutable);
-
bool drawDashLine(const SkPoint pts[2], const SkPaint& paint);
static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&,