blob: cac1e53f09027be746a535fe8298d994d6161371 [file] [log] [blame]
joshualitt259fbf12015-07-21 11:39:34 -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#include "GrAtlasTextBlob.h"
9
joshualitt2e2202e2015-12-10 11:22:08 -080010#include "GrBlurUtils.h"
11#include "GrContext.h"
12#include "GrDrawContext.h"
joshualitt0a42e682015-12-10 13:20:58 -080013#include "GrTextUtils.h"
joshualitt2e2202e2015-12-10 11:22:08 -080014#include "SkColorFilter.h"
15#include "SkDrawFilter.h"
joshualitte76b4bb2015-12-28 07:23:58 -080016#include "SkGlyphCache.h"
joshualitt2e2202e2015-12-10 11:22:08 -080017#include "SkTextBlobRunIterator.h"
18#include "batches/GrAtlasTextBatch.h"
19
joshualitte76b4bb2015-12-28 07:23:58 -080020SkGlyphCache* GrAtlasTextBlob::setupCache(int runIndex,
21 const SkSurfaceProps& props,
22 const SkPaint& skPaint,
23 const SkMatrix* viewMatrix,
24 bool noGamma) {
25 GrAtlasTextBlob::Run* run = &fRuns[runIndex];
26
27 // if we have an override descriptor for the run, then we should use that
28 SkAutoDescriptor* desc = run->fOverrideDescriptor.get() ? run->fOverrideDescriptor.get() :
29 &run->fDescriptor;
30 skPaint.getScalerContextDescriptor(desc, props, viewMatrix, noGamma);
31 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
32 return SkGlyphCache::DetachCache(run->fTypeface, desc->getDesc());
33}
34
joshualittf528e0d2015-12-09 06:42:52 -080035void GrAtlasTextBlob::appendGlyph(int runIndex,
36 const SkRect& positions,
37 GrColor color,
38 GrBatchTextStrike* strike,
joshualitta06e6ab2015-12-10 08:54:41 -080039 GrGlyph* glyph,
40 GrFontScaler* scaler, const SkGlyph& skGlyph,
41 SkScalar x, SkScalar y, SkScalar scale, bool applyVM) {
42
43 // If the glyph is too large we fall back to paths
44 if (glyph->fTooLargeForAtlas) {
45 this->appendLargeGlyph(glyph, scaler, skGlyph, x, y, scale, applyVM);
46 return;
47 }
48
joshualittf528e0d2015-12-09 06:42:52 -080049 Run& run = fRuns[runIndex];
50 GrMaskFormat format = glyph->fMaskFormat;
51
52 Run::SubRunInfo* subRun = &run.fSubRunInfo.back();
53 if (run.fInitialized && subRun->maskFormat() != format) {
54 subRun = &run.push_back();
55 subRun->setStrike(strike);
56 } else if (!run.fInitialized) {
57 subRun->setStrike(strike);
58 }
59
60 run.fInitialized = true;
61
62 size_t vertexStride = GetVertexStride(format);
63
64 subRun->setMaskFormat(format);
65
joshualitt7481e752016-01-22 06:08:48 -080066 subRun->joinGlyphBounds(positions);
joshualittf9e658b2015-12-09 09:26:44 -080067 subRun->setColor(color);
joshualitt18b072d2015-12-07 12:26:12 -080068
69 intptr_t vertex = reinterpret_cast<intptr_t>(this->fVertices + subRun->vertexEndIndex());
70
joshualittf528e0d2015-12-09 06:42:52 -080071 if (kARGB_GrMaskFormat != glyph->fMaskFormat) {
joshualitt18b072d2015-12-07 12:26:12 -080072 // V0
73 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
74 position->set(positions.fLeft, positions.fTop);
75 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
76 *colorPtr = color;
77 vertex += vertexStride;
78
79 // V1
80 position = reinterpret_cast<SkPoint*>(vertex);
81 position->set(positions.fLeft, positions.fBottom);
82 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
83 *colorPtr = color;
84 vertex += vertexStride;
85
86 // V2
87 position = reinterpret_cast<SkPoint*>(vertex);
88 position->set(positions.fRight, positions.fBottom);
89 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
90 *colorPtr = color;
91 vertex += vertexStride;
92
93 // V3
94 position = reinterpret_cast<SkPoint*>(vertex);
95 position->set(positions.fRight, positions.fTop);
96 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
97 *colorPtr = color;
98 } else {
99 // V0
100 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
101 position->set(positions.fLeft, positions.fTop);
102 vertex += vertexStride;
103
104 // V1
105 position = reinterpret_cast<SkPoint*>(vertex);
106 position->set(positions.fLeft, positions.fBottom);
107 vertex += vertexStride;
108
109 // V2
110 position = reinterpret_cast<SkPoint*>(vertex);
111 position->set(positions.fRight, positions.fBottom);
112 vertex += vertexStride;
113
114 // V3
115 position = reinterpret_cast<SkPoint*>(vertex);
116 position->set(positions.fRight, positions.fTop);
117 }
118 subRun->appendVertices(vertexStride);
119 fGlyphs[subRun->glyphEndIndex()] = glyph;
120 subRun->glyphAppended();
121}
122
joshualitta06e6ab2015-12-10 08:54:41 -0800123void GrAtlasTextBlob::appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, const SkGlyph& skGlyph,
124 SkScalar x, SkScalar y, SkScalar scale, bool applyVM) {
125 if (nullptr == glyph->fPath) {
126 const SkPath* glyphPath = scaler->getGlyphPath(skGlyph);
127 if (!glyphPath) {
128 return;
129 }
130
131 glyph->fPath = new SkPath(*glyphPath);
132 }
133 fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, applyVM));
134}
135
joshualittfd5f6c12015-12-10 07:44:50 -0800136bool GrAtlasTextBlob::mustRegenerate(SkScalar* outTransX, SkScalar* outTransY,
137 const SkPaint& paint,
138 GrColor color, const SkMaskFilter::BlurRec& blurRec,
139 const SkMatrix& viewMatrix, SkScalar x, SkScalar y) {
140 // If we have LCD text then our canonical color will be set to transparent, in this case we have
141 // to regenerate the blob on any color change
142 // We use the grPaint to get any color filter effects
143 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
144 fPaintColor != color) {
145 return true;
146 }
147
148 if (fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) {
149 return true;
150 }
151
152 if (fViewMatrix.hasPerspective() && !fViewMatrix.cheapEqualTo(viewMatrix)) {
153 return true;
154 }
155
156 // We only cache one masked version
157 if (fKey.fHasBlur &&
158 (fBlurRec.fSigma != blurRec.fSigma ||
159 fBlurRec.fStyle != blurRec.fStyle ||
160 fBlurRec.fQuality != blurRec.fQuality)) {
161 return true;
162 }
163
164 // Similarly, we only cache one version for each style
165 if (fKey.fStyle != SkPaint::kFill_Style &&
166 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
167 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
168 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
169 return true;
170 }
171
172 // Mixed blobs must be regenerated. We could probably figure out a way to do integer scrolls
173 // for mixed blobs if this becomes an issue.
174 if (this->hasBitmap() && this->hasDistanceField()) {
175 // Identical viewmatrices and we can reuse in all cases
176 if (fViewMatrix.cheapEqualTo(viewMatrix) && x == fX && y == fY) {
177 return false;
178 }
179 return true;
180 }
181
182 if (this->hasBitmap()) {
183 if (fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
184 fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
185 fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
186 fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
187 return true;
188 }
189
190 // We can update the positions in the cachedtextblobs without regenerating the whole blob,
191 // but only for integer translations.
192 // This cool bit of math will determine the necessary translation to apply to the already
193 // generated vertex coordinates to move them to the correct position
194 SkScalar transX = viewMatrix.getTranslateX() +
195 viewMatrix.getScaleX() * (x - fX) +
196 viewMatrix.getSkewX() * (y - fY) -
197 fViewMatrix.getTranslateX();
198 SkScalar transY = viewMatrix.getTranslateY() +
199 viewMatrix.getSkewY() * (x - fX) +
200 viewMatrix.getScaleY() * (y - fY) -
201 fViewMatrix.getTranslateY();
202 if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) {
203 return true;
204 }
205
206 (*outTransX) = transX;
207 (*outTransY) = transY;
208 } else if (this->hasDistanceField()) {
209 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would result in a different
210 // distance field being generated, so we have to regenerate in those cases
211 SkScalar newMaxScale = viewMatrix.getMaxScale();
212 SkScalar oldMaxScale = fViewMatrix.getMaxScale();
213 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
214 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
215 return true;
216 }
217
218 (*outTransX) = x - fX;
219 (*outTransY) = y - fY;
220 }
221
joshualittfd5f6c12015-12-10 07:44:50 -0800222 // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y
223 // offsets. Note, we offset the vertex bounds right before flushing
224 fViewMatrix = viewMatrix;
225 fX = x;
226 fY = y;
227
228 // It is possible that a blob has neither distanceField nor bitmaptext. This is in the case
229 // when all of the runs inside the blob are drawn as paths. In this case, we always regenerate
230 // the blob anyways at flush time, so no need to regenerate explicitly
231 return false;
232}
233
joshualitt323c2eb2016-01-20 06:48:47 -0800234inline GrDrawBatch* GrAtlasTextBlob::createBatch(
235 const Run::SubRunInfo& info,
236 int glyphCount, int run, int subRun,
237 GrColor color, SkScalar transX, SkScalar transY,
238 const SkPaint& skPaint, const SkSurfaceProps& props,
239 const GrDistanceFieldAdjustTable* distanceAdjustTable,
240 GrBatchFontCache* cache) {
joshualitt2e2202e2015-12-10 11:22:08 -0800241 GrMaskFormat format = info.maskFormat();
242 GrColor subRunColor;
243 if (kARGB_GrMaskFormat == format) {
244 uint8_t paintAlpha = skPaint.getAlpha();
245 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha);
246 } else {
247 subRunColor = color;
248 }
249
250 GrAtlasTextBatch* batch;
251 if (info.drawAsDistanceFields()) {
252 SkColor filteredColor;
253 SkColorFilter* colorFilter = skPaint.getColorFilter();
254 if (colorFilter) {
255 filteredColor = colorFilter->filterColor(skPaint.getColor());
256 } else {
257 filteredColor = skPaint.getColor();
258 }
259 bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
260 batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache,
261 distanceAdjustTable, filteredColor,
262 info.hasUseLCDText(), useBGR);
263 } else {
264 batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache);
265 }
266 GrAtlasTextBatch::Geometry& geometry = batch->geometry();
267 geometry.fBlob = SkRef(this);
268 geometry.fRun = run;
269 geometry.fSubRun = subRun;
270 geometry.fColor = subRunColor;
271 geometry.fTransX = transX;
272 geometry.fTransY = transY;
273 batch->init();
274
275 return batch;
276}
277
278inline
279void GrAtlasTextBlob::flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBuilder,
280 int run, GrColor color,
281 SkScalar transX, SkScalar transY,
282 const SkPaint& skPaint, const SkSurfaceProps& props,
283 const GrDistanceFieldAdjustTable* distanceAdjustTable,
284 GrBatchFontCache* cache) {
285 for (int subRun = 0; subRun < fRuns[run].fSubRunInfo.count(); subRun++) {
286 const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
287 int glyphCount = info.glyphCount();
288 if (0 == glyphCount) {
289 continue;
290 }
291
292 SkAutoTUnref<GrDrawBatch> batch(this->createBatch(info, glyphCount, run,
293 subRun, color, transX, transY,
294 skPaint, props,
295 distanceAdjustTable, cache));
296 dc->drawBatch(pipelineBuilder, batch);
297 }
298}
299
300void GrAtlasTextBlob::flushBigGlyphs(GrContext* context, GrDrawContext* dc,
301 const GrClip& clip, const SkPaint& skPaint,
302 SkScalar transX, SkScalar transY,
303 const SkIRect& clipBounds) {
304 for (int i = 0; i < fBigGlyphs.count(); i++) {
305 GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i];
306 bigGlyph.fVx += transX;
307 bigGlyph.fVy += transY;
308 SkMatrix ctm;
309 ctm.setScale(bigGlyph.fScale, bigGlyph.fScale);
310 ctm.postTranslate(bigGlyph.fVx, bigGlyph.fVy);
311 if (bigGlyph.fApplyVM) {
312 ctm.postConcat(fViewMatrix);
313 }
314
315 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, bigGlyph.fPath,
316 skPaint, ctm, nullptr, clipBounds, false);
317 }
318}
319
joshualitt0a42e682015-12-10 13:20:58 -0800320void GrAtlasTextBlob::flushRunAsPaths(GrContext* context, GrDrawContext* dc,
joshualitt2e2202e2015-12-10 11:22:08 -0800321 const SkSurfaceProps& props,
322 const SkTextBlobRunIterator& it,
323 const GrClip& clip, const SkPaint& skPaint,
324 SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
325 const SkIRect& clipBounds, SkScalar x, SkScalar y) {
326 SkPaint runPaint = skPaint;
327
328 size_t textLen = it.glyphCount() * sizeof(uint16_t);
329 const SkPoint& offset = it.offset();
330
331 it.applyFontToPaint(&runPaint);
332
333 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
334 return;
335 }
336
337 runPaint.setFlags(GrTextContext::FilterTextFlags(props, runPaint));
338
339 switch (it.positioning()) {
340 case SkTextBlob::kDefault_Positioning:
joshualitt0a42e682015-12-10 13:20:58 -0800341 GrTextUtils::DrawTextAsPath(context, dc, clip, runPaint, viewMatrix,
joshualitt2e2202e2015-12-10 11:22:08 -0800342 (const char *)it.glyphs(),
343 textLen, x + offset.x(), y + offset.y(), clipBounds);
344 break;
345 case SkTextBlob::kHorizontal_Positioning:
joshualitt0a42e682015-12-10 13:20:58 -0800346 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix,
joshualitt2e2202e2015-12-10 11:22:08 -0800347 (const char*)it.glyphs(),
348 textLen, it.pos(), 1, SkPoint::Make(x, y + offset.y()),
349 clipBounds);
350 break;
351 case SkTextBlob::kFull_Positioning:
joshualitt0a42e682015-12-10 13:20:58 -0800352 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, viewMatrix,
joshualitt2e2202e2015-12-10 11:22:08 -0800353 (const char*)it.glyphs(),
354 textLen, it.pos(), 2, SkPoint::Make(x, y), clipBounds);
355 break;
356 }
357}
358
joshualitt0a42e682015-12-10 13:20:58 -0800359void GrAtlasTextBlob::flushCached(GrContext* context,
joshualitt2e2202e2015-12-10 11:22:08 -0800360 GrDrawContext* dc,
joshualitt0a42e682015-12-10 13:20:58 -0800361 const SkTextBlob* blob,
joshualitt2e2202e2015-12-10 11:22:08 -0800362 const SkSurfaceProps& props,
363 const GrDistanceFieldAdjustTable* distanceAdjustTable,
364 const SkPaint& skPaint,
365 const GrPaint& grPaint,
366 SkDrawFilter* drawFilter,
367 const GrClip& clip,
368 const SkMatrix& viewMatrix,
369 const SkIRect& clipBounds,
370 SkScalar x, SkScalar y,
371 SkScalar transX, SkScalar transY) {
372 // We loop through the runs of the blob, flushing each. If any run is too large, then we flush
373 // it as paths
374 GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip);
375
376 GrColor color = grPaint.getColor();
377
378 SkTextBlobRunIterator it(blob);
379 for (int run = 0; !it.done(); it.next(), run++) {
380 if (fRuns[run].fDrawAsPaths) {
joshualitt0a42e682015-12-10 13:20:58 -0800381 this->flushRunAsPaths(context, dc, props, it, clip, skPaint,
joshualitt2e2202e2015-12-10 11:22:08 -0800382 drawFilter, viewMatrix, clipBounds, x, y);
383 continue;
384 }
joshualitt2e2202e2015-12-10 11:22:08 -0800385 this->flushRun(dc, &pipelineBuilder, run, color,
386 transX, transY, skPaint, props,
387 distanceAdjustTable, context->getBatchFontCache());
388 }
389
390 // Now flush big glyphs
391 this->flushBigGlyphs(context, dc, clip, skPaint, transX, transY, clipBounds);
392}
393
394void GrAtlasTextBlob::flushThrowaway(GrContext* context,
395 GrDrawContext* dc,
396 const SkSurfaceProps& props,
397 const GrDistanceFieldAdjustTable* distanceAdjustTable,
398 const SkPaint& skPaint,
399 const GrPaint& grPaint,
400 const GrClip& clip,
401 const SkIRect& clipBounds) {
402 GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip);
403
404 GrColor color = grPaint.getColor();
405 for (int run = 0; run < fRunCount; run++) {
406 this->flushRun(dc, &pipelineBuilder, run, color, 0, 0, skPaint, props,
407 distanceAdjustTable, context->getBatchFontCache());
408 }
409
410 // Now flush big glyphs
411 this->flushBigGlyphs(context, dc, clip, skPaint, 0, 0, clipBounds);
412}
413
joshualitt323c2eb2016-01-20 06:48:47 -0800414GrDrawBatch* GrAtlasTextBlob::test_createBatch(
415 int glyphCount, int run, int subRun,
416 GrColor color, SkScalar transX, SkScalar transY,
417 const SkPaint& skPaint, const SkSurfaceProps& props,
418 const GrDistanceFieldAdjustTable* distanceAdjustTable,
419 GrBatchFontCache* cache) {
joshualitt7481e752016-01-22 06:08:48 -0800420 const GrAtlasTextBlob::Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
421 return this->createBatch(info, glyphCount, run, subRun, color, transX, transY, skPaint,
joshualitt323c2eb2016-01-20 06:48:47 -0800422 props, distanceAdjustTable, cache);
423}
joshualitt2e2202e2015-12-10 11:22:08 -0800424
joshualitt259fbf12015-07-21 11:39:34 -0700425void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlob& r) {
joshualitt2f2ee832016-02-10 08:52:24 -0800426 SkASSERT_RELEASE(l.fSize == r.fSize);
427 SkASSERT_RELEASE(l.fPool == r.fPool);
joshualitt259fbf12015-07-21 11:39:34 -0700428
joshualitt2f2ee832016-02-10 08:52:24 -0800429 SkASSERT_RELEASE(l.fBlurRec.fSigma == r.fBlurRec.fSigma);
430 SkASSERT_RELEASE(l.fBlurRec.fStyle == r.fBlurRec.fStyle);
431 SkASSERT_RELEASE(l.fBlurRec.fQuality == r.fBlurRec.fQuality);
joshualitt259fbf12015-07-21 11:39:34 -0700432
joshualitt2f2ee832016-02-10 08:52:24 -0800433 SkASSERT_RELEASE(l.fStrokeInfo.fFrameWidth == r.fStrokeInfo.fFrameWidth);
434 SkASSERT_RELEASE(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit);
435 SkASSERT_RELEASE(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin);
joshualitt259fbf12015-07-21 11:39:34 -0700436
joshualitt2f2ee832016-02-10 08:52:24 -0800437 SkASSERT_RELEASE(l.fBigGlyphs.count() == r.fBigGlyphs.count());
joshualitt259fbf12015-07-21 11:39:34 -0700438 for (int i = 0; i < l.fBigGlyphs.count(); i++) {
439 const BigGlyph& lBigGlyph = l.fBigGlyphs[i];
440 const BigGlyph& rBigGlyph = r.fBigGlyphs[i];
441
joshualitt2f2ee832016-02-10 08:52:24 -0800442 SkASSERT_RELEASE(lBigGlyph.fPath == rBigGlyph.fPath);
joshualitt259fbf12015-07-21 11:39:34 -0700443 // We can't assert that these have the same translations
444 }
445
joshualitt2f2ee832016-02-10 08:52:24 -0800446 SkASSERT_RELEASE(l.fKey == r.fKey);
447 SkASSERT_RELEASE(l.fViewMatrix.cheapEqualTo(r.fViewMatrix));
448 //SkASSERT_RELEASE(l.fPaintColor == r.fPaintColor); // Colors might not actually be identical
449 SkASSERT_RELEASE(l.fMaxMinScale == r.fMaxMinScale);
450 SkASSERT_RELEASE(l.fMinMaxScale == r.fMinMaxScale);
451 SkASSERT_RELEASE(l.fTextType == r.fTextType);
joshualitt259fbf12015-07-21 11:39:34 -0700452
joshualitt2f2ee832016-02-10 08:52:24 -0800453 SkASSERT_RELEASE(l.fRunCount == r.fRunCount);
joshualitt259fbf12015-07-21 11:39:34 -0700454 for (int i = 0; i < l.fRunCount; i++) {
455 const Run& lRun = l.fRuns[i];
456 const Run& rRun = r.fRuns[i];
457
joshualitt259fbf12015-07-21 11:39:34 -0700458 if (lRun.fTypeface.get()) {
joshualitt2f2ee832016-02-10 08:52:24 -0800459 SkASSERT_RELEASE(rRun.fTypeface.get());
460 SkASSERT_RELEASE(SkTypeface::Equal(lRun.fTypeface, rRun.fTypeface));
joshualitt259fbf12015-07-21 11:39:34 -0700461 } else {
joshualitt2f2ee832016-02-10 08:52:24 -0800462 SkASSERT_RELEASE(!rRun.fTypeface.get());
joshualitt259fbf12015-07-21 11:39:34 -0700463 }
464
joshualitt259fbf12015-07-21 11:39:34 -0700465
joshualitt2f2ee832016-02-10 08:52:24 -0800466 SkASSERT_RELEASE(lRun.fDescriptor.getDesc());
467 SkASSERT_RELEASE(rRun.fDescriptor.getDesc());
468 SkASSERT_RELEASE(lRun.fDescriptor.getDesc()->equals(*rRun.fDescriptor.getDesc()));
joshualitt259fbf12015-07-21 11:39:34 -0700469
470 if (lRun.fOverrideDescriptor.get()) {
joshualitt2f2ee832016-02-10 08:52:24 -0800471 SkASSERT_RELEASE(lRun.fOverrideDescriptor->getDesc());
472 SkASSERT_RELEASE(rRun.fOverrideDescriptor.get() && rRun.fOverrideDescriptor->getDesc());
473 SkASSERT_RELEASE(lRun.fOverrideDescriptor->getDesc()->equals(
joshualitt259fbf12015-07-21 11:39:34 -0700474 *rRun.fOverrideDescriptor->getDesc()));
475 } else {
joshualitt2f2ee832016-02-10 08:52:24 -0800476 SkASSERT_RELEASE(!rRun.fOverrideDescriptor.get());
joshualitt259fbf12015-07-21 11:39:34 -0700477 }
478
479 // color can be changed
480 //SkASSERT(lRun.fColor == rRun.fColor);
joshualitt2f2ee832016-02-10 08:52:24 -0800481 SkASSERT_RELEASE(lRun.fInitialized == rRun.fInitialized);
482 SkASSERT_RELEASE(lRun.fDrawAsPaths == rRun.fDrawAsPaths);
joshualitt259fbf12015-07-21 11:39:34 -0700483
joshualitt2f2ee832016-02-10 08:52:24 -0800484 SkASSERT_RELEASE(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count());
joshualitt259fbf12015-07-21 11:39:34 -0700485 for(int j = 0; j < lRun.fSubRunInfo.count(); j++) {
486 const Run::SubRunInfo& lSubRun = lRun.fSubRunInfo[j];
487 const Run::SubRunInfo& rSubRun = rRun.fSubRunInfo[j];
488
joshualitt2f2ee832016-02-10 08:52:24 -0800489 // TODO we can do this check, but we have to apply the VM to the old vertex bounds
490 //SkASSERT_RELEASE(lSubRun.vertexBounds() == rSubRun.vertexBounds());
joshualitt259fbf12015-07-21 11:39:34 -0700491
joshualitt2f2ee832016-02-10 08:52:24 -0800492 if (lSubRun.strike()) {
493 SkASSERT_RELEASE(rSubRun.strike());
494 SkASSERT_RELEASE(GrBatchTextStrike::GetKey(*lSubRun.strike()) ==
495 GrBatchTextStrike::GetKey(*rSubRun.strike()));
496
497 } else {
498 SkASSERT_RELEASE(!rSubRun.strike());
499 }
500
501 SkASSERT_RELEASE(lSubRun.vertexStartIndex() == rSubRun.vertexStartIndex());
502 SkASSERT_RELEASE(lSubRun.vertexEndIndex() == rSubRun.vertexEndIndex());
503 SkASSERT_RELEASE(lSubRun.glyphStartIndex() == rSubRun.glyphStartIndex());
504 SkASSERT_RELEASE(lSubRun.glyphEndIndex() == rSubRun.glyphEndIndex());
505 SkASSERT_RELEASE(lSubRun.maskFormat() == rSubRun.maskFormat());
506 SkASSERT_RELEASE(lSubRun.drawAsDistanceFields() == rSubRun.drawAsDistanceFields());
507 SkASSERT_RELEASE(lSubRun.hasUseLCDText() == rSubRun.hasUseLCDText());
joshualitt259fbf12015-07-21 11:39:34 -0700508 }
509 }
510}