blob: 63eb56b6f8e53ea4fd57cbd3c490d3b7094a3f94 [file] [log] [blame]
joshualitt374b2f72015-07-21 08:05:03 -07001/*
2 * Copyright 2015 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrAtlasTextBlob_DEFINED
9#define GrAtlasTextBlob_DEFINED
10
11#include "GrBatchAtlas.h"
12#include "GrBatchFontCache.h"
joshualitt259fbf12015-07-21 11:39:34 -070013#include "GrColor.h"
joshualitt2e2202e2015-12-10 11:22:08 -080014#include "GrMemoryPool.h"
joshualitt374b2f72015-07-21 08:05:03 -070015#include "SkDescriptor.h"
16#include "SkMaskFilter.h"
joshualitt259fbf12015-07-21 11:39:34 -070017#include "SkSurfaceProps.h"
joshualitt374b2f72015-07-21 08:05:03 -070018#include "SkTInternalLList.h"
19
joshualittddd22d82016-02-16 06:47:52 -080020class GrBlobRegenHelper;
joshualitt2e2202e2015-12-10 11:22:08 -080021struct GrDistanceFieldAdjustTable;
joshualitt92303772016-02-10 11:55:52 -080022class GrMemoryPool;
joshualitt2e2202e2015-12-10 11:22:08 -080023class GrTextContext;
24class SkDrawFilter;
25class SkTextBlob;
26class SkTextBlobRunIterator;
27
joshualitt259fbf12015-07-21 11:39:34 -070028// With this flag enabled, the GrAtlasTextContext will, as a sanity check, regenerate every blob
29// that comes in to verify the integrity of its cache
joshualitt2f2ee832016-02-10 08:52:24 -080030#define CACHE_SANITY_CHECK 0
joshualitt259fbf12015-07-21 11:39:34 -070031
joshualitt374b2f72015-07-21 08:05:03 -070032/*
33 * A GrAtlasTextBlob contains a fully processed SkTextBlob, suitable for nearly immediate drawing
34 * on the GPU. These are initially created with valid positions and colors, but invalid
35 * texture coordinates. The GrAtlasTextBlob itself has a few Blob-wide properties, and also
36 * consists of a number of runs. Runs inside a blob are flushed individually so they can be
37 * reordered.
38 *
39 * The only thing(aside from a memcopy) required to flush a GrAtlasTextBlob is to ensure that
40 * the GrAtlas will not evict anything the Blob needs.
41 *
42 * Note: This struct should really be named GrCachedAtasTextBlob, but that is too verbose.
joshualitt259fbf12015-07-21 11:39:34 -070043 *
44 * *WARNING* If you add new fields to this struct, then you may need to to update AssertEqual
joshualitt374b2f72015-07-21 08:05:03 -070045 */
joshualitt2e2202e2015-12-10 11:22:08 -080046class GrAtlasTextBlob : public SkNVRefCnt<GrAtlasTextBlob> {
47public:
joshualitt374b2f72015-07-21 08:05:03 -070048 SK_DECLARE_INTERNAL_LLIST_INTERFACE(GrAtlasTextBlob);
49
joshualitt92303772016-02-10 11:55:52 -080050 static GrAtlasTextBlob* Create(GrMemoryPool* pool, int glyphCount, int runCount);
joshualitt323c2eb2016-01-20 06:48:47 -080051
52 struct Key {
53 Key() {
54 sk_bzero(this, sizeof(Key));
55 }
56 uint32_t fUniqueID;
57 // Color may affect the gamma of the mask we generate, but in a fairly limited way.
58 // Each color is assigned to on of a fixed number of buckets based on its
59 // luminance. For each luminance bucket there is a "canonical color" that
60 // represents the bucket. This functionality is currently only supported for A8
61 SkColor fCanonicalColor;
62 SkPaint::Style fStyle;
63 SkPixelGeometry fPixelGeometry;
64 bool fHasBlur;
65
66 bool operator==(const Key& other) const {
67 return 0 == memcmp(this, &other, sizeof(Key));
68 }
69 };
70
joshualitt92303772016-02-10 11:55:52 -080071 void setupKey(const GrAtlasTextBlob::Key& key,
72 const SkMaskFilter::BlurRec& blurRec,
73 const SkPaint& paint) {
74 fKey = key;
75 if (key.fHasBlur) {
76 fBlurRec = blurRec;
77 }
78 if (key.fStyle != SkPaint::kFill_Style) {
79 fStrokeInfo.fFrameWidth = paint.getStrokeWidth();
80 fStrokeInfo.fMiterLimit = paint.getStrokeMiter();
81 fStrokeInfo.fJoin = paint.getStrokeJoin();
82 }
83 }
84
joshualitt323c2eb2016-01-20 06:48:47 -080085 static const Key& GetKey(const GrAtlasTextBlob& blob) {
86 return blob.fKey;
87 }
88
89 static uint32_t Hash(const Key& key) {
90 return SkChecksum::Murmur3(&key, sizeof(Key));
91 }
92
93 void operator delete(void* p) {
94 GrAtlasTextBlob* blob = reinterpret_cast<GrAtlasTextBlob*>(p);
95 blob->fPool->release(p);
96 }
97 void* operator new(size_t) {
98 SkFAIL("All blobs are created by placement new.");
99 return sk_malloc_throw(0);
100 }
101
102 void* operator new(size_t, void* p) { return p; }
103 void operator delete(void* target, void* placement) {
104 ::operator delete(target, placement);
105 }
106
107 bool hasDistanceField() const { return SkToBool(fTextType & kHasDistanceField_TextType); }
108 bool hasBitmap() const { return SkToBool(fTextType & kHasBitmap_TextType); }
109 void setHasDistanceField() { fTextType |= kHasDistanceField_TextType; }
110 void setHasBitmap() { fTextType |= kHasBitmap_TextType; }
111
joshualittddd22d82016-02-16 06:47:52 -0800112 int runCount() const { return fRunCount; }
113
joshualitt323c2eb2016-01-20 06:48:47 -0800114 void push_back_run(int currRun) {
115 SkASSERT(currRun < fRunCount);
116 if (currRun > 0) {
117 Run::SubRunInfo& newRun = fRuns[currRun].fSubRunInfo.back();
118 Run::SubRunInfo& lastRun = fRuns[currRun - 1].fSubRunInfo.back();
119 newRun.setAsSuccessor(lastRun);
120 }
121 }
122
123 // sets the last subrun of runIndex to use distance field text
124 void setSubRunHasDistanceFields(int runIndex, bool hasLCD) {
125 Run& run = fRuns[runIndex];
126 Run::SubRunInfo& subRun = run.fSubRunInfo.back();
127 subRun.setUseLCDText(hasLCD);
128 subRun.setDrawAsDistanceFields();
129 }
130
131 void setRunDrawAsPaths(int runIndex) {
132 fRuns[runIndex].fDrawAsPaths = true;
133 }
134
135 void setMinAndMaxScale(SkScalar scaledMax, SkScalar scaledMin) {
136 // we init fMaxMinScale and fMinMaxScale in the constructor
137 fMaxMinScale = SkMaxScalar(scaledMax, fMaxMinScale);
138 fMinMaxScale = SkMinScalar(scaledMin, fMinMaxScale);
139 }
140
141 // inits the override descriptor on the current run. All following subruns must use this
142 // descriptor
143 void initOverride(int runIndex) {
144 Run& run = fRuns[runIndex];
145 // Push back a new subrun to fill and set the override descriptor
146 run.push_back();
147 run.fOverrideDescriptor.reset(new SkAutoDescriptor);
148 }
149
150 SkGlyphCache* setupCache(int runIndex,
151 const SkSurfaceProps& props,
152 const SkPaint& skPaint,
153 const SkMatrix* viewMatrix,
154 bool noGamma);
155
156 // Appends a glyph to the blob. If the glyph is too large, the glyph will be appended
157 // as a path.
158 void appendGlyph(int runIndex,
159 const SkRect& positions,
160 GrColor color,
161 GrBatchTextStrike* strike,
162 GrGlyph* glyph,
163 GrFontScaler* scaler, const SkGlyph& skGlyph,
164 SkScalar x, SkScalar y, SkScalar scale, bool applyVM);
165
166 static size_t GetVertexStride(GrMaskFormat maskFormat) {
167 switch (maskFormat) {
168 case kA8_GrMaskFormat:
169 return kGrayTextVASize;
170 case kARGB_GrMaskFormat:
171 return kColorTextVASize;
172 default:
173 return kLCDTextVASize;
174 }
175 }
176
177 bool mustRegenerate(SkScalar* outTransX, SkScalar* outTransY, const SkPaint& paint,
178 GrColor color, const SkMaskFilter::BlurRec& blurRec,
179 const SkMatrix& viewMatrix, SkScalar x, SkScalar y);
180
181 // flush a GrAtlasTextBlob associated with a SkTextBlob
182 void flushCached(GrContext* context,
183 GrDrawContext* dc,
184 const SkTextBlob* blob,
185 const SkSurfaceProps& props,
186 const GrDistanceFieldAdjustTable* distanceAdjustTable,
187 const SkPaint& skPaint,
188 const GrPaint& grPaint,
189 SkDrawFilter* drawFilter,
190 const GrClip& clip,
191 const SkMatrix& viewMatrix,
192 const SkIRect& clipBounds,
193 SkScalar x, SkScalar y,
194 SkScalar transX, SkScalar transY);
195
196 // flush a throwaway GrAtlasTextBlob *not* associated with an SkTextBlob
197 void flushThrowaway(GrContext* context,
198 GrDrawContext* dc,
199 const SkSurfaceProps& props,
200 const GrDistanceFieldAdjustTable* distanceAdjustTable,
201 const SkPaint& skPaint,
202 const GrPaint& grPaint,
203 const GrClip& clip,
204 const SkIRect& clipBounds);
205
joshualittbc811112016-02-11 12:42:02 -0800206 void computeSubRunBounds(SkRect* outBounds, int runIndex, int subRunIndex) {
207 // We don't yet position distance field text on the cpu, so we have to map the vertex bounds
208 // into device space.
209 // We handle vertex bounds differently for distance field text and bitmap text because
210 // the vertex bounds of bitmap text are in device space. If we are flushing multiple runs
211 // from one blob then we are going to pay the price here of mapping the rect for each run.
212 const Run& run = fRuns[runIndex];
213 const Run::SubRunInfo& subRun = run.fSubRunInfo[subRunIndex];
214 *outBounds = subRun.vertexBounds();
215 if (subRun.drawAsDistanceFields()) {
216 // Distance field text is positioned with the (X,Y) as part of the glyph position,
217 // and currently the view matrix is applied on the GPU
218 outBounds->offset(fX - fInitialX, fY - fInitialY);
219 fViewMatrix.mapRect(outBounds);
220 } else {
221 // Bitmap text is fully positioned on the CPU, and offset by an (X,Y) translate in
222 // device space.
223 SkMatrix boundsMatrix = fInitialViewMatrixInverse;
224
225 boundsMatrix.postTranslate(-fInitialX, -fInitialY);
226
227 boundsMatrix.postTranslate(fX, fY);
228
229 boundsMatrix.postConcat(fViewMatrix);
230 boundsMatrix.mapRect(outBounds);
231
232 // Due to floating point numerical inaccuracies, we have to round out here
233 outBounds->roundOut(outBounds);
234 }
235 }
236
237 const SkMatrix& viewMatrix() const { return fViewMatrix; }
238
239
joshualitt323c2eb2016-01-20 06:48:47 -0800240 // position + local coord
241 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
242 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint16);
243 static const size_t kLCDTextVASize = kGrayTextVASize;
joshualitt92303772016-02-10 11:55:52 -0800244 static const size_t kMaxVASize = kGrayTextVASize;
joshualitt323c2eb2016-01-20 06:48:47 -0800245 static const int kVerticesPerGlyph = 4;
246
joshualitt323c2eb2016-01-20 06:48:47 -0800247 static void AssertEqual(const GrAtlasTextBlob&, const GrAtlasTextBlob&);
joshualitt323c2eb2016-01-20 06:48:47 -0800248
249 // The color here is the GrPaint color, and it is used to determine whether we
250 // have to regenerate LCD text blobs.
251 // We use this color vs the SkPaint color because it has the colorfilter applied.
252 void initReusableBlob(GrColor color, const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
253 fPaintColor = color;
joshualitt7481e752016-01-22 06:08:48 -0800254 this->setupViewMatrix(viewMatrix, x, y);
joshualitt323c2eb2016-01-20 06:48:47 -0800255 }
256
joshualitt7481e752016-01-22 06:08:48 -0800257 void initThrowawayBlob(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
258 this->setupViewMatrix(viewMatrix, x, y);
joshualitt323c2eb2016-01-20 06:48:47 -0800259 }
260
joshualittddd22d82016-02-16 06:47:52 -0800261 void regenInBatch(GrDrawBatch::Target* target, GrBatchFontCache* fontCache,
262 GrBlobRegenHelper *helper, int run, int subRun, SkGlyphCache** cache,
263 SkTypeface** typeface, GrFontScaler** scaler,
264 const SkDescriptor** desc, size_t vertexStride,
265 GrColor color, SkScalar transX, SkScalar transY,
266 void** vertices, size_t* byteCount, int* glyphCount);
267
joshualitt92303772016-02-10 11:55:52 -0800268 const Key& key() const { return fKey; }
269
270 ~GrAtlasTextBlob() {
271 for (int i = 0; i < fRunCount; i++) {
272 fRuns[i].~Run();
273 }
274 }
275
joshualittbc811112016-02-11 12:42:02 -0800276 ////////////////////////////////////////////////////////////////////////////////////////////////
277 // Internal test methods
278 GrDrawBatch* test_createBatch(int glyphCount, int run, int subRun,
279 GrColor color, SkScalar transX, SkScalar transY,
280 const SkPaint& skPaint, const SkSurfaceProps& props,
281 const GrDistanceFieldAdjustTable* distanceAdjustTable,
282 GrBatchFontCache* cache);
283
joshualitt323c2eb2016-01-20 06:48:47 -0800284private:
joshualitt92303772016-02-10 11:55:52 -0800285 GrAtlasTextBlob()
286 : fMaxMinScale(-SK_ScalarMax)
287 , fMinMaxScale(SK_ScalarMax)
288 , fTextType(0) {}
289
joshualitt323c2eb2016-01-20 06:48:47 -0800290 void appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, const SkGlyph& skGlyph,
291 SkScalar x, SkScalar y, SkScalar scale, bool applyVM);
292
293 inline void flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder,
294 int run, GrColor color,
295 SkScalar transX, SkScalar transY,
296 const SkPaint& skPaint, const SkSurfaceProps& props,
297 const GrDistanceFieldAdjustTable* distanceAdjustTable,
298 GrBatchFontCache* cache);
299
300 void flushBigGlyphs(GrContext* context, GrDrawContext* dc,
301 const GrClip& clip, const SkPaint& skPaint,
302 SkScalar transX, SkScalar transY,
303 const SkIRect& clipBounds);
304
305 void flushRunAsPaths(GrContext* context,
306 GrDrawContext* dc,
307 const SkSurfaceProps& props,
308 const SkTextBlobRunIterator& it,
309 const GrClip& clip, const SkPaint& skPaint,
310 SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
311 const SkIRect& clipBounds, SkScalar x, SkScalar y);
312
joshualitt7481e752016-01-22 06:08:48 -0800313 // This function will only be called when we are regenerating a blob from scratch. We record the
314 // initial view matrix and initial offsets(x,y), because we record vertex bounds relative to
315 // these numbers. When blobs are reused with new matrices, we need to return to model space so
316 // we can update the vertex bounds appropriately.
317 void setupViewMatrix(const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
318 fViewMatrix = viewMatrix;
319 if (!viewMatrix.invert(&fInitialViewMatrixInverse)) {
320 fInitialViewMatrixInverse = SkMatrix::I();
321 SkDebugf("Could not invert viewmatrix\n");
322 }
323 fX = fInitialX = x;
324 fY = fInitialY = y;
325 }
326
joshualitt374b2f72015-07-21 08:05:03 -0700327 /*
328 * Each Run inside of the blob can have its texture coordinates regenerated if required.
329 * To determine if regeneration is necessary, fAtlasGeneration is used. If there have been
330 * any evictions inside of the atlas, then we will simply regenerate Runs. We could track
331 * this at a more fine grained level, but its not clear if this is worth it, as evictions
332 * should be fairly rare.
333 *
334 * One additional point, each run can contain glyphs with any of the three mask formats.
335 * We call these SubRuns. Because a subrun must be a contiguous range, we have to create
336 * a new subrun each time the mask format changes in a run. In theory, a run can have as
337 * many SubRuns as it has glyphs, ie if a run alternates between color emoji and A8. In
338 * practice, the vast majority of runs have only a single subrun.
339 *
340 * Finally, for runs where the entire thing is too large for the GrAtlasTextContext to
341 * handle, we have a bit to mark the run as flusahable via rendering as paths. It is worth
342 * pointing. It would be a bit expensive to figure out ahead of time whether or not a run
343 * can flush in this manner, so we always allocate vertices for the run, regardless of
344 * whether or not it is too large. The benefit of this strategy is that we can always reuse
345 * a blob allocation regardless of viewmatrix changes. We could store positions for these
346 * glyphs. However, its not clear if this is a win because we'd still have to either go the
347 * glyph cache to get the path at flush time, or hold onto the path in the cache, which
348 * would greatly increase the memory of these cached items.
349 */
350 struct Run {
351 Run()
joshualittf9e658b2015-12-09 09:26:44 -0800352 : fInitialized(false)
joshualitt374b2f72015-07-21 08:05:03 -0700353 , fDrawAsPaths(false) {
joshualitt374b2f72015-07-21 08:05:03 -0700354 // To ensure we always have one subrun, we push back a fresh run here
355 fSubRunInfo.push_back();
356 }
357 struct SubRunInfo {
358 SubRunInfo()
359 : fAtlasGeneration(GrBatchAtlas::kInvalidAtlasGeneration)
360 , fVertexStartIndex(0)
361 , fVertexEndIndex(0)
362 , fGlyphStartIndex(0)
363 , fGlyphEndIndex(0)
joshualittf9e658b2015-12-09 09:26:44 -0800364 , fColor(GrColor_ILLEGAL)
jvanverthce79a3a2015-09-10 06:31:38 -0700365 , fMaskFormat(kA8_GrMaskFormat)
366 , fDrawAsDistanceFields(false)
joshualitt7481e752016-01-22 06:08:48 -0800367 , fUseLCDText(false) {
368 fVertexBounds.setLargestInverted();
369 }
joshualitt7e97b0b2015-07-31 15:18:08 -0700370 SubRunInfo(const SubRunInfo& that)
371 : fBulkUseToken(that.fBulkUseToken)
372 , fStrike(SkSafeRef(that.fStrike.get()))
joshualitt7481e752016-01-22 06:08:48 -0800373 , fVertexBounds(that.fVertexBounds)
joshualitt7e97b0b2015-07-31 15:18:08 -0700374 , fAtlasGeneration(that.fAtlasGeneration)
375 , fVertexStartIndex(that.fVertexStartIndex)
376 , fVertexEndIndex(that.fVertexEndIndex)
377 , fGlyphStartIndex(that.fGlyphStartIndex)
378 , fGlyphEndIndex(that.fGlyphEndIndex)
joshualittf9e658b2015-12-09 09:26:44 -0800379 , fColor(that.fColor)
joshualitt7e97b0b2015-07-31 15:18:08 -0700380 , fMaskFormat(that.fMaskFormat)
381 , fDrawAsDistanceFields(that.fDrawAsDistanceFields)
382 , fUseLCDText(that.fUseLCDText) {
383 }
joshualitt3660d532015-12-07 11:32:50 -0800384
joshualitt18b072d2015-12-07 12:26:12 -0800385 // TODO when this object is more internal, drop the privacy
joshualitt3660d532015-12-07 11:32:50 -0800386 void resetBulkUseToken() { fBulkUseToken.reset(); }
387 GrBatchAtlas::BulkUseTokenUpdater* bulkUseToken() { return &fBulkUseToken; }
388 void setStrike(GrBatchTextStrike* strike) { fStrike.reset(SkRef(strike)); }
389 GrBatchTextStrike* strike() const { return fStrike.get(); }
390
391 void setAtlasGeneration(uint64_t atlasGeneration) { fAtlasGeneration = atlasGeneration;}
392 uint64_t atlasGeneration() const { return fAtlasGeneration; }
393
394 size_t byteCount() const { return fVertexEndIndex - fVertexStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800395 size_t vertexStartIndex() const { return fVertexStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800396 size_t vertexEndIndex() const { return fVertexEndIndex; }
397 void appendVertices(size_t vertexStride) {
398 fVertexEndIndex += vertexStride * kVerticesPerGlyph;
399 }
400
401 uint32_t glyphCount() const { return fGlyphEndIndex - fGlyphStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800402 uint32_t glyphStartIndex() const { return fGlyphStartIndex; }
joshualitt3660d532015-12-07 11:32:50 -0800403 uint32_t glyphEndIndex() const { return fGlyphEndIndex; }
404 void glyphAppended() { fGlyphEndIndex++; }
joshualittf9e658b2015-12-09 09:26:44 -0800405 void setColor(GrColor color) { fColor = color; }
406 GrColor color() const { return fColor; }
joshualitt3660d532015-12-07 11:32:50 -0800407 void setMaskFormat(GrMaskFormat format) { fMaskFormat = format; }
408 GrMaskFormat maskFormat() const { return fMaskFormat; }
409
joshualitt18b072d2015-12-07 12:26:12 -0800410 void setAsSuccessor(const SubRunInfo& prev) {
411 fGlyphStartIndex = prev.glyphEndIndex();
412 fGlyphEndIndex = prev.glyphEndIndex();
413
414 fVertexStartIndex = prev.vertexEndIndex();
415 fVertexEndIndex = prev.vertexEndIndex();
416 }
417
joshualitt7481e752016-01-22 06:08:48 -0800418 const SkRect& vertexBounds() const { return fVertexBounds; }
419 void joinGlyphBounds(const SkRect& glyphBounds) {
420 fVertexBounds.joinNonEmptyArg(glyphBounds);
421 }
422
joshualitt3660d532015-12-07 11:32:50 -0800423 // df properties
424 void setUseLCDText(bool useLCDText) { fUseLCDText = useLCDText; }
425 bool hasUseLCDText() const { return fUseLCDText; }
426 void setDrawAsDistanceFields() { fDrawAsDistanceFields = true; }
427 bool drawAsDistanceFields() const { return fDrawAsDistanceFields; }
428
429 private:
joshualitt374b2f72015-07-21 08:05:03 -0700430 GrBatchAtlas::BulkUseTokenUpdater fBulkUseToken;
joshualitt7e97b0b2015-07-31 15:18:08 -0700431 SkAutoTUnref<GrBatchTextStrike> fStrike;
joshualitt7481e752016-01-22 06:08:48 -0800432 SkRect fVertexBounds;
joshualitt374b2f72015-07-21 08:05:03 -0700433 uint64_t fAtlasGeneration;
434 size_t fVertexStartIndex;
435 size_t fVertexEndIndex;
436 uint32_t fGlyphStartIndex;
437 uint32_t fGlyphEndIndex;
joshualittf9e658b2015-12-09 09:26:44 -0800438 GrColor fColor;
joshualitt374b2f72015-07-21 08:05:03 -0700439 GrMaskFormat fMaskFormat;
440 bool fDrawAsDistanceFields; // df property
441 bool fUseLCDText; // df property
442 };
443
444 SubRunInfo& push_back() {
445 // Forward glyph / vertex information to seed the new sub run
joshualitt374b2f72015-07-21 08:05:03 -0700446 SubRunInfo& newSubRun = fSubRunInfo.push_back();
joshualitt18b072d2015-12-07 12:26:12 -0800447 const SubRunInfo& prevSubRun = fSubRunInfo.fromBack(1);
joshualitte43e3bd2015-07-29 11:10:38 -0700448
joshualitt18b072d2015-12-07 12:26:12 -0800449 newSubRun.setAsSuccessor(prevSubRun);
joshualitt374b2f72015-07-21 08:05:03 -0700450 return newSubRun;
451 }
452 static const int kMinSubRuns = 1;
joshualitt374b2f72015-07-21 08:05:03 -0700453 SkAutoTUnref<SkTypeface> fTypeface;
joshualitt374b2f72015-07-21 08:05:03 -0700454 SkSTArray<kMinSubRuns, SubRunInfo> fSubRunInfo;
455 SkAutoDescriptor fDescriptor;
joshualitt3660d532015-12-07 11:32:50 -0800456
457 // Distance field text cannot draw coloremoji, and so has to fall back. However,
458 // though the distance field text and the coloremoji may share the same run, they
459 // will have different descriptors. If fOverrideDescriptor is non-nullptr, then it
460 // will be used in place of the run's descriptor to regen texture coords
joshualitt374b2f72015-07-21 08:05:03 -0700461 SkAutoTDelete<SkAutoDescriptor> fOverrideDescriptor; // df properties
joshualitt374b2f72015-07-21 08:05:03 -0700462 bool fInitialized;
463 bool fDrawAsPaths;
464 };
465
joshualittddd22d82016-02-16 06:47:52 -0800466 template <bool regenPos, bool regenCol, bool regenTexCoords, bool regenGlyphs>
467 void regenInBatch(GrDrawBatch::Target* target,
468 GrBatchFontCache* fontCache,
469 GrBlobRegenHelper* helper,
470 Run* run, Run::SubRunInfo* info, SkGlyphCache** cache,
471 SkTypeface** typeface, GrFontScaler** scaler,
472 const SkDescriptor** desc,
473 int glyphCount, size_t vertexStride,
474 GrColor color, SkScalar transX,
475 SkScalar transY) const;
476
joshualitt323c2eb2016-01-20 06:48:47 -0800477 inline GrDrawBatch* createBatch(const Run::SubRunInfo& info,
478 int glyphCount, int run, int subRun,
479 GrColor color, SkScalar transX, SkScalar transY,
480 const SkPaint& skPaint, const SkSurfaceProps& props,
481 const GrDistanceFieldAdjustTable* distanceAdjustTable,
482 GrBatchFontCache* cache);
483
joshualitt374b2f72015-07-21 08:05:03 -0700484 struct BigGlyph {
joshualitt0fe04a22015-08-25 12:05:50 -0700485 BigGlyph(const SkPath& path, SkScalar vx, SkScalar vy, SkScalar scale, bool applyVM)
joshualitt374b2f72015-07-21 08:05:03 -0700486 : fPath(path)
487 , fVx(vx)
joshualitt0fe04a22015-08-25 12:05:50 -0700488 , fVy(vy)
489 , fScale(scale)
490 , fApplyVM(applyVM) {}
joshualitt374b2f72015-07-21 08:05:03 -0700491 SkPath fPath;
492 SkScalar fVx;
493 SkScalar fVy;
joshualitt0fe04a22015-08-25 12:05:50 -0700494 SkScalar fScale;
495 bool fApplyVM;
joshualitt374b2f72015-07-21 08:05:03 -0700496 };
497
joshualitt374b2f72015-07-21 08:05:03 -0700498 struct StrokeInfo {
499 SkScalar fFrameWidth;
500 SkScalar fMiterLimit;
501 SkPaint::Join fJoin;
502 };
503
504 enum TextType {
505 kHasDistanceField_TextType = 0x1,
506 kHasBitmap_TextType = 0x2,
507 };
508
509 // all glyph / vertex offsets are into these pools.
510 unsigned char* fVertices;
511 GrGlyph** fGlyphs;
512 Run* fRuns;
513 GrMemoryPool* fPool;
514 SkMaskFilter::BlurRec fBlurRec;
515 StrokeInfo fStrokeInfo;
516 SkTArray<BigGlyph> fBigGlyphs;
517 Key fKey;
518 SkMatrix fViewMatrix;
joshualitt7481e752016-01-22 06:08:48 -0800519 SkMatrix fInitialViewMatrixInverse;
joshualitt2f2ee832016-02-10 08:52:24 -0800520 size_t fSize;
jvanverth0628a522015-08-18 07:44:22 -0700521 GrColor fPaintColor;
joshualitt7481e752016-01-22 06:08:48 -0800522 SkScalar fInitialX;
523 SkScalar fInitialY;
joshualitt374b2f72015-07-21 08:05:03 -0700524 SkScalar fX;
525 SkScalar fY;
526
527 // We can reuse distance field text, but only if the new viewmatrix would not result in
528 // a mip change. Because there can be multiple runs in a blob, we track the overall
529 // maximum minimum scale, and minimum maximum scale, we can support before we need to regen
530 SkScalar fMaxMinScale;
531 SkScalar fMinMaxScale;
532 int fRunCount;
533 uint8_t fTextType;
joshualitt374b2f72015-07-21 08:05:03 -0700534};
535
536#endif