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

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: feedback inc 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,
jvanverth1 2015/04/17 15:29:04 Why was this changed to a pointer?
joshualitt 2015/04/17 15:30:30 From what I could tell, distanceField text doesn't
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 size_t 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(size_t 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, sx - dx, sy - dy);
1211 return true;
1212 }
1213
1214 Run& run = blob->fRuns[runIndex];
1215
1216 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
1217 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat);
1218 subRun->fMaskFormat = kA8_GrMaskFormat;
1219
1220 size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCD Text);
1221
1222 bool useColorVerts = !subRun->fUseLCDText;
1223 this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride, useColorVerts,
1224 packed);
1225 return true;
1226 }
1227
1228 inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* g lyph,
1229 GrFontScaler* scaler, int x, int y) {
1230 if (NULL == glyph->fPath) {
1231 SkPath* path = SkNEW(SkPath);
1232 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
1233 // flag the glyph as being dead?
1234 SkDELETE(path);
1235 return;
1236 }
1237 glyph->fPath = path;
1238 }
1239 SkASSERT(glyph->fPath);
1240 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y));
1241 }
1242
1243 inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run ,
1244 Run::SubRunInfo* subRun,
1245 const SkRect& positions, GrCol or color,
1246 size_t vertexStride, bool useV ertexColor,
1247 GrGlyph::PackedID packed) {
1248 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
1249 run->fVertexBounds.joinNonEmptyArg(positions);
1250 run->fColor = color;
740 1251
741 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex); 1252 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex);
742 1253
743 // V0 1254 // V0
744 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); 1255 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
745 position->set(r.fLeft, r.fTop); 1256 position->set(positions.fLeft, positions.fTop);
746 if (kA8_GrMaskFormat == format) { 1257 if (useVertexColor) {
747 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1258 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
748 *colorPtr = color; 1259 *colorPtr = color;
749 } 1260 }
750 vertex += vertexStride; 1261 vertex += vertexStride;
1262
751 // V1 1263 // V1
752 position = reinterpret_cast<SkPoint*>(vertex); 1264 position = reinterpret_cast<SkPoint*>(vertex);
753 position->set(r.fLeft, r.fBottom); 1265 position->set(positions.fLeft, positions.fBottom);
754 if (kA8_GrMaskFormat == format) { 1266 if (useVertexColor) {
755 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1267 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
756 *colorPtr = color; 1268 *colorPtr = color;
757 } 1269 }
758 vertex += vertexStride; 1270 vertex += vertexStride;
759 1271
760 // V2 1272 // V2
761 position = reinterpret_cast<SkPoint*>(vertex); 1273 position = reinterpret_cast<SkPoint*>(vertex);
762 position->set(r.fRight, r.fBottom); 1274 position->set(positions.fRight, positions.fBottom);
763 if (kA8_GrMaskFormat == format) { 1275 if (useVertexColor) {
764 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1276 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
765 *colorPtr = color; 1277 *colorPtr = color;
766 } 1278 }
767 vertex += vertexStride; 1279 vertex += vertexStride;
768 1280
769 // V3 1281 // V3
770 position = reinterpret_cast<SkPoint*>(vertex); 1282 position = reinterpret_cast<SkPoint*>(vertex);
771 position->set(r.fRight, r.fTop); 1283 position->set(positions.fRight, positions.fTop);
772 if (kA8_GrMaskFormat == format) { 1284 if (useVertexColor) {
773 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ; 1285 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
774 *colorPtr = color; 1286 *colorPtr = color;
775 } 1287 }
776 1288
777 subRun->fGlyphEndIndex++; 1289 subRun->fGlyphEndIndex++;
778 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; 1290 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
779 } 1291 }
780 1292
781 class BitmapTextBatch : public GrBatch { 1293 class BitmapTextBatch : public GrBatch {
782 public: 1294 public:
1295 typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable;
783 typedef GrAtlasTextContext::BitmapTextBlob Blob; 1296 typedef GrAtlasTextContext::BitmapTextBlob Blob;
784 typedef Blob::Run Run; 1297 typedef Blob::Run Run;
785 typedef Run::SubRunInfo TextInfo; 1298 typedef Run::SubRunInfo TextInfo;
786 struct Geometry { 1299 struct Geometry {
787 Blob* fBlob; 1300 Blob* fBlob;
788 int fRun; 1301 int fRun;
789 int fSubRun; 1302 int fSubRun;
790 GrColor fColor; 1303 GrColor fColor;
791 SkScalar fTransX; 1304 SkScalar fTransX;
792 SkScalar fTransY; 1305 SkScalar fTransY;
793 }; 1306 };
794 1307
795 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, 1308 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
796 GrBatchFontCache* fontCache) { 1309 GrBatchFontCache* fontCache) {
797 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache)); 1310 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache));
798 } 1311 }
799 1312
1313 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount,
1314 GrBatchFontCache* fontCache,
1315 DistanceAdjustTable* distanceAdjustTable,
1316 SkColor filteredColor, bool useLCDText,
1317 bool useBGR, float gamma) {
1318 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache, d istanceAdjustTable,
1319 filteredColor, useLCDText, useBGR, g amma));
1320 }
1321
800 const char* name() const override { return "BitmapTextBatch"; } 1322 const char* name() const override { return "BitmapTextBatch"; }
801 1323
802 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { 1324 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
803 if (kARGB_GrMaskFormat == fMaskFormat) { 1325 if (kARGB_GrMaskFormat == fMaskFormat) {
804 out->setUnknownFourComponents(); 1326 out->setUnknownFourComponents();
805 } else { 1327 } else {
806 out->setKnownFourComponents(fBatch.fColor); 1328 out->setKnownFourComponents(fBatch.fColor);
807 } 1329 }
808 } 1330 }
809 1331
810 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { 1332 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
811 if (kARGB_GrMaskFormat != fMaskFormat) { 1333 if (!fUseDistanceFields) {
812 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) { 1334 // Bitmap Text
1335 if (kARGB_GrMaskFormat != fMaskFormat) {
1336 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
1337 out->setUnknownSingleComponent();
1338 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
1339 out->setUnknownOpaqueFourComponents();
1340 out->setUsingLCDCoverage();
1341 } else {
1342 out->setUnknownFourComponents();
1343 out->setUsingLCDCoverage();
1344 }
1345 } else {
1346 out->setKnownSingleComponent(0xff);
1347 }
1348 } else {
1349 // Distance fields
1350 if (!fUseLCDText) {
813 out->setUnknownSingleComponent(); 1351 out->setUnknownSingleComponent();
814 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
815 out->setUnknownOpaqueFourComponents();
816 out->setUsingLCDCoverage();
817 } else { 1352 } else {
818 out->setUnknownFourComponents(); 1353 out->setUnknownFourComponents();
819 out->setUsingLCDCoverage(); 1354 out->setUsingLCDCoverage();
820 } 1355 }
821 } else {
822 out->setKnownSingleComponent(0xff);
823 } 1356 }
824 } 1357 }
825 1358
826 void initBatchTracker(const GrPipelineInfo& init) override { 1359 void initBatchTracker(const GrPipelineInfo& init) override {
827 // Handle any color overrides 1360 // Handle any color overrides
828 if (init.fColorIgnored) { 1361 if (init.fColorIgnored) {
829 fBatch.fColor = GrColor_ILLEGAL; 1362 fBatch.fColor = GrColor_ILLEGAL;
830 } else if (GrColor_ILLEGAL != init.fOverrideColor) { 1363 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
831 fBatch.fColor = init.fOverrideColor; 1364 fBatch.fColor = init.fOverrideColor;
832 } 1365 }
(...skipping 12 matching lines...) Expand all
845 SkDebugf("Cannot invert viewmatrix\n"); 1378 SkDebugf("Cannot invert viewmatrix\n");
846 return; 1379 return;
847 } 1380 }
848 1381
849 GrTexture* texture = fFontCache->getTexture(fMaskFormat); 1382 GrTexture* texture = fFontCache->getTexture(fMaskFormat);
850 if (!texture) { 1383 if (!texture) {
851 SkDebugf("Could not allocate backing texture for atlas\n"); 1384 SkDebugf("Could not allocate backing texture for atlas\n");
852 return; 1385 return;
853 } 1386 }
854 1387
855 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode); 1388 SkAutoTUnref<const GrGeometryProcessor> gp;
1389 if (fUseDistanceFields) {
1390 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor, this->color(),
1391 texture));
1392 } else {
1393 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k None_FilterMode);
856 1394
857 // This will be ignored in the non A8 case 1395 // This will be ignored in the non A8 case
858 bool opaqueVertexColors = GrColorIsOpaque(this->color()); 1396 bool opaqueVertexColors = GrColorIsOpaque(this->color());
859 SkAutoTUnref<const GrGeometryProcessor> gp( 1397 gp.reset(GrBitmapTextGeoProc::Create(this->color(),
860 GrBitmapTextGeoProc::Create(this->color(), 1398 texture,
861 texture, 1399 params,
862 params, 1400 fMaskFormat,
863 fMaskFormat, 1401 opaqueVertexColors,
864 opaqueVertexColors, 1402 localMatrix));
865 localMatrix)); 1403 }
866 1404
867 size_t vertexStride = gp->getVertexStride(); 1405 size_t vertexStride = gp->getVertexStride();
868 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat)); 1406 SkASSERT(vertexStride == fUseDistanceFields ?
1407 get_vertex_stride_df(fMaskFormat, fUseLCDText) :
1408 get_vertex_stride(fMaskFormat));
869 1409
870 this->initDraw(batchTarget, gp, pipeline); 1410 this->initDraw(batchTarget, gp, pipeline);
871 1411
872 int glyphCount = this->numGlyphs(); 1412 int glyphCount = this->numGlyphs();
873 int instanceCount = fInstanceCount; 1413 int instanceCount = fInstanceCount;
874 const GrVertexBuffer* vertexBuffer; 1414 const GrVertexBuffer* vertexBuffer;
875 int firstVertex; 1415 int firstVertex;
876 1416
877 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, 1417 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
878 glyphCount * kVert icesPerGlyph, 1418 glyphCount * kVert icesPerGlyph,
(...skipping 22 matching lines...) Expand all
901 1441
902 int instancesToFlush = 0; 1442 int instancesToFlush = 0;
903 for (int i = 0; i < instanceCount; i++) { 1443 for (int i = 0; i < instanceCount; i++) {
904 Geometry& args = fGeoData[i]; 1444 Geometry& args = fGeoData[i];
905 Blob* blob = args.fBlob; 1445 Blob* blob = args.fBlob;
906 Run& run = blob->fRuns[args.fRun]; 1446 Run& run = blob->fRuns[args.fRun];
907 TextInfo& info = run.fSubRunInfo[args.fSubRun]; 1447 TextInfo& info = run.fSubRunInfo[args.fSubRun];
908 1448
909 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); 1449 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
910 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen; 1450 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen;
911 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor; 1451 bool regenerateColors;
1452 if (fUseDistanceFields) {
1453 regenerateColors = fUseLCDText && run.fColor != args.fColor;
1454 } else {
1455 regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor != args.fColor;
1456 }
912 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f; 1457 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0. f;
913 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1458 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
914 1459
915 // We regenerate both texture coords and colors in the blob itself, and update the 1460 // 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 1461 // 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 1462 // 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. 1463 // 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 1464 // 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 1465 // 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 1466 // 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 1567 // 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 1568 // is used to seed the batch with its initial geometry. After seeding, the client should call
1024 // init() so the Batch can initialize itself 1569 // init() so the Batch can initialize itself
1025 Geometry& geometry() { return fGeoData[0]; } 1570 Geometry& geometry() { return fGeoData[0]; }
1026 void init() { 1571 void init() {
1027 fBatch.fColor = fGeoData[0].fColor; 1572 fBatch.fColor = fGeoData[0].fColor;
1028 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix; 1573 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix;
1029 } 1574 }
1030 1575
1031 private: 1576 private:
1032 BitmapTextBatch(GrMaskFormat maskFormat, 1577 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache)
1033 int glyphCount, GrBatchFontCache* fontCache)
1034 : fMaskFormat(maskFormat) 1578 : fMaskFormat(maskFormat)
1035 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) 1579 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1036 , fFontCache(fontCache) { 1580 , fFontCache(fontCache)
1581 , fUseDistanceFields(false) {
1037 this->initClassID<BitmapTextBatch>(); 1582 this->initClassID<BitmapTextBatch>();
1038 fBatch.fNumGlyphs = glyphCount; 1583 fBatch.fNumGlyphs = glyphCount;
1039 fInstanceCount = 1; 1584 fInstanceCount = 1;
1040 fAllocatedCount = kMinAllocated; 1585 fAllocatedCount = kMinAllocated;
1041 } 1586 }
1042 1587
1588 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f ontCache,
1589 DistanceAdjustTable* distanceAdjustTable, SkColor filteredCo lor,
1590 bool useLCDText, bool useBGR, float gamma)
1591 : fMaskFormat(maskFormat)
1592 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
1593 , fFontCache(fontCache)
1594 , fDistanceAdjustTable(SkRef(distanceAdjustTable))
1595 , fFilteredColor(filteredColor)
1596 , fUseDistanceFields(true)
1597 , fUseLCDText(useLCDText)
1598 , fUseBGR(useBGR)
1599 , fGamma(gamma) {
1600 this->initClassID<BitmapTextBatch>();
1601 fBatch.fNumGlyphs = glyphCount;
1602 fInstanceCount = 1;
1603 fAllocatedCount = kMinAllocated;
1604 SkASSERT(fMaskFormat == kA8_GrMaskFormat);
1605 }
1606
1043 ~BitmapTextBatch() { 1607 ~BitmapTextBatch() {
1044 for (int i = 0; i < fInstanceCount; i++) { 1608 for (int i = 0; i < fInstanceCount; i++) {
1045 fGeoData[i].fBlob->unref(); 1609 fGeoData[i].fBlob->unref();
1046 } 1610 }
1047 } 1611 }
1048 1612
1049 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) { 1613 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) {
1050 int width = glyph->fBounds.width(); 1614 int width = glyph->fBounds.width();
1051 int height = glyph->fBounds.height(); 1615 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 1616
1057 // we assume texture coords are the last vertex attribute, this is a bit fragile. 1617 int u0, v0, u1, v1;
1058 // TODO pass in this offset or something 1618 if (fUseDistanceFields) {
1619 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
1620 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
1621 u1 = u0 + width - 2 * SK_DistanceFieldInset;
1622 v1 = v0 + height - 2 * SK_DistanceFieldInset;
1623 } else {
1624 u0 = glyph->fAtlasLocation.fX;
1625 v0 = glyph->fAtlasLocation.fY;
1626 u1 = u0 + width;
1627 v1 = v0 + height;
1628 }
1629
1059 SkIPoint16* textureCoords; 1630 SkIPoint16* textureCoords;
1060 // V0 1631 // V0
1061 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1632 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1062 textureCoords->set(u0, v0); 1633 textureCoords->set(u0, v0);
1063 vertex += vertexStride; 1634 vertex += vertexStride;
1064 1635
1065 // V1 1636 // V1
1066 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); 1637 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
1067 textureCoords->set(u0, v1); 1638 textureCoords->set(u0, v1);
1068 vertex += vertexStride; 1639 vertex += vertexStride;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1126 } 1697 }
1127 1698
1128 GrColor color() const { return fBatch.fColor; } 1699 GrColor color() const { return fBatch.fColor; }
1129 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } 1700 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
1130 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } 1701 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
1131 int numGlyphs() const { return fBatch.fNumGlyphs; } 1702 int numGlyphs() const { return fBatch.fNumGlyphs; }
1132 1703
1133 bool onCombineIfPossible(GrBatch* t) override { 1704 bool onCombineIfPossible(GrBatch* t) override {
1134 BitmapTextBatch* that = t->cast<BitmapTextBatch>(); 1705 BitmapTextBatch* that = t->cast<BitmapTextBatch>();
1135 1706
1136 if (this->fMaskFormat != that->fMaskFormat) { 1707 if (fUseDistanceFields != that->fUseDistanceFields) {
1137 return false; 1708 return false;
1138 } 1709 }
1139 1710
1140 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo r()) { 1711 if (!fUseDistanceFields) {
1141 return false; 1712 // Bitmap Text
1142 } 1713 if (fMaskFormat != that->fMaskFormat) {
1714 return false;
1715 }
1143 1716
1144 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) { 1717 // TODO we can often batch across LCD text if we have dual source bl ending and don't
1145 return false; 1718 // have to use the blend constant
1719 if (fMaskFormat != kA8_GrMaskFormat && this->color() != that->color( )) {
1720 return false;
1721 }
1722
1723 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that ->viewMatrix())) {
1724 return false;
1725 }
1726 } else {
1727 // Distance Fields
1728 SkASSERT(this->fMaskFormat == that->fMaskFormat &&
1729 this->fMaskFormat == kA8_GrMaskFormat);
1730
1731 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
1732 return false;
1733 }
1734
1735 if (fFilteredColor != that->fFilteredColor) {
1736 return false;
1737 }
1738
1739 if (fUseLCDText != that->fUseLCDText) {
1740 return false;
1741 }
1742
1743 if (fUseBGR != that->fUseBGR) {
1744 return false;
1745 }
1746
1747 if (fGamma != that->fGamma) {
1748 return false;
1749 }
1750
1751 // TODO see note above
1752 if (fUseLCDText && this->color() != that->color()) {
1753 return false;
1754 }
1146 } 1755 }
1147 1756
1148 fBatch.fNumGlyphs += that->numGlyphs(); 1757 fBatch.fNumGlyphs += that->numGlyphs();
1149 1758
1150 // copy that->geoData(). We do this manually for performance reasons 1759 // copy that->geoData(). We do this manually for performance reasons
1151 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData(); 1760 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData();
1152 int otherInstanceCount = that->instanceCount(); 1761 int otherInstanceCount = that->instanceCount();
1153 int allocSize = otherInstanceCount + fInstanceCount; 1762 int allocSize = otherInstanceCount + fInstanceCount;
1154 if (allocSize > fAllocatedCount) { 1763 if (allocSize > fAllocatedCount) {
1155 while (allocSize > fAllocatedCount) { 1764 while (allocSize > fAllocatedCount) {
1156 fAllocatedCount = fAllocatedCount << 1; 1765 fAllocatedCount = fAllocatedCount << 1;
1157 } 1766 }
1158 fGeoData.realloc(fAllocatedCount); 1767 fGeoData.realloc(fAllocatedCount);
1159 } 1768 }
1160 1769
1161 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(), 1770 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(),
1162 otherInstanceCount * sizeof(Geometry)); 1771 otherInstanceCount * sizeof(Geometry));
1163 int total = fInstanceCount + otherInstanceCount; 1772 int total = fInstanceCount + otherInstanceCount;
1164 for (int i = fInstanceCount; i < total; i++) { 1773 for (int i = fInstanceCount; i < total; i++) {
1165 fGeoData[i].fBlob->ref(); 1774 fGeoData[i].fBlob->ref();
1166 } 1775 }
1167 fInstanceCount = total; 1776 fInstanceCount = total;
1168 return true; 1777 return true;
1169 } 1778 }
1170 1779
1780 // TODO just use class params
1781 // TODO trying to figure out why lcd is so whack
1782 GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor fi lteredColor,
1783 GrColor color, GrTexture* texture) {
1784 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile rp_FilterMode);
1785
1786 // set up any flags
1787 uint32_t flags = 0;
1788 flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
1789 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
1790 flags |= fUseLCDText && viewMatrix.rectStaysRect() ?
1791 kRectToRect_DistanceFieldEffectFlag : 0;
1792 flags |= fUseLCDText && fUseBGR ? kBGR_DistanceFieldEffectFlag : 0;
1793
1794 // see if we need to create a new effect
1795 if (fUseLCDText) {
1796 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or);
1797
1798 float redCorrection =
1799 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistan ceAdjustLumShift];
1800 float greenCorrection =
1801 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistan ceAdjustLumShift];
1802 float blueCorrection =
1803 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistan ceAdjustLumShift];
1804 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
1805 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio n,
1806 greenCorrect ion,
1807 blueCorrecti on);
1808
1809 return GrDistanceFieldLCDTextGeoProc::Create(color,
1810 viewMatrix,
1811 texture,
1812 params,
1813 widthAdjust,
1814 flags);
1815 } else {
1816 flags |= kColorAttr_DistanceFieldEffectFlag;
1817 bool opaque = GrColorIsOpaque(color);
1818 #ifdef SK_GAMMA_APPLY_TO_A8
1819 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fGamma, filtered Color);
1820 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLum Shift];
1821 return GrDistanceFieldA8TextGeoProc::Create(color,
1822 viewMatrix,
1823 texture,
1824 params,
1825 correction,
1826 flags,
1827 opaque);
1828 #else
1829 return GrDistanceFieldA8TextGeoProc::Create(color,
1830 viewMatrix,
1831 texture,
1832 params,
1833 flags,
1834 opaque);
1835 #endif
1836 }
1837
1838 }
1839
1171 struct BatchTracker { 1840 struct BatchTracker {
1172 GrColor fColor; 1841 GrColor fColor;
1173 SkMatrix fViewMatrix; 1842 SkMatrix fViewMatrix;
1174 bool fUsesLocalCoords; 1843 bool fUsesLocalCoords;
1175 bool fColorIgnored; 1844 bool fColorIgnored;
1176 bool fCoverageIgnored; 1845 bool fCoverageIgnored;
1177 int fNumGlyphs; 1846 int fNumGlyphs;
1178 }; 1847 };
1179 1848
1180 BatchTracker fBatch; 1849 BatchTracker fBatch;
1181 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData; 1850 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData;
1182 int fInstanceCount; 1851 int fInstanceCount;
1183 int fAllocatedCount; 1852 int fAllocatedCount;
1184 GrMaskFormat fMaskFormat; 1853 GrMaskFormat fMaskFormat;
1185 GrPixelConfig fPixelConfig; 1854 GrPixelConfig fPixelConfig;
1186 GrBatchFontCache* fFontCache; 1855 GrBatchFontCache* fFontCache;
1856
1857 // Distance field properties
1858 SkAutoTUnref<DistanceAdjustTable> fDistanceAdjustTable;
1859 SkColor fFilteredColor;
1860 bool fUseDistanceFields;
1861 bool fUseLCDText;
1862 bool fUseBGR;
1863 float fGamma;
1187 }; 1864 };
1188 1865
1189 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint, 1866 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons t SkPaint& skPaint,
1190 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix, 1867 SkDrawFilter* drawFilter, const SkMatri x& viewMatrix,
1191 const SkIRect& clipBounds, SkScalar x, SkScalar y) { 1868 const SkIRect& clipBounds, SkScalar x, SkScalar y) {
1192 SkPaint runPaint = skPaint; 1869 SkPaint runPaint = skPaint;
1193 1870
1194 size_t textLen = it.glyphCount() * sizeof(uint16_t); 1871 size_t textLen = it.glyphCount() * sizeof(uint16_t);
1195 const SkPoint& offset = it.offset(); 1872 const SkPoint& offset = it.offset();
1196 1873
(...skipping 17 matching lines...) Expand all
1214 break; 1891 break;
1215 case SkTextBlob::kFull_Positioning: 1892 case SkTextBlob::kFull_Positioning:
1216 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (), 1893 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs (),
1217 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds); 1894 textLen, it.pos(), 2, SkPoint::Make(x, y), c lipBounds);
1218 break; 1895 break;
1219 } 1896 }
1220 } 1897 }
1221 1898
1222 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder, 1899 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder * pipelineBuilder,
1223 BitmapTextBlob* cacheBlob, int run, GrC olor color, 1900 BitmapTextBlob* cacheBlob, int run, GrC olor color,
1224 uint8_t paintAlpha, SkScalar transX, Sk Scalar transY) { 1901 SkScalar transX, SkScalar transY, const SkPaint& skPaint) {
1225 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) { 1902 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub Run++) {
1226 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; 1903 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun];
1227 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; 1904 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
1228 if (0 == glyphCount) { 1905 if (0 == glyphCount) {
1229 continue; 1906 continue;
1230 } 1907 }
1231 1908
1232 GrMaskFormat format = info.fMaskFormat; 1909 GrMaskFormat format = info.fMaskFormat;
1233 GrColor subRunColor = kARGB_GrMaskFormat == format ? 1910 GrColor subRunColor;
1234 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paintAlpha) : 1911 if (kARGB_GrMaskFormat == format) {
1235 color; 1912 uint8_t paintAlpha = skPaint.getAlpha();
1913 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, pai ntAlpha);
1914 } else {
1915 subRunColor = color;
1916 }
1236 1917
1237 SkAutoTUnref<BitmapTextBatch> batch(BitmapTextBatch::Create(format, glyp hCount, 1918 SkAutoTUnref<BitmapTextBatch> batch;
1238 fContext->getBatchFo ntCache())); 1919 if (info.fDrawAsDistanceFields) {
1920 SkColor filteredColor;
1921 SkColorFilter* colorFilter = skPaint.getColorFilter();
1922 if (colorFilter) {
1923 filteredColor = colorFilter->filterColor(skPaint.getColor());
1924 } else {
1925 filteredColor = skPaint.getColor();
1926 }
1927 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry() );
1928 float gamma = fDeviceProperties.gamma();
1929 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache(),
1930 fDistanceAdjustTable, filteredCo lor,
1931 info.fUseLCDText, useBGR,
1932 gamma));
1933 } else {
1934 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge tBatchFontCache()));
1935 }
1239 BitmapTextBatch::Geometry& geometry = batch->geometry(); 1936 BitmapTextBatch::Geometry& geometry = batch->geometry();
1240 geometry.fBlob = SkRef(cacheBlob); 1937 geometry.fBlob = SkRef(cacheBlob);
1241 geometry.fRun = run; 1938 geometry.fRun = run;
1242 geometry.fSubRun = subRun; 1939 geometry.fSubRun = subRun;
1243 geometry.fColor = subRunColor; 1940 geometry.fColor = subRunColor;
1244 geometry.fTransX = transX; 1941 geometry.fTransX = transX;
1245 geometry.fTransY = transY; 1942 geometry.fTransY = transY;
1246 batch->init(); 1943 batch->init();
1247 1944
1248 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds); 1945 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex Bounds);
(...skipping 28 matching lines...) Expand all
1277 const SkMatrix& viewMatrix, 1974 const SkMatrix& viewMatrix,
1278 const SkIRect& clipBounds, 1975 const SkIRect& clipBounds,
1279 SkScalar x, SkScalar y, 1976 SkScalar x, SkScalar y,
1280 SkScalar transX, SkScalar transY) { 1977 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 1978 // We loop through the runs of the blob, flushing each. If any run is too l arge, then we flush
1282 // it as paths 1979 // it as paths
1283 GrPipelineBuilder pipelineBuilder; 1980 GrPipelineBuilder pipelineBuilder;
1284 pipelineBuilder.setFromPaint(grPaint, rt, clip); 1981 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1285 1982
1286 GrColor color = grPaint.getColor(); 1983 GrColor color = grPaint.getColor();
1287 uint8_t paintAlpha = skPaint.getAlpha();
1288 1984
1289 SkTextBlob::RunIterator it(blob); 1985 SkTextBlob::RunIterator it(blob);
1290 for (int run = 0; !it.done(); it.next(), run++) { 1986 for (int run = 0; !it.done(); it.next(), run++) {
1291 if (cacheBlob->fRuns[run].fDrawAsPaths) { 1987 if (cacheBlob->fRuns[run].fDrawAsPaths) {
1292 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y); 1988 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound s, x, y);
1293 continue; 1989 continue;
1294 } 1990 }
1295 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); 1991 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY);
1296 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, transX, transY); 1992 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, transX, transY, skPaint);
1297 } 1993 }
1298 1994
1299 // Now flush big glyphs 1995 // Now flush big glyphs
1300 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); 1996 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY);
1301 } 1997 }
1302 1998
1303 void GrAtlasTextContext::flush(GrDrawTarget* target, 1999 void GrAtlasTextContext::flush(GrDrawTarget* target,
1304 BitmapTextBlob* cacheBlob, 2000 BitmapTextBlob* cacheBlob,
1305 GrRenderTarget* rt, 2001 GrRenderTarget* rt,
1306 const SkPaint& skPaint, 2002 const SkPaint& skPaint,
1307 const GrPaint& grPaint, 2003 const GrPaint& grPaint,
1308 const GrClip& clip, 2004 const GrClip& clip) {
1309 const SkMatrix& viewMatrix) {
1310 GrPipelineBuilder pipelineBuilder; 2005 GrPipelineBuilder pipelineBuilder;
1311 pipelineBuilder.setFromPaint(grPaint, rt, clip); 2006 pipelineBuilder.setFromPaint(grPaint, rt, clip);
1312 2007
1313 GrColor color = grPaint.getColor(); 2008 GrColor color = grPaint.getColor();
1314 uint8_t paintAlpha = skPaint.getAlpha();
1315 for (int run = 0; run < cacheBlob->fRunCount; run++) { 2009 for (int run = 0; run < cacheBlob->fRunCount; run++) {
1316 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp ha, 0, 0); 2010 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk Paint);
1317 } 2011 }
1318 2012
1319 // Now flush big glyphs 2013 // Now flush big glyphs
1320 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); 2014 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0);
1321 } 2015 }
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