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

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

Powered by Google App Engine
This is Rietveld 408576698