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

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

Issue 1104343003: remove old text contexts and fontcache (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: tweak Created 5 years, 7 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/GrDistanceFieldTextContext.h ('k') | src/gpu/GrFlushToGpuDrawTarget.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 2013 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 "GrDistanceFieldTextContext.h"
9 #include "GrAtlas.h"
10 #include "GrAtlasTextContext.h"
11 #include "GrBitmapTextContext.h"
12 #include "GrDrawTarget.h"
13 #include "GrDrawTargetCaps.h"
14 #include "GrFontAtlasSizes.h"
15 #include "GrFontCache.h"
16 #include "GrFontScaler.h"
17 #include "GrGpu.h"
18 #include "GrIndexBuffer.h"
19 #include "GrStrokeInfo.h"
20 #include "GrTexturePriv.h"
21
22 #include "SkAutoKern.h"
23 #include "SkColorFilter.h"
24 #include "SkDistanceFieldGen.h"
25 #include "SkDraw.h"
26 #include "SkGlyphCache.h"
27 #include "SkGpuDevice.h"
28 #include "SkPath.h"
29 #include "SkRTConf.h"
30 #include "SkStrokeRec.h"
31 #include "effects/GrDistanceFieldGeoProc.h"
32
33 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
34 "Dump the contents of the font cache before every purge.");
35
36 static const int kMinDFFontSize = 18;
37 static const int kSmallDFFontSize = 32;
38 static const int kSmallDFFontLimit = 32;
39 static const int kMediumDFFontSize = 72;
40 static const int kMediumDFFontLimit = 72;
41 static const int kLargeDFFontSize = 162;
42
43 static const int kVerticesPerGlyph = 4;
44 static const int kIndicesPerGlyph = 6;
45
46 #ifdef SK_DEBUG
47 static const int kExpectedDistanceAdjustTableSize = 8;
48 #endif
49 static const int kDistanceAdjustLumShift = 5;
50
51 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
52 SkGpuDevice* gpuDevice,
53 const SkDeviceProperties& properties,
54 bool enable)
55 : GrTextContext(context, gpuDevice, properties) {
56 #if SK_FORCE_DISTANCE_FIELD_TEXT
57 fEnableDFRendering = true;
58 #else
59 fEnableDFRendering = enable;
60 #endif
61 fStrike = NULL;
62 fDistanceAdjustTable = NULL;
63
64 fEffectTextureUniqueID = SK_InvalidUniqueID;
65 fEffectColor = GrColor_ILLEGAL;
66 fEffectFlags = kInvalid_DistanceFieldEffectFlag;
67
68 fVertices = NULL;
69 fCurrVertex = 0;
70 fAllocVertexCount = 0;
71 fTotalVertexCount = 0;
72 fCurrTexture = NULL;
73
74 fVertexBounds.setLargestInverted();
75 }
76
77 GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex t,
78 SkGpuDevice* gpuD evice,
79 const SkDevicePro perties& props,
80 bool enable) {
81 GrDistanceFieldTextContext* textContext = SkNEW_ARGS(GrDistanceFieldTextCont ext,
82 (context, gpuDevice, pr ops, enable));
83 textContext->buildDistanceAdjustTable();
84 #ifdef USE_BITMAP_TEXTBLOBS
85 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, gpuD evice, props,
86 enable);
87 #else
88 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, gpu Device, props);
89 #endif
90
91 return textContext;
92 }
93
94 void GrDistanceFieldTextContext::buildDistanceAdjustTable() {
95
96 // This is used for an approximation of the mask gamma hack, used by raster and bitmap
97 // text. The mask gamma hack is based off of guessing what the blend color i s going to
98 // be, and adjusting the mask so that when run through the linear blend will
99 // produce the value closest to the desired result. However, in practice thi s means
100 // that the 'adjusted' mask is just increasing or decreasing the coverage of
101 // the mask depending on what it is thought it will blit against. For black (on
102 // assumed white) this means that coverages are decreased (on a curve). For white (on
103 // assumed black) this means that coverages are increased (on a a curve). At
104 // middle (perceptual) gray (which could be blit against anything) the cover ages
105 // remain the same.
106 //
107 // The idea here is that instead of determining the initial (real) coverage and
108 // then adjusting that coverage, we determine an adjusted coverage directly by
109 // essentially manipulating the geometry (in this case, the distance to the glyph
110 // edge). So for black (on assumed white) this thins a bit; for white (on
111 // assumed black) this fake bolds the geometry a bit.
112 //
113 // The distance adjustment is calculated by determining the actual coverage value which
114 // when fed into in the mask gamma table gives us an 'adjusted coverage' val ue of 0.5. This
115 // actual coverage value (assuming it's between 0 and 1) corresponds to a di stance from the
116 // actual edge. So by subtracting this distance adjustment and computing wit hout the
117 // the coverage adjustment we should get 0.5 coverage at the same point.
118 //
119 // This has several implications:
120 // For non-gray lcd smoothed text, each subpixel essentially is using a
121 // slightly different geometry.
122 //
123 // For black (on assumed white) this may not cover some pixels which wer e
124 // previously covered; however those pixels would have been only slightl y
125 // covered and that slight coverage would have been decreased anyway. Al so, some pixels
126 // which were previously fully covered may no longer be fully covered.
127 //
128 // For white (on assumed black) this may cover some pixels which weren't
129 // previously covered at all.
130
131 int width, height;
132 size_t size;
133
134 #ifdef SK_GAMMA_CONTRAST
135 SkScalar contrast = SK_GAMMA_CONTRAST;
136 #else
137 SkScalar contrast = 0.5f;
138 #endif
139 SkScalar paintGamma = fDeviceProperties.gamma();
140 SkScalar deviceGamma = fDeviceProperties.gamma();
141
142 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
143 &width, &height);
144
145 SkASSERT(kExpectedDistanceAdjustTableSize == height);
146 fDistanceAdjustTable = SkNEW_ARRAY(SkScalar, height);
147
148 SkAutoTArray<uint8_t> data((int)size);
149 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get ());
150
151 // find the inverse points where we cross 0.5
152 // binsearch might be better, but we only need to do this once on creation
153 for (int row = 0; row < height; ++row) {
154 uint8_t* rowPtr = data.get() + row*width;
155 for (int col = 0; col < width - 1; ++col) {
156 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) {
157 // compute point where a mask value will give us a result of 0.5
158 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt r[col]);
159 float borderAlpha = (col + interp) / 255.f;
160
161 // compute t value for that alpha
162 // this is an approximate inverse for smoothstep()
163 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5 .0f) / 3.0f;
164
165 // compute distance which gives us that t value
166 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D istanceFieldAAFactor
167 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor ;
168
169 fDistanceAdjustTable[row] = d;
170 break;
171 }
172 }
173 }
174 }
175
176
177 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
178 SkDELETE_ARRAY(fDistanceAdjustTable);
179 fDistanceAdjustTable = NULL;
180 }
181
182 bool GrDistanceFieldTextContext::canDraw(const GrRenderTarget* rt,
183 const GrClip& clip,
184 const GrPaint& paint,
185 const SkPaint& skPaint,
186 const SkMatrix& viewMatrix) {
187 // TODO: support perspective (need getMaxScale replacement)
188 if (viewMatrix.hasPerspective()) {
189 return false;
190 }
191
192 SkScalar maxScale = viewMatrix.getMaxScale();
193 SkScalar scaledTextSize = maxScale*skPaint.getTextSize();
194 // Hinted text looks far better at small resolutions
195 // Scaling up beyond 2x yields undesireable artifacts
196 if (scaledTextSize < kMinDFFontSize || scaledTextSize > 2*kLargeDFFontSize) {
197 return false;
198 }
199
200 if (!fEnableDFRendering && !skPaint.isDistanceFieldTextTEMP() &&
201 scaledTextSize < kLargeDFFontSize) {
202 return false;
203 }
204
205 // rasterizers and mask filters modify alpha, which doesn't
206 // translate well to distance
207 if (skPaint.getRasterizer() || skPaint.getMaskFilter() ||
208 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
209 return false;
210 }
211
212 // TODO: add some stroking support
213 if (skPaint.getStyle() != SkPaint::kFill_Style) {
214 return false;
215 }
216
217 return true;
218 }
219
220 inline void GrDistanceFieldTextContext::init(GrRenderTarget* rt, const GrClip& c lip,
221 const GrPaint& paint, const SkPaint & skPaint,
222 const SkIRect& regionClipBounds) {
223 GrTextContext::init(rt, clip, paint, skPaint, regionClipBounds);
224
225 fStrike = NULL;
226
227 const SkMatrix& ctm = fViewMatrix;
228
229 // getMaxScale doesn't support perspective, so neither do we at the moment
230 SkASSERT(!ctm.hasPerspective());
231 SkScalar maxScale = ctm.getMaxScale();
232 SkScalar textSize = fSkPaint.getTextSize();
233 SkScalar scaledTextSize = textSize;
234 // if we have non-unity scale, we need to choose our base text size
235 // based on the SkPaint's text size multiplied by the max scale factor
236 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)?
237 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) {
238 scaledTextSize *= maxScale;
239 }
240
241 fVertices = NULL;
242 fCurrVertex = 0;
243 fAllocVertexCount = 0;
244 fTotalVertexCount = 0;
245
246 if (scaledTextSize <= kSmallDFFontLimit) {
247 fTextRatio = textSize / kSmallDFFontSize;
248 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
249 #if DEBUG_TEXT_SIZE
250 fSkPaint.setColor(SkColorSetARGB(0xFF, 0x00, 0x00, 0x7F));
251 fPaint.setColor(GrColorPackRGBA(0x00, 0x00, 0x7F, 0xFF));
252 #endif
253 } else if (scaledTextSize <= kMediumDFFontLimit) {
254 fTextRatio = textSize / kMediumDFFontSize;
255 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
256 #if DEBUG_TEXT_SIZE
257 fSkPaint.setColor(SkColorSetARGB(0xFF, 0x00, 0x3F, 0x00));
258 fPaint.setColor(GrColorPackRGBA(0x00, 0x3F, 0x00, 0xFF));
259 #endif
260 } else {
261 fTextRatio = textSize / kLargeDFFontSize;
262 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
263 #if DEBUG_TEXT_SIZE
264 fSkPaint.setColor(SkColorSetARGB(0xFF, 0x7F, 0x00, 0x00));
265 fPaint.setColor(GrColorPackRGBA(0x7F, 0x00, 0x00, 0xFF));
266 #endif
267 }
268
269 fUseLCDText = fSkPaint.isLCDRenderText();
270
271 fSkPaint.setLCDRenderText(false);
272 fSkPaint.setAutohinted(false);
273 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
274 fSkPaint.setSubpixelText(true);
275 }
276
277 void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& cl ip,
278 const GrPaint& paint,
279 const SkPaint& skPaint, const SkMatr ix& viewMatrix,
280 const char text[], size_t byteLength ,
281 SkScalar x, SkScalar y,
282 const SkIRect& regionClipBounds) {
283 SkASSERT(byteLength == 0 || text != NULL);
284
285 // nothing to draw
286 if (text == NULL || byteLength == 0) {
287 return;
288 }
289
290 fViewMatrix = viewMatrix;
291 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc();
292 SkAutoGlyphCache autoCache(skPaint, &fDeviceProperties, NULL);
293 SkGlyphCache* cache = autoCache.getCache();
294
295 SkTArray<SkScalar> positions;
296
297 const char* textPtr = text;
298 SkFixed stopX = 0;
299 SkFixed stopY = 0;
300 SkFixed origin;
301 switch (skPaint.getTextAlign()) {
302 case SkPaint::kRight_Align: origin = SK_Fixed1; break;
303 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
304 case SkPaint::kLeft_Align: origin = 0; break;
305 default: SkFAIL("Invalid paint origin"); return;
306 }
307
308 SkAutoKern autokern;
309 const char* stop = text + byteLength;
310 while (textPtr < stop) {
311 // don't need x, y here, since all subpixel variants will have the
312 // same advance
313 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
314
315 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
316 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));
317
318 SkFixed height = glyph.fAdvanceY;
319 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height))) ;
320
321 stopX += width;
322 stopY += height;
323 }
324 SkASSERT(textPtr == stop);
325
326 // now adjust starting point depending on alignment
327 SkScalar alignX = SkFixedToScalar(stopX);
328 SkScalar alignY = SkFixedToScalar(stopY);
329 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
330 alignX = SkScalarHalf(alignX);
331 alignY = SkScalarHalf(alignY);
332 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
333 alignX = 0;
334 alignY = 0;
335 }
336 x -= alignX;
337 y -= alignY;
338 SkPoint offset = SkPoint::Make(x, y);
339
340 this->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, positions.begin(),
341 2, offset, regionClipBounds);
342 }
343
344 void GrDistanceFieldTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
345 const GrPaint& paint,
346 const SkPaint& skPaint, const SkM atrix& viewMatrix,
347 const char text[], size_t byteLen gth,
348 const SkScalar pos[], int scalars PerPosition,
349 const SkPoint& offset,
350 const SkIRect& regionClipBounds) {
351
352 SkASSERT(byteLength == 0 || text != NULL);
353 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
354
355 // nothing to draw
356 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
357 return;
358 }
359
360 fViewMatrix = viewMatrix;
361 this->init(rt, clip, paint, skPaint, regionClipBounds);
362
363 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
364
365 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
366 SkGlyphCache* cache = autoCache.getCache();
367 GrFontScaler* fontScaler = GetGrFontScaler(cache);
368
369 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
370 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
371
372 const char* stop = text + byteLength;
373 SkTArray<char> fallbackTxt;
374 SkTArray<SkScalar> fallbackPos;
375
376 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
377 while (text < stop) {
378 const char* lastText = text;
379 // the last 2 parameters are ignored
380 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
381
382 if (glyph.fWidth) {
383 SkScalar x = offset.x() + pos[0];
384 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
385
386 if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
387 glyph.getSubXFixed(),
388 glyph.getSubYFixed(),
389 GrGlyph::kDistance_MaskStyl e),
390 x, y, fontScaler)) {
391 // couldn't append, send to fallback
392 fallbackTxt.push_back_n(SkToInt(text-lastText), lastText);
393 fallbackPos.push_back(pos[0]);
394 if (2 == scalarsPerPosition) {
395 fallbackPos.push_back(pos[1]);
396 }
397 }
398 }
399 pos += scalarsPerPosition;
400 }
401 } else {
402 SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
403 : SK_Scalar1;
404 while (text < stop) {
405 const char* lastText = text;
406 // the last 2 parameters are ignored
407 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
408
409 if (glyph.fWidth) {
410 SkScalar x = offset.x() + pos[0];
411 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0) ;
412
413 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX)*alignMul*fT extRatio;
414 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY)*alignMul*fT extRatio;
415
416 if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
417 glyph.getSubXFixed(),
418 glyph.getSubYFixed(),
419 GrGlyph::kDistance_MaskStyl e),
420 x - advanceX, y - advanceY, fontScaler)) {
421 // couldn't append, send to fallback
422 fallbackTxt.push_back_n(SkToInt(text-lastText), lastText);
423 fallbackPos.push_back(pos[0]);
424 if (2 == scalarsPerPosition) {
425 fallbackPos.push_back(pos[1]);
426 }
427 }
428 }
429 pos += scalarsPerPosition;
430 }
431 }
432
433 this->finish();
434
435 if (fallbackTxt.count() > 0) {
436 fFallbackTextContext->drawPosText(rt, clip, paint, skPaint, viewMatrix,
437 fallbackTxt.begin(), fallbackTxt.count (),
438 fallbackPos.begin(), scalarsPerPositio n, offset,
439 regionClipBounds);
440 }
441 }
442
443 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
444 unsigned r = SkColorGetR(c);
445 unsigned g = SkColorGetG(c);
446 unsigned b = SkColorGetB(c);
447 return GrColorPackRGBA(r, g, b, 0xff);
448 }
449
450 static size_t get_vertex_stride(bool useColorVerts) {
451 return useColorVerts ? (sizeof(SkPoint) + sizeof(GrColor) + sizeof(SkIPoint1 6)) :
452 (sizeof(SkPoint) + sizeof(SkIPoint16));
453 }
454
455 static void* alloc_vertices(GrDrawTarget* drawTarget,
456 int numVertices,
457 bool useColorVerts) {
458 if (numVertices <= 0) {
459 return NULL;
460 }
461
462 void* vertices = NULL;
463 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
464 get_vertex_stride(useC olorVerts),
465 0,
466 &vertices,
467 NULL);
468 GrAlwaysAssert(success);
469 return vertices;
470 }
471
472 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo r) {
473 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBilerp_F ilterMode);
474 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNon e_FilterMode);
475
476 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
477 const SkMatrix& ctm = fViewMatrix;
478
479 // set up any flags
480 uint32_t flags = 0;
481 flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
482 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
483 flags |= fUseLCDText && ctm.rectStaysRect() ?
484 kRectToRect_DistanceFieldEffectFlag : 0;
485 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry());
486 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
487
488 // see if we need to create a new effect
489 if (textureUniqueID != fEffectTextureUniqueID ||
490 filteredColor != fEffectColor ||
491 flags != fEffectFlags ||
492 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) {
493 GrColor color = fPaint.getColor();
494
495 if (fUseLCDText) {
496 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol or);
497
498 float redCorrection =
499 fDistanceAdjustTable[GrColorUnpackR(colorNoPreMul) >> kDistanceA djustLumShift];
500 float greenCorrection =
501 fDistanceAdjustTable[GrColorUnpackG(colorNoPreMul) >> kDistanceA djustLumShift];
502 float blueCorrection =
503 fDistanceAdjustTable[GrColorUnpackB(colorNoPreMul) >> kDistanceA djustLumShift];
504 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust =
505 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio n,
506 greenCorrect ion,
507 blueCorrecti on);
508 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextGeoProc::Create (color,
509 fViewMatrix,
510 fCurrTexture,
511 params,
512 widthAdjust,
513 flags));
514 } else {
515 flags |= kColorAttr_DistanceFieldEffectFlag;
516 bool opaque = GrColorIsOpaque(color);
517 #ifdef SK_GAMMA_APPLY_TO_A8
518 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie s.gamma(),
519 filteredColor);
520 float correction = fDistanceAdjustTable[lum >> kDistanceAdjustLumShi ft];
521 fCachedGeometryProcessor.reset(GrDistanceFieldA8TextGeoProc::Create( color,
522 fViewMatrix,
523 fCurrTexture,
524 params,
525 correction,
526 flags,
527 opaque));
528 #else
529 fCachedGeometryProcessor.reset(GrDistanceFieldA8TextGeoProc::Create( color,
530 fViewMatrix,
531 fCurrTexture,
532 params,
533 flags,
534 opaque));
535 #endif
536 }
537 fEffectTextureUniqueID = textureUniqueID;
538 fEffectColor = filteredColor;
539 fEffectFlags = flags;
540 }
541
542 }
543
544 inline bool GrDistanceFieldTextContext::uploadGlyph(GrGlyph* glyph, GrFontScaler * scaler) {
545 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
546 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
547 return true;
548 }
549
550 // try to clear out an unused plot before we flush
551 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
552 fStrike->addGlyphToAtlas(glyph, scaler)) {
553 return true;
554 }
555
556 if (c_DumpFontCache) {
557 #ifdef SK_DEVELOPER
558 fContext->getFontCache()->dump();
559 #endif
560 }
561
562 // before we purge the cache, we must flush any accumulated draws
563 this->flush();
564 fContext->flush();
565
566 // we should have an unused plot now
567 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
568 fStrike->addGlyphToAtlas(glyph, scaler)) {
569 return true;
570 }
571
572 // we should never get here
573 SkASSERT(false);
574 }
575
576 return false;
577 }
578
579
580 // Returns true if this method handled the glyph, false if needs to be passed to fallback
581 //
582 bool GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed,
583 SkScalar sx, SkScalar sy,
584 GrFontScaler* scaler) {
585 if (NULL == fDrawTarget) {
586 return true;
587 }
588
589 if (NULL == fStrike) {
590 fStrike = fContext->getFontCache()->getStrike(scaler);
591 }
592
593 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
594 if (NULL == glyph || glyph->fBounds.isEmpty()) {
595 return true;
596 }
597
598 // fallback to color glyph support
599 if (kA8_GrMaskFormat != glyph->fMaskFormat) {
600 return false;
601 }
602
603 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
604 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
605 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldIn set);
606 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceField Inset);
607
608 SkScalar scale = fTextRatio;
609 dx *= scale;
610 dy *= scale;
611 width *= scale;
612 height *= scale;
613 sx += dx;
614 sy += dy;
615 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height);
616
617 // check if we clipped out
618 SkRect dstRect;
619 const SkMatrix& ctm = fViewMatrix;
620 (void) ctm.mapRect(&dstRect, glyphRect);
621 if (fClipRect.quickReject(SkScalarTruncToInt(dstRect.left()),
622 SkScalarTruncToInt(dstRect.top()),
623 SkScalarTruncToInt(dstRect.right()),
624 SkScalarTruncToInt(dstRect.bottom()))) {
625 return true;
626 }
627
628 if (NULL == glyph->fPlot) {
629 // needs to be a separate conditional to avoid over-optimization
630 // on Nexus 7 and Nexus 10
631
632 // If the glyph is too large we fall back to paths
633 if (!uploadGlyph(glyph, scaler)) {
634 if (NULL == glyph->fPath) {
635 SkPath* path = SkNEW(SkPath);
636 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
637 // flag the glyph as being dead?
638 delete path;
639 return true;
640 }
641 glyph->fPath = path;
642 }
643
644 // flush any accumulated draws before drawing this glyph as a path.
645 this->flush();
646
647 SkMatrix ctm;
648 ctm.postTranslate(sx - dx, sy - dy);
649
650 SkPath tmpPath(*glyph->fPath);
651 tmpPath.transform(ctm);
652
653 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
654 fContext->drawPath(fRenderTarget, fClip, fPaint, fViewMatrix, tmpPat h, strokeInfo);
655
656 // remove this glyph from the vertices we need to allocate
657 fTotalVertexCount -= kVerticesPerGlyph;
658 return true;
659 }
660 }
661
662 SkASSERT(glyph->fPlot);
663 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
664 glyph->fPlot->setDrawToken(drawToken);
665
666 GrTexture* texture = glyph->fPlot->texture();
667 SkASSERT(texture);
668
669 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fTotalVerte xCount) {
670 this->flush();
671 fCurrTexture = texture;
672 fCurrTexture->ref();
673 }
674
675 bool useColorVerts = !fUseLCDText;
676
677 if (NULL == fVertices) {
678 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer() ->maxQuads();
679 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
680 fVertices = alloc_vertices(fDrawTarget,
681 fAllocVertexCount,
682 useColorVerts);
683 }
684
685 fVertexBounds.joinNonEmptyArg(glyphRect);
686
687 int u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset;
688 int v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset;
689 int u1 = u0 + glyph->fBounds.width() - 2*SK_DistanceFieldInset;
690 int v1 = v0 + glyph->fBounds.height() - 2*SK_DistanceFieldInset;
691
692 size_t vertSize = get_vertex_stride(useColorVerts);
693 intptr_t vertex = reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVe rtex;
694
695 // V0
696 SkPoint* position = reinterpret_cast<SkPoint*>(vertex);
697 position->set(glyphRect.fLeft, glyphRect.fTop);
698 if (useColorVerts) {
699 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
700 *color = fPaint.getColor();
701 }
702 SkIPoint16* textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize -
703 sizeof(SkIPoint16) );
704 textureCoords->set(u0, v0);
705 vertex += vertSize;
706
707 // V1
708 position = reinterpret_cast<SkPoint*>(vertex);
709 position->set(glyphRect.fLeft, glyphRect.fBottom);
710 if (useColorVerts) {
711 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
712 *color = fPaint.getColor();
713 }
714 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk IPoint16));
715 textureCoords->set(u0, v1);
716 vertex += vertSize;
717
718 // V2
719 position = reinterpret_cast<SkPoint*>(vertex);
720 position->set(glyphRect.fRight, glyphRect.fBottom);
721 if (useColorVerts) {
722 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
723 *color = fPaint.getColor();
724 }
725 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk IPoint16));
726 textureCoords->set(u1, v1);
727 vertex += vertSize;
728
729 // V3
730 position = reinterpret_cast<SkPoint*>(vertex);
731 position->set(glyphRect.fRight, glyphRect.fTop);
732 if (useColorVerts) {
733 SkColor* color = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint));
734 *color = fPaint.getColor();
735 }
736 textureCoords = reinterpret_cast<SkIPoint16*>(vertex + vertSize - sizeof(Sk IPoint16));
737 textureCoords->set(u1, v0);
738
739 fCurrVertex += 4;
740
741 return true;
742 }
743
744 void GrDistanceFieldTextContext::flush() {
745 if (NULL == fDrawTarget) {
746 return;
747 }
748
749 if (fCurrVertex > 0) {
750 GrPipelineBuilder pipelineBuilder;
751 pipelineBuilder.setFromPaint(fPaint, fRenderTarget, fClip);
752
753 // setup our sampler state for our text texture/atlas
754 SkASSERT(SkIsAlign4(fCurrVertex));
755
756 // get our current color
757 SkColor filteredColor;
758 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
759 if (colorFilter) {
760 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
761 } else {
762 filteredColor = fSkPaint.getColor();
763 }
764 this->setupCoverageEffect(filteredColor);
765
766 // Set draw state
767 if (fUseLCDText) {
768 // TODO: move supportsRGBCoverage check to setupCoverageEffect and o nly add LCD
769 // processor if the xp can support it. For now we will simply assume that if
770 // fUseLCDText is true, then we have a known color output.
771 const GrXPFactory* xpFactory = pipelineBuilder.getXPFactory();
772 if (!xpFactory->supportsRGBCoverage(0, kRGBA_GrColorComponentFlags)) {
773 SkDebugf("LCD Text will not draw correctly.\n");
774 }
775 SkASSERT(!fCachedGeometryProcessor->hasVertexColor());
776 } else {
777 // We're using per-vertex color.
778 SkASSERT(fCachedGeometryProcessor->hasVertexColor());
779 }
780 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
781 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
782 fDrawTarget->drawIndexedInstances(&pipelineBuilder,
783 fCachedGeometryProcessor.get(),
784 kTriangles_GrPrimitiveType,
785 nGlyphs,
786 kVerticesPerGlyph,
787 kIndicesPerGlyph,
788 &fVertexBounds);
789 fDrawTarget->resetVertexSource();
790 fVertices = NULL;
791 fTotalVertexCount -= fCurrVertex;
792 fCurrVertex = 0;
793 SkSafeSetNull(fCurrTexture);
794 fVertexBounds.setLargestInverted();
795 }
796 }
797
798 inline void GrDistanceFieldTextContext::finish() {
799 this->flush();
800 fTotalVertexCount = 0;
801
802 GrTextContext::finish();
803 }
804
OLDNEW
« no previous file with comments | « src/gpu/GrDistanceFieldTextContext.h ('k') | src/gpu/GrFlushToGpuDrawTarget.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698