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

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

Issue 1082843002: Initial CL to add distance field support to GrAtlasTextContext (Closed) Base URL: https://skia.googlesource.com/skia.git@attryst2
Patch Set: rebase Created 5 years, 8 months 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
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 #include "GrAtlasTextContext.h" 7 #include "GrAtlasTextContext.h"
8 8
9 #include "GrAtlas.h" 9 #include "GrAtlas.h"
10 #include "GrBatch.h" 10 #include "GrBatch.h"
11 #include "GrBatchFontCache.h" 11 #include "GrBatchFontCache.h"
12 #include "GrBatchTarget.h" 12 #include "GrBatchTarget.h"
13 #include "GrDefaultGeoProcFactory.h" 13 #include "GrDefaultGeoProcFactory.h"
14 #include "GrDrawTarget.h" 14 #include "GrDrawTarget.h"
15 #include "GrFontScaler.h" 15 #include "GrFontScaler.h"
16 #include "GrIndexBuffer.h" 16 #include "GrIndexBuffer.h"
17 #include "GrStrokeInfo.h" 17 #include "GrStrokeInfo.h"
18 #include "GrTextBlobCache.h" 18 #include "GrTextBlobCache.h"
19 #include "GrTexturePriv.h" 19 #include "GrTexturePriv.h"
20 20
21 #include "SkAutoKern.h" 21 #include "SkAutoKern.h"
22 #include "SkColorPriv.h" 22 #include "SkColorPriv.h"
23 #include "SkColorFilter.h"
24 #include "SkDistanceFieldGen.h"
23 #include "SkDraw.h" 25 #include "SkDraw.h"
24 #include "SkDrawFilter.h" 26 #include "SkDrawFilter.h"
25 #include "SkDrawProcs.h" 27 #include "SkDrawProcs.h"
26 #include "SkGlyphCache.h" 28 #include "SkGlyphCache.h"
27 #include "SkGpuDevice.h" 29 #include "SkGpuDevice.h"
28 #include "SkGr.h" 30 #include "SkGr.h"
29 #include "SkPath.h" 31 #include "SkPath.h"
30 #include "SkRTConf.h" 32 #include "SkRTConf.h"
31 #include "SkStrokeRec.h" 33 #include "SkStrokeRec.h"
32 #include "SkTextBlob.h" 34 #include "SkTextBlob.h"
33 #include "SkTextMapStateProc.h" 35 #include "SkTextMapStateProc.h"
34 36
35 #include "effects/GrBitmapTextGeoProc.h" 37 #include "effects/GrBitmapTextGeoProc.h"
36 #include "effects/GrSimpleTextureEffect.h" 38 #include "effects/GrDistanceFieldGeoProc.h"
37 39
38 namespace { 40 namespace {
39 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 41 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
40 42
41 // position + local coord 43 // position + local coord
42 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 44 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
43 45
44 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16); 46 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16);
45 47
48 static const int kMinDFFontSize = 18;
49 static const int kSmallDFFontSize = 32;
50 static const int kSmallDFFontLimit = 32;
51 static const int kMediumDFFontSize = 72;
52 static const int kMediumDFFontLimit = 72;
53 static const int kLargeDFFontSize = 162;
54
55 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;)
56 static const int kDistanceAdjustLumShift = 5;
57
46 static const int kVerticesPerGlyph = 4; 58 static const int kVerticesPerGlyph = 4;
47 static const int kIndicesPerGlyph = 6; 59 static const int kIndicesPerGlyph = 6;
48 60
49 static size_t get_vertex_stride(GrMaskFormat maskFormat) { 61 static size_t get_vertex_stride(GrMaskFormat maskFormat) {
50 switch (maskFormat) { 62 switch (maskFormat) {
51 case kA8_GrMaskFormat: 63 case kA8_GrMaskFormat:
52 return kGrayTextVASize; 64 return kGrayTextVASize;
53 case kARGB_GrMaskFormat: 65 case kARGB_GrMaskFormat:
54 return kColorTextVASize; 66 return kColorTextVASize;
55 default: 67 default:
56 return kLCDTextVASize; 68 return kLCDTextVASize;
57 } 69 }
58 } 70 }
59 71
72 static size_t get_vertex_stride_df(GrMaskFormat maskFormat, bool useLCDText) {
73 SkASSERT(maskFormat == kA8_GrMaskFormat);
74 if (useLCDText) {
75 return kLCDTextVASize;
76 } else {
77 return kGrayTextVASize;
78 }
79 }
80
81 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
82 unsigned r = SkColorGetR(c);
83 unsigned g = SkColorGetG(c);
84 unsigned b = SkColorGetB(c);
85 return GrColorPackRGBA(r, g, b, 0xff);
86 }
87
60 }; 88 };
61 89
62 // TODO 90 // TODO
63 // Gamma slotting to preserve color 91 // Distance field text in textblobs
64 // Better reuse on regeneration
65 // Telemetry tests
66 // possibly consider having a regeneration ratio on the textblob itself for anim ated textblobs
67 92
68 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, 93 GrAtlasTextContext::GrAtlasTextContext(GrContext* context,
69 SkGpuDevice* gpuDevice, 94 SkGpuDevice* gpuDevice,
70 const SkDeviceProperties& properties) 95 const SkDeviceProperties& properties,
71 : INHERITED(context, gpuDevice, properties) { 96 bool enableDistanceFields)
97 : INHERITED(context, gpuDevice, properties)
98 , fDistanceAdjustTable(SkNEW_ARGS(DistanceAdjustTable, (properties.gamma())) ) {
72 // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest 99 // We overallocate vertices in our textblobs based on the assumption that A8 has the greatest
73 // vertexStride 100 // vertexStride
74 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize, 101 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
75 vertex_attribute_changed); 102 vertex_attribute_changed);
76 fCurrStrike = NULL; 103 fCurrStrike = NULL;
77 fCache = context->getTextBlobCache(); 104 fCache = context->getTextBlobCache();
105
106 #if SK_FORCE_DISTANCE_FIELD_TEXT
107 fEnableDFRendering = true;
108 #else
109 fEnableDFRendering = enableDistanceFields;
110 #endif
111 }
112
113 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable(float gam ma) {
114
115 // This is used for an approximation of the mask gamma hack, used by raster and bitmap
116 // text. The mask gamma hack is based off of guessing what the blend color i s going to
117 // be, and adjusting the mask so that when run through the linear blend will
118 // produce the value closest to the desired result. However, in practice thi s means
119 // that the 'adjusted' mask is just increasing or decreasing the coverage of
120 // the mask depending on what it is thought it will blit against. For black (on
121 // assumed white) this means that coverages are decreased (on a curve). For white (on
122 // assumed black) this means that coverages are increased (on a a curve). At
123 // middle (perceptual) gray (which could be blit against anything) the cover ages
124 // remain the same.
125 //
126 // The idea here is that instead of determining the initial (real) coverage and
127 // then adjusting that coverage, we determine an adjusted coverage directly by
128 // essentially manipulating the geometry (in this case, the distance to the glyph
129 // edge). So for black (on assumed white) this thins a bit; for white (on
130 // assumed black) this fake bolds the geometry a bit.
131 //
132 // The distance adjustment is calculated by determining the actual coverage value which
133 // when fed into in the mask gamma table gives us an 'adjusted coverage' val ue of 0.5. This
134 // actual coverage value (assuming it's between 0 and 1) corresponds to a di stance from the
135 // actual edge. So by subtracting this distance adjustment and computing wit hout the
136 // the coverage adjustment we should get 0.5 coverage at the same point.
137 //
138 // This has several implications:
139 // For non-gray lcd smoothed text, each subpixel essentially is using a
140 // slightly different geometry.
141 //
142 // For black (on assumed white) this may not cover some pixels which wer e
143 // previously covered; however those pixels would have been only slightl y
144 // covered and that slight coverage would have been decreased anyway. Al so, some pixels
145 // which were previously fully covered may no longer be fully covered.
146 //
147 // For white (on assumed black) this may cover some pixels which weren't
148 // previously covered at all.
149
150 int width, height;
151 size_t size;
152
153 #ifdef SK_GAMMA_CONTRAST
154 SkScalar contrast = SK_GAMMA_CONTRAST;
155 #else
156 SkScalar contrast = 0.5f;
157 #endif
158 SkScalar paintGamma = gamma;
159 SkScalar deviceGamma = gamma;
160
161 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
162 &width, &height);
163
164 SkASSERT(kExpectedDistanceAdjustTableSize == height);
165 fTable = SkNEW_ARRAY(SkScalar, height);
166
167 SkAutoTArray<uint8_t> data((int)size);
168 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get ());
169
170 // find the inverse points where we cross 0.5
171 // binsearch might be better, but we only need to do this once on creation
172 for (int row = 0; row < height; ++row) {
173 uint8_t* rowPtr = data.get() + row*width;
174 for (int col = 0; col < width - 1; ++col) {
175 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) {
176 // compute point where a mask value will give us a result of 0.5
177 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt r[col]);
178 float borderAlpha = (col + interp) / 255.f;
179
180 // compute t value for that alpha
181 // this is an approximate inverse for smoothstep()
182 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5 .0f) / 3.0f;
183
184 // compute distance which gives us that t value
185 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D istanceFieldAAFactor
186 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor ;
187
188 fTable[row] = d;
189 break;
190 }
191 }
192 }
78 } 193 }
79 194
80 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, 195 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context,
81 SkGpuDevice* gpuDevice, 196 SkGpuDevice* gpuDevice,
82 const SkDeviceProperties& props) { 197 const SkDeviceProperties& props,
83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); 198 bool enableDistanceFields) {
199 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props, enableDist anceFields));
84 } 200 }
85 201
86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, 202 bool GrAtlasTextContext::canDraw(const GrRenderTarget*,
87 const GrClip&, 203 const GrClip&,
88 const GrPaint&, 204 const GrPaint&,
89 const SkPaint& skPaint, 205 const SkPaint& skPaint,
90 const SkMatrix& viewMatrix) { 206 const SkMatrix& viewMatrix) {
91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); 207 return this->canDrawAsDistanceFields(skPaint, viewMatrix) ||
208 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix);
92 } 209 }
93 210
94 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd ) { 211 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd ) {
95 GrColor canonicalColor = paint.computeLuminanceColor(); 212 GrColor canonicalColor = paint.computeLuminanceColor();
96 if (lcd) { 213 if (lcd) {
97 // This is the correct computation, but there are tons of cases where LC D can be overridden. 214 // This is the correct computation, but there are tons of cases where LC D can be overridden.
98 // For now we just regenerate if any run in a textblob has LCD. 215 // For now we just regenerate if any run in a textblob has LCD.
99 // TODO figure out where all of these overrides are and see if we can in corporate that logic 216 // TODO figure out where all of these overrides are and see if we can in corporate that logic
100 // at a higher level *OR* use sRGB 217 // at a higher level *OR* use sRGB
101 SkASSERT(false); 218 SkASSERT(false);
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 } 313 }
197 #endif 314 #endif
198 (*outTransX) = transX; 315 (*outTransX) = transX;
199 (*outTransY) = transY; 316 (*outTransY) = transY;
200 return false; 317 return false;
201 } 318 }
202 319
203 320
204 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, 321 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run,
205 const SkPaint& skPaint, 322 const SkPaint& skPaint,
206 const SkMatrix& viewMatrix) { 323 const SkMatrix* viewMatrix,
207 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false); 324 bool noGamma) {
325 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, vi ewMatrix, noGamma);
208 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); 326 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
209 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ; 327 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ;
210 } 328 }
211 329
212 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, 330 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
213 const SkPaint& skPaint, const SkMatrix& vi ewMatrix, 331 const SkPaint& skPaint, const SkMatrix& vi ewMatrix,
214 const SkTextBlob* blob, SkScalar x, SkScal ar y, 332 const SkTextBlob* blob, SkScalar x, SkScal ar y,
215 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) { 333 SkDrawFilter* drawFilter, const SkIRect& c lipBounds) {
216 SkAutoTUnref<BitmapTextBlob> cacheBlob; 334 SkAutoTUnref<BitmapTextBlob> cacheBlob;
217 SkMaskFilter::BlurRec blurRec; 335 SkMaskFilter::BlurRec blurRec;
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
276 } 394 }
277 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat rix, blob, x, y, 395 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat rix, blob, x, y,
278 drawFilter, clipRect); 396 drawFilter, clipRect);
279 } 397 }
280 398
281 cacheBlob->fPaintColor = skPaint.getColor(); 399 cacheBlob->fPaintColor = skPaint.getColor();
282 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, 400 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter,
283 clip, viewMatrix, clipBounds, x, y, transX, transY); 401 clip, viewMatrix, clipBounds, x, y, transX, transY);
284 } 402 }
285 403
404 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint,
405 const SkMatrix& viewMatr ix) {
406 // TODO: support perspective (need getMaxScale replacement)
407 if (viewMatrix.hasPerspective()) {
408 return false;
409 }
410
411 SkScalar maxScale = viewMatrix.getMaxScale();
412 SkScalar scaledTextSize = maxScale*skPaint.getTextSize();
413 // Hinted text looks far better at small resolutions
414 // Scaling up beyond 2x yields undesireable artifacts
415 if (scaledTextSize < kMinDFFontSize || scaledTextSize > 2 * kLargeDFFontSize ) {
416 return false;
417 }
418
419 if (!fEnableDFRendering && !skPaint.isDistanceFieldTextTEMP() &&
420 scaledTextSize < kLargeDFFontSize) {
421 return false;
422 }
423
424 // rasterizers and mask filters modify alpha, which doesn't
425 // translate well to distance
426 if (skPaint.getRasterizer() || skPaint.getMaskFilter() ||
427 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
428 return false;
429 }
430
431 // TODO: add some stroking support
432 if (skPaint.getStyle() != SkPaint::kFill_Style) {
433 return false;
434 }
435
436 return true;
437 }
438
286 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, 439 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
287 const SkPaint& skPaint, GrColor colo r, 440 const SkPaint& skPaint, GrColor colo r,
288 const SkMatrix& viewMatrix, 441 const SkMatrix& viewMatrix,
289 const SkTextBlob* blob, SkScalar x, SkScalar y, 442 const SkTextBlob* blob, SkScalar x, SkScalar y,
290 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { 443 SkDrawFilter* drawFilter, const SkIR ect& clipRect) {
291 cacheBlob->fViewMatrix = viewMatrix; 444 cacheBlob->fViewMatrix = viewMatrix;
292 cacheBlob->fX = x; 445 cacheBlob->fX = x;
293 cacheBlob->fY = y; 446 cacheBlob->fY = y;
294 447
295 // Regenerate textblob 448 // Regenerate textblob
296 SkPaint runPaint = skPaint; 449 SkPaint runPaint = skPaint;
297 SkTextBlob::RunIterator it(blob); 450 SkTextBlob::RunIterator it(blob);
298 for (int run = 0; !it.done(); it.next(), run++) { 451 for (int run = 0; !it.done(); it.next(), run++) {
299 int glyphCount = it.glyphCount(); 452 int glyphCount = it.glyphCount();
300 size_t textLen = glyphCount * sizeof(uint16_t); 453 size_t textLen = glyphCount * sizeof(uint16_t);
301 const SkPoint& offset = it.offset(); 454 const SkPoint& offset = it.offset();
302 // applyFontToPaint() always overwrites the exact same attributes, 455 // applyFontToPaint() always overwrites the exact same attributes,
303 // so it is safe to not re-seed the paint for this reason. 456 // so it is safe to not re-seed the paint for this reason.
304 it.applyFontToPaint(&runPaint); 457 it.applyFontToPaint(&runPaint);
305 458
306 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) { 459 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) {
307 // A false return from filter() means we should abort the current dr aw. 460 // A false return from filter() means we should abort the current dr aw.
308 runPaint = skPaint; 461 runPaint = skPaint;
309 continue; 462 continue;
310 } 463 }
311 464
312 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); 465 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
313 466
314 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix); 467 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, &viewMatrix,
468 false);
315 469
316 // setup vertex / glyphIndex for the new run 470 // setup vertex / glyphIndex for the new run
317 if (run > 0) { 471 if (run > 0) {
318 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); 472 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back();
319 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); 473 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( );
320 474
321 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; 475 newRun.fVertexStartIndex = lastRun.fVertexEndIndex;
322 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; 476 newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
323 477
324 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; 478 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
325 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; 479 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
326 } 480 }
327 481
328 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { 482 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
329 cacheBlob->fRuns[run].fDrawAsPaths = true; 483 cacheBlob->fRuns[run].fDrawAsPaths = true;
330 continue; 484 continue;
331 } 485 }
332 cacheBlob->fRuns[run].fDrawAsPaths = false; 486 cacheBlob->fRuns[run].fDrawAsPaths = false;
333 487
334 switch (it.positioning()) { 488 switch (it.positioning()) {
335 case SkTextBlob::kDefault_Positioning: 489 case SkTextBlob::kDefault_Positioning:
336 this->internalDrawText(cacheBlob, run, cache, runPaint, color, v iewMatrix, 490 this->internalDrawBmpText(cacheBlob, run, cache, runPaint, color , viewMatrix,
337 (const char *)it.glyphs(), textLen, 491 (const char *)it.glyphs(), textLen,
338 x + offset.x(), y + offset.y(), clipRect) ; 492 x + offset.x(), y + offset.y(), clipRe ct);
339 break; 493 break;
340 case SkTextBlob::kHorizontal_Positioning: 494 case SkTextBlob::kHorizontal_Positioning:
341 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color , viewMatrix, 495 this->internalDrawBmpPosText(cacheBlob, run, cache, runPaint, co lor, viewMatrix,
342 (const char*)it.glyphs(), textLen, it. pos(), 1, 496 (const char*)it.glyphs(), textLen, it.pos(), 1,
343 SkPoint::Make(x, y + offset.y()), clip Rect); 497 SkPoint::Make(x, y + offset.y()), c lipRect);
344 break; 498 break;
345 case SkTextBlob::kFull_Positioning: 499 case SkTextBlob::kFull_Positioning:
346 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color , viewMatrix, 500 this->internalDrawBmpPosText(cacheBlob, run, cache, runPaint, co lor, viewMatrix,
347 (const char*)it.glyphs(), textLen, it. pos(), 2, 501 (const char*)it.glyphs(), textLen, it.pos(), 2,
348 SkPoint::Make(x, y), clipRect); 502 SkPoint::Make(x, y), clipRect);
349 break; 503 break;
350 } 504 }
351 505
352 if (drawFilter) { 506 if (drawFilter) {
353 // A draw filter may change the paint arbitrarily, so we must re-see d in this case. 507 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
354 runPaint = skPaint; 508 runPaint = skPaint;
355 } 509 }
356 510
357 SkGlyphCache::AttachCache(cache); 511 SkGlyphCache::AttachCache(cache);
358 } 512 }
359 } 513 }
360 514
515 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala r* textRatio,
516 const SkMatrix& viewMatri x) {
517 // getMaxScale doesn't support perspective, so neither do we at the moment
518 SkASSERT(!viewMatrix.hasPerspective());
519 SkScalar maxScale = viewMatrix.getMaxScale();
520 SkScalar textSize = skPaint->getTextSize();
521 SkScalar scaledTextSize = textSize;
522 // if we have non-unity scale, we need to choose our base text size
523 // based on the SkPaint's text size multiplied by the max scale factor
524 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
525 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
526 scaledTextSize *= maxScale;
527 }
528
529 if (scaledTextSize <= kSmallDFFontLimit) {
530 *textRatio = textSize / kSmallDFFontSize;
531 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
532 } else if (scaledTextSize <= kMediumDFFontLimit) {
533 *textRatio = textSize / kMediumDFFontSize;
534 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
535 } else {
536 *textRatio = textSize / kLargeDFFontSize;
537 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
538 }
539
540 skPaint->setLCDRenderText(false);
541 skPaint->setAutohinted(false);
542 skPaint->setHinting(SkPaint::kNormal_Hinting);
543 skPaint->setSubpixelText(true);
544 }
545
546 inline void GrAtlasTextContext::fallbackDrawPosText(GrRenderTarget* rt, const Gr Clip& clip,
547 const GrPaint& paint,
548 const SkPaint& skPaint,
549 const SkMatrix& viewMatrix,
550 const SkTArray<char>& fallba ckTxt,
551 const SkTArray<SkScalar>& fa llbackPos,
552 int scalarsPerPosition,
553 const SkPoint& offset,
554 const SkIRect& clipRect) {
555 size_t glyphCount = fallbackTxt.count();
556 if (glyphCount) {
557 // TODO currently we have to create a whole new blob for fallback text. This is because
558 // they have a different descriptor and we currently only have one descr iptor per run.
559 // We should fix this and allow an override descriptor on each subrun
560 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra yTextVASize));
561 blob->fViewMatrix = viewMatrix;
562
563 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa trix, false);
564 this->internalDrawBmpPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix,
565 fallbackTxt.begin(), fallbackTxt.count(),
566 fallbackPos.begin(), scalarsPerPosition, of fset, clipRect);
567 SkGlyphCache::AttachCache(cache);
568 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
569 }
570 }
571
572 inline GrAtlasTextContext::BitmapTextBlob*
573 GrAtlasTextContext::setupDfBlob(size_t glyphCount, const SkPaint& origPaint,
574 const SkMatrix& viewMatrix, SkGlyphCache** cache ,
575 SkPaint* dfPaint, SkScalar* textRatio) {
576 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
577
578 *dfPaint = origPaint;
579 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix);
580 blob->fViewMatrix = viewMatrix;
581 blob->fRuns[0].fSubRunInfo.back().fUseLCDText = origPaint.isLCDRenderText();
582 blob->fRuns[0].fSubRunInfo.back().fDrawAsDistanceFields = true;
583
584 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true);
585 return blob;
586 }
587
361 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, 588 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
362 const GrPaint& paint, const SkPaint& skPaint , 589 const GrPaint& paint, const SkPaint& skPaint ,
363 const SkMatrix& viewMatrix, 590 const SkMatrix& viewMatrix,
364 const char text[], size_t byteLength, 591 const char text[], size_t byteLength,
365 SkScalar x, SkScalar y, const SkIRect& regio nClipBounds) { 592 SkScalar x, SkScalar y, const SkIRect& regio nClipBounds) {
366 int glyphCount = skPaint.countText(text, byteLength); 593 int glyphCount = skPaint.countText(text, byteLength);
367 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex tVASize)); 594 SkIRect clipRect;
368 blob->fViewMatrix = viewMatrix; 595 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
369 blob->fX = x; 596
370 blob->fY = y; 597 // setup cache
598 if (canDrawAsDistanceFields(skPaint, viewMatrix)) {
bsalomon 2015/04/16 15:03:55 this->
joshualitt 2015/04/16 15:36:11 Acknowledged.
599 SkPaint dfPaint;
600 SkMatrix dfViewMatrix;
jvanverth1 2015/04/16 15:19:22 Where is dfViewMatrix set?
joshualitt 2015/04/16 15:36:11 I guess df doesn't use the viewmatrix anymore with
601 SkScalar textRatio;
602 SkGlyphCache* cache;
603 SkAutoTUnref<BitmapTextBlob> blob(this->setupDfBlob(glyphCount, skPaint, viewMatrix, &cache,
604 &dfPaint, &textRatio ));
605
606 SkTArray<char> fallbackTxt;
bsalomon 2015/04/16 15:03:55 I believe that when using POD and no prealloc SkTD
joshualitt 2015/04/16 15:36:12 Acknowledged.
607 SkTArray<SkScalar> fallbackPos;
608 SkPoint offset;
609 this->internalDrawDfText(blob, 0, cache, dfPaint, paint.getColor(), dfVi ewMatrix, text,
610 byteLength, x, y, clipRect, textRatio, &fallbac kTxt, &fallbackPos,
611 &offset, skPaint);
612 SkGlyphCache::AttachCache(cache);
613 this->flush(fContext->getTextTarget(), blob, rt, dfPaint, paint, clip);
614 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fallback Txt, fallbackPos,
bsalomon 2015/04/16 15:03:55 Wonder if it is worth checking for empty outside o
joshualitt 2015/04/16 15:36:12 Acknowledged.
615 2, offset, clipRect);
616 } else {
617 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra yTextVASize));
618 blob->fViewMatrix = viewMatrix;
619
620 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa trix, false);
621 this->internalDrawBmpText(blob, 0, cache, skPaint, paint.getColor(), vie wMatrix, text,
622 byteLength, x, y, clipRect);
623 SkGlyphCache::AttachCache(cache);
624 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
625 }
626 }
627
628 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
629 const GrPaint& paint, const SkPaint& skPa int,
630 const SkMatrix& viewMatrix,
631 const char text[], size_t byteLength,
632 const SkScalar pos[], int scalarsPerPosit ion,
633 const SkPoint& offset, const SkIRect& reg ionClipBounds) {
634 int glyphCount = skPaint.countText(text, byteLength);
371 635
372 SkIRect clipRect; 636 SkIRect clipRect;
373 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); 637 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
374 638
375 // setup cache 639 if (canDrawAsDistanceFields(skPaint, viewMatrix)) {
bsalomon 2015/04/16 15:03:55 this->
joshualitt 2015/04/16 15:36:11 Acknowledged.
376 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ; 640 SkPaint dfPaint;
377 this->internalDrawText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix , text, byteLength, 641 SkMatrix dfViewMatrix;
jvanverth1 2015/04/16 15:26:54 Again, dfViewMatrix is used without being (to my e
joshualitt 2015/04/16 15:36:12 Acknowledged.
378 x, y, clipRect); 642 SkScalar textRatio;
379 SkGlyphCache::AttachCache(cache); 643 SkGlyphCache* cache;
644 SkAutoTUnref<BitmapTextBlob> blob(this->setupDfBlob(glyphCount, skPaint, viewMatrix, &cache,
jvanverth1 2015/04/16 15:19:22 It seems odd that setupDfBlob creates a BitmapText
joshualitt 2015/04/16 15:36:11 I'll rename the blob after I've landed all of my d
645 &dfPaint, &textRatio ));
380 646
381 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM atrix); 647 SkTArray<char> fallbackTxt;
648 SkTArray<SkScalar> fallbackPos;
649 this->internalDrawDfPosText(blob, 0, cache, dfPaint, paint.getColor(), d fViewMatrix, text,
650 byteLength, pos, scalarsPerPosition, offset, clipRect,
651 textRatio, &fallbackTxt, &fallbackPos);
652 SkGlyphCache::AttachCache(cache);
653 this->flush(fContext->getTextTarget(), blob, rt, dfPaint, paint, clip);
654 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fallback Txt, fallbackPos,
bsalomon 2015/04/16 15:03:55 same Q as above
joshualitt 2015/04/16 15:36:11 Acknowledged.
655 scalarsPerPosition, offset, clipRect);
656 } else {
657 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra yTextVASize));
658 blob->fViewMatrix = viewMatrix;
659 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa trix, false);
660 this->internalDrawBmpPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text,
661 byteLength, pos, scalarsPerPosition, offset , clipRect);
662 SkGlyphCache::AttachCache(cache);
663 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
664 }
382 } 665 }
383 666
384 void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, 667 void GrAtlasTextContext::internalDrawBmpText(BitmapTextBlob* blob, int runIndex,
385 SkGlyphCache* cache, const SkPaint& sk Paint, 668 SkGlyphCache* cache, const SkPaint& skPaint,
386 GrColor color, 669 GrColor color,
387 const SkMatrix& viewMatrix, 670 const SkMatrix& viewMatrix,
388 const char text[], size_t byteLength, 671 const char text[], size_t byteLengt h,
389 SkScalar x, SkScalar y, const SkIRect& clipRect) { 672 SkScalar x, SkScalar y, const SkIRe ct& clipRect) {
390 SkASSERT(byteLength == 0 || text != NULL); 673 SkASSERT(byteLength == 0 || text != NULL);
391 674
392 // nothing to draw 675 // nothing to draw
393 if (text == NULL || byteLength == 0) { 676 if (text == NULL || byteLength == 0) {
394 return; 677 return;
395 } 678 }
396 679
397 fCurrStrike = NULL; 680 fCurrStrike = NULL;
398 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); 681 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
399 682
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 730
448 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); 731 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
449 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); 732 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
450 733
451 while (text < stop) { 734 while (text < stop) {
452 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask); 735 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask);
453 736
454 fx += autokern.adjust(glyph); 737 fx += autokern.adjust(glyph);
455 738
456 if (glyph.fWidth) { 739 if (glyph.fWidth) {
457 this->appendGlyph(blob, 740 this->bmpAppendGlyph(blob,
458 runIndex, 741 runIndex,
459 GrGlyph::Pack(glyph.getGlyphID(), 742 GrGlyph::Pack(glyph.getGlyphID(),
460 glyph.getSubXFixed(), 743 glyph.getSubXFixed(),
461 glyph.getSubYFixed(), 744 glyph.getSubYFixed(),
462 GrGlyph::kCoverage_MaskStyle), 745 GrGlyph::kCoverage_MaskStyle),
463 Sk48Dot16FloorToInt(fx), 746 Sk48Dot16FloorToInt(fx),
464 Sk48Dot16FloorToInt(fy), 747 Sk48Dot16FloorToInt(fy),
465 color, 748 color,
466 fontScaler, 749 fontScaler,
467 clipRect); 750 clipRect);
468 } 751 }
469 752
470 fx += glyph.fAdvanceX; 753 fx += glyph.fAdvanceX;
471 fy += glyph.fAdvanceY; 754 fy += glyph.fAdvanceY;
472 } 755 }
473 } 756 }
474 757
475 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, 758 void GrAtlasTextContext::internalDrawBmpPosText(BitmapTextBlob* blob, int runInd ex,
476 const GrPaint& paint, const SkPaint& skPa int, 759 SkGlyphCache* cache, const SkPai nt& skPaint,
477 const SkMatrix& viewMatrix, 760 GrColor color,
478 const char text[], size_t byteLength, 761 const SkMatrix& viewMatrix,
479 const SkScalar pos[], int scalarsPerPosit ion, 762 const char text[], size_t byteLe ngth,
480 const SkPoint& offset, const SkIRect& reg ionClipBounds) { 763 const SkScalar pos[], int scalar sPerPosition,
481 int glyphCount = skPaint.countText(text, byteLength); 764 const SkPoint& offset, const SkI Rect& clipRect) {
482 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex tVASize));
483 blob->fViewMatrix = viewMatrix;
484
485 SkIRect clipRect;
486 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
487
488 // setup cache
489 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ;
490 this->internalDrawPosText(blob, 0, cache, skPaint, paint.getColor(), viewMat rix, text,
491 byteLength, pos, scalarsPerPosition, offset, clipR ect);
492 SkGlyphCache::AttachCache(cache);
493
494 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM atrix);
495 }
496
497 void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex,
498 SkGlyphCache* cache, const SkPaint& skPaint,
499 GrColor color,
500 const SkMatrix& viewMatrix,
501 const char text[], size_t byteLengt h,
502 const SkScalar pos[], int scalarsPe rPosition,
503 const SkPoint& offset, const SkIRec t& clipRect) {
504 SkASSERT(byteLength == 0 || text != NULL); 765 SkASSERT(byteLength == 0 || text != NULL);
505 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 766 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
506 767
507 // nothing to draw 768 // nothing to draw
508 if (text == NULL || byteLength == 0) { 769 if (text == NULL || byteLength == 0) {
509 return; 770 return;
510 } 771 }
511 772
512 fCurrStrike = NULL; 773 fCurrStrike = NULL;
513 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); 774 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
(...skipping 25 matching lines...) Expand all
539 while (text < stop) { 800 while (text < stop) {
540 SkPoint tmsLoc; 801 SkPoint tmsLoc;
541 tmsProc(pos, &tmsLoc); 802 tmsProc(pos, &tmsLoc);
542 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); 803 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX);
543 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); 804 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY);
544 805
545 const SkGlyph& glyph = glyphCacheProc(cache, &text, 806 const SkGlyph& glyph = glyphCacheProc(cache, &text,
546 fx & fxMask, fy & fyMask); 807 fx & fxMask, fy & fyMask);
547 808
548 if (glyph.fWidth) { 809 if (glyph.fWidth) {
549 this->appendGlyph(blob, 810 this->bmpAppendGlyph(blob,
550 runIndex, 811 runIndex,
551 GrGlyph::Pack(glyph.getGlyphID(), 812 GrGlyph::Pack(glyph.getGlyphID(),
552 glyph.getSubXFixed(), 813 glyph.getSubXFixed(),
553 glyph.getSubYFixed(), 814 glyph.getSubYFixed(),
554 GrGlyph::kCoverage_MaskStyle ), 815 GrGlyph::kCoverage_MaskSt yle),
555 Sk48Dot16FloorToInt(fx), 816 Sk48Dot16FloorToInt(fx),
556 Sk48Dot16FloorToInt(fy), 817 Sk48Dot16FloorToInt(fy),
557 color, 818 color,
558 fontScaler, 819 fontScaler,
559 clipRect); 820 clipRect);
560 } 821 }
561 pos += scalarsPerPosition; 822 pos += scalarsPerPosition;
562 } 823 }
563 } else { 824 } else {
564 while (text < stop) { 825 while (text < stop) {
565 const char* currentText = text; 826 const char* currentText = text;
566 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 827 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
567 828
568 if (metricGlyph.fWidth) { 829 if (metricGlyph.fWidth) {
569 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 830 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
570 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 831 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
571 SkPoint tmsLoc; 832 SkPoint tmsLoc;
572 tmsProc(pos, &tmsLoc); 833 tmsProc(pos, &tmsLoc);
573 SkPoint alignLoc; 834 SkPoint alignLoc;
574 alignProc(tmsLoc, metricGlyph, &alignLoc); 835 alignProc(tmsLoc, metricGlyph, &alignLoc);
575 836
576 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); 837 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX);
577 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); 838 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY);
578 839
579 // have to call again, now that we've been "aligned" 840 // have to call again, now that we've been "aligned"
580 const SkGlyph& glyph = glyphCacheProc(cache, &currentText, 841 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
581 fx & fxMask, fy & fyMa sk); 842 fx & fxMask, fy & fyMa sk);
582 // the assumption is that the metrics haven't changed 843 // the assumption is that the metrics haven't changed
583 SkASSERT(prevAdvX == glyph.fAdvanceX); 844 SkASSERT(prevAdvX == glyph.fAdvanceX);
584 SkASSERT(prevAdvY == glyph.fAdvanceY); 845 SkASSERT(prevAdvY == glyph.fAdvanceY);
585 SkASSERT(glyph.fWidth); 846 SkASSERT(glyph.fWidth);
586 847
587 this->appendGlyph(blob, 848 this->bmpAppendGlyph(blob,
588 runIndex, 849 runIndex,
589 GrGlyph::Pack(glyph.getGlyphID(), 850 GrGlyph::Pack(glyph.getGlyphID(),
590 glyph.getSubXFixed(), 851 glyph.getSubXFixed(),
591 glyph.getSubYFixed(), 852 glyph.getSubYFixed(),
592 GrGlyph::kCoverage_MaskStyle ), 853 GrGlyph::kCoverage_MaskSt yle),
593 Sk48Dot16FloorToInt(fx), 854 Sk48Dot16FloorToInt(fx),
594 Sk48Dot16FloorToInt(fy), 855 Sk48Dot16FloorToInt(fy),
595 color, 856 color,
596 fontScaler, 857 fontScaler,
597 clipRect); 858 clipRect);
598 } 859 }
599 pos += scalarsPerPosition; 860 pos += scalarsPerPosition;
600 } 861 }
601 } 862 }
602 } else { // not subpixel 863 } else { // not subpixel
603 864
604 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { 865 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
605 while (text < stop) { 866 while (text < stop) {
606 // the last 2 parameters are ignored 867 // the last 2 parameters are ignored
607 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 868 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
608 869
609 if (glyph.fWidth) { 870 if (glyph.fWidth) {
610 SkPoint tmsLoc; 871 SkPoint tmsLoc;
611 tmsProc(pos, &tmsLoc); 872 tmsProc(pos, &tmsLoc);
612 873
613 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX; 874 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
614 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY; 875 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
615 this->appendGlyph(blob, 876 this->bmpAppendGlyph(blob,
616 runIndex, 877 runIndex,
617 GrGlyph::Pack(glyph.getGlyphID(), 878 GrGlyph::Pack(glyph.getGlyphID(),
618 glyph.getSubXFixed(), 879 glyph.getSubXFixed(),
619 glyph.getSubYFixed(), 880 glyph.getSubYFixed(),
620 GrGlyph::kCoverage_MaskStyle ), 881 GrGlyph::kCoverage_MaskSt yle),
621 Sk48Dot16FloorToInt(fx), 882 Sk48Dot16FloorToInt(fx),
622 Sk48Dot16FloorToInt(fy), 883 Sk48Dot16FloorToInt(fy),
623 color, 884 color,
624 fontScaler, 885 fontScaler,
625 clipRect); 886 clipRect);
626 } 887 }
627 pos += scalarsPerPosition; 888 pos += scalarsPerPosition;
628 } 889 }
629 } else { 890 } else {
630 while (text < stop) { 891 while (text < stop) {
631 // the last 2 parameters are ignored 892 // the last 2 parameters are ignored
632 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 893 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
633 894
634 if (glyph.fWidth) { 895 if (glyph.fWidth) {
635 SkPoint tmsLoc; 896 SkPoint tmsLoc;
636 tmsProc(pos, &tmsLoc); 897 tmsProc(pos, &tmsLoc);
637 898
638 SkPoint alignLoc; 899 SkPoint alignLoc;
639 alignProc(tmsLoc, glyph, &alignLoc); 900 alignProc(tmsLoc, glyph, &alignLoc);
640 901
641 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX; 902 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX;
642 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY; 903 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY;
643 this->appendGlyph(blob, 904 this->bmpAppendGlyph(blob,
644 runIndex, 905 runIndex,
645 GrGlyph::Pack(glyph.getGlyphID(), 906 GrGlyph::Pack(glyph.getGlyphID(),
646 glyph.getSubXFixed(), 907 glyph.getSubXFixed(),
647 glyph.getSubYFixed(), 908 glyph.getSubYFixed(),
648 GrGlyph::kCoverage_MaskStyle ), 909 GrGlyph::kCoverage_MaskSt yle),
649 Sk48Dot16FloorToInt(fx), 910 Sk48Dot16FloorToInt(fx),
650 Sk48Dot16FloorToInt(fy), 911 Sk48Dot16FloorToInt(fy),
651 color, 912 color,
652 fontScaler, 913 fontScaler,
653 clipRect); 914 clipRect);
654 } 915 }
655 pos += scalarsPerPosition; 916 pos += scalarsPerPosition;
656 } 917 }
657 } 918 }
658 } 919 }
659 } 920 }
660 921
661 void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph ::PackedID packed, 922
662 int vx, int vy, GrColor color, GrFontScaler * scaler, 923 void GrAtlasTextContext::internalDrawDfText(BitmapTextBlob* blob, int runIndex,
663 const SkIRect& clipRect) { 924 SkGlyphCache* cache, const SkPaint& skPaint,
925 GrColor color,
926 const SkMatrix& viewMatrix,
927 const char text[], size_t byteLength ,
928 SkScalar x, SkScalar y, const SkIRec t& clipRect,
929 SkScalar textRatio,
930 SkTArray<char>* fallbackTxt,
931 SkTArray<SkScalar>* fallbackPos,
932 SkPoint* offset,
933 const SkPaint& origPaint) {
934 SkASSERT(byteLength == 0 || text != NULL);
935
936 // nothing to draw
937 if (text == NULL || byteLength == 0) {
938 return;
939 }
940
941 SkDrawCacheProc glyphCacheProc = origPaint.getDrawCacheProc();
942 SkAutoDescriptor desc;
943 origPaint.getScalerContextDescriptor(&desc, &fDeviceProperties, NULL, true);
944 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(origPaint.getTypefa ce(),
945 desc.getDesc());
946
947 SkTArray<SkScalar> positions;
948
949 const char* textPtr = text;
950 SkFixed stopX = 0;
951 SkFixed stopY = 0;
952 SkFixed origin = 0;
953 switch (origPaint.getTextAlign()) {
954 case SkPaint::kRight_Align: origin = SK_Fixed1; break;
955 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
956 case SkPaint::kLeft_Align: origin = 0; break;
957 }
958
959 SkAutoKern autokern;
960 const char* stop = text + byteLength;
961 while (textPtr < stop) {
962 // don't need x, y here, since all subpixel variants will have the
963 // same advance
964 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0);
965
966 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
967 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));
968
969 SkFixed height = glyph.fAdvanceY;
970 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))) ;
971
972 stopX += width;
973 stopY += height;
974 }
975 SkASSERT(textPtr == stop);
976
977 // now adjust starting point depending on alignment
978 SkScalar alignX = SkFixedToScalar(stopX);
979 SkScalar alignY = SkFixedToScalar(stopY);
980 if (origPaint.getTextAlign() == SkPaint::kCenter_Align) {
981 alignX = SkScalarHalf(alignX);
982 alignY = SkScalarHalf(alignY);
983 } else if (origPaint.getTextAlign() == SkPaint::kLeft_Align) {
984 alignX = 0;
985 alignY = 0;
986 }
987 x -= alignX;
988 y -= alignY;
989 *offset = SkPoint::Make(x, y);
990
991 this->internalDrawDfPosText(blob, runIndex, cache, skPaint, color, viewMatri x, text, byteLength,
992 positions.begin(), 2, *offset, clipRect, textRat io, fallbackTxt,
993 fallbackPos);
994 SkGlyphCache::AttachCache(origPaintCache);
995 }
996
997 void GrAtlasTextContext::internalDrawDfPosText(BitmapTextBlob* blob, int runInde x,
998 SkGlyphCache* cache, const SkPain t& skPaint,
999 GrColor color,
1000 const SkMatrix& viewMatrix,
1001 const char text[], size_t byteLen gth,
1002 const SkScalar pos[], int scalars PerPosition,
1003 const SkPoint& offset, const SkIR ect& clipRect,
1004 SkScalar textRatio,
1005 SkTArray<char>* fallbackTxt,
1006 SkTArray<SkScalar>* fallbackPos) {
1007
1008 SkASSERT(byteLength == 0 || text != NULL);
1009 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1010
1011 // nothing to draw
1012 if (text == NULL || byteLength == 0) {
1013 return;
1014 }
1015
1016 fCurrStrike = NULL;
1017
1018 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
1019 GrFontScaler* fontScaler = GetGrFontScaler(cache);
1020
1021 const char* stop = text + byteLength;
1022
1023 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
1024 while (text < stop) {
1025 const char* lastText = text;
1026 // the last 2 parameters are ignored
1027 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1028
1029 if (glyph.fWidth) {
1030 SkScalar x = offset.x() + pos[0];
1031 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
1032
1033 if (!this->dfAppendGlyph(blob,
1034 runIndex,
1035 GrGlyph::Pack(glyph.getGlyphID(),
1036 glyph.getSubXFixed(),
1037 glyph.getSubYFixed(),
1038 GrGlyph::kDistance_MaskSt yle),
1039 x, y, color, fontScaler, clipRect,
1040 textRatio, viewMatrix)) {
1041 // couldn't append, send to fallback
1042 fallbackTxt->push_back_n(SkToInt(text-lastText), lastText);
1043 fallbackPos->push_back(pos[0]);
1044 if (2 == scalarsPerPosition) {
1045 fallbackPos->push_back(pos[1]);
1046 }
1047 }
1048 }
1049 pos += scalarsPerPosition;
1050 }
1051 } else {
1052 SkScalar alignMul = SkPaint::kCenter_Align == skPaint.getTextAlign() ? S K_ScalarHalf
1053 : S K_Scalar1;
1054 while (text < stop) {
1055 const char* lastText = text;
1056 // the last 2 parameters are ignored
1057 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1058
1059 if (glyph.fWidth) {
1060 SkScalar x = offset.x() + pos[0];
1061 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
1062
1063 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio;
1064 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio;
1065
1066 if (!this->dfAppendGlyph(blob,
1067 runIndex,
1068 GrGlyph::Pack(glyph.getGlyphID(),
1069 glyph.getSubXFixed(),
1070 glyph.getSubYFixed(),
1071 GrGlyph::kDistance_MaskSt yle),
1072 x - advanceX, y - advanceY, color,
1073 fontScaler,
1074 clipRect,
1075 textRatio,
1076 viewMatrix)) {
1077 // couldn't append, send to fallback
1078 fallbackTxt->push_back_n(SkToInt(text-lastText), lastText);
1079 fallbackPos->push_back(pos[0]);
1080 if (2 == scalarsPerPosition) {
1081 fallbackPos->push_back(pos[1]);
1082 }
1083 }
1084 }
1085 pos += scalarsPerPosition;
1086 }
1087 }
1088 }
1089
1090 void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
1091 GrGlyph::PackedID packed,
1092 int vx, int vy, GrColor color, GrFontSca ler* scaler,
1093 const SkIRect& clipRect) {
664 if (NULL == fCurrStrike) { 1094 if (NULL == fCurrStrike) {
665 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); 1095 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
666 } 1096 }
667 1097
668 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); 1098 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
669 if (NULL == glyph || glyph->fBounds.isEmpty()) { 1099 if (NULL == glyph || glyph->fBounds.isEmpty()) {
670 return; 1100 return;
671 } 1101 }
672 1102
673 int x = vx + glyph->fBounds.fLeft; 1103 int x = vx + glyph->fBounds.fLeft;
(...skipping 10 matching lines...) Expand all
684 // We could store the cliprect in the key, but then we'd lose the ability to do integer scrolls 1114 // We could store the cliprect in the key, but then we'd lose the ability to do integer scrolls
685 // TODO verify this 1115 // TODO verify this
686 // check if we clipped out 1116 // check if we clipped out
687 if (clipRect.quickReject(x, y, x + width, y + height)) { 1117 if (clipRect.quickReject(x, y, x + width, y + height)) {
688 return; 1118 return;
689 } 1119 }
690 #endif 1120 #endif
691 1121
692 // If the glyph is too large we fall back to paths 1122 // If the glyph is too large we fall back to paths
693 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { 1123 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
694 if (NULL == glyph->fPath) { 1124 this->appendBigGlyph(blob, glyph, scaler, vx, vy);
bsalomon 2015/04/16 15:03:55 appendGlyphPath? appendGlyphAsPath?
695 SkPath* path = SkNEW(SkPath);
696 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
697 // flag the glyph as being dead?
698 SkDELETE(path);
699 return;
700 }
701 glyph->fPath = path;
702 }
703 SkASSERT(glyph->fPath);
704 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v y));
705 return; 1125 return;
706 } 1126 }
707 1127
708 Run& run = blob->fRuns[runIndex]; 1128 Run& run = blob->fRuns[runIndex];
709 1129
710 GrMaskFormat format = glyph->fMaskFormat; 1130 GrMaskFormat format = glyph->fMaskFormat;
711 1131
712 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); 1132 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
713 if (run.fInitialized && subRun->fMaskFormat != format) { 1133 if (run.fInitialized && subRun->fMaskFormat != format) {
714 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back(); 1134 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back();
715 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex; 1135 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex;
716 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex; 1136 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex;
717 1137
718 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex; 1138 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex;
719 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex; 1139 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex;
720 1140
721 subRun = newSubRun; 1141 subRun = newSubRun;
722 } 1142 }
723 1143
724 run.fInitialized = true; 1144 run.fInitialized = true;
725 subRun->fMaskFormat = format;
726 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
727 1145
728 size_t vertexStride = get_vertex_stride(format); 1146 size_t vertexStride = get_vertex_stride(format);
729 1147
730 SkRect r; 1148 SkRect r;
731 r.fLeft = SkIntToScalar(x); 1149 r.fLeft = SkIntToScalar(x);
732 r.fTop = SkIntToScalar(y); 1150 r.fTop = SkIntToScalar(y);
733 r.fRight = r.fLeft + SkIntToScalar(width); 1151 r.fRight = r.fLeft + SkIntToScalar(width);
734 r.fBottom = r.fTop + SkIntToScalar(height); 1152 r.fBottom = r.fTop + SkIntToScalar(height);
1153 subRun->fMaskFormat = format;
1154 this->innerAppendGlyph(blob, &run, subRun, r, color, vertexStride, kA8_GrMas kFormat == format,
1155 packed);
1156 }
735 1157
736 run.fVertexBounds.joinNonEmptyArg(r); 1158 bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
737 run.fColor = color; 1159 GrGlyph::PackedID packed,
1160 SkScalar sx, SkScalar sy, GrColor color,
1161 GrFontScaler* scaler,
1162 const SkIRect& clipRect,
1163 SkScalar textRatio, const SkMatrix& viewM atrix) {
1164 if (NULL == fCurrStrike) {
bsalomon 2015/04/16 15:03:55 can just say if (!fCurrStrike)
joshualitt 2015/04/16 15:36:12 Acknowledged.
1165 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
1166 }
1167
1168 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
1169 if (NULL == glyph || glyph->fBounds.isEmpty()) {
bsalomon 2015/04/16 15:03:55 if (glyph || ...)
joshualitt 2015/04/16 15:36:12 Acknowledged.
1170 return true;
1171 }
1172
1173 // fallback to color glyph support
1174 if (kA8_GrMaskFormat != glyph->fMaskFormat) {
1175 return false;
1176 }
1177
1178 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
1179 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
1180 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField Inset);
1181 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie ldInset);
1182
1183 SkScalar scale = textRatio;
1184 dx *= scale;
1185 dy *= scale;
1186 width *= scale;
1187 height *= scale;
1188 sx += dx;
1189 sy += dy;
1190 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
1191
1192 #if 0
1193 // check if we clipped out
1194 SkRect dstRect;
1195 viewMatrix.mapRect(&dstRect, glyphRect);
1196 if (clipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
1197 SkScalarTruncToInt(dstRect.top()),
1198 SkScalarTruncToInt(dstRect.right()),
1199 SkScalarTruncToInt(dstRect.bottom()))) {
1200 return true;
1201 }
1202 #endif
1203
1204 // TODO combine with the above
1205 // If the glyph is too large we fall back to paths
1206 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
1207 this->appendBigGlyph(blob, glyph, scaler, sx - dx, sy - dy);
1208 return true;
1209 }
1210
1211 Run& run = blob->fRuns[runIndex];
1212
1213 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
1214 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat);
1215 subRun->fMaskFormat = kA8_GrMaskFormat;
1216
1217 size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCD Text);
1218
1219 bool useColorVerts = !subRun->fUseLCDText;
1220 this->innerAppendGlyph(blob, &run, subRun, glyphRect, color, vertexStride, u seColorVerts,
1221 packed);
1222 return true;
1223 }
1224
1225 inline void GrAtlasTextContext::appendBigGlyph(BitmapTextBlob* blob, GrGlyph* gl yph,
1226 GrFontScaler* scaler, int x, int y) {
1227 if (NULL == glyph->fPath) {
1228 SkPath* path = SkNEW(SkPath);
1229 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
1230 // flag the glyph as being dead?
1231 SkDELETE(path);
1232 return;
1233 }
1234 glyph->fPath = path;
1235 }
1236 SkASSERT(glyph->fPath);
1237 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y));
1238 }
1239
1240 inline void GrAtlasTextContext::innerAppendGlyph(BitmapTextBlob* blob, Run* run,
1241 Run::SubRunInfo* subRun,
1242 const SkRect& positions, GrColo r color,
1243 size_t vertexStride, bool useVe rtexColor,
1244 GrGlyph::PackedID packed) {
1245 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
1246 run->fVertexBounds.joinNonEmptyArg(positions);
1247 run->fColor = color;
738 1248
739 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); 1249 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex);
740 1250
741 // V0 1251 // V0
742 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); 1252 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
743 position->set(r.fLeft, r.fTop); 1253 position->set(positions.fLeft, positions.fTop);
744 if (kA8_GrMaskFormat == format) { 1254 if (useVertexColor) {
745 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1255 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
746 *colorPtr = color; 1256 *colorPtr = color;
747 } 1257 }
748 vertex += vertexStride; 1258 vertex += vertexStride;
1259
749 // V1 1260 // V1
750 position = reinterpret_cast<SkPoint*>(vertex); 1261 position = reinterpret_cast<SkPoint*>(vertex);
751 position->set(r.fLeft, r.fBottom); 1262 position->set(positions.fLeft, positions.fBottom);
752 if (kA8_GrMaskFormat == format) { 1263 if (useVertexColor) {
753 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1264 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
754 *colorPtr = color; 1265 *colorPtr = color;
755 } 1266 }
756 vertex += vertexStride; 1267 vertex += vertexStride;
757 1268
758 // V2 1269 // V2
759 position = reinterpret_cast<SkPoint*>(vertex); 1270 position = reinterpret_cast<SkPoint*>(vertex);
760 position->set(r.fRight, r.fBottom); 1271 position->set(positions.fRight, positions.fBottom);
761 if (kA8_GrMaskFormat == format) { 1272 if (useVertexColor) {
762 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1273 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
763 *colorPtr = color; 1274 *colorPtr = color;
764 } 1275 }
765 vertex += vertexStride; 1276 vertex += vertexStride;
766 1277
767 // V3 1278 // V3
768 position = reinterpret_cast<SkPoint*>(vertex); 1279 position = reinterpret_cast<SkPoint*>(vertex);
769 position->set(r.fRight, r.fTop); 1280 position->set(positions.fRight, positions.fTop);
770 if (kA8_GrMaskFormat == format) { 1281 if (useVertexColor) {
771 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1282 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
772 *colorPtr = color; 1283 *colorPtr = color;
773 } 1284 }
774 1285
775 subRun->fGlyphEndIndex++; 1286 subRun->fGlyphEndIndex++;
776 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; 1287 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
777 } 1288 }
778 1289
779 class BitmapTextBatch : public GrBatch { 1290 class BitmapTextBatch : public GrBatch {
780 public: 1291 public:
1292 typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable;
781 typedef GrAtlasTextContext::BitmapTextBlob Blob; 1293 typedef GrAtlasTextContext::BitmapTextBlob Blob;
782 typedef Blob::Run Run; 1294 typedef Blob::Run Run;
783 typedef Run::SubRunInfo TextInfo; 1295 typedef Run::SubRunInfo TextInfo;
784 struct Geometry { 1296 struct Geometry {
785 Blob* fBlob; 1297 Blob* fBlob;
786 int fRun; 1298 int fRun;
787 int fSubRun; 1299 int fSubRun;
788 GrColor fColor; 1300 GrColor fColor;
789 SkScalar fTransX; 1301 SkScalar fTransX;
790 SkScalar fTransY; 1302 SkScalar fTransY;
791 }; 1303 };
792 1304
793 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, 1305 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
794 GrBatchFontCache* fontCache) { 1306 GrBatchFontCache* fontCache) {
795 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache)); 1307 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache));
796 } 1308 }
797 1309
1310 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
1311 GrBatchFontCache* fontCache,
1312 DistanceAdjustTable* distanceAdjustTable,
1313 SkColor filteredColor, bool useLCDText,
1314 bool useBGR, float gamma) {
1315 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache, d istanceAdjustTable,
1316 filteredColor, useLCDText, useBGR, g amma));
1317 }
1318
798 const char* name() const override { return "BitmapTextBatch"; } 1319 const char* name() const override { return "BitmapTextBatch"; }
799 1320
800 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { 1321 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
801 if (kARGB_GrMaskFormat == fMaskFormat) { 1322 if (kARGB_GrMaskFormat == fMaskFormat) {
802 out->setUnknownFourComponents(); 1323 out->setUnknownFourComponents();
803 } else { 1324 } else {
804 out->setKnownFourComponents(fBatch.fColor); 1325 out->setKnownFourComponents(fBatch.fColor);
805 } 1326 }
806 } 1327 }
807 1328
808 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { 1329 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
809 if (kARGB_GrMaskFormat != fMaskFormat) { 1330 if (!fUseDistanceFields) {
810 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) { 1331 // Bitmap Text
1332 if (kARGB_GrMaskFormat != fMaskFormat) {
1333 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
1334 out->setUnknownSingleComponent();
1335 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
1336 out->setUnknownOpaqueFourComponents();
1337 out->setUsingLCDCoverage();
1338 } else {
1339 out->setUnknownFourComponents();
1340 out->setUsingLCDCoverage();
1341 }
1342 } else {
1343 out->setKnownSingleComponent(0xff);
1344 }
1345 } else {
1346 // Distance fields
1347 if (!fUseLCDText) {
811 out->setUnknownSingleComponent(); 1348 out->setUnknownSingleComponent();
812 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
813 out->setUnknownOpaqueFourComponents();
814 out->setUsingLCDCoverage();
815 } else { 1349 } else {
816 out->setUnknownFourComponents(); 1350 out->setUnknownFourComponents();
817 out->setUsingLCDCoverage(); 1351 out->setUsingLCDCoverage();
818 } 1352 }
819 } else {
820 out->setKnownSingleComponent(0xff);
821 } 1353 }
822 } 1354 }
823 1355
824 void initBatchTracker(const GrPipelineInfo& init) override { 1356 void initBatchTracker(const GrPipelineInfo& init) override {
825 // Handle any color overrides 1357 // Handle any color overrides
826 if (init.fColorIgnored) { 1358 if (init.fColorIgnored) {
827 fBatch.fColor = GrColor_ILLEGAL; 1359 fBatch.fColor = GrColor_ILLEGAL;
828 } else if (GrColor_ILLEGAL != init.fOverrideColor) { 1360 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
829 fBatch.fColor = init.fOverrideColor; 1361 fBatch.fColor = init.fOverrideColor;
830 } 1362 }
(...skipping 12 matching lines...) Expand all
843 SkDebugf("Cannot invert viewmatrix\n"); 1375 SkDebugf("Cannot invert viewmatrix\n");
844 return; 1376 return;
845 } 1377 }
846 1378
847 GrTexture* texture = fFontCache->getTexture(fMaskFormat); 1379 GrTexture* texture = fFontCache->getTexture(fMaskFormat);
848 if (!texture) { 1380 if (!texture) {
849 SkDebugf("Could not allocate backing texture for atlas\n"); 1381 SkDebugf("Could not allocate backing texture for atlas\n");
850 return; 1382 return;
851 } 1383 }
852 1384
853 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode); 1385 SkAutoTUnref<const GrGeometryProcessor> gp;
1386 if (fUseDistanceFields) {
1387 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(),
1388 texture));
1389 } else {
1390 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k None_FilterMode);
854 1391
855 // This will be ignored in the non A8 case 1392 // This will be ignored in the non A8 case
856 bool opaqueVertexColors = GrColorIsOpaque(this->color()); 1393 bool opaqueVertexColors = GrColorIsOpaque(this->color());
857 SkAutoTUnref<const GrGeometryProcessor> gp( 1394 gp.reset(GrBitmapTextGeoProc::Create(this->color(),
858 GrBitmapTextGeoProc::Create(this->color(), 1395 texture,
859 texture, 1396 params,
860 params, 1397 fMaskFormat,
861 fMaskFormat, 1398 opaqueVertexColors,
862 opaqueVertexColors, 1399 localMatrix));
863 localMatrix)); 1400 }
864 1401
865 size_t vertexStride = gp->getVertexStride(); 1402 size_t vertexStride = gp->getVertexStride();
866 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat)); 1403 SkASSERT(vertexStride == fUseDistanceFields ?
1404 get_vertex_stride_df(fMaskFormat, fUseLCDText) :
1405 get_vertex_stride(fMaskFormat));
867 1406
868 this->initDraw(batchTarget, gp, pipeline); 1407 this->initDraw(batchTarget, gp, pipeline);
869 1408
870 int glyphCount = this->numGlyphs(); 1409 int glyphCount = this->numGlyphs();
871 int instanceCount = fInstanceCount; 1410 int instanceCount = fInstanceCount;
872 const GrVertexBuffer* vertexBuffer; 1411 const GrVertexBuffer* vertexBuffer;
873 int firstVertex; 1412 int firstVertex;
874 1413
875 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, 1414 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
876 glyphCount * kVert icesPerGlyph, 1415 glyphCount * kVert icesPerGlyph,
(...skipping 22 matching lines...) Expand all
899 1438
900 int instancesToFlush = 0; 1439 int instancesToFlush = 0;
901 for (int i = 0; i < instanceCount; i++) { 1440 for (int i = 0; i < instanceCount; i++) {
902 Geometry& args = fGeoData[i]; 1441 Geometry& args = fGeoData[i];
903 Blob* blob = args.fBlob; 1442 Blob* blob = args.fBlob;
904 Run& run = blob->fRuns[args.fRun]; 1443 Run& run = blob->fRuns[args.fRun];
905 TextInfo& info = run.fSubRunInfo[args.fSubRun]; 1444 TextInfo& info = run.fSubRunInfo[args.fSubRun];
906 1445
907 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); 1446 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
908 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; 1447 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen;
909 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; 1448 bool regenerateColors;
1449 if (fUseDistanceFields) {
1450 regenerateColors = fUseLCDText && run.fColor != args.fColor;
1451 } else {
1452 regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
1453 }
910 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f; 1454 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f;
911 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1455 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
912 1456
913 // We regenerate both texture coords and colors in the blob itself, and update the 1457 // We regenerate both texture coords and colors in the blob itself, and update the
914 // atlas generation. If we don't end up purging any unused plots, w e can avoid 1458 // atlas generation. If we don't end up purging any unused plots, w e can avoid
915 // regenerating the coords. We could take a finer grained approach to updating texture 1459 // regenerating the coords. We could take a finer grained approach to updating texture
916 // coords but its not clear if the extra bookkeeping would offset an y gains. 1460 // coords but its not clear if the extra bookkeeping would offset an y gains.
917 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color 1461 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color
918 // or coords as needed. One final note, if we have to break a run f or an atlas eviction 1462 // or coords as needed. One final note, if we have to break a run f or an atlas eviction
919 // then we can't really trust the atlas has all of the correct data. Atlas evictions 1463 // then we can't really trust the atlas has all of the correct data. Atlas evictions
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
1020 // to avoid even the initial copy of the struct, we have a getter for the fi rst item which 1564 // to avoid even the initial copy of the struct, we have a getter for the fi rst item which
1021 // is used to seed the batch with its initial geometry. After seeding, the client should call 1565 // is used to seed the batch with its initial geometry. After seeding, the client should call
1022 // init() so the Batch can initialize itself 1566 // init() so the Batch can initialize itself
1023 Geometry& geometry() { return fGeoData[0]; } 1567 Geometry& geometry() { return fGeoData[0]; }
1024 void init() { 1568 void init() {
1025 fBatch.fColor = fGeoData[0].fColor; 1569 fBatch.fColor = fGeoData[0].fColor;
1026 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix; 1570 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix;
1027 } 1571 }
1028 1572
1029 private: 1573 private:
1030 BitmapTextBatch(GrMaskFormat maskFormat, 1574 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache)
1031 int glyphCount, GrBatchFontCache* fontCache)
1032 : fMaskFormat(maskFormat) 1575 : fMaskFormat(maskFormat)
1033 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) 1576 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1034 , fFontCache(fontCache) { 1577 , fFontCache(fontCache)
1578 , fUseDistanceFields(false) {
1035 this->initClassID<BitmapTextBatch>(); 1579 this->initClassID<BitmapTextBatch>();
1036 fBatch.fNumGlyphs = glyphCount; 1580 fBatch.fNumGlyphs = glyphCount;
1037 fInstanceCount = 1; 1581 fInstanceCount = 1;
1038 fAllocatedCount = kMinAllocated; 1582 fAllocatedCount = kMinAllocated;
1039 } 1583 }
1040 1584
1585 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache,
1586 DistanceAdjustTable* distanceAdjustTable, SkColor filteredCo lor,
1587 bool useLCDText, bool useBGR, float gamma)
1588 : fMaskFormat(maskFormat)
1589 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1590 , fFontCache(fontCache)
1591 , fDistanceAdjustTable(SkRef(distanceAdjustTable))
1592 , fFilteredColor(filteredColor)
1593 , fUseDistanceFields(true)
1594 , fUseLCDText(useLCDText)
1595 , fUseBGR(useBGR)
1596 , fGamma(gamma) {
1597 this->initClassID<BitmapTextBatch>();
1598 fBatch.fNumGlyphs = glyphCount;
1599 fInstanceCount = 1;
1600 fAllocatedCount = kMinAllocated;
1601 SkASSERT(fMaskFormat == kA8_GrMaskFormat);
1602 }
1603
1041 ~BitmapTextBatch() { 1604 ~BitmapTextBatch() {
1042 for (int i = 0; i < fInstanceCount; i++) { 1605 for (int i = 0; i < fInstanceCount; i++) {
1043 fGeoData[i].fBlob->unref(); 1606 fGeoData[i].fBlob->unref();
1044 } 1607 }
1045 } 1608 }
1046 1609
1047 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) { 1610 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) {
1048 int width = glyph->fBounds.width(); 1611 int width = glyph->fBounds.width();
1049 int height = glyph->fBounds.height(); 1612 int height = glyph->fBounds.height();
1050 int u0 = glyph->fAtlasLocation.fX;
1051 int v0 = glyph->fAtlasLocation.fY;
1052 int u1 = u0 + width;
1053 int v1 = v0 + height;
1054 1613
1055 // we assume texture coords are the last vertex attribute, this is a bit fragile. 1614 int u0, v0, u1, v1;
1056 // TODO pass in this offset or something 1615 if (fUseDistanceFields) {
1616 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
1617 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
1618 u1 = u0 + width - 2 * SK_DistanceFieldInset;
1619 v1 = v0 + height - 2 * SK_DistanceFieldInset;
1620 } else {
1621 u0 = glyph->fAtlasLocation.fX;
1622 v0 = glyph->fAtlasLocation.fY;
1623 u1 = u0 + width;
1624 v1 = v0 + height;
1625 }
1626
1057 SkIPoint16* textureCoords; 1627 SkIPoint16* textureCoords;
1058 // V0 1628 // V0
1059 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1629 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1060 textureCoords->set(u0, v0); 1630 textureCoords->set(u0, v0);
1061 vertex += vertexStride; 1631 vertex += vertexStride;
1062 1632
1063 // V1 1633 // V1
1064 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1634 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1065 textureCoords->set(u0, v1); 1635 textureCoords->set(u0, v1);
1066 vertex += vertexStride; 1636 vertex += vertexStride;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1124 } 1694 }
1125 1695
1126 GrColor color() const { return fBatch.fColor; } 1696 GrColor color() const { return fBatch.fColor; }
1127 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } 1697 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1128 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 1698 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1129 int numGlyphs() const { return fBatch.fNumGlyphs; } 1699 int numGlyphs() const { return fBatch.fNumGlyphs; }
1130 1700
1131 bool onCombineIfPossible(GrBatch* t) override { 1701 bool onCombineIfPossible(GrBatch* t) override {
1132 BitmapTextBatch* that = t->cast<BitmapTextBatch>(); 1702 BitmapTextBatch* that = t->cast<BitmapTextBatch>();
1133 1703
1134 if (this->fMaskFormat != that->fMaskFormat) { 1704 if (fUseDistanceFields != that->fUseDistanceFields) {
1135 return false; 1705 return false;
1136 } 1706 }
1137 1707
1138 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo r()) { 1708 if (!fUseDistanceFields) {
1139 return false; 1709 // Bitmap Text
1140 } 1710 if (fMaskFormat != that->fMaskFormat) {
1711 return false;
1712 }
1141 1713
1142 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) { 1714 // TODO we can often batch across LCD text if we have dual source bl ending and don't
1143 return false; 1715 // have to use the blend constant
1716 if (fMaskFormat != kA8_GrMaskFormat && this->color() != that->color( )) {
1717 return false;
1718 }
1719
1720 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that ->viewMatrix())) {
1721 return false;
1722 }
1723 } else {
1724 // Distance Fields
1725 SkASSERT(this->fMaskFormat == that->fMaskFormat &&
1726 this->fMaskFormat == kA8_GrMaskFormat);
1727
1728 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1729 return false;
1730 }
1731
1732 if (fFilteredColor != that->fFilteredColor) {
1733 return false;
1734 }
1735
1736 if (fUseLCDText != that->fUseLCDText) {
1737 return false;
1738 }
1739
1740 if (fUseBGR != that->fUseBGR) {
1741 return false;
1742 }
1743
1744 if (fGamma != that->fGamma) {
1745 return false;
1746 }
1747
1748 // TODO see note above
1749 if (fUseLCDText && this->color() != that->color()) {
1750 return false;
1751 }
1144 } 1752 }
1145 1753
1146 fBatch.fNumGlyphs += that->numGlyphs(); 1754 fBatch.fNumGlyphs += that->numGlyphs();
1147 1755
1148 // copy that->geoData(). We do this manually for performance reasons 1756 // copy that->geoData(). We do this manually for performance reasons
1149 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData(); 1757 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData();
1150 int otherInstanceCount = that->instanceCount(); 1758 int otherInstanceCount = that->instanceCount();
1151 int allocSize = otherInstanceCount + fInstanceCount; 1759 int allocSize = otherInstanceCount + fInstanceCount;
1152 if (allocSize > fAllocatedCount) { 1760 if (allocSize > fAllocatedCount) {
1153 while (allocSize > fAllocatedCount) { 1761 while (allocSize > fAllocatedCount) {
1154 fAllocatedCount = fAllocatedCount << 1; 1762 fAllocatedCount = fAllocatedCount << 1;
1155 } 1763 }
1156 fGeoData.realloc(fAllocatedCount); 1764 fGeoData.realloc(fAllocatedCount);
1157 } 1765 }
1158 1766
1159 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(), 1767 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(),
1160 otherInstanceCount * sizeof(Geometry)); 1768 otherInstanceCount * sizeof(Geometry));
1161 int total = fInstanceCount + otherInstanceCount; 1769 int total = fInstanceCount + otherInstanceCount;
1162 for (int i = fInstanceCount; i < total; i++) { 1770 for (int i = fInstanceCount; i < total; i++) {
1163 fGeoData[i].fBlob->ref(); 1771 fGeoData[i].fBlob->ref();
1164 } 1772 }
1165 fInstanceCount = total; 1773 fInstanceCount = total;
1166 return true; 1774 return true;
1167 } 1775 }
1168 1776
1777 // TODO just use class params
1778 // TODO trying to figure out why lcd is so whack
1779 GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor fi lteredColor,
1780 GrColor color, GrTexture* texture) {
1781 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile rp_FilterMode);
1782
1783 // set up any flags
1784 uint32_t flags = 0;
1785 flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1786 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
1787 flags |= fUseLCDText && viewMatrix.rectStaysRect() ?
1788 kRectToRect_DistanceFieldEffectFlag : 0;
1789 flags |= fUseLCDText && fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
1790
1791 // see if we need to create a new effect
1792 if (fUseLCDText) {
1793 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or);
1794
1795 float redCorrection =
1796 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistan ceAdjustLumShift];
1797 float greenCorrection =
1798 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistan ceAdjustLumShift];
1799 float blueCorrection =
1800 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistan ceAdjustLumShift];
1801 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
1802 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio n,
1803 greenCorrect ion,
1804 blueCorrecti on);
1805
1806 return GrDistanceFieldLCDTextGeoProc::Create(color,
1807 viewMatrix,
1808 texture,
1809 params,
1810 widthAdjust,
1811 flags);
1812 } else {
1813 flags |= kColorAttr_DistanceFieldEffectFlag;
1814 bool opaque = GrColorIsOpaque(color);
1815 #ifdef SK_GAMMA_APPLY_TO_A8
1816 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fGamma, filtered Color);
1817 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLum Shift];
1818 return GrDistanceFieldA8TextGeoProc::Create(color,
1819 viewMatrix,
1820 texture,
1821 params,
1822 correction,
1823 flags,
1824 opaque);
1825 #else
1826 return GrDistanceFieldA8TextGeoProc::Create(color,
1827 viewMatrix,
1828 texture,
1829 params,
1830 flags,
1831 opaque);
1832 #endif
1833 }
1834
1835 }
1836
1169 struct BatchTracker { 1837 struct BatchTracker {
1170 GrColor fColor; 1838 GrColor fColor;
1171 SkMatrix fViewMatrix; 1839 SkMatrix fViewMatrix;
1172 bool fUsesLocalCoords; 1840 bool fUsesLocalCoords;
1173 bool fColorIgnored; 1841 bool fColorIgnored;
1174 bool fCoverageIgnored; 1842 bool fCoverageIgnored;
1175 int fNumGlyphs; 1843 int fNumGlyphs;
1176 }; 1844 };
1177 1845
1178 BatchTracker fBatch; 1846 BatchTracker fBatch;
1179 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData; 1847 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData;
1180 int fInstanceCount; 1848 int fInstanceCount;
1181 int fAllocatedCount; 1849 int fAllocatedCount;
1182 GrMaskFormat fMaskFormat; 1850 GrMaskFormat fMaskFormat;
1183 GrPixelConfig fPixelConfig; 1851 GrPixelConfig fPixelConfig;
1184 GrBatchFontCache* fFontCache; 1852 GrBatchFontCache* fFontCache;
1853
1854 // Distance field properties
1855 SkAutoTUnref<DistanceAdjustTable> fDistanceAdjustTable;
1856 SkColor fFilteredColor;
1857 bool fUseDistanceFields;
1858 bool fUseLCDText;
1859 bool fUseBGR;
1860 float fGamma;
1185 }; 1861 };
1186 1862
1187 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint, 1863 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint,
1188 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix, 1864 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix,
1189 const SkIRect& clipBounds, SkScalar x, SkScalar y) { 1865 const SkIRect& clipBounds, SkScalar x, SkScalar y) {
1190 SkPaint runPaint = skPaint; 1866 SkPaint runPaint = skPaint;
1191 1867
1192 size_t textLen = it.glyphCount() * sizeof(uint16_t); 1868 size_t textLen = it.glyphCount() * sizeof(uint16_t);
1193 const SkPoint& offset = it.offset(); 1869 const SkPoint& offset = it.offset();
1194 1870
(...skipping 17 matching lines...) Expand all
1212 break; 1888 break;
1213 case SkTextBlob::kFull_Positioning: 1889 case SkTextBlob::kFull_Positioning:
1214 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), 1890 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (),
1215 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); 1891 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds);
1216 break; 1892 break;
1217 } 1893 }
1218 } 1894 }
1219 1895
1220 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, 1896 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder,
1221 BitmapTextBlob* cacheBlob, int run, GrC olor color, 1897 BitmapTextBlob* cacheBlob, int run, GrC olor color,
1222 uint8_t paintAlpha, SkScalar transX, Sk Scalar transY) { 1898 SkScalar transX, SkScalar transY, const SkPaint& skPaint) {
1223 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { 1899 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) {
1224 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; 1900 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
1225 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1901 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
1226 if (0 == glyphCount) { 1902 if (0 == glyphCount) {
1227 continue; 1903 continue;
1228 } 1904 }
1229 1905
1230 GrMaskFormat format = info.fMaskFormat; 1906 GrMaskFormat format = info.fMaskFormat;
1231 GrColor subRunColor = kARGB_GrMaskFormat == format ? 1907 GrColor subRunColor;
1232 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : 1908 if (kARGB_GrMaskFormat == format) {
1233 color; 1909 uint8_t paintAlpha = skPaint.getAlpha();
1910 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, pai ntAlpha);
1911 } else {
1912 subRunColor = color;
1913 }
1234 1914
1235 SkAutoTUnref<BitmapTextBatch> batch(BitmapTextBatch::Create(format, glyp hCount, 1915 SkAutoTUnref<BitmapTextBatch> batch;
1236 fContext->getBatchFo ntCache())); 1916 if (info.fDrawAsDistanceFields) {
1917 SkColor filteredColor;
1918 SkColorFilter* colorFilter = skPaint.getColorFilter();
1919 if (colorFilter) {
1920 filteredColor = colorFilter->filterColor(skPaint.getColor());
1921 } else {
1922 filteredColor = skPaint.getColor();
1923 }
1924 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry() );
1925 float gamma = fDeviceProperties.gamma();
1926 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache(),
1927 fDistanceAdjustTable, filteredCo lor,
1928 info.fUseLCDText, useBGR,
1929 gamma));
1930 } else {
1931 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache()));
1932 }
1237 BitmapTextBatch::Geometry& geometry = batch->geometry(); 1933 BitmapTextBatch::Geometry& geometry = batch->geometry();
1238 geometry.fBlob = SkRef(cacheBlob); 1934 geometry.fBlob = SkRef(cacheBlob);
1239 geometry.fRun = run; 1935 geometry.fRun = run;
1240 geometry.fSubRun = subRun; 1936 geometry.fSubRun = subRun;
1241 geometry.fColor = subRunColor; 1937 geometry.fColor = subRunColor;
1242 geometry.fTransX = transX; 1938 geometry.fTransX = transX;
1243 geometry.fTransY = transY; 1939 geometry.fTransY = transY;
1244 batch->init(); 1940 batch->init();
1245 1941
1246 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); 1942 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds);
(...skipping 28 matching lines...) Expand all
1275 const SkMatrix& viewMatrix, 1971 const SkMatrix& viewMatrix,
1276 const SkIRect& clipBounds, 1972 const SkIRect& clipBounds,
1277 SkScalar x, SkScalar y, 1973 SkScalar x, SkScalar y,
1278 SkScalar transX, SkScalar transY) { 1974 SkScalar transX, SkScalar transY) {
1279 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush 1975 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush
1280 // it as paths 1976 // it as paths
1281 GrPipelineBuilder pipelineBuilder; 1977 GrPipelineBuilder pipelineBuilder;
1282 pipelineBuilder.setFromPaint(grPaint, rt, clip); 1978 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1283 1979
1284 GrColor color = grPaint.getColor(); 1980 GrColor color = grPaint.getColor();
1285 uint8_t paintAlpha = skPaint.getAlpha();
1286 1981
1287 SkTextBlob::RunIterator it(blob); 1982 SkTextBlob::RunIterator it(blob);
1288 for (int run = 0; !it.done(); it.next(), run++) { 1983 for (int run = 0; !it.done(); it.next(), run++) {
1289 if (cacheBlob->fRuns[run].fDrawAsPaths) { 1984 if (cacheBlob->fRuns[run].fDrawAsPaths) {
1290 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); 1985 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y);
1291 continue; 1986 continue;
1292 } 1987 }
1293 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); 1988 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
1294 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, transX, transY); 1989 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, transX, transY, skPaint);
1295 } 1990 }
1296 1991
1297 // Now flush big glyphs 1992 // Now flush big glyphs
1298 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); 1993 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY);
1299 } 1994 }
1300 1995
1301 void GrAtlasTextContext::flush(GrDrawTarget* target, 1996 void GrAtlasTextContext::flush(GrDrawTarget* target,
1302 BitmapTextBlob* cacheBlob, 1997 BitmapTextBlob* cacheBlob,
1303 GrRenderTarget* rt, 1998 GrRenderTarget* rt,
1304 const SkPaint& skPaint, 1999 const SkPaint& skPaint,
1305 const GrPaint& grPaint, 2000 const GrPaint& grPaint,
1306 const GrClip& clip, 2001 const GrClip& clip) {
1307 const SkMatrix& viewMatrix) {
1308 GrPipelineBuilder pipelineBuilder; 2002 GrPipelineBuilder pipelineBuilder;
1309 pipelineBuilder.setFromPaint(grPaint, rt, clip); 2003 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1310 2004
1311 GrColor color = grPaint.getColor(); 2005 GrColor color = grPaint.getColor();
1312 uint8_t paintAlpha = skPaint.getAlpha();
1313 for (int run = 0; run < cacheBlob->fRunCount; run++) { 2006 for (int run = 0; run < cacheBlob->fRunCount; run++) {
1314 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, 0, 0); 2007 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint);
1315 } 2008 }
1316 2009
1317 // Now flush big glyphs 2010 // Now flush big glyphs
1318 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); 2011 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
1319 } 2012 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698