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

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

Powered by Google App Engine
This is Rietveld 408576698