Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: src/gpu/GrAtlasTextBlob.cpp

Issue 1521453002: Move all text stuff to its own folder (Closed) Base URL: https://skia.googlesource.com/skia.git@cleanuptext11textutils2
Patch Set: Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/GrAtlasTextBlob.h ('k') | src/gpu/GrAtlasTextContext.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
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
10 #include "GrBlurUtils.h"
11 #include "GrContext.h"
12 #include "GrDrawContext.h"
13 #include "GrTextUtils.h"
14 #include "SkColorFilter.h"
15 #include "SkDrawFilter.h"
16 #include "SkTextBlobRunIterator.h"
17 #include "batches/GrAtlasTextBatch.h"
18
19 void GrAtlasTextBlob::appendGlyph(int runIndex,
20 const SkRect& positions,
21 GrColor color,
22 GrBatchTextStrike* strike,
23 GrGlyph* glyph,
24 GrFontScaler* scaler, const SkGlyph& skGlyph,
25 SkScalar x, SkScalar y, SkScalar scale, bool a pplyVM) {
26
27 // If the glyph is too large we fall back to paths
28 if (glyph->fTooLargeForAtlas) {
29 this->appendLargeGlyph(glyph, scaler, skGlyph, x, y, scale, applyVM);
30 return;
31 }
32
33 Run& run = fRuns[runIndex];
34 GrMaskFormat format = glyph->fMaskFormat;
35
36 Run::SubRunInfo* subRun = &run.fSubRunInfo.back();
37 if (run.fInitialized && subRun->maskFormat() != format) {
38 subRun = &run.push_back();
39 subRun->setStrike(strike);
40 } else if (!run.fInitialized) {
41 subRun->setStrike(strike);
42 }
43
44 run.fInitialized = true;
45
46 size_t vertexStride = GetVertexStride(format);
47
48 subRun->setMaskFormat(format);
49
50 run.fVertexBounds.joinNonEmptyArg(positions);
51 subRun->setColor(color);
52
53 intptr_t vertex = reinterpret_cast<intptr_t>(this->fVertices + subRun->verte xEndIndex());
54
55 if (kARGB_GrMaskFormat != glyph->fMaskFormat) {
56 // V0
57 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
58 position->set(positions.fLeft, positions.fTop);
59 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
60 *colorPtr = color;
61 vertex += vertexStride;
62
63 // V1
64 position = reinterpret_cast<SkPoint*>(vertex);
65 position->set(positions.fLeft, positions.fBottom);
66 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
67 *colorPtr = color;
68 vertex += vertexStride;
69
70 // V2
71 position = reinterpret_cast<SkPoint*>(vertex);
72 position->set(positions.fRight, positions.fBottom);
73 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
74 *colorPtr = color;
75 vertex += vertexStride;
76
77 // V3
78 position = reinterpret_cast<SkPoint*>(vertex);
79 position->set(positions.fRight, positions.fTop);
80 colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
81 *colorPtr = color;
82 } else {
83 // V0
84 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
85 position->set(positions.fLeft, positions.fTop);
86 vertex += vertexStride;
87
88 // V1
89 position = reinterpret_cast<SkPoint*>(vertex);
90 position->set(positions.fLeft, positions.fBottom);
91 vertex += vertexStride;
92
93 // V2
94 position = reinterpret_cast<SkPoint*>(vertex);
95 position->set(positions.fRight, positions.fBottom);
96 vertex += vertexStride;
97
98 // V3
99 position = reinterpret_cast<SkPoint*>(vertex);
100 position->set(positions.fRight, positions.fTop);
101 }
102 subRun->appendVertices(vertexStride);
103 fGlyphs[subRun->glyphEndIndex()] = glyph;
104 subRun->glyphAppended();
105 }
106
107 void GrAtlasTextBlob::appendLargeGlyph(GrGlyph* glyph, GrFontScaler* scaler, con st SkGlyph& skGlyph,
108 SkScalar x, SkScalar y, SkScalar scale, b ool applyVM) {
109 if (nullptr == glyph->fPath) {
110 const SkPath* glyphPath = scaler->getGlyphPath(skGlyph);
111 if (!glyphPath) {
112 return;
113 }
114
115 glyph->fPath = new SkPath(*glyphPath);
116 }
117 fBigGlyphs.push_back(GrAtlasTextBlob::BigGlyph(*glyph->fPath, x, y, scale, a pplyVM));
118 }
119
120 bool GrAtlasTextBlob::mustRegenerate(SkScalar* outTransX, SkScalar* outTransY,
121 const SkPaint& paint,
122 GrColor color, const SkMaskFilter::BlurRec& blurRec,
123 const SkMatrix& viewMatrix, SkScalar x, SkS calar y) {
124 // If we have LCD text then our canonical color will be set to transparent, in this case we have
125 // to regenerate the blob on any color change
126 // We use the grPaint to get any color filter effects
127 if (fKey.fCanonicalColor == SK_ColorTRANSPARENT &&
128 fPaintColor != color) {
129 return true;
130 }
131
132 if (fViewMatrix.hasPerspective() != viewMatrix.hasPerspective()) {
133 return true;
134 }
135
136 if (fViewMatrix.hasPerspective() && !fViewMatrix.cheapEqualTo(viewMatrix)) {
137 return true;
138 }
139
140 // We only cache one masked version
141 if (fKey.fHasBlur &&
142 (fBlurRec.fSigma != blurRec.fSigma ||
143 fBlurRec.fStyle != blurRec.fStyle ||
144 fBlurRec.fQuality != blurRec.fQuality)) {
145 return true;
146 }
147
148 // Similarly, we only cache one version for each style
149 if (fKey.fStyle != SkPaint::kFill_Style &&
150 (fStrokeInfo.fFrameWidth != paint.getStrokeWidth() ||
151 fStrokeInfo.fMiterLimit != paint.getStrokeMiter() ||
152 fStrokeInfo.fJoin != paint.getStrokeJoin())) {
153 return true;
154 }
155
156 // Mixed blobs must be regenerated. We could probably figure out a way to d o integer scrolls
157 // for mixed blobs if this becomes an issue.
158 if (this->hasBitmap() && this->hasDistanceField()) {
159 // Identical viewmatrices and we can reuse in all cases
160 if (fViewMatrix.cheapEqualTo(viewMatrix) && x == fX && y == fY) {
161 return false;
162 }
163 return true;
164 }
165
166 if (this->hasBitmap()) {
167 if (fViewMatrix.getScaleX() != viewMatrix.getScaleX() ||
168 fViewMatrix.getScaleY() != viewMatrix.getScaleY() ||
169 fViewMatrix.getSkewX() != viewMatrix.getSkewX() ||
170 fViewMatrix.getSkewY() != viewMatrix.getSkewY()) {
171 return true;
172 }
173
174 // We can update the positions in the cachedtextblobs without regenerati ng the whole blob,
175 // but only for integer translations.
176 // This cool bit of math will determine the necessary translation to app ly to the already
177 // generated vertex coordinates to move them to the correct position
178 SkScalar transX = viewMatrix.getTranslateX() +
179 viewMatrix.getScaleX() * (x - fX) +
180 viewMatrix.getSkewX() * (y - fY) -
181 fViewMatrix.getTranslateX();
182 SkScalar transY = viewMatrix.getTranslateY() +
183 viewMatrix.getSkewY() * (x - fX) +
184 viewMatrix.getScaleY() * (y - fY) -
185 fViewMatrix.getTranslateY();
186 if (!SkScalarIsInt(transX) || !SkScalarIsInt(transY) ) {
187 return true;
188 }
189
190 (*outTransX) = transX;
191 (*outTransY) = transY;
192 } else if (this->hasDistanceField()) {
193 // A scale outside of [blob.fMaxMinScale, blob.fMinMaxScale] would resul t in a different
194 // distance field being generated, so we have to regenerate in those cas es
195 SkScalar newMaxScale = viewMatrix.getMaxScale();
196 SkScalar oldMaxScale = fViewMatrix.getMaxScale();
197 SkScalar scaleAdjust = newMaxScale / oldMaxScale;
198 if (scaleAdjust < fMaxMinScale || scaleAdjust > fMinMaxScale) {
199 return true;
200 }
201
202 (*outTransX) = x - fX;
203 (*outTransY) = y - fY;
204 }
205
206
207 // If we can reuse the blob, then make sure we update the blob's viewmatrix, and x/y
208 // offsets. Note, we offset the vertex bounds right before flushing
209 fViewMatrix = viewMatrix;
210 fX = x;
211 fY = y;
212
213 // It is possible that a blob has neither distanceField nor bitmaptext. Thi s is in the case
214 // when all of the runs inside the blob are drawn as paths. In this case, w e always regenerate
215 // the blob anyways at flush time, so no need to regenerate explicitly
216 return false;
217 }
218
219 GrDrawBatch* GrAtlasTextBlob::createBatch(const Run::SubRunInfo& info,
220 int glyphCount, int run, int subRun,
221 GrColor color, SkScalar transX, SkScal ar transY,
222 const SkPaint& skPaint, const SkSurfac eProps& props,
223 const GrDistanceFieldAdjustTable* dist anceAdjustTable,
224 GrBatchFontCache* cache) {
225 GrMaskFormat format = info.maskFormat();
226 GrColor subRunColor;
227 if (kARGB_GrMaskFormat == format) {
228 uint8_t paintAlpha = skPaint.getAlpha();
229 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAl pha);
230 } else {
231 subRunColor = color;
232 }
233
234 GrAtlasTextBatch* batch;
235 if (info.drawAsDistanceFields()) {
236 SkColor filteredColor;
237 SkColorFilter* colorFilter = skPaint.getColorFilter();
238 if (colorFilter) {
239 filteredColor = colorFilter->filterColor(skPaint.getColor());
240 } else {
241 filteredColor = skPaint.getColor();
242 }
243 bool useBGR = SkPixelGeometryIsBGR(props.pixelGeometry());
244 batch = GrAtlasTextBatch::CreateDistanceField(glyphCount, cache,
245 distanceAdjustTable, filte redColor,
246 info.hasUseLCDText(), useB GR);
247 } else {
248 batch = GrAtlasTextBatch::CreateBitmap(format, glyphCount, cache);
249 }
250 GrAtlasTextBatch::Geometry& geometry = batch->geometry();
251 geometry.fBlob = SkRef(this);
252 geometry.fRun = run;
253 geometry.fSubRun = subRun;
254 geometry.fColor = subRunColor;
255 geometry.fTransX = transX;
256 geometry.fTransY = transY;
257 batch->init();
258
259 return batch;
260 }
261
262 inline
263 void GrAtlasTextBlob::flushRun(GrDrawContext* dc, GrPipelineBuilder* pipelineBui lder,
264 int run, GrColor color,
265 SkScalar transX, SkScalar transY,
266 const SkPaint& skPaint, const SkSurfaceProps& pro ps,
267 const GrDistanceFieldAdjustTable* distanceAdjustT able,
268 GrBatchFontCache* cache) {
269 for (int subRun = 0; subRun < fRuns[run].fSubRunInfo.count(); subRun++) {
270 const Run::SubRunInfo& info = fRuns[run].fSubRunInfo[subRun];
271 int glyphCount = info.glyphCount();
272 if (0 == glyphCount) {
273 continue;
274 }
275
276 SkAutoTUnref<GrDrawBatch> batch(this->createBatch(info, glyphCount, run,
277 subRun, color, transX, transY,
278 skPaint, props,
279 distanceAdjustTable, c ache));
280 dc->drawBatch(pipelineBuilder, batch);
281 }
282 }
283
284 void GrAtlasTextBlob::flushBigGlyphs(GrContext* context, GrDrawContext* dc,
285 const GrClip& clip, const SkPaint& skPaint,
286 SkScalar transX, SkScalar transY,
287 const SkIRect& clipBounds) {
288 for (int i = 0; i < fBigGlyphs.count(); i++) {
289 GrAtlasTextBlob::BigGlyph& bigGlyph = fBigGlyphs[i];
290 bigGlyph.fVx += transX;
291 bigGlyph.fVy += transY;
292 SkMatrix ctm;
293 ctm.setScale(bigGlyph.fScale, bigGlyph.fScale);
294 ctm.postTranslate(bigGlyph.fVx, bigGlyph.fVy);
295 if (bigGlyph.fApplyVM) {
296 ctm.postConcat(fViewMatrix);
297 }
298
299 GrBlurUtils::drawPathWithMaskFilter(context, dc, clip, bigGlyph.fPath,
300 skPaint, ctm, nullptr, clipBounds, f alse);
301 }
302 }
303
304 void GrAtlasTextBlob::flushRunAsPaths(GrContext* context, GrDrawContext* dc,
305 const SkSurfaceProps& props,
306 const SkTextBlobRunIterator& it,
307 const GrClip& clip, const SkPaint& skPaint ,
308 SkDrawFilter* drawFilter, const SkMatrix& viewMatrix,
309 const SkIRect& clipBounds, SkScalar x, SkS calar y) {
310 SkPaint runPaint = skPaint;
311
312 size_t textLen = it.glyphCount() * sizeof(uint16_t);
313 const SkPoint& offset = it.offset();
314
315 it.applyFontToPaint(&runPaint);
316
317 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Type)) {
318 return;
319 }
320
321 runPaint.setFlags(GrTextContext::FilterTextFlags(props, runPaint));
322
323 switch (it.positioning()) {
324 case SkTextBlob::kDefault_Positioning:
325 GrTextUtils::DrawTextAsPath(context, dc, clip, runPaint, viewMatrix,
326 (const char *)it.glyphs(),
327 textLen, x + offset.x(), y + offset.y(), clipBounds);
328 break;
329 case SkTextBlob::kHorizontal_Positioning:
330 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, v iewMatrix,
331 (const char*)it.glyphs(),
332 textLen, it.pos(), 1, SkPoint::Make(x , y + offset.y()),
333 clipBounds);
334 break;
335 case SkTextBlob::kFull_Positioning:
336 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, runPaint, v iewMatrix,
337 (const char*)it.glyphs(),
338 textLen, it.pos(), 2, SkPoint::Make(x , y), clipBounds);
339 break;
340 }
341 }
342
343 void GrAtlasTextBlob::flushCached(GrContext* context,
344 GrDrawContext* dc,
345 const SkTextBlob* blob,
346 const SkSurfaceProps& props,
347 const GrDistanceFieldAdjustTable* distanceAdju stTable,
348 const SkPaint& skPaint,
349 const GrPaint& grPaint,
350 SkDrawFilter* drawFilter,
351 const GrClip& clip,
352 const SkMatrix& viewMatrix,
353 const SkIRect& clipBounds,
354 SkScalar x, SkScalar y,
355 SkScalar transX, SkScalar transY) {
356 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush
357 // it as paths
358 GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip);
359
360 GrColor color = grPaint.getColor();
361
362 SkTextBlobRunIterator it(blob);
363 for (int run = 0; !it.done(); it.next(), run++) {
364 if (fRuns[run].fDrawAsPaths) {
365 this->flushRunAsPaths(context, dc, props, it, clip, skPaint,
366 drawFilter, viewMatrix, clipBounds, x, y);
367 continue;
368 }
369 fRuns[run].fVertexBounds.offset(transX, transY);
370 this->flushRun(dc, &pipelineBuilder, run, color,
371 transX, transY, skPaint, props,
372 distanceAdjustTable, context->getBatchFontCache());
373 }
374
375 // Now flush big glyphs
376 this->flushBigGlyphs(context, dc, clip, skPaint, transX, transY, clipBounds) ;
377 }
378
379 void GrAtlasTextBlob::flushThrowaway(GrContext* context,
380 GrDrawContext* dc,
381 const SkSurfaceProps& props,
382 const GrDistanceFieldAdjustTable* distanceA djustTable,
383 const SkPaint& skPaint,
384 const GrPaint& grPaint,
385 const GrClip& clip,
386 const SkIRect& clipBounds) {
387 GrPipelineBuilder pipelineBuilder(grPaint, dc->accessRenderTarget(), clip);
388
389 GrColor color = grPaint.getColor();
390 for (int run = 0; run < fRunCount; run++) {
391 this->flushRun(dc, &pipelineBuilder, run, color, 0, 0, skPaint, props,
392 distanceAdjustTable, context->getBatchFontCache());
393 }
394
395 // Now flush big glyphs
396 this->flushBigGlyphs(context, dc, clip, skPaint, 0, 0, clipBounds);
397 }
398
399
400 // TODO get this code building again
401 #ifdef CACHE_SANITY_CHECK
402 void GrAtlasTextBlob::AssertEqual(const GrAtlasTextBlob& l, const GrAtlasTextBlo b& r) {
403 SkASSERT(l.fSize == r.fSize);
404 SkASSERT(l.fPool == r.fPool);
405
406 SkASSERT(l.fBlurRec.fSigma == r.fBlurRec.fSigma);
407 SkASSERT(l.fBlurRec.fStyle == r.fBlurRec.fStyle);
408 SkASSERT(l.fBlurRec.fQuality == r.fBlurRec.fQuality);
409
410 SkASSERT(l.fStrokeInfo.fFrameWidth == r.fStrokeInfo.fFrameWidth);
411 SkASSERT(l.fStrokeInfo.fMiterLimit == r.fStrokeInfo.fMiterLimit);
412 SkASSERT(l.fStrokeInfo.fJoin == r.fStrokeInfo.fJoin);
413
414 SkASSERT(l.fBigGlyphs.count() == r.fBigGlyphs.count());
415 for (int i = 0; i < l.fBigGlyphs.count(); i++) {
416 const BigGlyph& lBigGlyph = l.fBigGlyphs[i];
417 const BigGlyph& rBigGlyph = r.fBigGlyphs[i];
418
419 SkASSERT(lBigGlyph.fPath == rBigGlyph.fPath);
420 // We can't assert that these have the same translations
421 }
422
423 SkASSERT(l.fKey == r.fKey);
424 SkASSERT(l.fViewMatrix.cheapEqualTo(r.fViewMatrix));
425 SkASSERT(l.fPaintColor == r.fPaintColor);
426 SkASSERT(l.fMaxMinScale == r.fMaxMinScale);
427 SkASSERT(l.fMinMaxScale == r.fMinMaxScale);
428 SkASSERT(l.fTextType == r.fTextType);
429
430 SkASSERT(l.fRunCount == r.fRunCount);
431 for (int i = 0; i < l.fRunCount; i++) {
432 const Run& lRun = l.fRuns[i];
433 const Run& rRun = r.fRuns[i];
434
435 if (lRun.fStrike.get()) {
436 SkASSERT(rRun.fStrike.get());
437 SkASSERT(GrBatchTextStrike::GetKey(*lRun.fStrike) ==
438 GrBatchTextStrike::GetKey(*rRun.fStrike));
439
440 } else {
441 SkASSERT(!rRun.fStrike.get());
442 }
443
444 if (lRun.fTypeface.get()) {
445 SkASSERT(rRun.fTypeface.get());
446 SkASSERT(SkTypeface::Equal(lRun.fTypeface, rRun.fTypeface));
447 } else {
448 SkASSERT(!rRun.fTypeface.get());
449 }
450
451 // We offset bounds right before flush time so they will not be correct here
452 //SkASSERT(lRun.fVertexBounds == rRun.fVertexBounds);
453
454 SkASSERT(lRun.fDescriptor.getDesc());
455 SkASSERT(rRun.fDescriptor.getDesc());
456 SkASSERT(lRun.fDescriptor.getDesc()->equals(*rRun.fDescriptor.getDesc()) );
457
458 if (lRun.fOverrideDescriptor.get()) {
459 SkASSERT(lRun.fOverrideDescriptor->getDesc());
460 SkASSERT(rRun.fOverrideDescriptor.get() && rRun.fOverrideDescriptor- >getDesc());;
461 SkASSERT(lRun.fOverrideDescriptor->getDesc()->equals(
462 *rRun.fOverrideDescriptor->getDesc()));
463 } else {
464 SkASSERT(!rRun.fOverrideDescriptor.get());
465 }
466
467 // color can be changed
468 //SkASSERT(lRun.fColor == rRun.fColor);
469 SkASSERT(lRun.fInitialized == rRun.fInitialized);
470 SkASSERT(lRun.fDrawAsPaths == rRun.fDrawAsPaths);
471
472 SkASSERT(lRun.fSubRunInfo.count() == rRun.fSubRunInfo.count());
473 for(int j = 0; j < lRun.fSubRunInfo.count(); j++) {
474 const Run::SubRunInfo& lSubRun = lRun.fSubRunInfo[j];
475 const Run::SubRunInfo& rSubRun = rRun.fSubRunInfo[j];
476
477 SkASSERT(lSubRun.fVertexStartIndex == rSubRun.fVertexStartIndex);
478 SkASSERT(lSubRun.fVertexEndIndex == rSubRun.fVertexEndIndex);
479 SkASSERT(lSubRun.fGlyphStartIndex == rSubRun.fGlyphStartIndex);
480 SkASSERT(lSubRun.fGlyphEndIndex == rSubRun.fGlyphEndIndex);
481 SkASSERT(lSubRun.fTextRatio == rSubRun.fTextRatio);
482 SkASSERT(lSubRun.fMaskFormat == rSubRun.fMaskFormat);
483 SkASSERT(lSubRun.fDrawAsDistanceFields == rSubRun.fDrawAsDistanceFie lds);
484 SkASSERT(lSubRun.fUseLCDText == rSubRun.fUseLCDText);
485
486 //We can't compare the bulk use tokens with this method
487 /*
488 SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate.count() ==
489 rSubRun.fBulkUseToken.fPlotsToUpdate.count());
490 SkASSERT(lSubRun.fBulkUseToken.fPlotAlreadyUpdated ==
491 rSubRun.fBulkUseToken.fPlotAlreadyUpdated);
492 for (int k = 0; k < lSubRun.fBulkUseToken.fPlotsToUpdate.count(); k+ +) {
493 SkASSERT(lSubRun.fBulkUseToken.fPlotsToUpdate[k] ==
494 rSubRun.fBulkUseToken.fPlotsToUpdate[k]);
495 }*/
496 }
497 }
498 }
499
500 #endif
OLDNEW
« no previous file with comments | « src/gpu/GrAtlasTextBlob.h ('k') | src/gpu/GrAtlasTextContext.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698