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

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

Issue 1045723010: move Atlas Text Context to its own file (Closed) Base URL: https://skia.googlesource.com/skia.git@bmptext3
Patch Set: rebase 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 #include "GrBitmapTextContext.h"
8 8
9 #include "GrAtlas.h" 9 #include "GrAtlas.h"
10 #include "GrBatch.h" 10 #include "GrBatch.h"
(...skipping 30 matching lines...) Expand all
41 namespace { 41 namespace {
42 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 42 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
43 43
44 // position + local coord 44 // position + local coord
45 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); 45 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16);
46 46
47 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16); 47 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof (SkIPoint16);
48 48
49 static const int kVerticesPerGlyph = 4; 49 static const int kVerticesPerGlyph = 4;
50 static const int kIndicesPerGlyph = 6; 50 static const int kIndicesPerGlyph = 6;
51 };
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
105 inline SkGlyphCache* GrBitmapTextContextB::setupCache(BitmapTextBlob::Run* run,
106 const SkPaint& skPaint,
107 const SkMatrix& viewMatrix ) {
108 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v iewMatrix, false);
109 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface()));
110 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc()) ;
111 }
112
113 inline void GrBitmapTextContextB::BlobGlyphCount(int* glyphCount, int* runCount,
114 const SkTextBlob* blob) {
115 SkTextBlob::RunIterator itCounter(blob);
116 for (; !itCounter.done(); itCounter.next(), (*runCount)++) {
117 *glyphCount += itCounter.glyphCount();
118 }
119 }
120
121 GrBitmapTextContextB::BitmapTextBlob* GrBitmapTextContextB::CreateBlob(int glyph Count,
122 int runCo unt) {
123 // We allocate size for the BitmapTextBlob itself, plus size for the vertice s array,
124 // and size for the glyphIds array.
125 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >= kLCDTextVASize,
126 vertex_attribute_changed);
127 size_t verticesCount = glyphCount * kVerticesPerGlyph * kGrayTextVASize;
128 size_t length = sizeof(BitmapTextBlob) +
129 verticesCount +
130 glyphCount * sizeof(GrGlyph::PackedID) +
131 sizeof(BitmapTextBlob::Run) * runCount;
132
133 BitmapTextBlob* cacheBlob = SkNEW_PLACEMENT(sk_malloc_throw(length), BitmapT extBlob);
134
135 // setup offsets for vertices / glyphs
136 cacheBlob->fVertices = sizeof(BitmapTextBlob) + reinterpret_cast<unsigned ch ar*>(cacheBlob);
137 cacheBlob->fGlyphIDs =
138 reinterpret_cast<GrGlyph::PackedID*>(cacheBlob->fVertices + vertices Count);
139 cacheBlob->fRuns = reinterpret_cast<BitmapTextBlob::Run*>(cacheBlob->fGlyphI Ds + glyphCount);
140
141 // Initialize runs
142 for (int i = 0; i < runCount; i++) {
143 SkNEW_PLACEMENT(&cacheBlob->fRuns[i], BitmapTextBlob::Run);
144 }
145 cacheBlob->fRunCount = runCount;
146 return cacheBlob;
147 }
148
149 void GrBitmapTextContextB::drawTextBlob(GrRenderTarget* rt, const GrClip& clip,
150 const SkPaint& skPaint, const SkMatrix& viewMatrix,
151 const SkTextBlob* blob, SkScalar x, SkSc alar y,
152 SkDrawFilter* drawFilter, const SkIRect& clipBounds) {
153 BitmapTextBlob* cacheBlob;
154 BitmapTextBlob** foundBlob = fCache.find(blob->uniqueID());
155 SkIRect clipRect;
156 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
157
158 if (foundBlob) {
159 cacheBlob = *foundBlob;
160 if (MustRegenerateBlob(*cacheBlob, skPaint, viewMatrix, x, y)) {
161 // We have to remake the blob because changes may invalidate our mas ks.
162 // TODO we could probably get away reuse most of the time if the poi nter is unique,
163 // but we'd have to clear the subrun information
164 cacheBlob->unref();
165 int glyphCount = 0;
166 int runCount = 0;
167 BlobGlyphCount(&glyphCount, &runCount, blob);
168 cacheBlob = CreateBlob(glyphCount, runCount);
169 fCache.set(blob->uniqueID(), cacheBlob);
170 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, drawFilter,
171 clipRect);
172 }
173 } else {
174 int glyphCount = 0;
175 int runCount = 0;
176 BlobGlyphCount(&glyphCount, &runCount, blob);
177 cacheBlob = CreateBlob(glyphCount, runCount);
178 fCache.set(blob->uniqueID(), cacheBlob);
179 this->regenerateTextBlob(cacheBlob, skPaint, viewMatrix, blob, x, y, dra wFilter, clipRect);
180 }
181
182 // Though for the time being runs in the textblob can override the paint, th ey only touch font
183 // info.
184 GrPaint grPaint;
185 SkPaint2GrPaintShader(fContext, rt, skPaint, viewMatrix, true, &grPaint);
186
187 this->flush(fContext->getTextTarget(), cacheBlob, rt, grPaint, clip, viewMat rix,
188 fSkPaint.getAlpha());
189 }
190
191 void GrBitmapTextContextB::regenerateTextBlob(BitmapTextBlob* cacheBlob,
192 const SkPaint& skPaint, const SkMa trix& viewMatrix,
193 const SkTextBlob* blob, SkScalar x , SkScalar y,
194 SkDrawFilter* drawFilter, const Sk IRect& clipRect) {
195 cacheBlob->fViewMatrix = viewMatrix;
196 cacheBlob->fX = x;
197 cacheBlob->fY = y;
198 cacheBlob->fStyle = skPaint.getStyle();
199
200 // Regenerate textblob
201 SkPaint runPaint = skPaint;
202 SkTextBlob::RunIterator it(blob);
203 for (int run = 0; !it.done(); it.next(), run++) {
204 int glyphCount = it.glyphCount();
205 size_t textLen = glyphCount * sizeof(uint16_t);
206 const SkPoint& offset = it.offset();
207 // applyFontToPaint() always overwrites the exact same attributes,
208 // so it is safe to not re-seed the paint for this reason.
209 it.applyFontToPaint(&runPaint);
210
211 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ e)) {
212 // A false return from filter() means we should abort the current dr aw.
213 runPaint = skPaint;
214 continue;
215 }
216
217 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint));
218
219 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint, viewMatrix);
220
221 // setup vertex / glyphIndex for the new run
222 if (run > 0) {
223 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back();
224 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back( );
225
226 newRun.fVertexStartIndex = lastRun.fVertexEndIndex;
227 newRun.fVertexEndIndex = lastRun.fVertexEndIndex;
228
229 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex;
230 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex;
231 }
232
233 switch (it.positioning()) {
234 case SkTextBlob::kDefault_Positioning:
235 this->internalDrawText(cacheBlob, run, cache, runPaint, viewMatr ix,
236 (const char *)it.glyphs(), textLen,
237 x + offset.x(), y + offset.y(), clipRect) ;
238 break;
239 case SkTextBlob::kHorizontal_Positioning:
240 this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewM atrix,
241 (const char*)it.glyphs(), textLen, it. pos(), 1,
242 SkPoint::Make(x, y + offset.y()), clip Rect);
243 break;
244 case SkTextBlob::kFull_Positioning:
245 this->internalDrawPosText(cacheBlob, run, cache, runPaint, viewM atrix,
246 (const char*)it.glyphs(), textLen, it. pos(), 2,
247 SkPoint::Make(x, y), clipRect);
248 break;
249 }
250
251 if (drawFilter) {
252 // A draw filter may change the paint arbitrarily, so we must re-see d in this case.
253 runPaint = skPaint;
254 }
255
256 SkGlyphCache::AttachCache(cache);
257 }
258 }
259
260 void GrBitmapTextContextB::onDrawText(GrRenderTarget* rt, const GrClip& clip,
261 const GrPaint& paint, const SkPaint& skPain t,
262 const SkMatrix& viewMatrix,
263 const char text[], size_t byteLength,
264 SkScalar x, SkScalar y, const SkIRect& regi onClipBounds) {
265 int glyphCount = skPaint.countText(text, byteLength);
266 SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
267 blob->fViewMatrix = viewMatrix;
268 blob->fX = x;
269 blob->fY = y;
270 blob->fStyle = skPaint.getStyle();
271
272 SkIRect clipRect;
273 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
274
275 // setup cache
276 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ;
277 this->internalDrawText(blob, 0, cache, skPaint, viewMatrix, text, byteLength , x, y, clipRect);
278 SkGlyphCache::AttachCache(cache);
279
280 this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, sk Paint.getAlpha());
281 }
282
283 void GrBitmapTextContextB::internalDrawText(BitmapTextBlob* blob, int runIndex,
284 SkGlyphCache* cache, const SkPaint& skPaint,
285 const SkMatrix& viewMatrix,
286 const char text[], size_t byteLength,
287 SkScalar x, SkScalar y, const SkIRect & clipRect) {
288 SkASSERT(byteLength == 0 || text != NULL);
289
290 // nothing to draw
291 if (text == NULL || byteLength == 0) {
292 return;
293 }
294
295 fCurrStrike = NULL;
296 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
297
298 // Get GrFontScaler from cache
299 GrFontScaler* fontScaler = GetGrFontScaler(cache);
300
301 // transform our starting point
302 {
303 SkPoint loc;
304 viewMatrix.mapXY(x, y, &loc);
305 x = loc.fX;
306 y = loc.fY;
307 }
308
309 // need to measure first
310 if (skPaint.getTextAlign() != SkPaint::kLeft_Align) {
311 SkVector stopVector;
312 MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
313
314 SkScalar stopX = stopVector.fX;
315 SkScalar stopY = stopVector.fY;
316
317 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
318 stopX = SkScalarHalf(stopX);
319 stopY = SkScalarHalf(stopY);
320 }
321 x -= stopX;
322 y -= stopY;
323 }
324
325 const char* stop = text + byteLength;
326
327 SkAutoKern autokern;
328
329 SkFixed fxMask = ~0;
330 SkFixed fyMask = ~0;
331 SkScalar halfSampleX, halfSampleY;
332 if (cache->isSubpixel()) {
333 halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
334 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
335 if (kX_SkAxisAlignment == baseline) {
336 fyMask = 0;
337 halfSampleY = SK_ScalarHalf;
338 } else if (kY_SkAxisAlignment == baseline) {
339 fxMask = 0;
340 halfSampleX = SK_ScalarHalf;
341 }
342 } else {
343 halfSampleX = halfSampleY = SK_ScalarHalf;
344 }
345
346 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
347 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);
348
349 while (text < stop) {
350 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy Mask);
351
352 fx += autokern.adjust(glyph);
353
354 if (glyph.fWidth) {
355 this->appendGlyph(blob,
356 runIndex,
357 GrGlyph::Pack(glyph.getGlyphID(),
358 glyph.getSubXFixed(),
359 glyph.getSubYFixed(),
360 GrGlyph::kCoverage_MaskStyle),
361 Sk48Dot16FloorToInt(fx),
362 Sk48Dot16FloorToInt(fy),
363 fontScaler,
364 clipRect);
365 }
366
367 fx += glyph.fAdvanceX;
368 fy += glyph.fAdvanceY;
369 }
370 }
371
372 void GrBitmapTextContextB::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
373 const GrPaint& paint, const SkPaint& skP aint,
374 const SkMatrix& viewMatrix,
375 const char text[], size_t byteLength,
376 const SkScalar pos[], int scalarsPerPosi tion,
377 const SkPoint& offset, const SkIRect& re gionClipBounds) {
378 int glyphCount = skPaint.countText(text, byteLength);
379 SkAutoTUnref<BitmapTextBlob> blob(CreateBlob(glyphCount, 1));
380 blob->fStyle = skPaint.getStyle();
381 blob->fViewMatrix = viewMatrix;
382
383 SkIRect clipRect;
384 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect);
385
386 // setup cache
387 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix) ;
388 this->internalDrawPosText(blob, 0, cache, skPaint, viewMatrix, text, byteLen gth, pos,
389 scalarsPerPosition, offset, clipRect);
390 SkGlyphCache::AttachCache(cache);
391
392 this->flush(fContext->getTextTarget(), blob, rt, paint, clip, viewMatrix, fS kPaint.getAlpha());
393 }
394
395 void GrBitmapTextContextB::internalDrawPosText(BitmapTextBlob* blob, int runInde x,
396 SkGlyphCache* cache, const SkPain t& skPaint,
397 const SkMatrix& viewMatrix,
398 const char text[], size_t byteLeng th,
399 const SkScalar pos[], int scalarsP erPosition,
400 const SkPoint& offset, const SkIRe ct& clipRect) {
401 SkASSERT(byteLength == 0 || text != NULL);
402 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
403
404 // nothing to draw
405 if (text == NULL || byteLength == 0) {
406 return;
407 }
408
409 fCurrStrike = NULL;
410 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
411
412 // Get GrFontScaler from cache
413 GrFontScaler* fontScaler = GetGrFontScaler(cache);
414
415 const char* stop = text + byteLength;
416 SkTextAlignProc alignProc(skPaint.getTextAlign());
417 SkTextMapStateProc tmsProc(viewMatrix, offset, scalarsPerPosition);
418 SkScalar halfSampleX = 0, halfSampleY = 0;
419
420 if (cache->isSubpixel()) {
421 // maybe we should skip the rounding if linearText is set
422 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
423
424 SkFixed fxMask = ~0;
425 SkFixed fyMask = ~0;
426 if (kX_SkAxisAlignment == baseline) {
427 fyMask = 0;
428 halfSampleY = SK_ScalarHalf;
429 } else if (kY_SkAxisAlignment == baseline) {
430 fxMask = 0;
431 halfSampleX = SK_ScalarHalf;
432 }
433
434 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
435 while (text < stop) {
436 SkPoint tmsLoc;
437 tmsProc(pos, &tmsLoc);
438 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX);
439 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY);
440
441 const SkGlyph& glyph = glyphCacheProc(cache, &text,
442 fx & fxMask, fy & fyMask);
443
444 if (glyph.fWidth) {
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 clipRect);
455 }
456 pos += scalarsPerPosition;
457 }
458 } else {
459 while (text < stop) {
460 const char* currentText = text;
461 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
462
463 if (metricGlyph.fWidth) {
464 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
465 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
466 SkPoint tmsLoc;
467 tmsProc(pos, &tmsLoc);
468 SkPoint alignLoc;
469 alignProc(tmsLoc, metricGlyph, &alignLoc);
470
471 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX);
472 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY);
473
474 // have to call again, now that we've been "aligned"
475 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
476 fx & fxMask, fy & fyMa sk);
477 // the assumption is that the metrics haven't changed
478 SkASSERT(prevAdvX == glyph.fAdvanceX);
479 SkASSERT(prevAdvY == glyph.fAdvanceY);
480 SkASSERT(glyph.fWidth);
481
482 this->appendGlyph(blob,
483 runIndex,
484 GrGlyph::Pack(glyph.getGlyphID(),
485 glyph.getSubXFixed(),
486 glyph.getSubYFixed(),
487 GrGlyph::kCoverage_MaskStyle ),
488 Sk48Dot16FloorToInt(fx),
489 Sk48Dot16FloorToInt(fy),
490 fontScaler,
491 clipRect);
492 }
493 pos += scalarsPerPosition;
494 }
495 }
496 } else { // not subpixel
497
498 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) {
499 while (text < stop) {
500 // the last 2 parameters are ignored
501 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
502
503 if (glyph.fWidth) {
504 SkPoint tmsLoc;
505 tmsProc(pos, &tmsLoc);
506
507 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf); //halfSampleX;
508 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf); //halfSampleY;
509 this->appendGlyph(blob,
510 runIndex,
511 GrGlyph::Pack(glyph.getGlyphID(),
512 glyph.getSubXFixed(),
513 glyph.getSubYFixed(),
514 GrGlyph::kCoverage_MaskStyle ),
515 Sk48Dot16FloorToInt(fx),
516 Sk48Dot16FloorToInt(fy),
517 fontScaler,
518 clipRect);
519 }
520 pos += scalarsPerPosition;
521 }
522 } else {
523 while (text < stop) {
524 // the last 2 parameters are ignored
525 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
526
527 if (glyph.fWidth) {
528 SkPoint tmsLoc;
529 tmsProc(pos, &tmsLoc);
530
531 SkPoint alignLoc;
532 alignProc(tmsLoc, glyph, &alignLoc);
533
534 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf ); //halfSampleX;
535 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf ); //halfSampleY;
536 this->appendGlyph(blob,
537 runIndex,
538 GrGlyph::Pack(glyph.getGlyphID(),
539 glyph.getSubXFixed(),
540 glyph.getSubYFixed(),
541 GrGlyph::kCoverage_MaskStyle ),
542 Sk48Dot16FloorToInt(fx),
543 Sk48Dot16FloorToInt(fy),
544 fontScaler,
545 clipRect);
546 }
547 pos += scalarsPerPosition;
548 }
549 }
550 }
551 }
552 51
553 static size_t get_vertex_stride(GrMaskFormat maskFormat) { 52 static size_t get_vertex_stride(GrMaskFormat maskFormat) {
554 switch (maskFormat) { 53 switch (maskFormat) {
555 case kA8_GrMaskFormat: 54 case kA8_GrMaskFormat:
556 return kGrayTextVASize; 55 return kGrayTextVASize;
557 case kARGB_GrMaskFormat: 56 case kARGB_GrMaskFormat:
558 return kColorTextVASize; 57 return kColorTextVASize;
559 default: 58 default:
560 return kLCDTextVASize; 59 return kLCDTextVASize;
561 } 60 }
562 } 61 }
563 62
564 void GrBitmapTextContextB::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGly ph::PackedID packed,
565 int vx, int vy, GrFontScaler* scaler,
566 const SkIRect& clipRect) {
567 if (NULL == fCurrStrike) {
568 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler);
569 }
570
571 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler);
572 if (NULL == glyph || glyph->fBounds.isEmpty()) {
573 return;
574 }
575
576 int x = vx + glyph->fBounds.fLeft;
577 int y = vy + glyph->fBounds.fTop;
578
579 // keep them as ints until we've done the clip-test
580 int width = glyph->fBounds.width();
581 int height = glyph->fBounds.height();
582
583 // check if we clipped out
584 if (clipRect.quickReject(x, y, x + width, y + height)) {
585 return;
586 }
587
588 // If the glyph is too large we fall back to paths
589 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) {
590 if (NULL == glyph->fPath) {
591 SkPath* path = SkNEW(SkPath);
592 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
593 // flag the glyph as being dead?
594 SkDELETE(path);
595 return;
596 }
597 glyph->fPath = path;
598 }
599 SkASSERT(glyph->fPath);
600 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v y));
601 return;
602 }
603
604 Run& run = blob->fRuns[runIndex];
605
606 GrMaskFormat format = glyph->fMaskFormat;
607
608 PerSubRunInfo* subRun = &run.fSubRunInfo.back();
609 if (run.fInitialized && subRun->fMaskFormat != format) {
610 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back();
611 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex;
612 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex;
613
614 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex;
615 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex;
616
617 subRun = newSubRun;
618 }
619
620 run.fInitialized = true;
621 subRun->fMaskFormat = format;
622 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed;
623
624 size_t vertexStride = get_vertex_stride(format);
625
626 SkRect r;
627 r.fLeft = SkIntToScalar(x);
628 r.fTop = SkIntToScalar(y);
629 r.fRight = r.fLeft + SkIntToScalar(width);
630 r.fBottom = r.fTop + SkIntToScalar(height);
631
632 run.fVertexBounds.joinNonEmptyArg(r);
633 GrColor color = fPaint.getColor();
634 run.fColor = color;
635
636 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert exEndIndex);
637
638 // V0
639 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
640 position->set(r.fLeft, r.fTop);
641 if (kA8_GrMaskFormat == format) {
642 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
643 *colorPtr = color;
644 }
645 vertex += vertexStride;
646
647 // V1
648 position = reinterpret_cast<SkPoint*>(vertex);
649 position->set(r.fLeft, r.fBottom);
650 if (kA8_GrMaskFormat == format) {
651 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
652 *colorPtr = color;
653 }
654 vertex += vertexStride;
655
656 // V2
657 position = reinterpret_cast<SkPoint*>(vertex);
658 position->set(r.fRight, r.fBottom);
659 if (kA8_GrMaskFormat == format) {
660 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
661 *colorPtr = color;
662 }
663 vertex += vertexStride;
664
665 // V3
666 position = reinterpret_cast<SkPoint*>(vertex);
667 position->set(r.fRight, r.fTop);
668 if (kA8_GrMaskFormat == format) {
669 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint)) ;
670 *colorPtr = color;
671 }
672
673 subRun->fGlyphEndIndex++;
674 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph;
675 }
676
677 class BitmapTextBatch : public GrBatch {
678 public:
679 typedef GrBitmapTextContextB::BitmapTextBlob Blob;
680 typedef Blob::Run Run;
681 typedef Run::SubRunInfo TextInfo;
682 struct Geometry {
683 Geometry() {}
684 Geometry(const Geometry& geometry)
685 : fBlob(SkRef(geometry.fBlob.get()))
686 , fRun(geometry.fRun)
687 , fSubRun(geometry.fSubRun)
688 , fColor(geometry.fColor) {}
689 SkAutoTUnref<Blob> fBlob;
690 int fRun;
691 int fSubRun;
692 GrColor fColor;
693 };
694
695 static GrBatch* Create(const Geometry& geometry, GrColor color, GrMaskFormat maskFormat,
696 int glyphCount, GrBatchFontCache* fontCache) {
697 return SkNEW_ARGS(BitmapTextBatch, (geometry, color, maskFormat, glyphCo unt, fontCache));
698 }
699
700 const char* name() const override { return "BitmapTextBatch"; }
701
702 void getInvariantOutputColor(GrInitInvariantOutput* out) const override {
703 if (kARGB_GrMaskFormat == fMaskFormat) {
704 out->setUnknownFourComponents();
705 } else {
706 out->setKnownFourComponents(fBatch.fColor);
707 }
708 }
709
710 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override {
711 if (kARGB_GrMaskFormat != fMaskFormat) {
712 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) {
713 out->setUnknownSingleComponent();
714 } else if (GrPixelConfigIsOpaque(fPixelConfig)) {
715 out->setUnknownOpaqueFourComponents();
716 out->setUsingLCDCoverage();
717 } else {
718 out->setUnknownFourComponents();
719 out->setUsingLCDCoverage();
720 }
721 } else {
722 out->setKnownSingleComponent(0xff);
723 }
724 }
725
726 void initBatchTracker(const GrPipelineInfo& init) override {
727 // Handle any color overrides
728 if (init.fColorIgnored) {
729 fBatch.fColor = GrColor_ILLEGAL;
730 } else if (GrColor_ILLEGAL != init.fOverrideColor) {
731 fBatch.fColor = init.fOverrideColor;
732 }
733
734 // setup batch properties
735 fBatch.fColorIgnored = init.fColorIgnored;
736 fBatch.fUsesLocalCoords = init.fUsesLocalCoords;
737 fBatch.fCoverageIgnored = init.fCoverageIgnored;
738 }
739
740 void generateGeometry(GrBatchTarget* batchTarget, const GrPipeline* pipeline ) override {
741 // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix.
742 // TODO actually only invert if we don't have RGBA
743 SkMatrix localMatrix;
744 if (this->usesLocalCoords() && !this->viewMatrix().invert(&localMatrix)) {
745 SkDebugf("Cannot invert viewmatrix\n");
746 return;
747 }
748
749 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone _FilterMode);
750 // This will be ignored in the non A8 case
751 bool opaqueVertexColors = GrColorIsOpaque(this->color());
752 SkAutoTUnref<const GrGeometryProcessor> gp(
753 GrBitmapTextGeoProc::Create(this->color(),
754 fFontCache->getTexture(fMaskFormat),
755 params,
756 fMaskFormat,
757 opaqueVertexColors,
758 localMatrix));
759
760 size_t vertexStride = gp->getVertexStride();
761 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat));
762
763 this->initDraw(batchTarget, gp, pipeline);
764
765 int glyphCount = this->numGlyphs();
766 int instanceCount = fGeoData.count();
767 const GrVertexBuffer* vertexBuffer;
768 int firstVertex;
769
770 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride,
771 glyphCount * kVert icesPerGlyph,
772 &vertexBuffer,
773 &firstVertex);
774 if (!vertices) {
775 SkDebugf("Could not allocate vertices\n");
776 return;
777 }
778
779 unsigned char* currVertex = reinterpret_cast<unsigned char*>(vertices);
780
781 // setup drawinfo
782 const GrIndexBuffer* quadIndexBuffer = batchTarget->quadIndexBuffer();
783 int maxInstancesPerDraw = quadIndexBuffer->maxQuads();
784
785 GrDrawTarget::DrawInfo drawInfo;
786 drawInfo.setPrimitiveType(kTriangles_GrPrimitiveType);
787 drawInfo.setStartVertex(0);
788 drawInfo.setStartIndex(0);
789 drawInfo.setVerticesPerInstance(kVerticesPerGlyph);
790 drawInfo.setIndicesPerInstance(kIndicesPerGlyph);
791 drawInfo.adjustStartVertex(firstVertex);
792 drawInfo.setVertexBuffer(vertexBuffer);
793 drawInfo.setIndexBuffer(quadIndexBuffer);
794
795 int instancesToFlush = 0;
796 for (int i = 0; i < instanceCount; i++) {
797 Geometry& args = fGeoData[i];
798 Blob* blob = args.fBlob;
799 Run& run = blob->fRuns[args.fRun];
800 TextInfo& info = run.fSubRunInfo[args.fSubRun];
801
802 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat);
803 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas Gen;
804 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo r != args.fColor;
805 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
806
807 // We regenerate both texture coords and colors in the blob itself, and update the
808 // atlas generation. If we don't end up purging any unused plots, w e can avoid
809 // regenerating the coords. We could take a finer grained approach to updating texture
810 // coords but its not clear if the extra bookkeeping would offset an y gains.
811 // To avoid looping over the glyphs twice, we do one loop and condit ionally update color
812 // or coords as needed. One final note, if we have to break a run f or an atlas eviction
813 // then we can't really trust the atlas has all of the correct data. Atlas evictions
814 // should be pretty rare, so we just always regenerate in those case s
815 if (regenerateTextureCoords || regenerateColors) {
816 // first regenerate texture coordinates / colors if need be
817 const SkDescriptor* desc = NULL;
818 SkGlyphCache* cache = NULL;
819 GrFontScaler* scaler = NULL;
820 GrBatchTextStrike* strike = NULL;
821 bool brokenRun = false;
822 if (regenerateTextureCoords) {
823 desc = run.fDescriptor.getDesc();
824 cache = SkGlyphCache::DetachCache(run.fTypeface, desc);
825 scaler = GrTextContext::GetGrFontScaler(cache);
826 strike = fFontCache->getStrike(scaler);
827 }
828 for (int glyphIdx = 0; glyphIdx < glyphCount; glyphIdx++) {
829 GrGlyph::PackedID glyphID = blob->fGlyphIDs[glyphIdx + info. fGlyphStartIndex];
830
831 if (regenerateTextureCoords) {
832 // Upload the glyph only if needed
833 GrGlyph* glyph = strike->getGlyph(glyphID, scaler);
834 SkASSERT(glyph);
835
836 if (!fFontCache->hasGlyph(glyph) &&
837 !strike->addGlyphToAtlas(batchTarget, glyph, scaler) ) {
838 this->flush(batchTarget, &drawInfo, instancesToFlush ,
839 maxInstancesPerDraw);
840 this->initDraw(batchTarget, gp, pipeline);
841 instancesToFlush = 0;
842 brokenRun = glyphIdx > 0;
843
844 SkDEBUGCODE(bool success =) strike->addGlyphToAtlas( batchTarget, glyph,
845 scaler);
846 SkASSERT(success);
847 }
848
849 fFontCache->setGlyphRefToken(glyph, batchTarget->current Token());
850
851 // Texture coords are the last vertex attribute so we ge t a pointer to the
852 // first one and then map with stride in regenerateTextu reCoords
853 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices);
854 vertex += info.fVertexStartIndex;
855 vertex += vertexStride * glyphIdx * kVerticesPerGlyph;
856 vertex += vertexStride - sizeof(SkIPoint16);
857
858 this->regenerateTextureCoords(glyph, vertex, vertexStrid e);
859 }
860
861 if (regenerateColors) {
862 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVert ices);
863 vertex += info.fVertexStartIndex;
864 vertex += vertexStride * glyphIdx * kVerticesPerGlyph + sizeof(SkPoint);
865 this->regenerateColors(vertex, vertexStride, args.fColor );
866 }
867
868 instancesToFlush++;
869 }
870
871 if (regenerateTextureCoords) {
872 SkGlyphCache::AttachCache(cache);
873 info.fAtlasGeneration = brokenRun ? GrBatchAtlas::kInvalidAt lasGeneration :
874 fFontCache->atlasGenerat ion(fMaskFormat);
875 }
876 } else {
877 instancesToFlush += glyphCount;
878 }
879
880 // now copy all vertices
881 size_t byteCount = info.fVertexEndIndex - info.fVertexStartIndex;
882 memcpy(currVertex, blob->fVertices + info.fVertexStartIndex, byteCou nt);
883
884 currVertex += byteCount;
885 }
886
887 this->flush(batchTarget, &drawInfo, instancesToFlush, maxInstancesPerDra w);
888 }
889
890 SkSTArray<1, Geometry, true>* geoData() { return &fGeoData; }
891
892 private:
893 BitmapTextBatch(const Geometry& geometry, GrColor color, GrMaskFormat maskFo rmat,
894 int glyphCount, GrBatchFontCache* fontCache)
895 : fMaskFormat(maskFormat)
896 , fPixelConfig(fontCache->getPixelConfig(maskFormat))
897 , fFontCache(fontCache) {
898 this->initClassID<BitmapTextBatch>();
899 fGeoData.push_back(geometry);
900 fBatch.fColor = color;
901 fBatch.fViewMatrix = geometry.fBlob->fViewMatrix;
902 fBatch.fNumGlyphs = glyphCount;
903 }
904
905 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS tride) {
906 int width = glyph->fBounds.width();
907 int height = glyph->fBounds.height();
908 int u0 = glyph->fAtlasLocation.fX;
909 int v0 = glyph->fAtlasLocation.fY;
910 int u1 = u0 + width;
911 int v1 = v0 + height;
912
913 // we assume texture coords are the last vertex attribute, this is a bit fragile.
914 // TODO pass in this offset or something
915 SkIPoint16* textureCoords;
916 // V0
917 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
918 textureCoords->set(u0, v0);
919 vertex += vertexStride;
920
921 // V1
922 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
923 textureCoords->set(u0, v1);
924 vertex += vertexStride;
925
926 // V2
927 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
928 textureCoords->set(u1, v1);
929 vertex += vertexStride;
930
931 // V3
932 textureCoords = reinterpret_cast<SkIPoint16*>(vertex);
933 textureCoords->set(u1, v0);
934 }
935
936 void regenerateColors(intptr_t vertex, size_t vertexStride, GrColor color) {
937 for (int i = 0; i < kVerticesPerGlyph; i++) {
938 SkColor* vcolor = reinterpret_cast<SkColor*>(vertex);
939 *vcolor = color;
940 vertex += vertexStride;
941 }
942 }
943
944 void initDraw(GrBatchTarget* batchTarget,
945 const GrGeometryProcessor* gp,
946 const GrPipeline* pipeline) {
947 batchTarget->initDraw(gp, pipeline);
948
949 // TODO remove this when batch is everywhere
950 GrPipelineInfo init;
951 init.fColorIgnored = fBatch.fColorIgnored;
952 init.fOverrideColor = GrColor_ILLEGAL;
953 init.fCoverageIgnored = fBatch.fCoverageIgnored;
954 init.fUsesLocalCoords = this->usesLocalCoords();
955 gp->initBatchTracker(batchTarget->currentBatchTracker(), init);
956 }
957
958 void flush(GrBatchTarget* batchTarget,
959 GrDrawTarget::DrawInfo* drawInfo,
960 int instanceCount,
961 int maxInstancesPerDraw) {
962 while (instanceCount) {
963 drawInfo->setInstanceCount(SkTMin(instanceCount, maxInstancesPerDraw ));
964 drawInfo->setVertexCount(drawInfo->instanceCount() * drawInfo->verti cesPerInstance());
965 drawInfo->setIndexCount(drawInfo->instanceCount() * drawInfo->indice sPerInstance());
966
967 batchTarget->draw(*drawInfo);
968
969 drawInfo->setStartVertex(drawInfo->startVertex() + drawInfo->vertexC ount());
970 instanceCount -= drawInfo->instanceCount();
971 }
972 }
973
974 GrColor color() const { return fBatch.fColor; }
975 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; }
976 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; }
977 int numGlyphs() const { return fBatch.fNumGlyphs; }
978
979 bool onCombineIfPossible(GrBatch* t) override {
980 BitmapTextBatch* that = t->cast<BitmapTextBatch>();
981
982 if (this->fMaskFormat != that->fMaskFormat) {
983 return false;
984 }
985
986 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo r()) {
987 return false;
988 }
989
990 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi ewMatrix())) {
991 return false;
992 }
993
994 fBatch.fNumGlyphs += that->numGlyphs();
995 fGeoData.push_back_n(that->geoData()->count(), that->geoData()->begin()) ;
996 return true;
997 }
998
999 struct BatchTracker {
1000 GrColor fColor;
1001 SkMatrix fViewMatrix;
1002 bool fUsesLocalCoords;
1003 bool fColorIgnored;
1004 bool fCoverageIgnored;
1005 int fNumGlyphs;
1006 };
1007
1008 BatchTracker fBatch;
1009 SkSTArray<1, Geometry, true> fGeoData;
1010 GrMaskFormat fMaskFormat;
1011 GrPixelConfig fPixelConfig;
1012 GrBatchFontCache* fFontCache;
1013 }; 63 };
1014 64
1015 void GrBitmapTextContextB::flush(GrDrawTarget* target, BitmapTextBlob* blob, GrR enderTarget* rt,
1016 const GrPaint& paint, const GrClip& clip,
1017 const SkMatrix& viewMatrix, int paintAlpha) {
1018 GrPipelineBuilder pipelineBuilder;
1019 pipelineBuilder.setFromPaint(paint, rt, clip);
1020
1021 GrColor color = paint.getColor();
1022 for (uint32_t run = 0; run < blob->fRunCount; run++) {
1023 for (int subRun = 0; subRun < blob->fRuns[run].fSubRunInfo.count(); subR un++) {
1024 PerSubRunInfo& info = blob->fRuns[run].fSubRunInfo[subRun];
1025 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex;
1026 if (0 == glyphCount) {
1027 continue;
1028 }
1029
1030 GrMaskFormat format = info.fMaskFormat;
1031 if (kARGB_GrMaskFormat == format) {
1032 color = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, paint Alpha);
1033 }
1034
1035 BitmapTextBatch::Geometry geometry;
1036 geometry.fBlob.reset(SkRef(blob));
1037 geometry.fRun = run;
1038 geometry.fSubRun = subRun;
1039 geometry.fColor = color;
1040 SkAutoTUnref<GrBatch> batch(BitmapTextBatch::Create(geometry, color, format, glyphCount,
1041 fContext->getBat chFontCache()));
1042
1043 target->drawBatch(&pipelineBuilder, batch, &blob->fRuns[run].fVertex Bounds);
1044 }
1045 }
1046
1047 // Now flush big glyphs
1048 for (int i = 0; i < blob->fBigGlyphs.count(); i++) {
1049 BitmapTextBlob::BigGlyph& bigGlyph = blob->fBigGlyphs[i];
1050 SkMatrix translate;
1051 translate.setTranslate(SkIntToScalar(bigGlyph.fVx), SkIntToScalar(bigGly ph.fVy));
1052 SkPath tmpPath(bigGlyph.fPath);
1053 tmpPath.transform(translate);
1054 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
1055 fContext->drawPath(rt, clip, paint, SkMatrix::I(), tmpPath, strokeInfo);
1056 }
1057 }
1058
1059 GrBitmapTextContext::GrBitmapTextContext(GrContext* context, 65 GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
1060 SkGpuDevice* gpuDevice, 66 SkGpuDevice* gpuDevice,
1061 const SkDeviceProperties& properties) 67 const SkDeviceProperties& properties)
1062 : GrTextContext(context, gpuDevice, properties) { 68 : GrTextContext(context, gpuDevice, properties) {
1063 fStrike = NULL; 69 fStrike = NULL;
1064 70
1065 fCurrTexture = NULL; 71 fCurrTexture = NULL;
1066 fEffectTextureUniqueID = SK_InvalidUniqueID; 72 fEffectTextureUniqueID = SK_InvalidUniqueID;
1067 73
1068 fVertices = NULL; 74 fVertices = NULL;
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after
1632 SkSafeSetNull(fCurrTexture); 638 SkSafeSetNull(fCurrTexture);
1633 } 639 }
1634 } 640 }
1635 641
1636 inline void GrBitmapTextContext::finish() { 642 inline void GrBitmapTextContext::finish() {
1637 this->flush(); 643 this->flush();
1638 fTotalVertexCount = 0; 644 fTotalVertexCount = 0;
1639 645
1640 GrTextContext::finish(); 646 GrTextContext::finish();
1641 } 647 }
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