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

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: windows warnigns 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
« no previous file with comments | « src/gpu/GrAtlasTextContext.h ('k') | src/gpu/GrContext.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
278 } 396 }
279 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat rix, blob, x, y, 397 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat rix, blob, x, y,
280 drawFilter, clipRect); 398 drawFilter, clipRect);
281 } 399 }
282 400
283 cacheBlob->fPaintColor = skPaint.getColor(); 401 cacheBlob->fPaintColor = skPaint.getColor();
284 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter, 402 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint , drawFilter,
285 clip, viewMatrix, clipBounds, x, y, transX, transY); 403 clip, viewMatrix, clipBounds, x, y, transX, transY);
286 } 404 }
287 405
406 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint,
407 const SkMatrix& viewMatr ix) {
408 // TODO: support perspective (need getMaxScale replacement)
409 if (viewMatrix.hasPerspective()) {
410 return false;
411 }
412
413 SkScalar maxScale = viewMatrix.getMaxScale();
414 SkScalar scaledTextSize = maxScale*skPaint.getTextSize();
415 // Hinted text looks far better at small resolutions
416 // Scaling up beyond 2x yields undesireable artifacts
417 if (scaledTextSize < kMinDFFontSize || scaledTextSize > 2 * kLargeDFFontSize ) {
418 return false;
419 }
420
421 if (!fEnableDFRendering && !skPaint.isDistanceFieldTextTEMP() &&
422 scaledTextSize < kLargeDFFontSize) {
423 return false;
424 }
425
426 // rasterizers and mask filters modify alpha, which doesn't
427 // translate well to distance
428 if (skPaint.getRasterizer() || skPaint.getMaskFilter() ||
429 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
430 return false;
431 }
432
433 // TODO: add some stroking support
434 if (skPaint.getStyle() != SkPaint::kFill_Style) {
435 return false;
436 }
437
438 return true;
439 }
440
288 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, 441 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob,
289 const SkPaint& skPaint, GrColor colo r, 442 const SkPaint& skPaint, GrColor colo r,
290 const SkMatrix& viewMatrix, 443 const SkMatrix& viewMatrix,
291 const SkTextBlob* blob, SkScalar x, SkScalar y, 444 const SkTextBlob* blob, SkScalar x, SkScalar y,
292 SkDrawFilter* drawFilter, const SkIR ect& clipRect) { 445 SkDrawFilter* drawFilter, const SkIR ect& clipRect) {
293 cacheBlob->fViewMatrix = viewMatrix; 446 cacheBlob->fViewMatrix = viewMatrix;
294 cacheBlob->fX = x; 447 cacheBlob->fX = x;
295 cacheBlob->fY = y; 448 cacheBlob->fY = y;
296 449
297 // Regenerate textblob 450 // Regenerate textblob
298 SkPaint runPaint = skPaint; 451 SkPaint runPaint = skPaint;
299 SkTextBlob::RunIterator it(blob); 452 SkTextBlob::RunIterator it(blob);
300 for (int run = 0; !it.done(); it.next(), run++) { 453 for (int run = 0; !it.done(); it.next(), run++) {
301 int glyphCount = it.glyphCount(); 454 int glyphCount = it.glyphCount();
302 size_t textLen = glyphCount * sizeof(uint16_t); 455 size_t textLen = glyphCount * sizeof(uint16_t);
303 const SkPoint& offset = it.offset(); 456 const SkPoint& offset = it.offset();
304 // applyFontToPaint() always overwrites the exact same attributes, 457 // applyFontToPaint() always overwrites the exact same attributes,
305 // so it is safe to not re-seed the paint for this reason. 458 // so it is safe to not re-seed the paint for this reason.
306 it.applyFontToPaint(&runPaint); 459 it.applyFontToPaint(&runPaint);
307 460
308 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) { 461 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) {
309 // A false return from filter() means we should abort the current dr aw. 462 // A false return from filter() means we should abort the current dr aw.
310 runPaint = skPaint; 463 runPaint = skPaint;
311 continue; 464 continue;
312 } 465 }
313 466
314 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); 467 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
315 468
316 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix); 469 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, &viewMatrix,
470 false);
317 471
318 // setup vertex / glyphIndex for the new run 472 // setup vertex / glyphIndex for the new run
319 if (run > 0) { 473 if (run > 0) {
320 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); 474 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back();
321 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( ); 475 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( );
322 476
323 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; 477 newRun.fVertexStartIndex = lastRun.fVertexEndIndex;
324 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; 478 newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
325 479
326 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; 480 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
327 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; 481 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
328 } 482 }
329 483
330 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { 484 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) {
331 cacheBlob->fRuns[run].fDrawAsPaths = true; 485 cacheBlob->fRuns[run].fDrawAsPaths = true;
332 continue; 486 continue;
333 } 487 }
334 cacheBlob->fRuns[run].fDrawAsPaths = false; 488 cacheBlob->fRuns[run].fDrawAsPaths = false;
335 489
336 switch (it.positioning()) { 490 switch (it.positioning()) {
337 case SkTextBlob::kDefault_Positioning: 491 case SkTextBlob::kDefault_Positioning:
338 this->internalDrawText(cacheBlob, run, cache, runPaint, color, v iewMatrix, 492 this->internalDrawBMPText(cacheBlob, run, cache, runPaint, color , viewMatrix,
339 (const char *)it.glyphs(), textLen, 493 (const char *)it.glyphs(), textLen,
340 x + offset.x(), y + offset.y(), clipRect) ; 494 x + offset.x(), y + offset.y(), clipRe ct);
341 break; 495 break;
342 case SkTextBlob::kHorizontal_Positioning: 496 case SkTextBlob::kHorizontal_Positioning:
343 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color , viewMatrix, 497 this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, co lor, viewMatrix,
344 (const char*)it.glyphs(), textLen, it. pos(), 1, 498 (const char*)it.glyphs(), textLen, it.pos(), 1,
345 SkPoint::Make(x, y + offset.y()), clip Rect); 499 SkPoint::Make(x, y + offset.y()), c lipRect);
346 break; 500 break;
347 case SkTextBlob::kFull_Positioning: 501 case SkTextBlob::kFull_Positioning:
348 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color , viewMatrix, 502 this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, co lor, viewMatrix,
349 (const char*)it.glyphs(), textLen, it. pos(), 2, 503 (const char*)it.glyphs(), textLen, it.pos(), 2,
350 SkPoint::Make(x, y), clipRect); 504 SkPoint::Make(x, y), clipRect);
351 break; 505 break;
352 } 506 }
353 507
354 if (drawFilter) { 508 if (drawFilter) {
355 // A draw filter may change the paint arbitrarily, so we must re-see d in this case. 509 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
356 runPaint = skPaint; 510 runPaint = skPaint;
357 } 511 }
358 512
359 SkGlyphCache::AttachCache(cache); 513 SkGlyphCache::AttachCache(cache);
360 } 514 }
361 } 515 }
362 516
517 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala r* textRatio,
518 const SkMatrix& viewMatri x) {
519 // getMaxScale doesn't support perspective, so neither do we at the moment
520 SkASSERT(!viewMatrix.hasPerspective());
521 SkScalar maxScale = viewMatrix.getMaxScale();
522 SkScalar textSize = skPaint->getTextSize();
523 SkScalar scaledTextSize = textSize;
524 // if we have non-unity scale, we need to choose our base text size
525 // based on the SkPaint's text size multiplied by the max scale factor
526 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
527 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
528 scaledTextSize *= maxScale;
529 }
530
531 if (scaledTextSize <= kSmallDFFontLimit) {
532 *textRatio = textSize / kSmallDFFontSize;
533 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize));
534 } else if (scaledTextSize <= kMediumDFFontLimit) {
535 *textRatio = textSize / kMediumDFFontSize;
536 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize));
537 } else {
538 *textRatio = textSize / kLargeDFFontSize;
539 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize));
540 }
541
542 skPaint->setLCDRenderText(false);
543 skPaint->setAutohinted(false);
544 skPaint->setHinting(SkPaint::kNormal_Hinting);
545 skPaint->setSubpixelText(true);
546 }
547
548 inline void GrAtlasTextContext::fallbackDrawPosText(GrRenderTarget* rt, const Gr Clip& clip,
549 const GrPaint& paint,
550 const SkPaint& skPaint,
551 const SkMatrix& viewMatrix,
552 const SkTDArray<char>& fallb ackTxt,
553 const SkTDArray<SkScalar>& f allbackPos,
554 int scalarsPerPosition,
555 const SkPoint& offset,
556 const SkIRect& clipRect) {
557 int glyphCount = fallbackTxt.count();
558 SkASSERT(glyphCount);
559 // TODO currently we have to create a whole new blob for fallback text. Thi s is because
560 // they have a different descriptor and we currently only have one descripto r per run.
561 // We should fix this and allow an override descriptor on each subrun
562 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex tVASize));
563 blob->fViewMatrix = viewMatrix;
564
565 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix , false);
566 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(), view Matrix,
567 fallbackTxt.begin(), fallbackTxt.count(),
568 fallbackPos.begin(), scalarsPerPosition, offset , clipRect);
569 SkGlyphCache::AttachCache(cache);
570 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
571 }
572
573 inline GrAtlasTextContext::BitmapTextBlob*
574 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint,
575 const SkMatrix& viewMatrix, SkGlyphCache** cache ,
576 SkPaint* dfPaint, SkScalar* textRatio) {
577 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize);
578
579 *dfPaint = origPaint;
580 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix);
581 blob->fViewMatrix = viewMatrix;
582 blob->fRuns[0].fSubRunInfo.back().fUseLCDText = origPaint.isLCDRenderText();
583 blob->fRuns[0].fSubRunInfo.back().fDrawAsDistanceFields = true;
584
585 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true);
586 return blob;
587 }
588
363 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, 589 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
364 const GrPaint& paint, const SkPaint& skPaint , 590 const GrPaint& paint, const SkPaint& skPaint ,
365 const SkMatrix& viewMatrix, 591 const SkMatrix& viewMatrix,
366 const char text[], size_t byteLength, 592 const char text[], size_t byteLength,
367 SkScalar x, SkScalar y, const SkIRect& regio nClipBounds) { 593 SkScalar x, SkScalar y, const SkIRect& regio nClipBounds) {
368 int glyphCount = skPaint.countText(text, byteLength); 594 int glyphCount = skPaint.countText(text, byteLength);
369 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex tVASize)); 595 SkIRect clipRect;
370 blob->fViewMatrix = viewMatrix; 596 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
371 blob->fX = x; 597
372 blob->fY = y; 598 // setup cache
599 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) {
600 SkPaint dfPaint;
601 SkScalar textRatio;
602 SkGlyphCache* cache;
603 SkAutoTUnref<BitmapTextBlob> blob(this->setupDFBlob(glyphCount, skPaint, viewMatrix, &cache,
604 &dfPaint, &textRatio ));
605
606 SkTDArray<char> fallbackTxt;
607 SkTDArray<SkScalar> fallbackPos;
608 SkPoint offset;
609 this->internalDrawDFText(blob, 0, cache, dfPaint, paint.getColor(), view Matrix, 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 if (fallbackTxt.count()) {
615 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fall backTxt,
616 fallbackPos, 2, offset, clipRect);
617 }
618 } else {
619 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra yTextVASize));
620 blob->fViewMatrix = viewMatrix;
621
622 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa trix, false);
623 this->internalDrawBMPText(blob, 0, cache, skPaint, paint.getColor(), vie wMatrix, text,
624 byteLength, x, y, clipRect);
625 SkGlyphCache::AttachCache(cache);
626 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
627 }
628 }
629
630 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
631 const GrPaint& paint, const SkPaint& skPa int,
632 const SkMatrix& viewMatrix,
633 const char text[], size_t byteLength,
634 const SkScalar pos[], int scalarsPerPosit ion,
635 const SkPoint& offset, const SkIRect& reg ionClipBounds) {
636 int glyphCount = skPaint.countText(text, byteLength);
373 637
374 SkIRect clipRect; 638 SkIRect clipRect;
375 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); 639 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
376 640
377 // setup cache 641 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) {
378 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ; 642 SkPaint dfPaint;
379 this->internalDrawText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix , text, byteLength, 643 SkScalar textRatio;
380 x, y, clipRect); 644 SkGlyphCache* cache;
381 SkGlyphCache::AttachCache(cache); 645 SkAutoTUnref<BitmapTextBlob> blob(this->setupDFBlob(glyphCount, skPaint, viewMatrix, &cache,
646 &dfPaint, &textRatio ));
382 647
383 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM atrix); 648 SkTDArray<char> fallbackTxt;
649 SkTDArray<SkScalar> fallbackPos;
650 this->internalDrawDFPosText(blob, 0, cache, dfPaint, paint.getColor(), v iewMatrix, text,
651 byteLength, pos, scalarsPerPosition, offset, clipRect,
652 textRatio, &fallbackTxt, &fallbackPos);
653 SkGlyphCache::AttachCache(cache);
654 this->flush(fContext->getTextTarget(), blob, rt, dfPaint, paint, clip);
655 if (fallbackTxt.count()) {
656 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fall backTxt,
657 fallbackPos, scalarsPerPosition, offset, c lipRect);
658 }
659 } else {
660 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra yTextVASize));
661 blob->fViewMatrix = viewMatrix;
662 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa trix, false);
663 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix, text,
664 byteLength, pos, scalarsPerPosition, offset , clipRect);
665 SkGlyphCache::AttachCache(cache);
666 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip);
667 }
384 } 668 }
385 669
386 void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, 670 void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex,
387 SkGlyphCache* cache, const SkPaint& sk Paint, 671 SkGlyphCache* cache, const SkPaint& skPaint,
388 GrColor color, 672 GrColor color,
389 const SkMatrix& viewMatrix, 673 const SkMatrix& viewMatrix,
390 const char text[], size_t byteLength, 674 const char text[], size_t byteLengt h,
391 SkScalar x, SkScalar y, const SkIRect& clipRect) { 675 SkScalar x, SkScalar y, const SkIRe ct& clipRect) {
392 SkASSERT(byteLength == 0 || text != NULL); 676 SkASSERT(byteLength == 0 || text != NULL);
393 677
394 // nothing to draw 678 // nothing to draw
395 if (text == NULL || byteLength == 0) { 679 if (text == NULL || byteLength == 0) {
396 return; 680 return;
397 } 681 }
398 682
399 fCurrStrike = NULL; 683 fCurrStrike = NULL;
400 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); 684 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
401 685
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
449 733
450 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); 734 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
451 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); 735 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
452 736
453 while (text < stop) { 737 while (text < stop) {
454 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask); 738 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask);
455 739
456 fx += autokern.adjust(glyph); 740 fx += autokern.adjust(glyph);
457 741
458 if (glyph.fWidth) { 742 if (glyph.fWidth) {
459 this->appendGlyph(blob, 743 this->bmpAppendGlyph(blob,
460 runIndex, 744 runIndex,
461 GrGlyph::Pack(glyph.getGlyphID(), 745 GrGlyph::Pack(glyph.getGlyphID(),
462 glyph.getSubXFixed(), 746 glyph.getSubXFixed(),
463 glyph.getSubYFixed(), 747 glyph.getSubYFixed(),
464 GrGlyph::kCoverage_MaskStyle), 748 GrGlyph::kCoverage_MaskStyle),
465 Sk48Dot16FloorToInt(fx), 749 Sk48Dot16FloorToInt(fx),
466 Sk48Dot16FloorToInt(fy), 750 Sk48Dot16FloorToInt(fy),
467 color, 751 color,
468 fontScaler, 752 fontScaler,
469 clipRect); 753 clipRect);
470 } 754 }
471 755
472 fx += glyph.fAdvanceX; 756 fx += glyph.fAdvanceX;
473 fy += glyph.fAdvanceY; 757 fy += glyph.fAdvanceY;
474 } 758 }
475 } 759 }
476 760
477 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, 761 void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runInd ex,
478 const GrPaint& paint, const SkPaint& skPa int, 762 SkGlyphCache* cache, const SkPai nt& skPaint,
479 const SkMatrix& viewMatrix, 763 GrColor color,
480 const char text[], size_t byteLength, 764 const SkMatrix& viewMatrix,
481 const SkScalar pos[], int scalarsPerPosit ion, 765 const char text[], size_t byteLe ngth,
482 const SkPoint& offset, const SkIRect& reg ionClipBounds) { 766 const SkScalar pos[], int scalar sPerPosition,
483 int glyphCount = skPaint.countText(text, byteLength); 767 const SkPoint& offset, const SkI Rect& clipRect) {
484 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex tVASize));
485 blob->fViewMatrix = viewMatrix;
486
487 SkIRect clipRect;
488 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
489
490 // setup cache
491 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ;
492 this->internalDrawPosText(blob, 0, cache, skPaint, paint.getColor(), viewMat rix, text,
493 byteLength, pos, scalarsPerPosition, offset, clipR ect);
494 SkGlyphCache::AttachCache(cache);
495
496 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM atrix);
497 }
498
499 void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex,
500 SkGlyphCache* cache, const SkPaint& skPaint,
501 GrColor color,
502 const SkMatrix& viewMatrix,
503 const char text[], size_t byteLengt h,
504 const SkScalar pos[], int scalarsPe rPosition,
505 const SkPoint& offset, const SkIRec t& clipRect) {
506 SkASSERT(byteLength == 0 || text != NULL); 768 SkASSERT(byteLength == 0 || text != NULL);
507 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 769 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
508 770
509 // nothing to draw 771 // nothing to draw
510 if (text == NULL || byteLength == 0) { 772 if (text == NULL || byteLength == 0) {
511 return; 773 return;
512 } 774 }
513 775
514 fCurrStrike = NULL; 776 fCurrStrike = NULL;
515 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); 777 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
(...skipping 25 matching lines...) Expand all
541 while (text < stop) { 803 while (text < stop) {
542 SkPoint tmsLoc; 804 SkPoint tmsLoc;
543 tmsProc(pos, &tmsLoc); 805 tmsProc(pos, &tmsLoc);
544 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); 806 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX);
545 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); 807 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY);
546 808
547 const SkGlyph& glyph = glyphCacheProc(cache, &text, 809 const SkGlyph& glyph = glyphCacheProc(cache, &text,
548 fx & fxMask, fy & fyMask); 810 fx & fxMask, fy & fyMask);
549 811
550 if (glyph.fWidth) { 812 if (glyph.fWidth) {
551 this->appendGlyph(blob, 813 this->bmpAppendGlyph(blob,
552 runIndex, 814 runIndex,
553 GrGlyph::Pack(glyph.getGlyphID(), 815 GrGlyph::Pack(glyph.getGlyphID(),
554 glyph.getSubXFixed(), 816 glyph.getSubXFixed(),
555 glyph.getSubYFixed(), 817 glyph.getSubYFixed(),
556 GrGlyph::kCoverage_MaskStyle ), 818 GrGlyph::kCoverage_MaskSt yle),
557 Sk48Dot16FloorToInt(fx), 819 Sk48Dot16FloorToInt(fx),
558 Sk48Dot16FloorToInt(fy), 820 Sk48Dot16FloorToInt(fy),
559 color, 821 color,
560 fontScaler, 822 fontScaler,
561 clipRect); 823 clipRect);
562 } 824 }
563 pos += scalarsPerPosition; 825 pos += scalarsPerPosition;
564 } 826 }
565 } else { 827 } else {
566 while (text < stop) { 828 while (text < stop) {
567 const char* currentText = text; 829 const char* currentText = text;
568 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 830 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
569 831
570 if (metricGlyph.fWidth) { 832 if (metricGlyph.fWidth) {
571 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 833 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
572 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 834 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
573 SkPoint tmsLoc; 835 SkPoint tmsLoc;
574 tmsProc(pos, &tmsLoc); 836 tmsProc(pos, &tmsLoc);
575 SkPoint alignLoc; 837 SkPoint alignLoc;
576 alignProc(tmsLoc, metricGlyph, &alignLoc); 838 alignProc(tmsLoc, metricGlyph, &alignLoc);
577 839
578 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); 840 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX);
579 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); 841 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY);
580 842
581 // have to call again, now that we've been "aligned" 843 // have to call again, now that we've been "aligned"
582 const SkGlyph& glyph = glyphCacheProc(cache, &currentText, 844 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
583 fx & fxMask, fy & fyMa sk); 845 fx & fxMask, fy & fyMa sk);
584 // the assumption is that the metrics haven't changed 846 // the assumption is that the metrics haven't changed
585 SkASSERT(prevAdvX == glyph.fAdvanceX); 847 SkASSERT(prevAdvX == glyph.fAdvanceX);
586 SkASSERT(prevAdvY == glyph.fAdvanceY); 848 SkASSERT(prevAdvY == glyph.fAdvanceY);
587 SkASSERT(glyph.fWidth); 849 SkASSERT(glyph.fWidth);
588 850
589 this->appendGlyph(blob, 851 this->bmpAppendGlyph(blob,
590 runIndex, 852 runIndex,
591 GrGlyph::Pack(glyph.getGlyphID(), 853 GrGlyph::Pack(glyph.getGlyphID(),
592 glyph.getSubXFixed(), 854 glyph.getSubXFixed(),
593 glyph.getSubYFixed(), 855 glyph.getSubYFixed(),
594 GrGlyph::kCoverage_MaskStyle ), 856 GrGlyph::kCoverage_MaskSt yle),
595 Sk48Dot16FloorToInt(fx), 857 Sk48Dot16FloorToInt(fx),
596 Sk48Dot16FloorToInt(fy), 858 Sk48Dot16FloorToInt(fy),
597 color, 859 color,
598 fontScaler, 860 fontScaler,
599 clipRect); 861 clipRect);
600 } 862 }
601 pos += scalarsPerPosition; 863 pos += scalarsPerPosition;
602 } 864 }
603 } 865 }
604 } else { // not subpixel 866 } else { // not subpixel
605 867
606 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { 868 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
607 while (text < stop) { 869 while (text < stop) {
608 // the last 2 parameters are ignored 870 // the last 2 parameters are ignored
609 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 871 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
610 872
611 if (glyph.fWidth) { 873 if (glyph.fWidth) {
612 SkPoint tmsLoc; 874 SkPoint tmsLoc;
613 tmsProc(pos, &tmsLoc); 875 tmsProc(pos, &tmsLoc);
614 876
615 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX; 877 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
616 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY; 878 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
617 this->appendGlyph(blob, 879 this->bmpAppendGlyph(blob,
618 runIndex, 880 runIndex,
619 GrGlyph::Pack(glyph.getGlyphID(), 881 GrGlyph::Pack(glyph.getGlyphID(),
620 glyph.getSubXFixed(), 882 glyph.getSubXFixed(),
621 glyph.getSubYFixed(), 883 glyph.getSubYFixed(),
622 GrGlyph::kCoverage_MaskStyle ), 884 GrGlyph::kCoverage_MaskSt yle),
623 Sk48Dot16FloorToInt(fx), 885 Sk48Dot16FloorToInt(fx),
624 Sk48Dot16FloorToInt(fy), 886 Sk48Dot16FloorToInt(fy),
625 color, 887 color,
626 fontScaler, 888 fontScaler,
627 clipRect); 889 clipRect);
628 } 890 }
629 pos += scalarsPerPosition; 891 pos += scalarsPerPosition;
630 } 892 }
631 } else { 893 } else {
632 while (text < stop) { 894 while (text < stop) {
633 // the last 2 parameters are ignored 895 // the last 2 parameters are ignored
634 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 896 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
635 897
636 if (glyph.fWidth) { 898 if (glyph.fWidth) {
637 SkPoint tmsLoc; 899 SkPoint tmsLoc;
638 tmsProc(pos, &tmsLoc); 900 tmsProc(pos, &tmsLoc);
639 901
640 SkPoint alignLoc; 902 SkPoint alignLoc;
641 alignProc(tmsLoc, glyph, &alignLoc); 903 alignProc(tmsLoc, glyph, &alignLoc);
642 904
643 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX; 905 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX;
644 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY; 906 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY;
645 this->appendGlyph(blob, 907 this->bmpAppendGlyph(blob,
646 runIndex, 908 runIndex,
647 GrGlyph::Pack(glyph.getGlyphID(), 909 GrGlyph::Pack(glyph.getGlyphID(),
648 glyph.getSubXFixed(), 910 glyph.getSubXFixed(),
649 glyph.getSubYFixed(), 911 glyph.getSubYFixed(),
650 GrGlyph::kCoverage_MaskStyle ), 912 GrGlyph::kCoverage_MaskSt yle),
651 Sk48Dot16FloorToInt(fx), 913 Sk48Dot16FloorToInt(fx),
652 Sk48Dot16FloorToInt(fy), 914 Sk48Dot16FloorToInt(fy),
653 color, 915 color,
654 fontScaler, 916 fontScaler,
655 clipRect); 917 clipRect);
656 } 918 }
657 pos += scalarsPerPosition; 919 pos += scalarsPerPosition;
658 } 920 }
659 } 921 }
660 } 922 }
661 } 923 }
662 924
663 void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph ::PackedID packed, 925
664 int vx, int vy, GrColor color, GrFontScaler * scaler, 926 void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex,
665 const SkIRect& clipRect) { 927 SkGlyphCache* cache, const SkPaint& skPaint,
666 if (NULL == fCurrStrike) { 928 GrColor color,
929 const SkMatrix& viewMatrix,
930 const char text[], size_t byteLength ,
931 SkScalar x, SkScalar y, const SkIRec t& clipRect,
932 SkScalar textRatio,
933 SkTDArray<char>* fallbackTxt,
934 SkTDArray<SkScalar>* fallbackPos,
935 SkPoint* offset,
936 const SkPaint& origPaint) {
937 SkASSERT(byteLength == 0 || text != NULL);
938
939 // nothing to draw
940 if (text == NULL || byteLength == 0) {
941 return;
942 }
943
944 SkDrawCacheProc glyphCacheProc = origPaint.getDrawCacheProc();
945 SkAutoDescriptor desc;
946 origPaint.getScalerContextDescriptor(&desc, &fDeviceProperties, NULL, true);
947 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(origPaint.getTypefa ce(),
948 desc.getDesc());
949
950 SkTArray<SkScalar> positions;
951
952 const char* textPtr = text;
953 SkFixed stopX = 0;
954 SkFixed stopY = 0;
955 SkFixed origin = 0;
956 switch (origPaint.getTextAlign()) {
957 case SkPaint::kRight_Align: origin = SK_Fixed1; break;
958 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
959 case SkPaint::kLeft_Align: origin = 0; break;
960 }
961
962 SkAutoKern autokern;
963 const char* stop = text + byteLength;
964 while (textPtr < stop) {
965 // don't need x, y here, since all subpixel variants will have the
966 // same advance
967 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0);
968
969 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
970 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));
971
972 SkFixed height = glyph.fAdvanceY;
973 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))) ;
974
975 stopX += width;
976 stopY += height;
977 }
978 SkASSERT(textPtr == stop);
979
980 // now adjust starting point depending on alignment
981 SkScalar alignX = SkFixedToScalar(stopX);
982 SkScalar alignY = SkFixedToScalar(stopY);
983 if (origPaint.getTextAlign() == SkPaint::kCenter_Align) {
984 alignX = SkScalarHalf(alignX);
985 alignY = SkScalarHalf(alignY);
986 } else if (origPaint.getTextAlign() == SkPaint::kLeft_Align) {
987 alignX = 0;
988 alignY = 0;
989 }
990 x -= alignX;
991 y -= alignY;
992 *offset = SkPoint::Make(x, y);
993
994 this->internalDrawDFPosText(blob, runIndex, cache, skPaint, color, viewMatri x, text, byteLength,
995 positions.begin(), 2, *offset, clipRect, textRat io, fallbackTxt,
996 fallbackPos);
997 SkGlyphCache::AttachCache(origPaintCache);
998 }
999
1000 void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runInde x,
1001 SkGlyphCache* cache, const SkPain t& skPaint,
1002 GrColor color,
1003 const SkMatrix& viewMatrix,
1004 const char text[], size_t byteLen gth,
1005 const SkScalar pos[], int scalars PerPosition,
1006 const SkPoint& offset, const SkIR ect& clipRect,
1007 SkScalar textRatio,
1008 SkTDArray<char>* fallbackTxt,
1009 SkTDArray<SkScalar>* fallbackPos) {
1010
1011 SkASSERT(byteLength == 0 || text != NULL);
1012 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1013
1014 // nothing to draw
1015 if (text == NULL || byteLength == 0) {
1016 return;
1017 }
1018
1019 fCurrStrike = NULL;
1020
1021 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
1022 GrFontScaler* fontScaler = GetGrFontScaler(cache);
1023
1024 const char* stop = text + byteLength;
1025
1026 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
1027 while (text < stop) {
1028 const char* lastText = text;
1029 // the last 2 parameters are ignored
1030 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1031
1032 if (glyph.fWidth) {
1033 SkScalar x = offset.x() + pos[0];
1034 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
1035
1036 if (!this->dfAppendGlyph(blob,
1037 runIndex,
1038 GrGlyph::Pack(glyph.getGlyphID(),
1039 glyph.getSubXFixed(),
1040 glyph.getSubYFixed(),
1041 GrGlyph::kDistance_MaskSt yle),
1042 x, y, color, fontScaler, clipRect,
1043 textRatio, viewMatrix)) {
1044 // couldn't append, send to fallback
1045 fallbackTxt->append(SkToInt(text-lastText), lastText);
1046 *fallbackPos->append() = pos[0];
1047 if (2 == scalarsPerPosition) {
1048 *fallbackPos->append() = pos[1];
1049 }
1050 }
1051 }
1052 pos += scalarsPerPosition;
1053 }
1054 } else {
1055 SkScalar alignMul = SkPaint::kCenter_Align == skPaint.getTextAlign() ? S K_ScalarHalf
1056 : S K_Scalar1;
1057 while (text < stop) {
1058 const char* lastText = text;
1059 // the last 2 parameters are ignored
1060 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1061
1062 if (glyph.fWidth) {
1063 SkScalar x = offset.x() + pos[0];
1064 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
1065
1066 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio;
1067 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio;
1068
1069 if (!this->dfAppendGlyph(blob,
1070 runIndex,
1071 GrGlyph::Pack(glyph.getGlyphID(),
1072 glyph.getSubXFixed(),
1073 glyph.getSubYFixed(),
1074 GrGlyph::kDistance_MaskSt yle),
1075 x - advanceX, y - advanceY, color,
1076 fontScaler,
1077 clipRect,
1078 textRatio,
1079 viewMatrix)) {
1080 // couldn't append, send to fallback
1081 fallbackTxt->append(SkToInt(text-lastText), lastText);
1082 *fallbackPos->append() = pos[0];
1083 if (2 == scalarsPerPosition) {
1084 *fallbackPos->append() = pos[1];
1085 }
1086 }
1087 }
1088 pos += scalarsPerPosition;
1089 }
1090 }
1091 }
1092
1093 void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex,
1094 GrGlyph::PackedID packed,
1095 int vx, int vy, GrColor color, GrFontSca ler* scaler,
1096 const SkIRect& clipRect) {
1097 if (!fCurrStrike) {
667 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); 1098 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
668 } 1099 }
669 1100
670 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); 1101 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
671 if (NULL == glyph || glyph->fBounds.isEmpty()) { 1102 if (!glyph || glyph->fBounds.isEmpty()) {
672 return; 1103 return;
673 } 1104 }
674 1105
675 int x = vx + glyph->fBounds.fLeft; 1106 int x = vx + glyph->fBounds.fLeft;
676 int y = vy + glyph->fBounds.fTop; 1107 int y = vy + glyph->fBounds.fTop;
677 1108
678 // keep them as ints until we've done the clip-test 1109 // keep them as ints until we've done the clip-test
679 int width = glyph->fBounds.width(); 1110 int width = glyph->fBounds.width();
680 int height = glyph->fBounds.height(); 1111 int height = glyph->fBounds.height();
681 1112
682 #if 0 1113 #if 0
683 // Not checking the clip bounds might introduce a performance regression. H owever, its not 1114 // Not checking the clip bounds might introduce a performance regression. H owever, its not
684 // clear if this is still true today with the larger tiles we use in Chrome. For repositionable 1115 // clear if this is still true today with the larger tiles we use in Chrome. For repositionable
685 // blobs, we want to make sure we have all of the glyphs, so clipping them o ut is not ideal. 1116 // blobs, we want to make sure we have all of the glyphs, so clipping them o ut is not ideal.
686 // We could store the cliprect in the key, but then we'd lose the ability to do integer scrolls 1117 // We could store the cliprect in the key, but then we'd lose the ability to do integer scrolls
687 // TODO verify this 1118 // TODO verify this
688 // check if we clipped out 1119 // check if we clipped out
689 if (clipRect.quickReject(x, y, x + width, y + height)) { 1120 if (clipRect.quickReject(x, y, x + width, y + height)) {
690 return; 1121 return;
691 } 1122 }
692 #endif 1123 #endif
693 1124
694 // If the glyph is too large we fall back to paths 1125 // If the glyph is too large we fall back to paths
695 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { 1126 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
696 if (NULL == glyph->fPath) { 1127 this->appendGlyphPath(blob, glyph, scaler, vx, vy);
697 SkPath* path = SkNEW(SkPath);
698 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
699 // flag the glyph as being dead?
700 SkDELETE(path);
701 return;
702 }
703 glyph->fPath = path;
704 }
705 SkASSERT(glyph->fPath);
706 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v y));
707 return; 1128 return;
708 } 1129 }
709 1130
710 Run& run = blob->fRuns[runIndex]; 1131 Run& run = blob->fRuns[runIndex];
711 1132
712 GrMaskFormat format = glyph->fMaskFormat; 1133 GrMaskFormat format = glyph->fMaskFormat;
713 1134
714 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); 1135 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
715 if (run.fInitialized && subRun->fMaskFormat != format) { 1136 if (run.fInitialized && subRun->fMaskFormat != format) {
716 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back(); 1137 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back();
717 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex; 1138 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex;
718 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex; 1139 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex;
719 1140
720 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex; 1141 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex;
721 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex; 1142 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex;
722 1143
723 subRun = newSubRun; 1144 subRun = newSubRun;
724 } 1145 }
725 1146
726 run.fInitialized = true; 1147 run.fInitialized = true;
727 subRun->fMaskFormat = format;
728 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
729 1148
730 size_t vertexStride = get_vertex_stride(format); 1149 size_t vertexStride = get_vertex_stride(format);
731 1150
732 SkRect r; 1151 SkRect r;
733 r.fLeft = SkIntToScalar(x); 1152 r.fLeft = SkIntToScalar(x);
734 r.fTop = SkIntToScalar(y); 1153 r.fTop = SkIntToScalar(y);
735 r.fRight = r.fLeft + SkIntToScalar(width); 1154 r.fRight = r.fLeft + SkIntToScalar(width);
736 r.fBottom = r.fTop + SkIntToScalar(height); 1155 r.fBottom = r.fTop + SkIntToScalar(height);
1156 subRun->fMaskFormat = format;
1157 this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMa skFormat == format,
1158 packed);
1159 }
737 1160
738 run.fVertexBounds.joinNonEmptyArg(r); 1161 bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex,
739 run.fColor = color; 1162 GrGlyph::PackedID packed,
1163 SkScalar sx, SkScalar sy, GrColor color,
1164 GrFontScaler* scaler,
1165 const SkIRect& clipRect,
1166 SkScalar textRatio, const SkMatrix& viewM atrix) {
1167 if (!fCurrStrike) {
1168 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
1169 }
1170
1171 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
1172 if (!glyph || glyph->fBounds.isEmpty()) {
1173 return true;
1174 }
1175
1176 // fallback to color glyph support
1177 if (kA8_GrMaskFormat != glyph->fMaskFormat) {
1178 return false;
1179 }
1180
1181 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
1182 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
1183 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField Inset);
1184 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie ldInset);
1185
1186 SkScalar scale = textRatio;
1187 dx *= scale;
1188 dy *= scale;
1189 width *= scale;
1190 height *= scale;
1191 sx += dx;
1192 sy += dy;
1193 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
1194
1195 #if 0
1196 // check if we clipped out
1197 SkRect dstRect;
1198 viewMatrix.mapRect(&dstRect, glyphRect);
1199 if (clipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
1200 SkScalarTruncToInt(dstRect.top()),
1201 SkScalarTruncToInt(dstRect.right()),
1202 SkScalarTruncToInt(dstRect.bottom()))) {
1203 return true;
1204 }
1205 #endif
1206
1207 // TODO combine with the above
1208 // If the glyph is too large we fall back to paths
1209 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
1210 this->appendGlyphPath(blob, glyph, scaler, SkScalarRoundToInt(sx - dx),
1211 SkScalarRoundToInt(sy - dy));
1212 return true;
1213 }
1214
1215 Run& run = blob->fRuns[runIndex];
1216
1217 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
1218 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat);
1219 subRun->fMaskFormat = kA8_GrMaskFormat;
1220
1221 size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCD Text);
1222
1223 bool useColorVerts = !subRun->fUseLCDText;
1224 this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride, useColorVerts,
1225 packed);
1226 return true;
1227 }
1228
1229 inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* g lyph,
1230 GrFontScaler* scaler, int x, int y) {
1231 if (NULL == glyph->fPath) {
1232 SkPath* path = SkNEW(SkPath);
1233 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
1234 // flag the glyph as being dead?
1235 SkDELETE(path);
1236 return;
1237 }
1238 glyph->fPath = path;
1239 }
1240 SkASSERT(glyph->fPath);
1241 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y));
1242 }
1243
1244 inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run ,
1245 Run::SubRunInfo* subRun,
1246 const SkRect& positions, GrCol or color,
1247 size_t vertexStride, bool useV ertexColor,
1248 GrGlyph::PackedID packed) {
1249 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
1250 run->fVertexBounds.joinNonEmptyArg(positions);
1251 run->fColor = color;
740 1252
741 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); 1253 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex);
742 1254
743 // V0 1255 // V0
744 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); 1256 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
745 position->set(r.fLeft, r.fTop); 1257 position->set(positions.fLeft, positions.fTop);
746 if (kA8_GrMaskFormat == format) { 1258 if (useVertexColor) {
747 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1259 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
748 *colorPtr = color; 1260 *colorPtr = color;
749 } 1261 }
750 vertex += vertexStride; 1262 vertex += vertexStride;
1263
751 // V1 1264 // V1
752 position = reinterpret_cast<SkPoint*>(vertex); 1265 position = reinterpret_cast<SkPoint*>(vertex);
753 position->set(r.fLeft, r.fBottom); 1266 position->set(positions.fLeft, positions.fBottom);
754 if (kA8_GrMaskFormat == format) { 1267 if (useVertexColor) {
755 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1268 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
756 *colorPtr = color; 1269 *colorPtr = color;
757 } 1270 }
758 vertex += vertexStride; 1271 vertex += vertexStride;
759 1272
760 // V2 1273 // V2
761 position = reinterpret_cast<SkPoint*>(vertex); 1274 position = reinterpret_cast<SkPoint*>(vertex);
762 position->set(r.fRight, r.fBottom); 1275 position->set(positions.fRight, positions.fBottom);
763 if (kA8_GrMaskFormat == format) { 1276 if (useVertexColor) {
764 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1277 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
765 *colorPtr = color; 1278 *colorPtr = color;
766 } 1279 }
767 vertex += vertexStride; 1280 vertex += vertexStride;
768 1281
769 // V3 1282 // V3
770 position = reinterpret_cast<SkPoint*>(vertex); 1283 position = reinterpret_cast<SkPoint*>(vertex);
771 position->set(r.fRight, r.fTop); 1284 position->set(positions.fRight, positions.fTop);
772 if (kA8_GrMaskFormat == format) { 1285 if (useVertexColor) {
773 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1286 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
774 *colorPtr = color; 1287 *colorPtr = color;
775 } 1288 }
776 1289
777 subRun->fGlyphEndIndex++; 1290 subRun->fGlyphEndIndex++;
778 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; 1291 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
779 } 1292 }
780 1293
781 class BitmapTextBatch : public GrBatch { 1294 class BitmapTextBatch : public GrBatch {
782 public: 1295 public:
1296 typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable;
783 typedef GrAtlasTextContext::BitmapTextBlob Blob; 1297 typedef GrAtlasTextContext::BitmapTextBlob Blob;
784 typedef Blob::Run Run; 1298 typedef Blob::Run Run;
785 typedef Run::SubRunInfo TextInfo; 1299 typedef Run::SubRunInfo TextInfo;
786 struct Geometry { 1300 struct Geometry {
787 Blob* fBlob; 1301 Blob* fBlob;
788 int fRun; 1302 int fRun;
789 int fSubRun; 1303 int fSubRun;
790 GrColor fColor; 1304 GrColor fColor;
791 SkScalar fTransX; 1305 SkScalar fTransX;
792 SkScalar fTransY; 1306 SkScalar fTransY;
793 }; 1307 };
794 1308
795 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, 1309 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
796 GrBatchFontCache* fontCache) { 1310 GrBatchFontCache* fontCache) {
797 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache)); 1311 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache));
798 } 1312 }
799 1313
1314 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
1315 GrBatchFontCache* fontCache,
1316 DistanceAdjustTable* distanceAdjustTable,
1317 SkColor filteredColor, bool useLCDText,
1318 bool useBGR, float gamma) {
1319 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache, d istanceAdjustTable,
1320 filteredColor, useLCDText, useBGR, g amma));
1321 }
1322
800 const char* name() const override { return "BitmapTextBatch"; } 1323 const char* name() const override { return "BitmapTextBatch"; }
801 1324
802 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { 1325 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
803 if (kARGB_GrMaskFormat == fMaskFormat) { 1326 if (kARGB_GrMaskFormat == fMaskFormat) {
804 out->setUnknownFourComponents(); 1327 out->setUnknownFourComponents();
805 } else { 1328 } else {
806 out->setKnownFourComponents(fBatch.fColor); 1329 out->setKnownFourComponents(fBatch.fColor);
807 } 1330 }
808 } 1331 }
809 1332
810 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { 1333 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
811 if (kARGB_GrMaskFormat != fMaskFormat) { 1334 if (!fUseDistanceFields) {
812 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) { 1335 // Bitmap Text
1336 if (kARGB_GrMaskFormat != fMaskFormat) {
1337 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
1338 out->setUnknownSingleComponent();
1339 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
1340 out->setUnknownOpaqueFourComponents();
1341 out->setUsingLCDCoverage();
1342 } else {
1343 out->setUnknownFourComponents();
1344 out->setUsingLCDCoverage();
1345 }
1346 } else {
1347 out->setKnownSingleComponent(0xff);
1348 }
1349 } else {
1350 // Distance fields
1351 if (!fUseLCDText) {
813 out->setUnknownSingleComponent(); 1352 out->setUnknownSingleComponent();
814 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
815 out->setUnknownOpaqueFourComponents();
816 out->setUsingLCDCoverage();
817 } else { 1353 } else {
818 out->setUnknownFourComponents(); 1354 out->setUnknownFourComponents();
819 out->setUsingLCDCoverage(); 1355 out->setUsingLCDCoverage();
820 } 1356 }
821 } else {
822 out->setKnownSingleComponent(0xff);
823 } 1357 }
824 } 1358 }
825 1359
826 void initBatchTracker(const GrPipelineInfo& init) override { 1360 void initBatchTracker(const GrPipelineInfo& init) override {
827 // Handle any color overrides 1361 // Handle any color overrides
828 if (init.fColorIgnored) { 1362 if (init.fColorIgnored) {
829 fBatch.fColor = GrColor_ILLEGAL; 1363 fBatch.fColor = GrColor_ILLEGAL;
830 } else if (GrColor_ILLEGAL != init.fOverrideColor) { 1364 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
831 fBatch.fColor = init.fOverrideColor; 1365 fBatch.fColor = init.fOverrideColor;
832 } 1366 }
(...skipping 12 matching lines...) Expand all
845 SkDebugf("Cannot invert viewmatrix\n"); 1379 SkDebugf("Cannot invert viewmatrix\n");
846 return; 1380 return;
847 } 1381 }
848 1382
849 GrTexture* texture = fFontCache->getTexture(fMaskFormat); 1383 GrTexture* texture = fFontCache->getTexture(fMaskFormat);
850 if (!texture) { 1384 if (!texture) {
851 SkDebugf("Could not allocate backing texture for atlas\n"); 1385 SkDebugf("Could not allocate backing texture for atlas\n");
852 return; 1386 return;
853 } 1387 }
854 1388
855 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode); 1389 SkAutoTUnref<const GrGeometryProcessor> gp;
1390 if (fUseDistanceFields) {
1391 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(),
1392 texture));
1393 } else {
1394 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k None_FilterMode);
856 1395
857 // This will be ignored in the non A8 case 1396 // This will be ignored in the non A8 case
858 bool opaqueVertexColors = GrColorIsOpaque(this->color()); 1397 bool opaqueVertexColors = GrColorIsOpaque(this->color());
859 SkAutoTUnref<const GrGeometryProcessor> gp( 1398 gp.reset(GrBitmapTextGeoProc::Create(this->color(),
860 GrBitmapTextGeoProc::Create(this->color(), 1399 texture,
861 texture, 1400 params,
862 params, 1401 fMaskFormat,
863 fMaskFormat, 1402 opaqueVertexColors,
864 opaqueVertexColors, 1403 localMatrix));
865 localMatrix)); 1404 }
866 1405
867 size_t vertexStride = gp->getVertexStride(); 1406 size_t vertexStride = gp->getVertexStride();
868 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat)); 1407 SkASSERT(vertexStride == (fUseDistanceFields ?
1408 get_vertex_stride_df(fMaskFormat, fUseLCDText) :
1409 get_vertex_stride(fMaskFormat)));
869 1410
870 this->initDraw(batchTarget, gp, pipeline); 1411 this->initDraw(batchTarget, gp, pipeline);
871 1412
872 int glyphCount = this->numGlyphs(); 1413 int glyphCount = this->numGlyphs();
873 int instanceCount = fInstanceCount; 1414 int instanceCount = fInstanceCount;
874 const GrVertexBuffer* vertexBuffer; 1415 const GrVertexBuffer* vertexBuffer;
875 int firstVertex; 1416 int firstVertex;
876 1417
877 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, 1418 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
878 glyphCount * kVert icesPerGlyph, 1419 glyphCount * kVert icesPerGlyph,
(...skipping 22 matching lines...) Expand all
901 1442
902 int instancesToFlush = 0; 1443 int instancesToFlush = 0;
903 for (int i = 0; i < instanceCount; i++) { 1444 for (int i = 0; i < instanceCount; i++) {
904 Geometry& args = fGeoData[i]; 1445 Geometry& args = fGeoData[i];
905 Blob* blob = args.fBlob; 1446 Blob* blob = args.fBlob;
906 Run& run = blob->fRuns[args.fRun]; 1447 Run& run = blob->fRuns[args.fRun];
907 TextInfo& info = run.fSubRunInfo[args.fSubRun]; 1448 TextInfo& info = run.fSubRunInfo[args.fSubRun];
908 1449
909 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); 1450 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
910 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; 1451 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen;
911 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; 1452 bool regenerateColors;
1453 if (fUseDistanceFields) {
1454 regenerateColors = fUseLCDText && run.fColor != args.fColor;
1455 } else {
1456 regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
1457 }
912 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f; 1458 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f;
913 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1459 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
914 1460
915 // We regenerate both texture coords and colors in the blob itself, and update the 1461 // We regenerate both texture coords and colors in the blob itself, and update the
916 // atlas generation. If we don't end up purging any unused plots, w e can avoid 1462 // atlas generation. If we don't end up purging any unused plots, w e can avoid
917 // regenerating the coords. We could take a finer grained approach to updating texture 1463 // regenerating the coords. We could take a finer grained approach to updating texture
918 // coords but its not clear if the extra bookkeeping would offset an y gains. 1464 // coords but its not clear if the extra bookkeeping would offset an y gains.
919 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color 1465 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color
920 // or coords as needed. One final note, if we have to break a run f or an atlas eviction 1466 // or coords as needed. One final note, if we have to break a run f or an atlas eviction
921 // then we can't really trust the atlas has all of the correct data. Atlas evictions 1467 // 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
1022 // to avoid even the initial copy of the struct, we have a getter for the fi rst item which 1568 // to avoid even the initial copy of the struct, we have a getter for the fi rst item which
1023 // is used to seed the batch with its initial geometry. After seeding, the client should call 1569 // is used to seed the batch with its initial geometry. After seeding, the client should call
1024 // init() so the Batch can initialize itself 1570 // init() so the Batch can initialize itself
1025 Geometry& geometry() { return fGeoData[0]; } 1571 Geometry& geometry() { return fGeoData[0]; }
1026 void init() { 1572 void init() {
1027 fBatch.fColor = fGeoData[0].fColor; 1573 fBatch.fColor = fGeoData[0].fColor;
1028 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix; 1574 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix;
1029 } 1575 }
1030 1576
1031 private: 1577 private:
1032 BitmapTextBatch(GrMaskFormat maskFormat, 1578 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache)
1033 int glyphCount, GrBatchFontCache* fontCache)
1034 : fMaskFormat(maskFormat) 1579 : fMaskFormat(maskFormat)
1035 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) 1580 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1036 , fFontCache(fontCache) { 1581 , fFontCache(fontCache)
1582 , fUseDistanceFields(false) {
1037 this->initClassID<BitmapTextBatch>(); 1583 this->initClassID<BitmapTextBatch>();
1038 fBatch.fNumGlyphs = glyphCount; 1584 fBatch.fNumGlyphs = glyphCount;
1039 fInstanceCount = 1; 1585 fInstanceCount = 1;
1040 fAllocatedCount = kMinAllocated; 1586 fAllocatedCount = kMinAllocated;
1041 } 1587 }
1042 1588
1589 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache,
1590 DistanceAdjustTable* distanceAdjustTable, SkColor filteredCo lor,
1591 bool useLCDText, bool useBGR, float gamma)
1592 : fMaskFormat(maskFormat)
1593 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1594 , fFontCache(fontCache)
1595 , fDistanceAdjustTable(SkRef(distanceAdjustTable))
1596 , fFilteredColor(filteredColor)
1597 , fUseDistanceFields(true)
1598 , fUseLCDText(useLCDText)
1599 , fUseBGR(useBGR)
1600 , fGamma(gamma) {
1601 this->initClassID<BitmapTextBatch>();
1602 fBatch.fNumGlyphs = glyphCount;
1603 fInstanceCount = 1;
1604 fAllocatedCount = kMinAllocated;
1605 SkASSERT(fMaskFormat == kA8_GrMaskFormat);
1606 }
1607
1043 ~BitmapTextBatch() { 1608 ~BitmapTextBatch() {
1044 for (int i = 0; i < fInstanceCount; i++) { 1609 for (int i = 0; i < fInstanceCount; i++) {
1045 fGeoData[i].fBlob->unref(); 1610 fGeoData[i].fBlob->unref();
1046 } 1611 }
1047 } 1612 }
1048 1613
1049 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) { 1614 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) {
1050 int width = glyph->fBounds.width(); 1615 int width = glyph->fBounds.width();
1051 int height = glyph->fBounds.height(); 1616 int height = glyph->fBounds.height();
1052 int u0 = glyph->fAtlasLocation.fX;
1053 int v0 = glyph->fAtlasLocation.fY;
1054 int u1 = u0 + width;
1055 int v1 = v0 + height;
1056 1617
1057 // we assume texture coords are the last vertex attribute, this is a bit fragile. 1618 int u0, v0, u1, v1;
1058 // TODO pass in this offset or something 1619 if (fUseDistanceFields) {
1620 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
1621 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
1622 u1 = u0 + width - 2 * SK_DistanceFieldInset;
1623 v1 = v0 + height - 2 * SK_DistanceFieldInset;
1624 } else {
1625 u0 = glyph->fAtlasLocation.fX;
1626 v0 = glyph->fAtlasLocation.fY;
1627 u1 = u0 + width;
1628 v1 = v0 + height;
1629 }
1630
1059 SkIPoint16* textureCoords; 1631 SkIPoint16* textureCoords;
1060 // V0 1632 // V0
1061 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1633 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1062 textureCoords->set(u0, v0); 1634 textureCoords->set(u0, v0);
1063 vertex += vertexStride; 1635 vertex += vertexStride;
1064 1636
1065 // V1 1637 // V1
1066 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1638 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1067 textureCoords->set(u0, v1); 1639 textureCoords->set(u0, v1);
1068 vertex += vertexStride; 1640 vertex += vertexStride;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1126 } 1698 }
1127 1699
1128 GrColor color() const { return fBatch.fColor; } 1700 GrColor color() const { return fBatch.fColor; }
1129 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } 1701 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1130 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 1702 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1131 int numGlyphs() const { return fBatch.fNumGlyphs; } 1703 int numGlyphs() const { return fBatch.fNumGlyphs; }
1132 1704
1133 bool onCombineIfPossible(GrBatch* t) override { 1705 bool onCombineIfPossible(GrBatch* t) override {
1134 BitmapTextBatch* that = t->cast<BitmapTextBatch>(); 1706 BitmapTextBatch* that = t->cast<BitmapTextBatch>();
1135 1707
1136 if (this->fMaskFormat != that->fMaskFormat) { 1708 if (fUseDistanceFields != that->fUseDistanceFields) {
1137 return false; 1709 return false;
1138 } 1710 }
1139 1711
1140 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo r()) { 1712 if (!fUseDistanceFields) {
1141 return false; 1713 // Bitmap Text
1142 } 1714 if (fMaskFormat != that->fMaskFormat) {
1715 return false;
1716 }
1143 1717
1144 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) { 1718 // TODO we can often batch across LCD text if we have dual source bl ending and don't
1145 return false; 1719 // have to use the blend constant
1720 if (fMaskFormat != kA8_GrMaskFormat && this->color() != that->color( )) {
1721 return false;
1722 }
1723
1724 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that ->viewMatrix())) {
1725 return false;
1726 }
1727 } else {
1728 // Distance Fields
1729 SkASSERT(this->fMaskFormat == that->fMaskFormat &&
1730 this->fMaskFormat == kA8_GrMaskFormat);
1731
1732 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1733 return false;
1734 }
1735
1736 if (fFilteredColor != that->fFilteredColor) {
1737 return false;
1738 }
1739
1740 if (fUseLCDText != that->fUseLCDText) {
1741 return false;
1742 }
1743
1744 if (fUseBGR != that->fUseBGR) {
1745 return false;
1746 }
1747
1748 if (fGamma != that->fGamma) {
1749 return false;
1750 }
1751
1752 // TODO see note above
1753 if (fUseLCDText && this->color() != that->color()) {
1754 return false;
1755 }
1146 } 1756 }
1147 1757
1148 fBatch.fNumGlyphs += that->numGlyphs(); 1758 fBatch.fNumGlyphs += that->numGlyphs();
1149 1759
1150 // copy that->geoData(). We do this manually for performance reasons 1760 // copy that->geoData(). We do this manually for performance reasons
1151 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData(); 1761 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData();
1152 int otherInstanceCount = that->instanceCount(); 1762 int otherInstanceCount = that->instanceCount();
1153 int allocSize = otherInstanceCount + fInstanceCount; 1763 int allocSize = otherInstanceCount + fInstanceCount;
1154 if (allocSize > fAllocatedCount) { 1764 if (allocSize > fAllocatedCount) {
1155 while (allocSize > fAllocatedCount) { 1765 while (allocSize > fAllocatedCount) {
1156 fAllocatedCount = fAllocatedCount << 1; 1766 fAllocatedCount = fAllocatedCount << 1;
1157 } 1767 }
1158 fGeoData.realloc(fAllocatedCount); 1768 fGeoData.realloc(fAllocatedCount);
1159 } 1769 }
1160 1770
1161 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(), 1771 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(),
1162 otherInstanceCount * sizeof(Geometry)); 1772 otherInstanceCount * sizeof(Geometry));
1163 int total = fInstanceCount + otherInstanceCount; 1773 int total = fInstanceCount + otherInstanceCount;
1164 for (int i = fInstanceCount; i < total; i++) { 1774 for (int i = fInstanceCount; i < total; i++) {
1165 fGeoData[i].fBlob->ref(); 1775 fGeoData[i].fBlob->ref();
1166 } 1776 }
1167 fInstanceCount = total; 1777 fInstanceCount = total;
1168 return true; 1778 return true;
1169 } 1779 }
1170 1780
1781 // TODO just use class params
1782 // TODO trying to figure out why lcd is so whack
1783 GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor fi lteredColor,
1784 GrColor color, GrTexture* texture) {
1785 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile rp_FilterMode);
1786
1787 // set up any flags
1788 uint32_t flags = 0;
1789 flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1790 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
1791 flags |= fUseLCDText && viewMatrix.rectStaysRect() ?
1792 kRectToRect_DistanceFieldEffectFlag : 0;
1793 flags |= fUseLCDText && fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
1794
1795 // see if we need to create a new effect
1796 if (fUseLCDText) {
1797 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or);
1798
1799 float redCorrection =
1800 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistan ceAdjustLumShift];
1801 float greenCorrection =
1802 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistan ceAdjustLumShift];
1803 float blueCorrection =
1804 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistan ceAdjustLumShift];
1805 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
1806 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio n,
1807 greenCorrect ion,
1808 blueCorrecti on);
1809
1810 return GrDistanceFieldLCDTextGeoProc::Create(color,
1811 viewMatrix,
1812 texture,
1813 params,
1814 widthAdjust,
1815 flags);
1816 } else {
1817 flags |= kColorAttr_DistanceFieldEffectFlag;
1818 bool opaque = GrColorIsOpaque(color);
1819 #ifdef SK_GAMMA_APPLY_TO_A8
1820 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fGamma, filtered Color);
1821 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLum Shift];
1822 return GrDistanceFieldA8TextGeoProc::Create(color,
1823 viewMatrix,
1824 texture,
1825 params,
1826 correction,
1827 flags,
1828 opaque);
1829 #else
1830 return GrDistanceFieldA8TextGeoProc::Create(color,
1831 viewMatrix,
1832 texture,
1833 params,
1834 flags,
1835 opaque);
1836 #endif
1837 }
1838
1839 }
1840
1171 struct BatchTracker { 1841 struct BatchTracker {
1172 GrColor fColor; 1842 GrColor fColor;
1173 SkMatrix fViewMatrix; 1843 SkMatrix fViewMatrix;
1174 bool fUsesLocalCoords; 1844 bool fUsesLocalCoords;
1175 bool fColorIgnored; 1845 bool fColorIgnored;
1176 bool fCoverageIgnored; 1846 bool fCoverageIgnored;
1177 int fNumGlyphs; 1847 int fNumGlyphs;
1178 }; 1848 };
1179 1849
1180 BatchTracker fBatch; 1850 BatchTracker fBatch;
1181 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData; 1851 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData;
1182 int fInstanceCount; 1852 int fInstanceCount;
1183 int fAllocatedCount; 1853 int fAllocatedCount;
1184 GrMaskFormat fMaskFormat; 1854 GrMaskFormat fMaskFormat;
1185 GrPixelConfig fPixelConfig; 1855 GrPixelConfig fPixelConfig;
1186 GrBatchFontCache* fFontCache; 1856 GrBatchFontCache* fFontCache;
1857
1858 // Distance field properties
1859 SkAutoTUnref<DistanceAdjustTable> fDistanceAdjustTable;
1860 SkColor fFilteredColor;
1861 bool fUseDistanceFields;
1862 bool fUseLCDText;
1863 bool fUseBGR;
1864 float fGamma;
1187 }; 1865 };
1188 1866
1189 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint, 1867 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint,
1190 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix, 1868 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix,
1191 const SkIRect& clipBounds, SkScalar x, SkScalar y) { 1869 const SkIRect& clipBounds, SkScalar x, SkScalar y) {
1192 SkPaint runPaint = skPaint; 1870 SkPaint runPaint = skPaint;
1193 1871
1194 size_t textLen = it.glyphCount() * sizeof(uint16_t); 1872 size_t textLen = it.glyphCount() * sizeof(uint16_t);
1195 const SkPoint& offset = it.offset(); 1873 const SkPoint& offset = it.offset();
1196 1874
(...skipping 17 matching lines...) Expand all
1214 break; 1892 break;
1215 case SkTextBlob::kFull_Positioning: 1893 case SkTextBlob::kFull_Positioning:
1216 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), 1894 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (),
1217 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); 1895 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds);
1218 break; 1896 break;
1219 } 1897 }
1220 } 1898 }
1221 1899
1222 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, 1900 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder,
1223 BitmapTextBlob* cacheBlob, int run, GrC olor color, 1901 BitmapTextBlob* cacheBlob, int run, GrC olor color,
1224 uint8_t paintAlpha, SkScalar transX, Sk Scalar transY) { 1902 SkScalar transX, SkScalar transY, const SkPaint& skPaint) {
1225 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { 1903 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) {
1226 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; 1904 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
1227 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1905 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
1228 if (0 == glyphCount) { 1906 if (0 == glyphCount) {
1229 continue; 1907 continue;
1230 } 1908 }
1231 1909
1232 GrMaskFormat format = info.fMaskFormat; 1910 GrMaskFormat format = info.fMaskFormat;
1233 GrColor subRunColor = kARGB_GrMaskFormat == format ? 1911 GrColor subRunColor;
1234 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : 1912 if (kARGB_GrMaskFormat == format) {
1235 color; 1913 uint8_t paintAlpha = skPaint.getAlpha();
1914 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, pai ntAlpha);
1915 } else {
1916 subRunColor = color;
1917 }
1236 1918
1237 SkAutoTUnref<BitmapTextBatch> batch(BitmapTextBatch::Create(format, glyp hCount, 1919 SkAutoTUnref<BitmapTextBatch> batch;
1238 fContext->getBatchFo ntCache())); 1920 if (info.fDrawAsDistanceFields) {
1921 SkColor filteredColor;
1922 SkColorFilter* colorFilter = skPaint.getColorFilter();
1923 if (colorFilter) {
1924 filteredColor = colorFilter->filterColor(skPaint.getColor());
1925 } else {
1926 filteredColor = skPaint.getColor();
1927 }
1928 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry() );
1929 float gamma = fDeviceProperties.gamma();
1930 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache(),
1931 fDistanceAdjustTable, filteredCo lor,
1932 info.fUseLCDText, useBGR,
1933 gamma));
1934 } else {
1935 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache()));
1936 }
1239 BitmapTextBatch::Geometry& geometry = batch->geometry(); 1937 BitmapTextBatch::Geometry& geometry = batch->geometry();
1240 geometry.fBlob = SkRef(cacheBlob); 1938 geometry.fBlob = SkRef(cacheBlob);
1241 geometry.fRun = run; 1939 geometry.fRun = run;
1242 geometry.fSubRun = subRun; 1940 geometry.fSubRun = subRun;
1243 geometry.fColor = subRunColor; 1941 geometry.fColor = subRunColor;
1244 geometry.fTransX = transX; 1942 geometry.fTransX = transX;
1245 geometry.fTransY = transY; 1943 geometry.fTransY = transY;
1246 batch->init(); 1944 batch->init();
1247 1945
1248 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); 1946 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds);
(...skipping 28 matching lines...) Expand all
1277 const SkMatrix& viewMatrix, 1975 const SkMatrix& viewMatrix,
1278 const SkIRect& clipBounds, 1976 const SkIRect& clipBounds,
1279 SkScalar x, SkScalar y, 1977 SkScalar x, SkScalar y,
1280 SkScalar transX, SkScalar transY) { 1978 SkScalar transX, SkScalar transY) {
1281 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush 1979 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush
1282 // it as paths 1980 // it as paths
1283 GrPipelineBuilder pipelineBuilder; 1981 GrPipelineBuilder pipelineBuilder;
1284 pipelineBuilder.setFromPaint(grPaint, rt, clip); 1982 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1285 1983
1286 GrColor color = grPaint.getColor(); 1984 GrColor color = grPaint.getColor();
1287 uint8_t paintAlpha = skPaint.getAlpha();
1288 1985
1289 SkTextBlob::RunIterator it(blob); 1986 SkTextBlob::RunIterator it(blob);
1290 for (int run = 0; !it.done(); it.next(), run++) { 1987 for (int run = 0; !it.done(); it.next(), run++) {
1291 if (cacheBlob->fRuns[run].fDrawAsPaths) { 1988 if (cacheBlob->fRuns[run].fDrawAsPaths) {
1292 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); 1989 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y);
1293 continue; 1990 continue;
1294 } 1991 }
1295 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); 1992 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
1296 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, transX, transY); 1993 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, transX, transY, skPaint);
1297 } 1994 }
1298 1995
1299 // Now flush big glyphs 1996 // Now flush big glyphs
1300 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); 1997 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY);
1301 } 1998 }
1302 1999
1303 void GrAtlasTextContext::flush(GrDrawTarget* target, 2000 void GrAtlasTextContext::flush(GrDrawTarget* target,
1304 BitmapTextBlob* cacheBlob, 2001 BitmapTextBlob* cacheBlob,
1305 GrRenderTarget* rt, 2002 GrRenderTarget* rt,
1306 const SkPaint& skPaint, 2003 const SkPaint& skPaint,
1307 const GrPaint& grPaint, 2004 const GrPaint& grPaint,
1308 const GrClip& clip, 2005 const GrClip& clip) {
1309 const SkMatrix& viewMatrix) {
1310 GrPipelineBuilder pipelineBuilder; 2006 GrPipelineBuilder pipelineBuilder;
1311 pipelineBuilder.setFromPaint(grPaint, rt, clip); 2007 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1312 2008
1313 GrColor color = grPaint.getColor(); 2009 GrColor color = grPaint.getColor();
1314 uint8_t paintAlpha = skPaint.getAlpha();
1315 for (int run = 0; run < cacheBlob->fRunCount; run++) { 2010 for (int run = 0; run < cacheBlob->fRunCount; run++) {
1316 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, 0, 0); 2011 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint);
1317 } 2012 }
1318 2013
1319 // Now flush big glyphs 2014 // Now flush big glyphs
1320 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); 2015 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
1321 } 2016 }
OLDNEW
« no previous file with comments | « src/gpu/GrAtlasTextContext.h ('k') | src/gpu/GrContext.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698