OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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, ¤tText, | 844 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |