Index: src/gpu/GrTextContext.cpp |
diff --git a/src/gpu/GrTextContext.cpp b/src/gpu/GrTextContext.cpp |
index ad5e7c0aa5e1e21347641625d5fb982895adbbe9..28e10e398c1d0d6b978a241e6050ae7293e15dca 100644 |
--- a/src/gpu/GrTextContext.cpp |
+++ b/src/gpu/GrTextContext.cpp |
@@ -11,11 +11,19 @@ |
#include "GrFontScaler.h" |
#include "SkAutoKern.h" |
+#include "SkDrawProcs.h" |
#include "SkGlyphCache.h" |
- |
-GrTextContext::GrTextContext(GrContext* context, const SkDeviceProperties& properties) : |
- fFallbackTextContext(NULL), |
- fContext(context), fDeviceProperties(properties), fDrawTarget(NULL) { |
+#include "SkGpuDevice.h" |
+#include "SkTextMapStateProc.h" |
+#include "SkTextToPathIter.h" |
+ |
+GrTextContext::GrTextContext(GrContext* context, SkGpuDevice* gpuDevice, |
+ const SkDeviceProperties& properties) |
+ : fFallbackTextContext(NULL) |
+ , fContext(context) |
+ , fGpuDevice(gpuDevice) |
+ , fDeviceProperties(properties) |
+ , fDrawTarget(NULL) { |
} |
GrTextContext::~GrTextContext() { |
@@ -23,11 +31,12 @@ GrTextContext::~GrTextContext() { |
} |
void GrTextContext::init(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint, |
- const SkPaint& skPaint) { |
+ const SkPaint& skPaint, const SkIRect& regionClipBounds) { |
fClip = clip; |
fRenderTarget.reset(SkRef(rt)); |
+ fRegionClipBounds = regionClipBounds; |
fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect); |
fDrawTarget = fContext->getTextTarget(); |
@@ -36,48 +45,119 @@ void GrTextContext::init(GrRenderTarget* rt, const GrClip& clip, const GrPaint& |
fSkPaint = skPaint; |
} |
-bool GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, |
+void GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, |
const SkPaint& skPaint, const SkMatrix& viewMatrix, |
const char text[], size_t byteLength, |
- SkScalar x, SkScalar y) { |
+ SkScalar x, SkScalar y, const SkIRect& clipBounds) { |
if (!fContext->getTextTarget()) { |
- return false; |
+ return; |
} |
GrTextContext* textContext = this; |
do { |
if (textContext->canDraw(skPaint, viewMatrix)) { |
- textContext->onDrawText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y); |
- return true; |
+ textContext->onDrawText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y, |
+ clipBounds); |
+ return; |
} |
textContext = textContext->fFallbackTextContext; |
} while (textContext); |
- return false; |
+ // fall back to drawing as a path |
+ this->drawTextAsPath(skPaint, viewMatrix, text, byteLength, x, y, clipBounds); |
} |
-bool GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint, |
+void GrTextContext::drawPosText(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 SkPoint& offset, const SkIRect& clipBounds) { |
if (!fContext->getTextTarget()) { |
- return false; |
+ return; |
} |
GrTextContext* textContext = this; |
do { |
if (textContext->canDraw(skPaint, viewMatrix)) { |
textContext->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, pos, |
- scalarsPerPosition, offset); |
- return true; |
+ scalarsPerPosition, offset, clipBounds); |
+ return; |
} |
textContext = textContext->fFallbackTextContext; |
} while (textContext); |
- return false; |
+ // fall back to drawing as a path |
+ this->drawPosTextAsPath(skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset, |
+ clipBounds); |
+} |
+ |
+void GrTextContext::drawTextAsPath(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); |
+ |
+ SkMatrix matrix; |
+ matrix.setScale(iter.getPathScale(), iter.getPathScale()); |
+ matrix.postTranslate(x, y); |
+ |
+ const SkPath* iterPath; |
+ SkScalar xpos, prevXPos = 0; |
+ |
+ while (iter.next(&iterPath, &xpos)) { |
+ matrix.postTranslate(xpos - prevXPos, 0); |
+ if (iterPath) { |
+ const SkPaint& pnt = iter.getPaint(); |
+ fGpuDevice->internalDrawPath(*iterPath, pnt, viewMatrix, &matrix, clipBounds, false); |
+ } |
+ prevXPos = xpos; |
+ } |
} |
+void GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix, |
+ const char text[], size_t byteLength, |
+ const SkScalar pos[], int scalarsPerPosition, |
+ const SkPoint& offset, const SkIRect& clipBounds) { |
+ // setup our std paint, in hopes of getting hits in the cache |
+ SkPaint paint(origPaint); |
+ SkScalar matrixScale = paint.setupForAsPaths(); |
+ |
+ SkMatrix matrix; |
+ matrix.setScale(matrixScale, matrixScale); |
+ |
+ // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache. |
+ paint.setStyle(SkPaint::kFill_Style); |
+ paint.setPathEffect(NULL); |
+ |
+ SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc(); |
+ SkAutoGlyphCache autoCache(paint, NULL, NULL); |
+ SkGlyphCache* cache = autoCache.getCache(); |
+ |
+ const char* stop = text + byteLength; |
+ SkTextAlignProc alignProc(paint.getTextAlign()); |
+ SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
+ |
+ // Now restore the original settings, so we "draw" with whatever style/stroking. |
+ paint.setStyle(origPaint.getStyle()); |
+ paint.setPathEffect(origPaint.getPathEffect()); |
+ |
+ while (text < stop) { |
+ const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
+ if (glyph.fWidth) { |
+ const SkPath* path = cache->findPath(glyph); |
+ if (path) { |
+ SkPoint tmsLoc; |
+ tmsProc(pos, &tmsLoc); |
+ SkPoint loc; |
+ alignProc(tmsLoc, glyph, &loc); |
+ |
+ matrix[SkMatrix::kMTransX] = loc.fX; |
+ matrix[SkMatrix::kMTransY] = loc.fY; |
+ fGpuDevice->internalDrawPath(*path, paint, viewMatrix, &matrix, clipBounds, false); |
+ } |
+ } |
+ pos += scalarsPerPosition; |
+ } |
+} |
//*** change to output positions? |
int GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc, |