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

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: tweak 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,
robertphillips 2015/03/23 19:03:12 xtra spaces ?
joshualitt 2015/03/23 19:56:08 As discussed offline, this is because eventually t
58 SkGpuDevice* gpuDevice,
59 const SkDeviceProperties& properties)
60 : GrTextContext(context, gpuDevice, prope rties) {
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,
robertphillips 2015/03/23 19:03:12 all the follow on lines seem to be off by 1 in thi
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
robertphillips 2015/03/23 19:03:12 Is inline even allowed here ?
joshualitt 2015/03/23 19:56:09 Yes because its only called in this file.
82 inline void GrBitmapTextContextB::init(GrRenderTarget* rt, const GrClip& clip,
83 const GrPaint& paint, const SkPaint& skPai nt,
84 const SkIRect& regionClipBounds) {
85 GrTextContext::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 ||
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 GrTextContext::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
robertphillips 2015/03/23 19:03:12 Is this void intentionally on its own line ?
joshualitt 2015/03/23 19:56:09 Acknowledged.
133 void
134 GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
135 GrRenderTarget* rt,
136 const GrClip& clip,
137 const SkPaint& skPaint, const SkMatrix& viewMatrix,
138 const SkTextBlob* blob, SkScalar x, SkSc alar y,
139 SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
140 cacheBlob->fViewMatrix = viewMatrix;
141 cacheBlob->fX = x;
142 cacheBlob->fY = y;
143 cacheBlob->fStyle = skPaint.getStyle();
144 cacheBlob->fRuns.reset(blob->fRunCount);
145
146 // Regenerate textblob
147 SkPaint runPaint = skPaint;
148 SkTextBlob::RunIterator it(blob);
149 for (int run = 0;!it.done(); it.next(), run++) {
150 size_t textLen = it.glyphCount() * sizeof(uint16_t);
151 const SkPoint& offset = it.offset();
152 // applyFontToPaint() always overwrites the exact same attributes,
153 // so it is safe to not re-seed the paint for this reason.
154 it.applyFontToPaint(&runPaint);
155
156 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) {
157 // A false return from filter() means we should abort the current dr aw.
158 runPaint = skPaint;
159 continue;
160 }
161
162 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
163
164 GrPaint grPaint;
165 SkPaint2GrPaintShader(fContext, fRenderTarget, runPaint, viewMatrix, tru e, &grPaint);
166
167 switch (it.positioning()) {
168 case SkTextBlob::kDefault_Positioning:
169 this->internalDrawText(cacheBlob, run, rt, clip, grPaint, runPai nt, viewMatrix,
170 (const char *)it.glyphs(), textLen,
171 x + offset.x(), y + offset.y(), clipBound s);
172 break;
173 case SkTextBlob::kHorizontal_Positioning:
174 this->internalDrawPosText(cacheBlob, run, rt, clip, grPaint, run Paint, viewMatrix,
175 (const char*)it.glyphs(), textLen, it. pos(), 1,
176 SkPoint::Make(x, y + offset.y()), clip Bounds);
177 break;
178 case SkTextBlob::kFull_Positioning:
179 this->internalDrawPosText(cacheBlob, run, rt, clip, grPaint, run Paint, viewMatrix,
180 (const char*)it.glyphs(), textLen, it. pos(), 2,
181 SkPoint::Make(x, y), clipBounds);
182 break;
183 }
184
185 if (drawFilter) {
186 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
187 runPaint = skPaint;
188 }
189 }
190 }
191
192 void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip,
193 const GrPaint& paint, const SkPaint& skPain t,
194 const SkMatrix& viewMatrix,
195 const char text[], size_t byteLength,
196 SkScalar x, SkScalar y, const SkIRect& regi onClipBounds) {
197 SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
198 blob->fViewMatrix = viewMatrix;
199 blob->fX = x;
200 blob->fY = y;
201 blob->fStyle = skPaint.getStyle();
202 blob->fRuns.push_back();
203 this->internalDrawText(blob, 0, rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y,
204 regionClipBounds);
205
206 this->finish(blob);
207 }
208
209 void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex, GrRenderTarget* rt,
210 const GrClip& clip,
211 const GrPaint& paint, const SkPaint& skPaint,
212 const SkMatrix& viewMatrix,
213 const char text[], size_t byteLength,
214 SkScalar x, SkScalar y,
215 const SkIRect& regionClipBounds) {
216 SkASSERT(byteLength == 0 || text != NULL);
217
218 // nothing to draw
219 if (text == NULL || byteLength == 0) {
220 return;
221 }
222
223 this->init(rt, clip, paint, skPaint, regionClipBounds);
224
225 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
226
227 // Get GrFontScaler from cache
228 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
229 run.fDescriptor.reset(fSkPaint.getScalerContextDescriptor(&fDeviceProperties , &viewMatrix,
230 false));
231 run.fTypeface.reset(SkSafeRef(fSkPaint.getTypeface()));
232 const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescri ptor->data());
233 SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
234 GrFontScaler* fontScaler = GetGrFontScaler(cache);
235
236 // transform our starting point
237 {
238 SkPoint loc;
239 viewMatrix.mapXY(x, y, &loc);
240 x = loc.fX;
241 y = loc.fY;
242 }
243
244 // need to measure first
245 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
246 SkVector stopVector;
247 MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
248
249 SkScalar stopX = stopVector.fX;
250 SkScalar stopY = stopVector.fY;
251
252 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
253 stopX = SkScalarHalf(stopX);
254 stopY = SkScalarHalf(stopY);
255 }
256 x -= stopX;
257 y -= stopY;
258 }
259
260 const char* stop = text + byteLength;
261
262 SkAutoKern autokern;
263
264 SkFixed fxMask = ~0;
265 SkFixed fyMask = ~0;
266 SkScalar halfSampleX, halfSampleY;
267 if (cache->isSubpixel()) {
268 halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
269 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
270 if (kX_SkAxisAlignment == baseline) {
271 fyMask = 0;
272 halfSampleY = SK_ScalarHalf;
273 } else if (kY_SkAxisAlignment == baseline) {
274 fxMask = 0;
275 halfSampleX = SK_ScalarHalf;
276 }
277 } else {
278 halfSampleX = halfSampleY = SK_ScalarHalf;
279 }
280
281 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
282 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
283
284 while (text < stop) {
285 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask);
286
287 fx += autokern.adjust(glyph);
288
289 if (glyph.fWidth) {
290 this->appendGlyph(blob,
291 runIndex,
292 GrGlyph::Pack(glyph.getGlyphID(),
293 glyph.getSubXFixed(),
294 glyph.getSubYFixed(),
295 GrGlyph::kCoverage_MaskStyle),
296 Sk48Dot16FloorToInt(fx),
297 Sk48Dot16FloorToInt(fy),
298 fontScaler);
299 }
300
301 fx += glyph.fAdvanceX;
302 fy += glyph.fAdvanceY;
303 }
304
305 SkGlyphCache::AttachCache(cache);
306 }
307
308 void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
309 const GrPaint& paint, const SkPaint& skP aint,
310 const SkMatrix& viewMatrix,
311 const char text[], size_t byteLength,
312 const SkScalar pos[], int scalarsPerPosi tion,
313 const SkPoint& offset, const SkIRect& re gionClipBounds) {
314 SkAutoTUnref<BitmapTextBlob> blob(SkNEW(BitmapTextBlob));
315 blob->fStyle = skPaint.getStyle();
316 blob->fRuns.push_back();
317 blob->fViewMatrix = viewMatrix;
318 this->internalDrawPosText(blob, 0, rt, clip, paint, skPaint, viewMatrix, tex t, byteLength, pos,
319 scalarsPerPosition, offset, regionClipBounds);
320 this->finish(blob);
321 }
322
robertphillips 2015/03/23 19:03:12 This method is officially too long
joshualitt 2015/03/23 19:56:09 This function is copied from the original bitmapte
323 void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde x,
324 GrRenderTarget* rt,
325 const GrClip& clip,
326 const GrPaint& paint, const SkPain t& skPaint,
327 const SkMatrix& viewMatrix,
328 const char text[], size_t byteLeng th,
329 const SkScalar pos[], int scalarsP erPosition,
330 const SkPoint& offset,
331 const SkIRect& regionClipBounds) {
332 SkASSERT(byteLength == 0 || text != NULL);
333 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
334
335 // nothing to draw
336 if (text == NULL || byteLength == 0) {
337 return;
338 }
339
340 this->init(rt, clip, paint, skPaint, regionClipBounds);
341
342 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
343
344 // Get GrFontScaler from cache
345 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
346 run.fDescriptor.reset(fSkPaint.getScalerContextDescriptor(&fDeviceProperties , &viewMatrix,
347 false));
348 run.fTypeface.reset(SkSafeRef(fSkPaint.getTypeface()));
349 const SkDescriptor* desc = reinterpret_cast<const SkDescriptor*>(run.fDescri ptor->data());
350 SkGlyphCache* cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
351 GrFontScaler* fontScaler = GetGrFontScaler(cache);
352
353 const char* stop = text + byteLength;
354 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
355 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
356 SkScalar halfSampleX = 0, halfSampleY = 0;
357
358 if (cache->isSubpixel()) {
359 // maybe we should skip the rounding if linearText is set
360 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
361
362 SkFixed fxMask = ~0;
363 SkFixed fyMask = ~0;
364 if (kX_SkAxisAlignment == baseline) {
365 fyMask = 0;
366 halfSampleY = SK_ScalarHalf;
367 } else if (kY_SkAxisAlignment == baseline) {
368 fxMask = 0;
369 halfSampleX = SK_ScalarHalf;
370 }
371
372 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
373 while (text < stop) {
374 SkPoint tmsLoc;
375 tmsProc(pos, &tmsLoc);
376 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX);
377 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY);
378
379 const SkGlyph& glyph = glyphCacheProc(cache, &text,
380 fx & fxMask, fy & fyMask);
381
382 if (glyph.fWidth) {
383 this->appendGlyph(blob,
384 runIndex,
385 GrGlyph::Pack(glyph.getGlyphID(),
386 glyph.getSubXFixed(),
387 glyph.getSubYFixed(),
388 GrGlyph::kCoverage_MaskStyle ),
389 Sk48Dot16FloorToInt(fx),
390 Sk48Dot16FloorToInt(fy),
391 fontScaler);
392 }
393 pos += scalarsPerPosition;
394 }
395 } else {
396 while (text < stop) {
397 const char* currentText = text;
398 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
399
400 if (metricGlyph.fWidth) {
401 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
402 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
403 SkPoint tmsLoc;
404 tmsProc(pos, &tmsLoc);
405 SkPoint alignLoc;
406 alignProc(tmsLoc, metricGlyph, &alignLoc);
407
408 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX);
409 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY);
410
411 // have to call again, now that we've been "aligned"
412 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
413 fx & fxMask, fy & fyMa sk);
414 // the assumption is that the metrics haven't changed
415 SkASSERT(prevAdvX == glyph.fAdvanceX);
416 SkASSERT(prevAdvY == glyph.fAdvanceY);
417 SkASSERT(glyph.fWidth);
418
419 this->appendGlyph(blob,
420 runIndex,
421 GrGlyph::Pack(glyph.getGlyphID(),
422 glyph.getSubXFixed(),
423 glyph.getSubYFixed(),
424 GrGlyph::kCoverage_MaskStyle ),
425 Sk48Dot16FloorToInt(fx),
426 Sk48Dot16FloorToInt(fy),
427 fontScaler);
428 }
429 pos += scalarsPerPosition;
430 }
431 }
432 } else { // not subpixel
433
434 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
435 while (text < stop) {
436 // the last 2 parameters are ignored
437 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
438
439 if (glyph.fWidth) {
440 SkPoint tmsLoc;
441 tmsProc(pos, &tmsLoc);
442
443 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
444 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
445 this->appendGlyph(blob,
446 runIndex,
447 GrGlyph::Pack(glyph.getGlyphID(),
448 glyph.getSubXFixed(),
449 glyph.getSubYFixed(),
450 GrGlyph::kCoverage_MaskStyle ),
451 Sk48Dot16FloorToInt(fx),
452 Sk48Dot16FloorToInt(fy),
453 fontScaler);
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 }
481 pos += scalarsPerPosition;
482 }
483 }
484 }
485 SkGlyphCache::AttachCache(cache);
486 }
487
488 static size_t get_vertex_stride(GrMaskFormat maskFormat) {
489 switch (maskFormat) {
490 case kA8_GrMaskFormat:
491 return kGrayTextVASize;
492 case kARGB_GrMaskFormat:
493 return kColorTextVASize;
494 default:
495 return kLCDTextVASize;
496 }
497 }
498
499 void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly ph::PackedID packed,
500 int vx, int vy,
501 GrFontScaler* scaler) {
502 if (NULL == fStrike) {
503 fStrike = fContext->getBatchFontCache()->getStrike(scaler);
504 }
505
506 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
507 if (NULL == glyph || glyph->fBounds.isEmpty()) {
508 return;
509 }
510
511 int x = vx + glyph->fBounds.fLeft;
512 int y = vy + glyph->fBounds.fTop;
513
514 // keep them as ints until we've done the clip-test
515 int width = glyph->fBounds.width();
516 int height = glyph->fBounds.height();
517
518 // check if we clipped out
519 if (fClipRect.quickReject(x, y, x + width, y + height)) {
520 return;
521 }
522
523 // If the glyph is too large we fall back to paths
524 if (fStrike->glyphTooLargeForAtlas(glyph)) {
525 if (NULL == glyph->fPath) {
526 SkPath* path = SkNEW(SkPath);
527 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
528 // flag the glyph as being dead?
robertphillips 2015/03/23 19:03:12 SkDELETE ?
joshualitt 2015/03/23 19:56:09 Acknowledged.
529 delete path;
530 return;
531 }
532 glyph->fPath = path;
533 }
534 SkASSERT(glyph->fPath);
535 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v y));
536 return;
537 }
538 GrMaskFormat format = glyph->fMaskFormat;
539 size_t vertexStride = get_vertex_stride(format);
540
541 BitmapTextBlob::Run& run = blob->fRuns[runIndex];
542 int glyphIdx = run.fInfos[format].fGlyphIDs.count();
543 *run.fInfos[format].fGlyphIDs.append() = packed;
544 run.fInfos[format].fVertices.append(vertexStride * kVerticesPerGlyph);
545
546 SkRect r;
547 r.fLeft = SkIntToScalar(x);
548 r.fTop = SkIntToScalar(y);
549 r.fRight = r.fLeft + SkIntToScalar(width);
550 r.fBottom = r.fTop + SkIntToScalar(height);
551
552 run.fVertexBounds.joinNonEmptyArg(r);
553 GrColor color = fPaint.getColor();
554 run.fColor = color;
555
556 intptr_t vertex = reinterpret_cast<intptr_t>(run.fInfos[format].fVertices.be gin());
557 vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
558
559 // V0
560 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
561 position->set(r.fLeft, r.fTop);
562 if (kA8_GrMaskFormat == format) {
563 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
564 *colorPtr = color;
565 }
566 vertex += vertexStride;
567
568 // V1
569 position = reinterpret_cast<SkPoint*>(vertex);
570 position->set(r.fLeft, r.fBottom);
571 if (kA8_GrMaskFormat == format) {
572 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
573 *colorPtr = color;
574 }
575 vertex += vertexStride;
576
577 // V2
578 position = reinterpret_cast<SkPoint*>(vertex);
579 position->set(r.fRight, r.fBottom);
580 if (kA8_GrMaskFormat == format) {
581 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
582 *colorPtr = color;
583 }
584 vertex += vertexStride;
585
586 // V3
587 position = reinterpret_cast<SkPoint*>(vertex);
588 position->set(r.fRight, r.fTop);
589 if (kA8_GrMaskFormat == format) {
590 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
591 *colorPtr = color;
592 }
593 }
594
595 class BitmapTextBatch : public GrBatch {
596 public:
597 typedef GrBitmapTextContextB::BitmapTextBlob Blob;
598 typedef Blob::Run Run;
599 typedef Run::TextInfo TextInfo;
600 struct Geometry {
601 Geometry() {}
602 Geometry(const Geometry& geometry)
603 : fBlob(SkRef(geometry.fBlob.get()))
604 , fRun(geometry.fRun)
605 , fColor(geometry.fColor) {}
606 SkAutoTUnref<Blob> fBlob;
607 int fRun;
608 GrColor fColor;
609 };
610
611 static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
612 GrBatchFontCache* fontCache) {
613 return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, fontCac he));
614 }
615
616 const char* name() const SK_OVERRIDE { return "BitmapTextBatch"; }
617
618 void getInvariantOutputColor(GrInitInvariantOutput* out) const SK_OVERRIDE {
619 if (kARGB_GrMaskFormat == fMaskFormat) {
620 out->setUnknownFourComponents();
621 } else {
622 out->setKnownFourComponents(fBatch.fColor);
623 }
624 }
robertphillips 2015/03/23 19:03:12 add \n ?
joshualitt 2015/03/23 19:56:08 Acknowledged.
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 != kA8_GrMaskFormat && this->color() != that->colo r()) {
897 return false;
898 }
899
900 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
901 return false;
902 }
903
robertphillips 2015/03/23 19:03:12 move this test up - since it is cheap ?
joshualitt 2015/03/23 19:56:09 Acknowledged.
904 if (this->fMaskFormat != that->fMaskFormat) {
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 GrTextContext::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