aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkDescriptor.h14
-rw-r--r--src/core/SkPaint.cpp13
-rwxr-xr-xsrc/gpu/GrBitmapTextContext.cpp244
-rw-r--r--src/gpu/GrBitmapTextContext.h77
4 files changed, 238 insertions, 110 deletions
diff --git a/src/core/SkDescriptor.h b/src/core/SkDescriptor.h
index 22ec29316f..0693ccfe60 100644
--- a/src/core/SkDescriptor.h
+++ b/src/core/SkDescriptor.h
@@ -134,7 +134,13 @@ private:
class SkAutoDescriptor : SkNoncopyable {
public:
- SkAutoDescriptor(size_t size) {
+ SkAutoDescriptor() : fDesc(NULL) {}
+ SkAutoDescriptor(size_t size) : fDesc(NULL) { this->reset(size); }
+
+ ~SkAutoDescriptor() { this->free(); }
+
+ void reset(size_t size) {
+ this->free();
if (size <= sizeof(fStorage)) {
fDesc = (SkDescriptor*)(void*)fStorage;
} else {
@@ -142,14 +148,14 @@ public:
}
}
- ~SkAutoDescriptor() {
+ SkDescriptor* getDesc() const { SkASSERT(fDesc); return fDesc; }
+private:
+ void free() {
if (fDesc != (SkDescriptor*)(void*)fStorage) {
SkDescriptor::Free(fDesc);
}
}
- SkDescriptor* getDesc() const { return fDesc; }
-private:
enum {
kStorageSize = sizeof(SkDescriptor)
+ sizeof(SkDescriptor::Entry) + sizeof(SkScalerContext::Rec) // for rec
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 24281d7cff..2c1745d00b 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1705,9 +1705,9 @@ static void test_desc(const SkScalerContext::Rec& rec,
#endif
/* see the note on ignoreGamma on descriptorProc */
-const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* deviceProperties,
- const SkMatrix* deviceMatrix,
- bool ignoreGamma) const {
+void SkPaint::getScalerContextDescriptor(SkAutoDescriptor* ad,
+ const SkDeviceProperties* deviceProperties,
+ const SkMatrix* deviceMatrix, bool ignoreGamma) const {
SkScalerContext::Rec rec;
SkPathEffect* pe = this->getPathEffect();
@@ -1718,9 +1718,8 @@ const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* devi
size_t descSize = fill_out_rec(*this, &rec, deviceProperties, deviceMatrix, ignoreGamma,
pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer);
- SkASSERT(SkAlign4(descSize) == descSize);
- SkData* data = SkData::NewUninitialized(descSize);
- SkDescriptor* desc = reinterpret_cast<SkDescriptor*>(data->writable_data());
+ ad->reset(descSize);
+ SkDescriptor* desc = ad->getDesc();
write_out_descriptor(desc, rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, descSize);
@@ -1729,8 +1728,6 @@ const SkData* SkPaint::getScalerContextDescriptor(const SkDeviceProperties* devi
#ifdef TEST_DESC
test_desc(rec, pe, &peBuffer, mf, &mfBuffer, ra, &raBuffer, desc, descSize);
#endif
-
- return data;
}
/*
diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
index 45926673ef..605703d1c6 100755
--- a/src/gpu/GrBitmapTextContext.cpp
+++ b/src/gpu/GrBitmapTextContext.cpp
@@ -101,31 +101,80 @@ bool GrBitmapTextContextB::MustRegenerateBlob(const BitmapTextBlob& blob, const
paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() != blob.fStyle;
}
+
+inline SkGlyphCache* GrBitmapTextContextB::setupCache(BitmapTextBlob::Run* run,
+ const SkPaint& skPaint,
+ const SkMatrix& viewMatrix) {
+ skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &viewMatrix, false);
+ run->fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
+ return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc());
+}
+
+inline void GrBitmapTextContextB::BlobGlyphCount(int* glyphCount, int* runCount,
+ const SkTextBlob* blob) {
+ SkTextBlob::RunIterator itCounter(blob);
+ for (; !itCounter.done(); itCounter.next(), (*runCount)++) {
+ *glyphCount += itCounter.glyphCount();
+ }
+}
+
+GrBitmapTextContextB::BitmapTextBlob* GrBitmapTextContextB::CreateBlob(int glyphCount,
+ int runCount) {
+ // We allocate size for the BitmapTextBlob itself, plus size for the vertices array,
+ // and size for the glyphIds array.
+ SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
+ vertex_attribute_changed);
+ size_t verticesCount = glyphCount * kVerticesPerGlyph * kGrayTextVASize;
+ size_t length = sizeof(BitmapTextBlob) +
+ verticesCount +
+ glyphCount * sizeof(GrGlyph::PackedID) +
+ sizeof(BitmapTextBlob::Run) * runCount;
+
+ BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(sk_malloc_throw(length), BitmapTextBlob);
+
+ // setup offsets for vertices / glyphs
+ cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned char*>(cacheBlob);
+ cacheBlob->fGlyphIDs =
+ reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + verticesCount);
+ cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphIDs + glyphCount);
+
+ // Initialize runs
+ for (int i = 0; i < runCount; i++) {
+ SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run);
+ }
+ cacheBlob->fRunCount = runCount;
+ return cacheBlob;
+}
+
void GrBitmapTextContextB::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
const SkPaint& skPaint, const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
BitmapTextBlob* cacheBlob;
BitmapTextBlob** foundBlob = fCache.find(blob->uniqueID());
-
SkIRect clipRect;
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
if (foundBlob) {
cacheBlob = *foundBlob;
if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) {
- // We can get away with reusing the blob if there are no outstanding refs on it.
- // However, we still have to reset all of the runs.
- if (!cacheBlob->unique()) {
- cacheBlob->unref();
- cacheBlob = SkNEW(BitmapTextBlob);
- fCache.set(blob->uniqueID(), cacheBlob);
- }
+ // We have to remake the blob because changes may invalidate our masks.
+ // TODO we could probably get away reuse most of the time if the pointer is unique,
+ // but we'd have to clear the subrun information
+ cacheBlob->unref();
+ int glyphCount = 0;
+ int runCount = 0;
+ BlobGlyphCount(&glyphCount, &runCount, blob);
+ cacheBlob = CreateBlob(glyphCount, runCount);
+ fCache.set(blob->uniqueID(), cacheBlob);
this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter,
clipRect);
}
} else {
- cacheBlob = SkNEW(BitmapTextBlob);
+ int glyphCount = 0;
+ int runCount = 0;
+ BlobGlyphCount(&glyphCount, &runCount, blob);
+ cacheBlob = CreateBlob(glyphCount, runCount);
fCache.set(blob->uniqueID(), cacheBlob);
this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter, clipRect);
}
@@ -147,13 +196,13 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
cacheBlob->fX = x;
cacheBlob->fY = y;
cacheBlob->fStyle = skPaint.getStyle();
- cacheBlob->fRuns.reset(blob->fRunCount);
// Regenerate textblob
SkPaint runPaint = skPaint;
SkTextBlob::RunIterator it(blob);
for (int run = 0; !it.done(); it.next(), run++) {
- size_t textLen = it.glyphCount() * sizeof(uint16_t);
+ int glyphCount = it.glyphCount();
+ size_t textLen = glyphCount * sizeof(uint16_t);
const SkPoint& offset = it.offset();
// applyFontToPaint() always overwrites the exact same attributes,
// so it is safe to not re-seed the paint for this reason.
@@ -167,19 +216,33 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
+ SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix);
+
+ // setup vertex / glyphIndex for the new run
+ if (run > 0) {
+ PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back();
+ PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back();
+
+ newRun.fVertexStartIndex = lastRun.fVertexEndIndex;
+ newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
+
+ newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
+ newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
+ }
+
switch (it.positioning()) {
case SkTextBlob::kDefault_Positioning:
- this->internalDrawText(cacheBlob, run, runPaint, viewMatrix,
+ this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatrix,
(const char *)it.glyphs(), textLen,
x + offset.x(), y + offset.y(), clipRect);
break;
case SkTextBlob::kHorizontal_Positioning:
- this->internalDrawPosText(cacheBlob, run, runPaint, viewMatrix,
+ this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix,
(const char*)it.glyphs(), textLen, it.pos(), 1,
SkPoint::Make(x, y + offset.y()), clipRect);
break;
case SkTextBlob::kFull_Positioning:
- this->internalDrawPosText(cacheBlob, run, runPaint, viewMatrix,
+ this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewMatrix,
(const char*)it.glyphs(), textLen, it.pos(), 2,
SkPoint::Make(x, y), clipRect);
break;
@@ -189,6 +252,8 @@ void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
// A draw filter may change the paint arbitrarily, so we must re-seed in this case.
runPaint = skPaint;
}
+
+ SkGlyphCache::AttachCache(cache);
}
}
@@ -197,21 +262,26 @@ void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& regionClipBounds) {
- SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
+ int glyphCount = skPaint.countText(text, byteLength);
+ SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
blob->fViewMatrix = viewMatrix;
blob->fX = x;
blob->fY = y;
blob->fStyle = skPaint.getStyle();
- blob->fRuns.push_back();
SkIRect clipRect;
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
- this->internalDrawText(blob, 0, skPaint, viewMatrix, text, byteLength, x, y, clipRect);
+
+ // setup cache
+ SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix);
+ this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, x, y, clipRect);
+ SkGlyphCache::AttachCache(cache);
+
this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, skPaint.getAlpha());
}
void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex,
- const SkPaint& skPaint,
+ SkGlyphCache* cache, const SkPaint& skPaint,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& clipRect) {
@@ -226,12 +296,6 @@ void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex,
SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
// Get GrFontScaler from cache
- BitmapTextBlob::Run& run = blob->fRuns[runIndex];
- run.fDescriptor.reset(skPaint.getScalerContextDescriptor(&fDeviceProperties, &viewMatrix,
- false));
- run.fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
- const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data());
- SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
GrFontScaler* fontScaler = GetGrFontScaler(cache);
// transform our starting point
@@ -303,8 +367,6 @@ void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex,
fx += glyph.fAdvanceX;
fy += glyph.fAdvanceY;
}
-
- SkGlyphCache::AttachCache(cache);
}
void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
@@ -313,20 +375,25 @@ void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& regionClipBounds) {
- SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
+ int glyphCount = skPaint.countText(text, byteLength);
+ SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
blob->fStyle = skPaint.getStyle();
- blob->fRuns.push_back();
blob->fViewMatrix = viewMatrix;
SkIRect clipRect;
clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
- this->internalDrawPosText(blob, 0, skPaint, viewMatrix, text, byteLength, pos,
+
+ // setup cache
+ SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix);
+ this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLength, pos,
scalarsPerPosition, offset, clipRect);
+ SkGlyphCache::AttachCache(cache);
+
this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, fSkPaint.getAlpha());
}
void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runIndex,
- const SkPaint& skPaint,
+ SkGlyphCache* cache, const SkPaint& skPaint,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
@@ -343,12 +410,6 @@ void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde
SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
// Get GrFontScaler from cache
- BitmapTextBlob::Run& run = blob->fRuns[runIndex];
- run.fDescriptor.reset(skPaint.getScalerContextDescriptor(&fDeviceProperties, &viewMatrix,
- false));
- run.fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
- const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data());
- SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
GrFontScaler* fontScaler = GetGrFontScaler(cache);
const char* stop = text + byteLength;
@@ -487,7 +548,6 @@ void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde
}
}
}
- SkGlyphCache::AttachCache(cache);
}
static size_t get_vertex_stride(GrMaskFormat maskFormat) {
@@ -540,13 +600,28 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly
blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, vy));
return;
}
+
+ Run& run = blob->fRuns[runIndex];
+
GrMaskFormat format = glyph->fMaskFormat;
- size_t vertexStride = get_vertex_stride(format);
- BitmapTextBlob::Run& run = blob->fRuns[runIndex];
- int glyphIdx = run.fInfos[format].fGlyphIDs.count();
- *run.fInfos[format].fGlyphIDs.append() = packed;
- run.fInfos[format].fVertices.append(static_cast<int>(vertexStride * kVerticesPerGlyph));
+ PerSubRunInfo* subRun = &run.fSubRunInfo.back();
+ if (run.fInitialized && subRun->fMaskFormat != format) {
+ PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back();
+ newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex;
+ newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex;
+
+ newSubRun->fVertexStartIndex = subRun->fVertexEndIndex;
+ newSubRun->fVertexEndIndex = subRun->fVertexEndIndex;
+
+ subRun = newSubRun;
+ }
+
+ run.fInitialized = true;
+ subRun->fMaskFormat = format;
+ blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
+
+ size_t vertexStride = get_vertex_stride(format);
SkRect r;
r.fLeft = SkIntToScalar(x);
@@ -558,8 +633,7 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly
GrColor color = fPaint.getColor();
run.fColor = color;
- intptr_t vertex = reinterpret_cast<intptr_t>(run.fInfos[format].fVertices.begin());
- vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
+ intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVertexEndIndex);
// V0
SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
@@ -595,27 +669,32 @@ void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly
SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
*colorPtr = color;
}
+
+ subRun->fGlyphEndIndex++;
+ subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
}
class BitmapTextBatch : public GrBatch {
public:
typedef GrBitmapTextContextB::BitmapTextBlob Blob;
typedef Blob::Run Run;
- typedef Run::PerFormatInfo TextInfo;
+ typedef Run::SubRunInfo TextInfo;
struct Geometry {
Geometry() {}
Geometry(const Geometry& geometry)
: fBlob(SkRef(geometry.fBlob.get()))
, fRun(geometry.fRun)
+ , fSubRun(geometry.fSubRun)
, fColor(geometry.fColor) {}
SkAutoTUnref<Blob> fBlob;
int fRun;
+ int fSubRun;
GrColor fColor;
};
static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
- GrBatchFontCache* fontCache) {
- return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, fontCache));
+ int glyphCount, GrBatchFontCache* fontCache) {
+ return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, glyphCount, fontCache));
}
const char* name() const override { return "BitmapTextBatch"; }
@@ -718,12 +797,12 @@ public:
Geometry& args = fGeoData[i];
Blob* blob = args.fBlob;
Run& run = blob->fRuns[args.fRun];
- TextInfo& info = run.fInfos[fMaskFormat];
+ TextInfo& info = run.fSubRunInfo[args.fSubRun];
uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlasGen;
bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
- int glyphCount = info.fGlyphIDs.count();
+ int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
// We regenerate both texture coords and colors in the blob itself, and update the
// atlas generation. If we don't end up purging any unused plots, we can avoid
@@ -741,13 +820,13 @@ public:
GrBatchTextStrike* strike = NULL;
bool brokenRun = false;
if (regenerateTextureCoords) {
- desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor->data());
+ desc = run.fDescriptor.getDesc();
cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
scaler = GrTextContext::GetGrFontScaler(cache);
strike = fFontCache->getStrike(scaler);
}
for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
- GrGlyph::PackedID glyphID = info.fGlyphIDs[glyphIdx];
+ GrGlyph::PackedID glyphID = blob->fGlyphIDs[glyphIdx + info.fGlyphStartIndex];
if (regenerateTextureCoords) {
// Upload the glyph only if needed
@@ -771,7 +850,8 @@ public:
// Texture coords are the last vertex attribute so we get a pointer to the
// first one and then map with stride in regenerateTextureCoords
- intptr_t vertex = reinterpret_cast<intptr_t>(info.fVertices.begin());
+ intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
+ vertex += info.fVertexStartIndex;
vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
vertex += vertexStride - sizeof(SkIPoint16);
@@ -779,7 +859,8 @@ public:
}
if (regenerateColors) {
- intptr_t vertex = reinterpret_cast<intptr_t>(info.fVertices.begin());
+ intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices);
+ vertex += info.fVertexStartIndex;
vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint);
this->regenerateColors(vertex, vertexStride, args.fColor);
}
@@ -797,8 +878,8 @@ public:
}
// now copy all vertices
- int byteCount = info.fVertices.count();
- memcpy(currVertex, info.fVertices.begin(), byteCount);
+ size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex;
+ memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCount);
currVertex += byteCount;
}
@@ -810,7 +891,7 @@ public:
private:
BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
- GrBatchFontCache* fontCache)
+ int glyphCount, GrBatchFontCache* fontCache)
: fMaskFormat(maskFormat)
, fPixelConfig(fontCache->getPixelConfig(maskFormat))
, fFontCache(fontCache) {
@@ -818,8 +899,7 @@ private:
fGeoData.push_back(geometry);
fBatch.fColor = color;
fBatch.fViewMatrix = geometry.fBlob->fViewMatrix;
- int numGlyphs = geometry.fBlob->fRuns[geometry.fRun].fInfos[maskFormat].fGlyphIDs.count();
- fBatch.fNumGlyphs = numGlyphs;
+ fBatch.fNumGlyphs = glyphCount;
}
void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexStride) {
@@ -932,27 +1012,6 @@ private:
GrBatchFontCache* fFontCache;
};
-void GrBitmapTextContextB::flushSubRun(GrDrawTarget* target, BitmapTextBlob* blob, int i,
- GrPipelineBuilder* pipelineBuilder, GrMaskFormat format,
- GrColor color, int paintAlpha) {
- if (0 == blob->fRuns[i].fInfos[format].fGlyphIDs.count()) {
- return;
- }
-
- if (kARGB_GrMaskFormat == format) {
- color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha);
- }
-
- BitmapTextBatch::Geometry geometry;
- geometry.fBlob.reset(SkRef(blob));
- geometry.fRun = i;
- geometry.fColor = color;
- SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format,
- fContext->getBatchFontCache()));
-
- target->drawBatch(pipelineBuilder, batch, &blob->fRuns[i].fVertexBounds);
-}
-
void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrRenderTarget* rt,
const GrPaint& paint, const GrClip& clip,
const SkMatrix& viewMatrix, int paintAlpha) {
@@ -960,10 +1019,29 @@ void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrR
pipelineBuilder.setFromPaint(paint, rt, clip);
GrColor color = paint.getColor();
- for (int i = 0; i < blob->fRuns.count(); i++) {
- this->flushSubRun(target, blob, i, &pipelineBuilder, kA8_GrMaskFormat, color, paintAlpha);
- this->flushSubRun(target, blob, i, &pipelineBuilder, kA565_GrMaskFormat, color, paintAlpha);
- this->flushSubRun(target, blob, i, &pipelineBuilder, kARGB_GrMaskFormat, color, paintAlpha);
+ for (uint32_t run = 0; run < blob->fRunCount; run++) {
+ for (int subRun = 0; subRun < blob->fRuns[run].fSubRunInfo.count(); subRun++) {
+ PerSubRunInfo& info = blob->fRuns[run].fSubRunInfo[subRun];
+ int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
+ if (0 == glyphCount) {
+ continue;
+ }
+
+ GrMaskFormat format = info.fMaskFormat;
+ if (kARGB_GrMaskFormat == format) {
+ color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha);
+ }
+
+ BitmapTextBatch::Geometry geometry;
+ geometry.fBlob.reset(SkRef(blob));
+ geometry.fRun = run;
+ geometry.fSubRun = subRun;
+ geometry.fColor = color;
+ SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, glyphCount,
+ fContext->getBatchFontCache()));
+
+ target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertexBounds);
+ }
}
// Now flush big glyphs
diff --git a/src/gpu/GrBitmapTextContext.h b/src/gpu/GrBitmapTextContext.h
index 3bf3a941c6..1f8a82f35a 100644
--- a/src/gpu/GrBitmapTextContext.h
+++ b/src/gpu/GrBitmapTextContext.h
@@ -11,6 +11,8 @@
#include "GrTextContext.h"
#include "GrGeometryProcessor.h"
+#include "GrMemoryPool.h"
+#include "SkDescriptor.h"
#include "SkTHash.h"
class GrBatchTextStrike;
@@ -65,63 +67,108 @@ private:
// this at a more fine grained level, but its not clear if this is worth it, as evictions
// should be fairly rare.
// One additional point, each run can contain glyphs with any of the three mask formats.
- // We maintain separate arrays for each format type, and flush them separately. In practice
- // most of the time a run will have the same format type
+ // We call these SubRuns. Because a subrun must be a contiguous range, we have to create
+ // a new subrun each time the mask format changes in a run. In theory, a run can have as
+ // many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
+ // practice, the vast majority of runs have only a single subrun.
+
struct Run {
- Run() : fColor(GrColor_ILLEGAL) { fVertexBounds.setLargestInverted(); }
- struct PerFormatInfo {
- PerFormatInfo() : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration) {}
- SkTDArray<unsigned char> fVertices;
- SkTDArray<GrGlyph::PackedID> fGlyphIDs;
+ Run() : fColor(GrColor_ILLEGAL), fInitialized(false) {
+ fVertexBounds.setLargestInverted();
+ // We insert the first subrun to gurantee a run always has atleast one subrun.
+ // We do this to simplify things when we 'hand off' data from one subrun to the
+ // next
+ fSubRunInfo.push_back();
+ }
+ struct SubRunInfo {
+ SubRunInfo()
+ : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
+ , fGlyphStartIndex(0)
+ , fGlyphEndIndex(0)
+ , fVertexStartIndex(0)
+ , fVertexEndIndex(0) {}
+ GrMaskFormat fMaskFormat;
uint64_t fAtlasGeneration;
+ uint32_t fGlyphStartIndex;
+ uint32_t fGlyphEndIndex;
+ size_t fVertexStartIndex;
+ size_t fVertexEndIndex;
};
- SkAutoTUnref<const SkData> fDescriptor;
+ SkSTArray<1, SubRunInfo, true> fSubRunInfo;
+ SkAutoDescriptor fDescriptor;
SkAutoTUnref<SkTypeface> fTypeface;
- PerFormatInfo fInfos[kMaskFormatCount];
SkRect fVertexBounds;
GrColor fColor;
+ bool fInitialized;
};
- SkSTArray<1, Run, true> fRuns;
+
struct BigGlyph {
BigGlyph(const SkPath& path, int vx, int vy) : fPath(path), fVx(vx), fVy(vy) {}
SkPath fPath;
int fVx;
int fVy;
};
+
SkTArray<BigGlyph> fBigGlyphs;
- SkTextBlob* fBlob;
SkMatrix fViewMatrix;
SkScalar fX;
SkScalar fY;
SkPaint::Style fStyle;
+ uint32_t fRunCount;
+
+ // all glyph / vertex offsets are into these pools.
+ unsigned char* fVertices;
+ GrGlyph::PackedID* fGlyphIDs;
+ Run* fRuns;
static uint32_t Hash(const uint32_t& key) {
return SkChecksum::Mix(key);
}
+
+ void operator delete(void* p) { sk_free(p); }
+ void* operator new(size_t) {
+ SkFAIL("All blobs are created by placement new.");
+ return sk_malloc_throw(0);
+ }
+
+ void* operator new(size_t, void* p) { return p; }
+ void operator delete(void* target, void* placement) {
+ ::operator delete(target, placement);
+ }
};
+ typedef BitmapTextBlob::Run Run;
+ typedef Run::SubRunInfo PerSubRunInfo;
+
+ BitmapTextBlob* CreateBlob(int glyphCount, int runCount);
+
void appendGlyph(BitmapTextBlob*, int runIndex, GrGlyph::PackedID, int left, int top,
GrFontScaler*, const SkIRect& clipRect);
- void flushSubRun(GrDrawTarget*, BitmapTextBlob*, int i, GrPipelineBuilder*, GrMaskFormat,
- GrColor color, int paintAlpha);
void flush(GrDrawTarget*, BitmapTextBlob*, GrRenderTarget*, const GrPaint&, const GrClip&,
const SkMatrix& viewMatrix, int paintAlpha);
- void internalDrawText(BitmapTextBlob*, int runIndex, const SkPaint&,
+ void internalDrawText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
const SkMatrix& viewMatrix, const char text[], size_t byteLength,
SkScalar x, SkScalar y, const SkIRect& clipRect);
- void internalDrawPosText(BitmapTextBlob*, int runIndex, const SkPaint&,
+ void internalDrawPosText(BitmapTextBlob*, int runIndex, SkGlyphCache*, const SkPaint&,
const SkMatrix& viewMatrix,
const char text[], size_t byteLength,
const SkScalar pos[], int scalarsPerPosition,
const SkPoint& offset, const SkIRect& clipRect);
+ // sets up the descriptor on the blob and returns a detached cache. Client must attach
+ inline SkGlyphCache* setupCache(Run*, const SkPaint&, const SkMatrix& viewMatrix);
static inline bool MustRegenerateBlob(const BitmapTextBlob&, const SkPaint&,
const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
void regenerateTextBlob(BitmapTextBlob* bmp, const SkPaint& skPaint, const SkMatrix& viewMatrix,
const SkTextBlob* blob, SkScalar x, SkScalar y,
SkDrawFilter* drawFilter, const SkIRect& clipRect);
+ // TODO this currently only uses the public interface of SkTextBlob, however, I may need to add
+ // functionality to it while looping over the runs so I'm putting this here for the time being.
+ // If this lands in Chrome without changes, move it to SkTextBlob.
+ static inline void BlobGlyphCount(int* glyphCount, int* runCount, const SkTextBlob*);
+
GrBatchTextStrike* fCurrStrike;
// TODO use real cache