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

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

Issue 1011403004: BitmapTextBatch and BitmapTextBlob (Closed) Base URL: https://skia.googlesource.com/skia.git@dfpr_take_2
Patch Set: tidy Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 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 "GrBitmapTextContext.h"
7 8
8 #include "GrBitmapTextContext.h"
9 #include "GrAtlas.h" 9 #include "GrAtlas.h"
10 #include "GrBatch.h"
11 #include "GrBatchFontCache.h"
12 #include "GrBatchTarget.h"
10 #include "GrDefaultGeoProcFactory.h" 13 #include "GrDefaultGeoProcFactory.h"
11 #include "GrDrawTarget.h" 14 #include "GrDrawTarget.h"
12 #include "GrFontCache.h" 15 #include "GrFontCache.h"
13 #include "GrFontScaler.h" 16 #include "GrFontScaler.h"
14 #include "GrIndexBuffer.h" 17 #include "GrIndexBuffer.h"
15 #include "GrStrokeInfo.h" 18 #include "GrStrokeInfo.h"
16 #include "GrTexturePriv.h" 19 #include "GrTexturePriv.h"
17 20
18 #include "SkAutoKern.h" 21 #include "SkAutoKern.h"
19 #include "SkColorPriv.h" 22 #include "SkColorPriv.h"
20 #include "SkDraw.h" 23 #include "SkDraw.h"
24 #include "SkDrawFilter.h"
21 #include "SkDrawProcs.h" 25 #include "SkDrawProcs.h"
22 #include "SkGlyphCache.h" 26 #include "SkGlyphCache.h"
23 #include "SkGpuDevice.h" 27 #include "SkGpuDevice.h"
24 #include "SkGr.h" 28 #include "SkGr.h"
25 #include "SkPath.h" 29 #include "SkPath.h"
26 #include "SkRTConf.h" 30 #include "SkRTConf.h"
27 #include "SkStrokeRec.h" 31 #include "SkStrokeRec.h"
32 #include "SkTextBlob.h"
28 #include "SkTextMapStateProc.h" 33 #include "SkTextMapStateProc.h"
29 34
30 #include "effects/GrBitmapTextGeoProc.h" 35 #include "effects/GrBitmapTextGeoProc.h"
31 #include "effects/GrSimpleTextureEffect.h" 36 #include "effects/GrSimpleTextureEffect.h"
32 37
33 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false, 38 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
34 "Dump the contents of the font cache before every purge."); 39 "Dump the contents of the font cache before every purge.");
35 40
36 namespace { 41 namespace {
37 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 42 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
38 43
39 // position + local coord 44 // position + local coord
40 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 45 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
41 46
42 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16); 47 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16);
43 48
44 static const int kVerticesPerGlyph = 4; 49 static const int kVerticesPerGlyph = 4;
45 static const int kIndicesPerGlyph = 6; 50 static const int kIndicesPerGlyph = 6;
46 }; 51 };
47 52
53 // TODO
54 // More tests
55 // move to SkCache
56
57 GrBitmapTextContextB::GrBitmapTextContextB(GrContext* context,
58 SkGpuDevice* gpuDevice,
59 const SkDeviceProperties& properties)
60 : INHERITED(context, gpuDevice, propertie s) {
61 fStrike = NULL;
62 }
63
64 void GrBitmapTextContextB::ClearCacheEntry(uint32_t key, BitmapTextBlob** blob) {
65 (*blob)->unref();
66 }
67
68 GrBitmapTextContextB::~GrBitmapTextContextB() {
69 fCache.foreach(&GrBitmapTextContextB::ClearCacheEntry);
70 }
71
72 GrBitmapTextContextB* GrBitmapTextContextB::Create(GrContext* context,
73 SkGpuDevice* gpuDevice,
74 const SkDeviceProperties& props ) {
75 return SkNEW_ARGS(GrBitmapTextContextB, (context, gpuDevice, props));
76 }
77
78 bool GrBitmapTextContextB::canDraw(const SkPaint& paint, const SkMatrix& viewMat rix) {
79 return !SkDraw::ShouldDrawTextAsPaths(paint, viewMatrix);
80 }
81
82 inline void GrBitmapTextContextB::init(GrRenderTarget* rt, const GrClip& clip,
83 const GrPaint& paint, const SkPaint& skPai nt,
84 const SkIRect& regionClipBounds) {
85 INHERITED::init(rt, clip, paint, skPaint, regionClipBounds);
86
87 fStrike = NULL;
88 }
89
90 bool GrBitmapTextContextB::MustRegenerateBlob(const BitmapTextBlob& blob, const SkPaint& paint,
91 const SkMatrix& viewMatrix, SkScala r x, SkScalar y) {
92 // We always regenerate blobs with patheffects or mask filters we could cach e these
93 // TODO find some way to cache the maskfilter / patheffects on the textblob
94 return !blob.fViewMatrix.cheapEqualTo(viewMatrix) || blob.fX != x || blob.fY != y ||
jvanverth1 2015/03/23 20:37:39 We might be able render blobs with different trans
joshualitt 2015/03/24 14:33:56 I added this as a comment in the CL so we can revi
95 paint.getMaskFilter() || paint.getPathEffect() || paint.getStyle() ! = blob.fStyle;
96 }
97
98 void GrBitmapTextContextB::onDrawTextBlob(GrRenderTarget* rt, const GrClip& clip ,
99 const SkPaint& skPaint, const SkMatrix& viewMatrix,
100 const SkTextBlob* blob, SkScalar x, SkS calar y,
101 SkDrawFilter* drawFilter, const SkIRect & clipBounds) {
102 BitmapTextBlob* cacheBlob;
103 BitmapTextBlob** foundBlob = fCache.find(blob->uniqueID());
104
105 if (foundBlob) {
106 cacheBlob = *foundBlob;
107 if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) {
108 // We can get away with reusing the blob if there are no outstanding refs on it.
109 // However, we still have to reset all of the runs.
110 if (!cacheBlob->unique()) {
111 cacheBlob->unref();
112 cacheBlob = SkNEW(BitmapTextBlob);
113 fCache.set(blob->uniqueID(), cacheBlob);
114 }
115 this->regenerateTextBlob(cacheBlob, rt, clip, skPaint, viewMatrix, b lob, x, y,
116 drawFilter, clipBounds);
117 }
118
119 // TODO is this right?
120 GrPaint grPaint;
121 SkPaint2GrPaintShader(fContext, fRenderTarget, skPaint, viewMatrix, true , &grPaint);
122 INHERITED::init(rt, clip, grPaint, skPaint, clipBounds);
123 } else {
124 cacheBlob = SkNEW(BitmapTextBlob);
125 fCache.set(blob->uniqueID(), cacheBlob);
126 this->regenerateTextBlob(cacheBlob, rt, clip, skPaint, viewMatrix, blob, x, y,
127 drawFilter, clipBounds);
128 }
129
130 this->finish(cacheBlob);
131 }
132
133 void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
134 GrRenderTarget* rt,
135 const GrClip& clip,
136 const SkPaint& skPaint, const SkMa trix& viewMatrix,
137 const SkTextBlob* blob, SkScalar x , SkScalar y,
138 SkDrawFilter* drawFilter, const Sk IRect& clipBounds) {
139 cacheBlob->fViewMatrix = viewMatrix;
140 cacheBlob->fX = x;
141 cacheBlob->fY = y;
142 cacheBlob->fStyle = skPaint.getStyle();
143 cacheBlob->fRuns.reset(blob->fRunCount);
144
145 // Regenerate textblob
146 SkPaint runPaint = skPaint;
147 SkTextBlob::RunIterator it(blob);
148 for (int run = 0;!it.done(); it.next(), run++) {
149 size_t textLen = it.glyphCount() * sizeof(uint16_t);
150 const SkPoint& offset = it.offset();
151 // applyFontToPaint() always overwrites the exact same attributes,
152 // so it is safe to not re-seed the paint for this reason.
153 it.applyFontToPaint(&runPaint);
154
155 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) {
156 // A false return from filter() means we should abort the current dr aw.
157 runPaint = skPaint;
158 continue;
159 }
160
161 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
162
163 GrPaint grPaint;
164 SkPaint2GrPaintShader(fContext, fRenderTarget, runPaint, viewMatrix, tru e, &grPaint);
165
166 switch (it.positioning()) {
167 case SkTextBlob::kDefault_Positioning:
168 this->internalDrawText(cacheBlob, run, rt, clip, grPaint, runPai nt, viewMatrix,
169 (const char *)it.glyphs(), textLen,
170 x + offset.x(), y + offset.y(), clipBound s);
171 break;
172 case SkTextBlob::kHorizontal_Positioning:
173 this->internalDrawPosText(cacheBlob, run, rt, clip, grPaint, run Paint, viewMatrix,
174 (const char*)it.glyphs(), textLen, it. pos(), 1,
175 SkPoint::Make(x, y + offset.y()), clip Bounds);
176 break;
177 case SkTextBlob::kFull_Positioning:
178 this->internalDrawPosText(cacheBlob, run, rt, clip, grPaint, run Paint, viewMatrix,
179 (const char*)it.glyphs(), textLen, it. pos(), 2,
180 SkPoint::Make(x, y), clipBounds);
181 break;
182 }
183
184 if (drawFilter) {
185 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
186 runPaint = skPaint;
187 }
188 }
189 }
190
191 void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip,
192 const GrPaint& paint, const SkPaint& skPain t,
193 const SkMatrix& viewMatrix,
194 const char text[], size_t byteLength,
195 SkScalar x, SkScalar y, const SkIRect& regi onClipBounds) {
196 SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
197 blob->fViewMatrix = viewMatrix;
198 blob->fX = x;
199 blob->fY = y;
200 blob->fStyle = skPaint.getStyle();
201 blob->fRuns.push_back();
202 this->internalDrawText(blob, 0, rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y,
203 regionClipBounds);
204
205 this->finish(blob);
206 }
207
208 void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex, GrRenderTarget* rt,
209 const GrClip& clip,
210 const GrPaint& paint, const SkPaint& skPaint,
211 const SkMatrix& viewMatrix,
212 const char text[], size_t byteLength,
213 SkScalar x, SkScalar y,
214 const SkIRect& regionClipBounds) {
215 SkASSERT(byteLength == 0 || text != NULL);
216
217 // nothing to draw
218 if (text == NULL || byteLength == 0) {
219 return;
220 }
221
222 this->init(rt, clip, paint, skPaint, regionClipBounds);
223
224 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
225
226 // Get GrFontScaler from cache
227 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
228 run.fDescriptor.reset(fSkPaint.getScalerContextDescriptor(&fDeviceProperties , &viewMatrix,
229 false));
230 run.fTypeface.reset(SkSafeRef(fSkPaint.getTypeface()));
231 const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescri ptor->data());
232 SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
233 GrFontScaler* fontScaler = GetGrFontScaler(cache);
234
235 // transform our starting point
236 {
237 SkPoint loc;
238 viewMatrix.mapXY(x, y, &loc);
239 x = loc.fX;
240 y = loc.fY;
241 }
242
243 // need to measure first
244 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
245 SkVector stopVector;
246 MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
247
248 SkScalar stopX = stopVector.fX;
249 SkScalar stopY = stopVector.fY;
250
251 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
252 stopX = SkScalarHalf(stopX);
253 stopY = SkScalarHalf(stopY);
254 }
255 x -= stopX;
256 y -= stopY;
257 }
258
259 const char* stop = text + byteLength;
260
261 SkAutoKern autokern;
262
263 SkFixed fxMask = ~0;
264 SkFixed fyMask = ~0;
265 SkScalar halfSampleX, halfSampleY;
266 if (cache->isSubpixel()) {
267 halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
268 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
269 if (kX_SkAxisAlignment == baseline) {
270 fyMask = 0;
271 halfSampleY = SK_ScalarHalf;
272 } else if (kY_SkAxisAlignment == baseline) {
273 fxMask = 0;
274 halfSampleX = SK_ScalarHalf;
275 }
276 } else {
277 halfSampleX = halfSampleY = SK_ScalarHalf;
278 }
279
280 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
281 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
282
283 while (text < stop) {
284 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask);
285
286 fx += autokern.adjust(glyph);
287
288 if (glyph.fWidth) {
289 this->appendGlyph(blob,
290 runIndex,
291 GrGlyph::Pack(glyph.getGlyphID(),
292 glyph.getSubXFixed(),
293 glyph.getSubYFixed(),
294 GrGlyph::kCoverage_MaskStyle),
295 Sk48Dot16FloorToInt(fx),
296 Sk48Dot16FloorToInt(fy),
297 fontScaler);
298 }
299
300 fx += glyph.fAdvanceX;
301 fy += glyph.fAdvanceY;
302 }
303
304 SkGlyphCache::AttachCache(cache);
305 }
306
307 void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
308 const GrPaint& paint, const SkPaint& skP aint,
309 const SkMatrix& viewMatrix,
310 const char text[], size_t byteLength,
311 const SkScalar pos[], int scalarsPerPosi tion,
312 const SkPoint& offset, const SkIRect& re gionClipBounds) {
313 SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
314 blob->fStyle = skPaint.getStyle();
315 blob->fRuns.push_back();
316 blob->fViewMatrix = viewMatrix;
317 this->internalDrawPosText(blob, 0, rt, clip, paint, skPaint, viewMatrix, tex t, byteLength, pos,
318 scalarsPerPosition, offset, regionClipBounds);
319 this->finish(blob);
320 }
321
322 void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde x,
323 GrRenderTarget* rt,
324 const GrClip& clip,
325 const GrPaint& paint, const SkPain t& skPaint,
326 const SkMatrix& viewMatrix,
327 const char text[], size_t byteLeng th,
328 const SkScalar pos[], int scalarsP erPosition,
329 const SkPoint& offset,
330 const SkIRect& regionClipBounds) {
331 SkASSERT(byteLength == 0 || text != NULL);
332 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
333
334 // nothing to draw
335 if (text == NULL || byteLength == 0) {
336 return;
337 }
338
339 this->init(rt, clip, paint, skPaint, regionClipBounds);
340
341 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
342
343 // Get GrFontScaler from cache
344 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
345 run.fDescriptor.reset(fSkPaint.getScalerContextDescriptor(&fDeviceProperties , &viewMatrix,
346 false));
347 run.fTypeface.reset(SkSafeRef(fSkPaint.getTypeface()));
348 const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescri ptor->data());
349 SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
350 GrFontScaler* fontScaler = GetGrFontScaler(cache);
351
352 const char* stop = text + byteLength;
353 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
354 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
355 SkScalar halfSampleX = 0, halfSampleY = 0;
356
357 if (cache->isSubpixel()) {
358 // maybe we should skip the rounding if linearText is set
359 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
360
361 SkFixed fxMask = ~0;
362 SkFixed fyMask = ~0;
363 if (kX_SkAxisAlignment == baseline) {
364 fyMask = 0;
365 halfSampleY = SK_ScalarHalf;
366 } else if (kY_SkAxisAlignment == baseline) {
367 fxMask = 0;
368 halfSampleX = SK_ScalarHalf;
369 }
370
371 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
372 while (text < stop) {
373 SkPoint tmsLoc;
374 tmsProc(pos, &tmsLoc);
375 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX);
376 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY);
377
378 const SkGlyph& glyph = glyphCacheProc(cache, &text,
379 fx & fxMask, fy & fyMask);
380
381 if (glyph.fWidth) {
382 this->appendGlyph(blob,
383 runIndex,
384 GrGlyph::Pack(glyph.getGlyphID(),
385 glyph.getSubXFixed(),
386 glyph.getSubYFixed(),
387 GrGlyph::kCoverage_MaskStyle ),
388 Sk48Dot16FloorToInt(fx),
389 Sk48Dot16FloorToInt(fy),
390 fontScaler);
391 }
392 pos += scalarsPerPosition;
393 }
394 } else {
395 while (text < stop) {
396 const char* currentText = text;
397 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
398
399 if (metricGlyph.fWidth) {
400 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
401 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
402 SkPoint tmsLoc;
403 tmsProc(pos, &tmsLoc);
404 SkPoint alignLoc;
405 alignProc(tmsLoc, metricGlyph, &alignLoc);
406
407 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX);
408 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY);
409
410 // have to call again, now that we've been "aligned"
411 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
412 fx & fxMask, fy & fyMa sk);
413 // the assumption is that the metrics haven't changed
414 SkASSERT(prevAdvX == glyph.fAdvanceX);
415 SkASSERT(prevAdvY == glyph.fAdvanceY);
416 SkASSERT(glyph.fWidth);
417
418 this->appendGlyph(blob,
419 runIndex,
420 GrGlyph::Pack(glyph.getGlyphID(),
421 glyph.getSubXFixed(),
422 glyph.getSubYFixed(),
423 GrGlyph::kCoverage_MaskStyle ),
424 Sk48Dot16FloorToInt(fx),
425 Sk48Dot16FloorToInt(fy),
426 fontScaler);
427 }
428 pos += scalarsPerPosition;
429 }
430 }
431 } else { // not subpixel
432
433 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
434 while (text < stop) {
435 // the last 2 parameters are ignored
436 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
437
438 if (glyph.fWidth) {
439 SkPoint tmsLoc;
440 tmsProc(pos, &tmsLoc);
441
442 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
443 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
444 this->appendGlyph(blob,
445 runIndex,
446 GrGlyph::Pack(glyph.getGlyphID(),
447 glyph.getSubXFixed(),
448 glyph.getSubYFixed(),
449 GrGlyph::kCoverage_MaskStyle ),
450 Sk48Dot16FloorToInt(fx),
451 Sk48Dot16FloorToInt(fy),
452 fontScaler);
453 }
454 pos += scalarsPerPosition;
455 }
456 } else {
457 while (text < stop) {
458 // the last 2 parameters are ignored
459 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
460
461 if (glyph.fWidth) {
462 SkPoint tmsLoc;
463 tmsProc(pos, &tmsLoc);
464
465 SkPoint alignLoc;
466 alignProc(tmsLoc, glyph, &alignLoc);
467
468 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX;
469 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY;
470 this->appendGlyph(blob,
471 runIndex,
472 GrGlyph::Pack(glyph.getGlyphID(),
473 glyph.getSubXFixed(),
474 glyph.getSubYFixed(),
475 GrGlyph::kCoverage_MaskStyle ),
476 Sk48Dot16FloorToInt(fx),
477 Sk48Dot16FloorToInt(fy),
478 fontScaler);
479 }
480 pos += scalarsPerPosition;
481 }
482 }
483 }
484 SkGlyphCache::AttachCache(cache);
485 }
486
487 static size_t get_vertex_stride(GrMaskFormat maskFormat) {
488 switch (maskFormat) {
489 case kA8_GrMaskFormat:
490 return kGrayTextVASize;
491 case kARGB_GrMaskFormat:
492 return kColorTextVASize;
493 default:
494 return kLCDTextVASize;
495 }
496 }
497
498 void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly ph::PackedID packed,
499 int vx, int vy,
500 GrFontScaler* scaler) {
501 if (NULL == fStrike) {
502 fStrike = fContext->getBatchFontCache()->getStrike(scaler);
503 }
504
505 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
506 if (NULL == glyph || glyph->fBounds.isEmpty()) {
507 return;
508 }
509
510 int x = vx + glyph->fBounds.fLeft;
511 int y = vy + glyph->fBounds.fTop;
512
513 // keep them as ints until we've done the clip-test
514 int width = glyph->fBounds.width();
515 int height = glyph->fBounds.height();
516
517 // check if we clipped out
518 if (fClipRect.quickReject(x, y, x + width, y + height)) {
519 return;
520 }
521
522 // If the glyph is too large we fall back to paths
523 if (fStrike->glyphTooLargeForAtlas(glyph)) {
524 if (NULL == glyph->fPath) {
525 SkPath* path = SkNEW(SkPath);
526 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
527 // flag the glyph as being dead?
528 SkDELETE(path);
529 return;
530 }
531 glyph->fPath = path;
532 }
533 SkASSERT(glyph->fPath);
534 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v y));
535 return;
536 }
537 GrMaskFormat format = glyph->fMaskFormat;
538 size_t vertexStride = get_vertex_stride(format);
539
540 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
541 int glyphIdx = run.fInfos[format].fGlyphIDs.count();
542 *run.fInfos[format].fGlyphIDs.append() = packed;
543 run.fInfos[format].fVertices.append(vertexStride * kVerticesPerGlyph);
544
545 SkRect r;
546 r.fLeft = SkIntToScalar(x);
547 r.fTop = SkIntToScalar(y);
548 r.fRight = r.fLeft + SkIntToScalar(width);
549 r.fBottom = r.fTop + SkIntToScalar(height);
550
551 run.fVertexBounds.joinNonEmptyArg(r);
552 GrColor color = fPaint.getColor();
553 run.fColor = color;
554
555 intptr_t vertex = reinterpret_cast<intptr_t>(run.fInfos[format].fVertices.be gin());
556 vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
557
558 // V0
559 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
560 position->set(r.fLeft, r.fTop);
561 if (kA8_GrMaskFormat == format) {
562 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
563 *colorPtr = color;
564 }
565 vertex += vertexStride;
566
567 // V1
568 position = reinterpret_cast<SkPoint*>(vertex);
569 position->set(r.fLeft, r.fBottom);
570 if (kA8_GrMaskFormat == format) {
571 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
572 *colorPtr = color;
573 }
574 vertex += vertexStride;
575
576 // V2
577 position = reinterpret_cast<SkPoint*>(vertex);
578 position->set(r.fRight, r.fBottom);
579 if (kA8_GrMaskFormat == format) {
580 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
581 *colorPtr = color;
582 }
583 vertex += vertexStride;
584
585 // V3
586 position = reinterpret_cast<SkPoint*>(vertex);
587 position->set(r.fRight, r.fTop);
588 if (kA8_GrMaskFormat == format) {
589 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
590 *colorPtr = color;
591 }
592 }
593
594 class BitmapTextBatch : public GrBatch {
595 public:
596 typedef GrBitmapTextContextB::BitmapTextBlob Blob;
597 typedef Blob::Run Run;
598 typedef Run::TextInfo TextInfo;
599 struct Geometry {
600 Geometry() {}
601 Geometry(const Geometry& geometry)
602 : fBlob(SkRef(geometry.fBlob.get()))
603 , fRun(geometry.fRun)
604 , fColor(geometry.fColor) {}
605 SkAutoTUnref<Blob> fBlob;
606 int fRun;
607 GrColor fColor;
608 };
609
610 static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
611 GrBatchFontCache* fontCache) {
612 return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, fontCac he));
613 }
614
615 const char* name() const SK_OVERRIDE { return "BitmapTextBatch"; }
616
617 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
618 if (kARGB_GrMaskFormat == fMaskFormat) {
619 out->setUnknownFourComponents();
620 } else {
621 out->setKnownFourComponents(fBatch.fColor);
622 }
623 }
624
625 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const SK_OVERRID E {
626 if (kARGB_GrMaskFormat != fMaskFormat) {
627 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
628 out->setUnknownSingleComponent();
629 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
630 out->setUnknownOpaqueFourComponents();
631 out->setUsingLCDCoverage();
632 } else {
633 out->setUnknownFourComponents();
634 out->setUsingLCDCoverage();
635 }
636 } else {
637 out->setKnownSingleComponent(0xff);
638 }
639 }
640
641 void initBatchTracker(const GrPipelineInfo& init) SK_OVERRIDE {
642 // Handle any color overrides
643 if (init.fColorIgnored) {
644 fBatch.fColor = GrColor_ILLEGAL;
645 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
646 fBatch.fColor = init.fOverrideColor;
647 }
648
649 // setup batch properties
650 fBatch.fColorIgnored = init.fColorIgnored;
651 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
652 fBatch.fCoverageIgnored = init.fCoverageIgnored;
653 }
654
655 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) SK_OVERRIDE {
656 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
657 // TODO actually only invert if we don't have RGBA
658 SkMatrix localMatrix;
659 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
660 SkDebugf("Cannot invert viewmatrix\n");
661 return;
662 }
663
664 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode);
665 // This will be ignored in the non A8 case
666 bool opaqueVertexColors = GrColorIsOpaque(this->color());
667 SkAutoTUnref<const GrGeometryProcessor> gp(
668 GrBitmapTextGeoProc::Create(this->color(),
669 fFontCache->getTexture(fMaskFormat),
670 params,
671 fMaskFormat,
672 opaqueVertexColors,
673 localMatrix));
674
675 size_t vertexStride = gp->getVertexStride();
676 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat));
677
678 this->initDraw(batchTarget, gp, pipeline);
679
680 int glyphCount = this->numGlyphs();
681 int instanceCount = fGeoData.count();
682 const GrVertexBuffer* vertexBuffer;
683 int firstVertex;
684
685 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
686 glyphCount * kVert icesPerGlyph,
687 &vertexBuffer,
688 &firstVertex);
689 if (!vertices) {
690 SkDebugf("Could not allocate vertices\n");
691 return;
692 }
693
694 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
695
696 // setup drawinfo
697 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
698 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
699
700 GrDrawTarget::DrawInfo drawInfo;
701 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
702 drawInfo.setStartVertex(0);
703 drawInfo.setStartIndex(0);
704 drawInfo.setVerticesPerInstance(kVerticesPerGlyph);
705 drawInfo.setIndicesPerInstance(kIndicesPerGlyph);
706 drawInfo.adjustStartVertex(firstVertex);
707 drawInfo.setVertexBuffer(vertexBuffer);
708 drawInfo.setIndexBuffer(quadIndexBuffer);
709
710 int instancesToFlush = 0;
711 for (int i = 0; i < instanceCount; i++) {
712 Geometry& args = fGeoData[i];
713 Blob* blob = args.fBlob;
714 Run& run = blob->fRuns[args.fRun];
715 TextInfo& info = run.fInfos[fMaskFormat];
716
717 uint32_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
718 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen;
719 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor;
720 int glyphCount = info.fGlyphIDs.count();
721
722 // We regenerate both texture coords and colors in the blob itself, and update the
723 // atlas generation. If we don't end up purging any unused plots, w e can avoid
724 // regenerating the coords. We could take a finer grained approach to updating texture
725 // coords but its not clear if the extra bookkeeping would offset an y gains.
726 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color
727 // or coords as needed. One final note, if we have to break a run f or an atlas eviction
728 // then we can't really trust the atlas has all of the correct data. Atlas evictions
729 // should be pretty rare, so we just always regenerate in those case s
730 if (regenerateTextureCoords || regenerateColors) {
731 // first regenerate texture coordinates / colors if need be
732 const SkDescriptor* desc = NULL;
733 SkGlyphCache* cache = NULL;
734 GrFontScaler* scaler = NULL;
735 GrBatchTextStrike* strike = NULL;
736 bool brokenRun = false;
737 if (regenerateTextureCoords) {
738 desc = reinterpret_cast<const SkDescriptor*>(run.fDescriptor ->data());
739 cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
740 scaler = GrTextContext::GetGrFontScaler(cache);
741 strike = fFontCache->getStrike(scaler);
742 }
743 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
744 GrGlyph::PackedID glyphID = info.fGlyphIDs[glyphIdx];
745
746 if (regenerateTextureCoords) {
747 // Upload the glyph only if needed
748 GrGlyph* glyph = strike->getGlyph(glyphID, scaler);
749 SkASSERT(glyph);
750
751 if (!fFontCache->hasGlyph(glyph) &&
752 !strike->addGlyphToAtlas(batchTarget, glyph, scaler) ) {
753 this->flush(batchTarget, &drawInfo, instancesToFlush ,
754 maxInstancesPerDraw);
755 this->initDraw(batchTarget, gp, pipeline);
756 instancesToFlush = 0;
757 brokenRun = glyphIdx > 0;
758
759 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas( batchTarget, glyph,
760 scaler);
761 SkASSERT(success);
762 }
763
764 fFontCache->refGlyph(glyph, batchTarget->currentToken()) ;
765
766 this->regenerateTextureCoords(glyph, (void*)info.fVertic es.begin(),
767 vertexStride, glyphIdx * k VerticesPerGlyph);
768 }
769
770 if (regenerateColors) {
771 this->regenerateColors((void*)info.fVertices.begin(), ve rtexStride,
772 glyphIdx * kVerticesPerGlyph, arg s.fColor);
773 }
774
775 instancesToFlush++;
776 }
777
778 if (regenerateTextureCoords) {
779 SkGlyphCache::AttachCache(cache);
780 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration :
781 fFontCache->atlasGenerat ion(fMaskFormat);
782 }
783 } else {
784 instancesToFlush += glyphCount;
785 }
786
787 // now copy all vertices
788 int byteCount = info.fVertices.count();
789 memcpy(currVertex, info.fVertices.begin(), byteCount);
790
791 currVertex += byteCount;
792 }
793
794 this->flush(batchTarget, &drawInfo, instancesToFlush, maxInstancesPerDra w);
795 }
796
797 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
798
799 private:
800 BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFo rmat,
801 GrBatchFontCache* fontCache)
802 : fMaskFormat(maskFormat)
803 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
804 , fFontCache(fontCache) {
805 this->initClassID<BitmapTextBatch>();
806 fGeoData.push_back(geometry);
807 fBatch.fColor = color;
808 fBatch.fViewMatrix = geometry.fBlob->fViewMatrix;
809 int numGlyphs = geometry.fBlob->fRuns[geometry.fRun].fInfos[maskFormat]. fGlyphIDs.count();
810 fBatch.fNumGlyphs = numGlyphs;
811 }
812
813 void regenerateTextureCoords(GrGlyph* glyph, void* vertices, size_t vertexSt ride,
814 int currVertex) {
815 int width = glyph->fBounds.width();
816 int height = glyph->fBounds.height();
817 int u0 = glyph->fAtlasLocation.fX;
818 int v0 = glyph->fAtlasLocation.fY;
819 int u1 = u0 + width;
820 int v1 = v0 + height;
821
822 intptr_t vertex = reinterpret_cast<intptr_t>(vertices) + vertexStride * currVertex;
823
824 // we assume texture coords are the last vertex attribute, this is a bit fragile.
825 // TODO pass in this offset or something
826 SkIPoint16* textureCoords;
827 // V0
828 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertexStride - si zeof(SkIPoint16));
829 textureCoords->set(u0, v0);
830 vertex += vertexStride;
831
832 // V1
833 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertexStride - si zeof(SkIPoint16));
834 textureCoords->set(u0, v1);
835 vertex += vertexStride;
836
837 // V2
838 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertexStride - si zeof(SkIPoint16));
839 textureCoords->set(u1, v1);
840 vertex += vertexStride;
841
842 // V3
843 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertexStride - si zeof(SkIPoint16));
844 textureCoords->set(u1, v0);
845 }
846
847 void regenerateColors(void* vertices, size_t vertexStride,
848 int currVertex, GrColor color) {
849 intptr_t vertex = reinterpret_cast<intptr_t>(vertices) + vertexStride * currVertex;
850
851 for (int i = 0; i < kVerticesPerGlyph; i++) {
852 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint ));
853 *vcolor = color;
854 vertex += vertexStride;
855 }
856 }
857
858 void initDraw(GrBatchTarget* batchTarget,
859 const GrGeometryProcessor* gp,
860 const GrPipeline* pipeline) {
861 batchTarget->initDraw(gp, pipeline);
862
863 // TODO remove this when batch is everywhere
864 GrPipelineInfo init;
865 init.fColorIgnored = fBatch.fColorIgnored;
866 init.fOverrideColor = GrColor_ILLEGAL;
867 init.fCoverageIgnored = fBatch.fCoverageIgnored;
868 init.fUsesLocalCoords = this->usesLocalCoords();
869 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
870 }
871
872 void flush(GrBatchTarget* batchTarget,
873 GrDrawTarget::DrawInfo* drawInfo,
874 int instanceCount,
875 int maxInstancesPerDraw) {
876 while (instanceCount) {
877 drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw ));
878 drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verti cesPerInstance());
879 drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indice sPerInstance());
880
881 batchTarget->draw(*drawInfo);
882
883 drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexC ount());
884 instanceCount -= drawInfo->instanceCount();
885 }
886 }
887
888 GrColor color() const { return fBatch.fColor; }
889 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
890 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
891 int numGlyphs() const { return fBatch.fNumGlyphs; }
892
893 bool onCombineIfPossible(GrBatch* t) SK_OVERRIDE {
894 BitmapTextBatch* that = t->cast<BitmapTextBatch>();
895
896 if (this->fMaskFormat != that->fMaskFormat) {
897 return false;
898 }
899
900 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo r()) {
901 return false;
902 }
903
904 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
905 return false;
906 }
907
908 fBatch.fNumGlyphs += that->numGlyphs();
909 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
910 return true;
911 }
912
913 struct BatchTracker {
914 GrColor fColor;
915 SkMatrix fViewMatrix;
916 bool fUsesLocalCoords;
917 bool fColorIgnored;
918 bool fCoverageIgnored;
919 int fNumGlyphs;
920 };
921
922 BatchTracker fBatch;
923 SkSTArray<1, Geometry, true> fGeoData;
924 GrMaskFormat fMaskFormat;
925 GrPixelConfig fPixelConfig;
926 GrBatchFontCache* fFontCache;
927 };
928
929 void GrBitmapTextContextB::flush(BitmapTextBlob* blob, int i, GrPipelineBuilder* pipelineBuilder,
930 GrMaskFormat format) {
931 if (0 == blob->fRuns[i].fInfos[format].fGlyphIDs.count()) {
932 return;
933 }
934
935 GrColor color = fPaint.getColor();
936 if (kARGB_GrMaskFormat == format) {
937 int a = fSkPaint.getAlpha();
938 color = SkColorSetARGB(a, a, a, a);
939 } else if (kA565_GrMaskFormat == format) {
940 // TODO: move supportsRGBCoverage check to setupCoverageEffect and only add LCD
941 // processor if the xp can support it. For now we will simply assume tha t if
942 // fUseLCDText is true, then we have a known color output.
943 const GrXPFactory* xpFactory = pipelineBuilder->getXPFactory();
944 if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
945 SkDebugf("LCD Text will not draw correctly.\n");
946 }
947 }
948
949 BitmapTextBatch::Geometry geometry;
950 geometry.fBlob.reset(SkRef(blob));
951 geometry.fRun = i;
952 geometry.fColor = color;
953 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format,
954 fContext->getBatchFontCa che()));
955
956 fDrawTarget->drawBatch(pipelineBuilder, batch, &blob->fRuns[i].fVertexBounds );
957 }
958
959 void GrBitmapTextContextB::flush(BitmapTextBlob* blob) {
960 GrPipelineBuilder pipelineBuilder;
961 pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
962
963 for (int i = 0; i < blob->fRuns.count(); i++) {
964 this->flush(blob, i, &pipelineBuilder, kA8_GrMaskFormat);
965 this->flush(blob, i, &pipelineBuilder, kA565_GrMaskFormat);
966 this->flush(blob, i, &pipelineBuilder, kARGB_GrMaskFormat);
967 }
968
969 // Now flush big glyphs
970 for (int i = 0; i < blob->fBigGlyphs.count(); i++) {
971 BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i];
972 SkMatrix translate;
973 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly ph.fVy));
974 SkPath tmpPath(bigGlyph.fPath);
975 tmpPath.transform(translate);
976 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
977 fContext->drawPath(fRenderTarget, fClip, fPaint, SkMatrix::I(), tmpPath, strokeInfo);
978 }
979 }
980
981 inline void GrBitmapTextContextB::finish(BitmapTextBlob* blob) {
982 this->flush(blob);
983
984 INHERITED::finish();
985 }
986
48 GrBitmapTextContext::GrBitmapTextContext(GrContext* context, 987 GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
49 SkGpuDevice* gpuDevice, 988 SkGpuDevice* gpuDevice,
50 const SkDeviceProperties& properties) 989 const SkDeviceProperties& properties)
51 : GrTextContext(context, gpuDevice, properties) { 990 : GrTextContext(context, gpuDevice, properties) {
52 fStrike = NULL; 991 fStrike = NULL;
53 992
54 fCurrTexture = NULL; 993 fCurrTexture = NULL;
55 fEffectTextureUniqueID = SK_InvalidUniqueID; 994 fEffectTextureUniqueID = SK_InvalidUniqueID;
56 995
57 fVertices = NULL; 996 fVertices = NULL;
(...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after
341 fontScaler); 1280 fontScaler);
342 } 1281 }
343 pos += scalarsPerPosition; 1282 pos += scalarsPerPosition;
344 } 1283 }
345 } 1284 }
346 } 1285 }
347 1286
348 this->finish(); 1287 this->finish();
349 } 1288 }
350 1289
351 static size_t get_vertex_stride(GrMaskFormat maskFormat) {
352 switch (maskFormat) {
353 case kA8_GrMaskFormat:
354 return kGrayTextVASize;
355 case kARGB_GrMaskFormat:
356 return kColorTextVASize;
357 default:
358 return kLCDTextVASize;
359 }
360 }
361
362 static void* alloc_vertices(GrDrawTarget* drawTarget, 1290 static void* alloc_vertices(GrDrawTarget* drawTarget,
363 int numVertices, 1291 int numVertices,
364 GrMaskFormat maskFormat) { 1292 GrMaskFormat maskFormat) {
365 if (numVertices <= 0) { 1293 if (numVertices <= 0) {
366 return NULL; 1294 return NULL;
367 } 1295 }
368 1296
369 // set up attributes 1297 // set up attributes
370 void* vertices = NULL; 1298 void* vertices = NULL;
371 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices, 1299 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
372 get_vertex_stride(mask Format), 1300 get_vertex_stride(mask Format),
373 0, 1301 0,
374 &vertices, 1302 &vertices,
375 NULL); 1303 NULL);
376 GrAlwaysAssert(success); 1304 GrAlwaysAssert(success);
377 return vertices; 1305 return vertices;
378 } 1306 }
379 1307
380 inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scale r) { 1308 inline bool GrBitmapTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler* scale r) {
381 if (!fStrike->glyphTooLargeForAtlas(glyph)) { 1309 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
382 if (fStrike->addGlyphToAtlas(glyph, scaler)) { 1310 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
383 return true; 1311 return true;
384 } 1312 }
385 1313
386 // try to clear out an unused plot before we flush 1314 // try to clear out an unused plot before we flush
387 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && 1315 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
388 fStrike->addGlyphToAtlas(glyph, scaler)) { 1316 fStrike->addGlyphToAtlas(glyph, scaler)) {
389 return true; 1317 return true;
390 } 1318 }
391 1319
392 if (c_DumpFontCache) { 1320 if (c_DumpFontCache) {
393 #ifdef SK_DEVELOPER 1321 #ifdef SK_DEVELOPER
394 fContext->getFontCache()->dump(); 1322 fContext->getFontCache()->dump();
395 #endif 1323 #endif
396 } 1324 }
397 1325
398 // before we purge the cache, we must flush any accumulated draws 1326 // before we purge the cache, we must flush any accumulated draws
399 this->flush(); 1327 this->flush();
400 fContext->flush(); 1328 fContext->flush();
401 1329
402 // we should have an unused plot now 1330 // we should have an unused plot now
403 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) && 1331 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
404 fStrike->addGlyphToAtlas(glyph, scaler)) { 1332 fStrike->addGlyphToAtlas(glyph, scaler)) {
405 return true; 1333 return true;
406 } 1334 }
407 1335
408 // we should never get here 1336 // we should never get here
409 SkASSERT(false); 1337 SkASSERT(false);
410 } 1338 }
411 1339
412 return false; 1340 return false;
413 } 1341 }
414 1342
415 void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed, 1343 void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
416 int vx, int vy, 1344 int vx, int vy,
417 GrFontScaler* scaler) { 1345 GrFontScaler* scaler) {
418 if (NULL == fDrawTarget) { 1346 if (NULL == fDrawTarget) {
419 return; 1347 return;
420 } 1348 }
421 1349
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
627 SkSafeSetNull(fCurrTexture); 1555 SkSafeSetNull(fCurrTexture);
628 } 1556 }
629 } 1557 }
630 1558
631 inline void GrBitmapTextContext::finish() { 1559 inline void GrBitmapTextContext::finish() {
632 this->flush(); 1560 this->flush();
633 fTotalVertexCount = 0; 1561 fTotalVertexCount = 0;
634 1562
635 GrTextContext::finish(); 1563 GrTextContext::finish();
636 } 1564 }
637
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698