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

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

Issue 1521453002: Move all text stuff to its own folder (Closed) Base URL: https://skia.googlesource.com/skia.git@cleanuptext11textutils2
Patch Set: Created 5 years 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/GrStencilAndCoverTextContext.h ('k') | src/gpu/GrTest.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8 #include "GrStencilAndCoverTextContext.h"
9 #include "GrAtlasTextContext.h"
10 #include "GrDrawContext.h"
11 #include "GrDrawTarget.h"
12 #include "GrPath.h"
13 #include "GrPathRange.h"
14 #include "GrResourceProvider.h"
15 #include "SkAutoKern.h"
16 #include "SkDraw.h"
17 #include "SkDrawProcs.h"
18 #include "SkGlyphCache.h"
19 #include "SkGpuDevice.h"
20 #include "SkGrPriv.h"
21 #include "SkPath.h"
22 #include "SkTextBlobRunIterator.h"
23 #include "SkTextMapStateProc.h"
24 #include "SkTextFormatParams.h"
25
26 #include "batches/GrDrawPathBatch.h"
27
28 template<typename Key, typename Val> static void delete_hash_map_entry(const Key &, Val* val) {
29 SkASSERT(*val);
30 delete *val;
31 }
32
33 template<typename T> static void delete_hash_table_entry(T* val) {
34 SkASSERT(*val);
35 delete *val;
36 }
37
38 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context,
39 const SkSurfaceProps& surfaceProps)
40 : INHERITED(context, surfaceProps),
41 fCacheSize(0) {
42 }
43
44 GrStencilAndCoverTextContext*
45 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s urfaceProps) {
46 GrStencilAndCoverTextContext* textContext =
47 new GrStencilAndCoverTextContext(context, surfaceProps);
48 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf aceProps);
49
50 return textContext;
51 }
52
53 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() {
54 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>);
55 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>);
56 }
57
58 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) {
59 if (skPaint.getRasterizer()) {
60 return false;
61 }
62 if (skPaint.getMaskFilter()) {
63 return false;
64 }
65 if (SkPathEffect* pe = skPaint.getPathEffect()) {
66 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) {
67 return false;
68 }
69 }
70 // No hairlines. They would require new paths with customized strokes for ev ery new draw matrix.
71 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok eWidth();
72 }
73
74 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc,
75 const GrClip& clip,
76 const GrPaint& paint,
77 const SkPaint& skPaint,
78 const SkMatrix& viewMatrix,
79 const char text[],
80 size_t byteLength,
81 SkScalar x, SkScalar y,
82 const SkIRect& clipBounds) {
83 TextRun run(skPaint);
84 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip);
85 run.setText(text, byteLength, x, y);
86 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds,
87 fFallbackTextContext, skPaint);
88 }
89
90 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc,
91 const GrClip& clip,
92 const GrPaint& paint,
93 const SkPaint& skPaint,
94 const SkMatrix& viewMatrix,
95 const char text[],
96 size_t byteLength,
97 const SkScalar pos[],
98 int scalarsPerPosition,
99 const SkPoint& offset,
100 const SkIRect& clipBounds) {
101 TextRun run(skPaint);
102 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip);
103 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset);
104 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBounds,
105 fFallbackTextContext, skPaint);
106 }
107
108 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc,
109 const GrClip& clip, const SkPain t& skPaint,
110 const SkMatrix& viewMatrix,
111 const SkTextBlob* skBlob, SkScal ar x, SkScalar y,
112 SkDrawFilter* drawFilter,
113 const SkIRect& clipBounds) {
114 if (!this->internalCanDraw(skPaint)) {
115 fFallbackTextContext->drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob , x, y,
116 drawFilter, clipBounds);
117 return;
118 }
119
120 if (drawFilter || skPaint.getPathEffect()) {
121 // This draw can't be cached.
122 INHERITED::drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob, x, y, dra wFilter,
123 clipBounds);
124 return;
125 }
126
127 if (fContext->abandoned()) {
128 return;
129 }
130
131 GrPaint paint;
132 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) {
133 return;
134 }
135
136 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint);
137 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip);
138
139 TextBlob::Iter iter(blob);
140 for (TextRun* run = iter.get(); run; run = iter.next()) {
141 run->draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clipBounds,
142 fFallbackTextContext, skPaint);
143 run->releaseGlyphCache();
144 }
145 }
146
147 const GrStencilAndCoverTextContext::TextBlob&
148 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob,
149 const SkPaint& skPaint) {
150 // The font-related parameters are baked into the text blob and will overrid e this skPaint, so
151 // the only remaining properties that can affect a TextBlob are the ones rel ated to stroke.
152 if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path.
153 if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) {
154 fLRUList.remove(*found);
155 fLRUList.addToTail(*found);
156 return **found;
157 }
158 TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint);
159 this->purgeToFit(*blob);
160 fBlobIdCache.set(skBlob->uniqueID(), blob);
161 fLRUList.addToTail(blob);
162 fCacheSize += blob->cpuMemorySize();
163 return *blob;
164 } else {
165 GrStrokeInfo stroke(skPaint);
166 SkSTArray<4, uint32_t, true> key;
167 key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt());
168 key[0] = skBlob->uniqueID();
169 stroke.asUniqueKeyFragment(&key[1]);
170 if (TextBlob** found = fBlobKeyCache.find(key)) {
171 fLRUList.remove(*found);
172 fLRUList.addToTail(*found);
173 return **found;
174 }
175 TextBlob* blob = new TextBlob(key, skBlob, skPaint);
176 this->purgeToFit(*blob);
177 fBlobKeyCache.set(blob);
178 fLRUList.addToTail(blob);
179 fCacheSize += blob->cpuMemorySize();
180 return *blob;
181 }
182 }
183
184 void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) {
185 static const size_t maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for caching text blobs.
186
187 size_t maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize();
188 while (fCacheSize && fCacheSize > maxSizeForNewBlob) {
189 TextBlob* lru = fLRUList.head();
190 if (1 == lru->key().count()) {
191 // 1-length keys are unterstood to be the blob id.
192 fBlobIdCache.remove(lru->key()[0]);
193 } else {
194 fBlobKeyCache.remove(lru->key());
195 }
196 fLRUList.remove(lru);
197 fCacheSize -= lru->cpuMemorySize();
198 delete lru;
199 }
200 }
201
202 //////////////////////////////////////////////////////////////////////////////// ////////////////////
203
204 void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob,
205 const SkPaint& skPaint) {
206 fCpuMemorySize = sizeof(TextBlob);
207 SkPaint runPaint(skPaint);
208 for (SkTextBlobRunIterator iter(skBlob); !iter.done(); iter.next()) {
209 iter.applyFontToPaint(&runPaint); // No need to re-seed the paint.
210 TextRun* run = this->addToTail(runPaint);
211
212 const char* text = reinterpret_cast<const char*>(iter.glyphs());
213 size_t byteLength = sizeof(uint16_t) * iter.glyphCount();
214 const SkPoint& runOffset = iter.offset();
215
216 switch (iter.positioning()) {
217 case SkTextBlob::kDefault_Positioning:
218 run->setText(text, byteLength, runOffset.fX, runOffset.fY);
219 break;
220 case SkTextBlob::kHorizontal_Positioning:
221 run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0 , runOffset.fY));
222 break;
223 case SkTextBlob::kFull_Positioning:
224 run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0 , 0));
225 break;
226 }
227
228 fCpuMemorySize += run->computeSizeInCache();
229 }
230 }
231
232 //////////////////////////////////////////////////////////////////////////////// ////////////////////
233
234 class GrStencilAndCoverTextContext::FallbackBlobBuilder {
235 public:
236 FallbackBlobBuilder() : fBuffIdx(0), fCount(0) {}
237
238 bool isInitialized() const { return SkToBool(fBuilder); }
239
240 void init(const SkPaint& font, SkScalar textRatio);
241
242 void appendGlyph(uint16_t glyphId, const SkPoint& pos);
243
244 const SkTextBlob* buildIfNeeded(int* count);
245
246 private:
247 enum { kWriteBufferSize = 1024 };
248
249 void flush();
250
251 SkAutoTDelete<SkTextBlobBuilder> fBuilder;
252 SkPaint fFont;
253 int fBuffIdx;
254 int fCount;
255 uint16_t fGlyphIds[kWriteBufferSize];
256 SkPoint fPositions[kWriteBufferSize];
257 };
258
259 //////////////////////////////////////////////////////////////////////////////// ////////////////////
260
261 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke)
262 : fStroke(fontAndStroke),
263 fFont(fontAndStroke),
264 fTotalGlyphCount(0),
265 fFallbackGlyphCount(0),
266 fDetachedGlyphCache(nullptr),
267 fLastDrawnGlyphsID(SK_InvalidUniqueID) {
268 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported.
269
270 // Setting to "fill" ensures that no strokes get baked into font outlines. ( We use the GPU path
271 // rendering API for stroking).
272 fFont.setStyle(SkPaint::kFill_Style);
273
274 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle ()) {
275 // Instead of letting fake bold get baked into the glyph outlines, do it with GPU stroke.
276 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(),
277 kStdFakeBoldInterpKeys,
278 kStdFakeBoldInterpValues,
279 kStdFakeBoldInterpLength);
280 SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale);
281 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extr a : extra,
282 true /*strokeAndFill*/);
283
284 fFont.setFakeBoldText(false);
285 }
286
287 if (!fFont.getPathEffect() && !fStroke.isDashed()) {
288 // We can draw the glyphs from canonically sized paths.
289 fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
290 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextS ize();
291
292 // Compensate for the glyphs being scaled by fTextRatio.
293 if (!fStroke.isFillStyle()) {
294 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio,
295 SkStrokeRec::kStrokeAndFill_Style == fStroke. getStyle());
296 }
297
298 fFont.setLinearText(true);
299 fFont.setLCDRenderText(false);
300 fFont.setAutohinted(false);
301 fFont.setHinting(SkPaint::kNo_Hinting);
302 fFont.setSubpixelText(true);
303 fFont.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
304
305 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() &&
306 0 == fFont.getTextSkewX() &&
307 !fFont.isFakeBoldText() &&
308 !fFont.isVerticalText();
309 } else {
310 fTextRatio = fTextInverseRatio = 1.0f;
311 fUsingRawGlyphPaths = false;
312 }
313
314 // Generate the key that will be used to cache the GPU glyph path objects.
315 if (fUsingRawGlyphPaths && fStroke.isFillStyle()) {
316 static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey:: GenerateDomain();
317
318 const SkTypeface* typeface = fFont.getTypeface();
319 GrUniqueKey::Builder builder(&fGlyphPathsKey, kRawFillPathGlyphDomain, 1 );
320 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID( ) : 0;
321 } else {
322 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::Generat eDomain();
323
324 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt();
325 if (fUsingRawGlyphPaths) {
326 const SkTypeface* typeface = fFont.getTypeface();
327 GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 + strokeDataCount);
328 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqu eID() : 0;
329 reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount;
330 fStroke.asUniqueKeyFragment(&builder[2]);
331 } else {
332 SkGlyphCache* glyphCache = this->getGlyphCache();
333 const SkTypeface* typeface = glyphCache->getScalerContext()->getType face();
334 const SkDescriptor* desc = &glyphCache->getDescriptor();
335 int descDataCount = (desc->getLength() + 3) / 4;
336 GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain,
337 2 + strokeDataCount + descDataCount);
338 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqu eID() : 0;
339 reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDat aCount << 16);
340 fStroke.asUniqueKeyFragment(&builder[2]);
341 memcpy(&builder[2 + strokeDataCount], desc, desc->getLength());
342 }
343 }
344 }
345
346 GrStencilAndCoverTextContext::TextRun::~TextRun() {
347 this->releaseGlyphCache();
348 }
349
350 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by teLength,
351 SkScalar x, SkScalar y) {
352 SkASSERT(byteLength == 0 || text != nullptr);
353
354 SkGlyphCache* glyphCache = this->getGlyphCache();
355 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
356
357 fTotalGlyphCount = fFont.countText(text, byteLength);
358 fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTran sformType,
359 fTotalGlyphCount));
360
361 const char* stop = text + byteLength;
362
363 // Measure first if needed.
364 if (fFont.getTextAlign() != SkPaint::kLeft_Align) {
365 SkFixed stopX = 0;
366 SkFixed stopY = 0;
367
368 const char* textPtr = text;
369 while (textPtr < stop) {
370 // We don't need x, y here, since all subpixel variants will have th e
371 // same advance.
372 const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr, 0, 0);
373
374 stopX += glyph.fAdvanceX;
375 stopY += glyph.fAdvanceY;
376 }
377 SkASSERT(textPtr == stop);
378
379 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
380 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;
381
382 if (fFont.getTextAlign() == SkPaint::kCenter_Align) {
383 alignX = SkScalarHalf(alignX);
384 alignY = SkScalarHalf(alignY);
385 }
386
387 x -= alignX;
388 y -= alignY;
389 }
390
391 SkAutoKern autokern;
392
393 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);
394
395 SkFixed fx = SkScalarToFixed(x);
396 SkFixed fy = SkScalarToFixed(y);
397 FallbackBlobBuilder fallback;
398 while (text < stop) {
399 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
400 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
401 if (glyph.fWidth) {
402 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT oScalar(fy)),
403 &fallback);
404 }
405
406 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
407 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
408 }
409
410 fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount));
411 }
412
413 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t byteLength,
414 const SkScalar pos[], int scalarsPerPosition,
415 const SkPoint& offset) {
416 SkASSERT(byteLength == 0 || text != nullptr);
417 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
418
419 SkGlyphCache* glyphCache = this->getGlyphCache();
420 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();
421
422 fTotalGlyphCount = fFont.countText(text, byteLength);
423 fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTran sformType,
424 fTotalGlyphCount));
425
426 const char* stop = text + byteLength;
427
428 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
429 SkTextAlignProc alignProc(fFont.getTextAlign());
430 FallbackBlobBuilder fallback;
431 while (text < stop) {
432 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
433 if (glyph.fWidth) {
434 SkPoint tmsLoc;
435 tmsProc(pos, &tmsLoc);
436 SkPoint loc;
437 alignProc(tmsLoc, glyph, &loc);
438
439 this->appendGlyph(glyph, loc, &fallback);
440 }
441 pos += scalarsPerPosition;
442 }
443
444 fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount));
445 }
446
447 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx) const {
448 GrPathRange* glyphs = static_cast<GrPathRange*>(
449 ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKe y));
450 if (nullptr == glyphs) {
451 if (fUsingRawGlyphPaths) {
452 glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(), nullptr, fStroke);
453 } else {
454 SkGlyphCache* cache = this->getGlyphCache();
455 glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerConte xt()->getTypeface(),
456 &cache->getDescriptor (),
457 fStroke);
458 }
459 ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyph s);
460 }
461 return glyphs;
462 }
463
464 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl yph,
465 const SkPoint& po s,
466 FallbackBlobBuild er* fallback) {
467 // Stick the glyphs we can't draw into the fallback text blob.
468 if (SkMask::kARGB32_Format == glyph.fMaskFormat) {
469 if (!fallback->isInitialized()) {
470 fallback->init(fFont, fTextRatio);
471 }
472 fallback->appendGlyph(glyph.getGlyphID(), pos);
473 } else {
474 fInstanceData->append(glyph.getGlyphID(), fTextInverseRatio * pos.x(),
475 fTextInverseRatio * pos.y());
476 }
477 }
478
479 void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx,
480 GrDrawContext* dc,
481 GrPipelineBuilder* pipelineBuil der,
482 GrColor color,
483 const SkMatrix& viewMatrix,
484 SkScalar x, SkScalar y,
485 const SkIRect& clipBounds,
486 GrTextContext* fallbackTextCont ext,
487 const SkPaint& originalSkPaint) const {
488 SkASSERT(fInstanceData);
489 SkASSERT(dc->accessRenderTarget()->isStencilBufferMultisampled() || !fFont.i sAntiAlias());
490
491 if (fInstanceData->count()) {
492 pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.is AntiAlias());
493
494 GR_STATIC_CONST_SAME_STENCIL(kStencilPass,
495 kZero_StencilOp,
496 kKeep_StencilOp,
497 kNotEqual_StencilFunc,
498 0xffff,
499 0x0000,
500 0xffff);
501
502 *pipelineBuilder->stencil() = kStencilPass;
503
504 SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx));
505 if (fLastDrawnGlyphsID != glyphs->getUniqueID()) {
506 // Either this is the first draw or the glyphs object was purged sin ce last draw.
507 glyphs->loadPathsIfNeeded(fInstanceData->indices(), fInstanceData->c ount());
508 fLastDrawnGlyphsID = glyphs->getUniqueID();
509 }
510
511 // Don't compute a bounding box. For dst copy texture, we'll opt instead for it to just copy
512 // the entire dst. Realistically this is a moot point, because any conte xt that supports
513 // NV_path_rendering will also support NV_blend_equation_advanced.
514 // For clipping we'll just skip any optimizations based on the bounds. T his does, however,
515 // hurt batching.
516 SkRect bounds = SkRect::MakeIWH(pipelineBuilder->getRenderTarget()->widt h(),
517 pipelineBuilder->getRenderTarget()->heig ht());
518
519 SkAutoTUnref<GrDrawPathBatchBase> batch(
520 GrDrawPathRangeBatch::Create(viewMatrix, fTextRatio, fTextInverseRat io * x,
521 fTextInverseRatio * y, color,
522 GrPathRendering::kWinding_FillType, gly phs, fInstanceData,
523 bounds));
524
525 dc->drawPathBatch(*pipelineBuilder, batch);
526 }
527
528 if (fFallbackTextBlob) {
529 SkPaint fallbackSkPaint(originalSkPaint);
530 fStroke.applyToPaint(&fallbackSkPaint);
531 if (!fStroke.isFillStyle()) {
532 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio);
533 }
534
535 fallbackTextContext->drawTextBlob(dc, pipelineBuilder->clip(), fallbackS kPaint, viewMatrix,
536 fFallbackTextBlob, x, y, nullptr, clip Bounds);
537 }
538 }
539
540 SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const {
541 if (!fDetachedGlyphCache) {
542 fDetachedGlyphCache = fFont.detachCache(nullptr, nullptr, true /*ignoreG amma*/);
543 }
544 return fDetachedGlyphCache;
545 }
546
547
548 void GrStencilAndCoverTextContext::TextRun::releaseGlyphCache() const {
549 if (fDetachedGlyphCache) {
550 SkGlyphCache::AttachCache(fDetachedGlyphCache);
551 fDetachedGlyphCache = nullptr;
552 }
553 }
554
555 size_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const {
556 size_t size = sizeof(TextRun) + fGlyphPathsKey.size();
557 // The instance data always reserves enough space for every glyph.
558 size += (fTotalGlyphCount + fFallbackGlyphCount) * (sizeof(uint16_t) + 2 * s izeof(float));
559 if (fInstanceData) {
560 size += sizeof(InstanceData);
561 }
562 if (fFallbackTextBlob) {
563 size += sizeof(SkTextBlob);
564 }
565 return size;
566 }
567
568 //////////////////////////////////////////////////////////////////////////////// ////////////////////
569
570 void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font ,
571 SkScalar textRatio) {
572 SkASSERT(!this->isInitialized());
573 fBuilder.reset(new SkTextBlobBuilder);
574 fFont = font;
575 fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will alread y account for align.
576 fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
577 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non -bitmap color glyphs
578 // show up and https://code.google.com/p/skia/issues/detail?id=4408 gets res olved.
579 fFont.setSubpixelText(false);
580 fFont.setTextSize(fFont.getTextSize() * textRatio);
581 fBuffIdx = 0;
582 }
583
584 void GrStencilAndCoverTextContext::FallbackBlobBuilder::appendGlyph(uint16_t gly phId,
585 const SkPoin t& pos) {
586 SkASSERT(this->isInitialized());
587 if (fBuffIdx >= kWriteBufferSize) {
588 this->flush();
589 }
590 fGlyphIds[fBuffIdx] = glyphId;
591 fPositions[fBuffIdx] = pos;
592 fBuffIdx++;
593 fCount++;
594 }
595
596 void GrStencilAndCoverTextContext::FallbackBlobBuilder::flush() {
597 SkASSERT(this->isInitialized());
598 SkASSERT(fBuffIdx <= kWriteBufferSize);
599 if (!fBuffIdx) {
600 return;
601 }
602 // This will automatically merge with previous runs since we use the same fo nt.
603 const SkTextBlobBuilder::RunBuffer& buff = fBuilder->allocRunPos(fFont, fBuf fIdx);
604 memcpy(buff.glyphs, fGlyphIds, fBuffIdx * sizeof(uint16_t));
605 memcpy(buff.pos, fPositions[0].asScalars(), fBuffIdx * 2 * sizeof(SkScalar)) ;
606 fBuffIdx = 0;
607 }
608
609 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeed ed(int *count) {
610 *count = fCount;
611 if (fCount) {
612 this->flush();
613 return fBuilder->build();
614 }
615 return nullptr;
616 }
OLDNEW
« no previous file with comments | « src/gpu/GrStencilAndCoverTextContext.h ('k') | src/gpu/GrTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698