OLD | NEW |
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 | 7 |
8 #include "GrDistanceFieldTextContext.h" | 8 #include "GrDistanceFieldTextContext.h" |
9 #include "GrAtlas.h" | 9 #include "GrAtlas.h" |
10 #include "GrBitmapTextContext.h" | 10 #include "GrBitmapTextContext.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 static const int kMinDFFontSize = 18; | 35 static const int kMinDFFontSize = 18; |
36 static const int kSmallDFFontSize = 32; | 36 static const int kSmallDFFontSize = 32; |
37 static const int kSmallDFFontLimit = 32; | 37 static const int kSmallDFFontLimit = 32; |
38 static const int kMediumDFFontSize = 72; | 38 static const int kMediumDFFontSize = 72; |
39 static const int kMediumDFFontLimit = 72; | 39 static const int kMediumDFFontLimit = 72; |
40 static const int kLargeDFFontSize = 162; | 40 static const int kLargeDFFontSize = 162; |
41 | 41 |
42 static const int kVerticesPerGlyph = 4; | 42 static const int kVerticesPerGlyph = 4; |
43 static const int kIndicesPerGlyph = 6; | 43 static const int kIndicesPerGlyph = 6; |
44 | 44 |
| 45 #ifdef SK_DEBUG |
| 46 static const int kExpectedWidthAdjustTableSize = 8; |
| 47 #endif |
| 48 static const int kWidthAdjustLumShift = 5; |
| 49 |
45 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context, | 50 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context, |
46 SkGpuDevice* gpuDevice, | 51 SkGpuDevice* gpuDevice, |
47 const SkDeviceProperties&
properties, | 52 const SkDeviceProperties&
properties, |
48 bool enable) | 53 bool enable) |
49 : GrTextContext(context, gpuDevice, properties) { | 54 : GrTextContext(context, gpuDevice, properties) { |
50 #if SK_FORCE_DISTANCE_FIELD_TEXT | 55 #if SK_FORCE_DISTANCE_FIELD_TEXT |
51 fEnableDFRendering = true; | 56 fEnableDFRendering = true; |
52 #else | 57 #else |
53 fEnableDFRendering = enable; | 58 fEnableDFRendering = enable; |
54 #endif | 59 #endif |
55 fStrike = NULL; | 60 fStrike = NULL; |
56 fGammaTexture = NULL; | 61 fWidthAdjustTable = NULL; |
57 | 62 |
58 fEffectTextureUniqueID = SK_InvalidUniqueID; | 63 fEffectTextureUniqueID = SK_InvalidUniqueID; |
59 fEffectColor = GrColor_ILLEGAL; | 64 fEffectColor = GrColor_ILLEGAL; |
60 fEffectFlags = kInvalid_DistanceFieldEffectFlag; | 65 fEffectFlags = kInvalid_DistanceFieldEffectFlag; |
61 | 66 |
62 fVertices = NULL; | 67 fVertices = NULL; |
63 fCurrVertex = 0; | 68 fCurrVertex = 0; |
64 fAllocVertexCount = 0; | 69 fAllocVertexCount = 0; |
65 fTotalVertexCount = 0; | 70 fTotalVertexCount = 0; |
66 fCurrTexture = NULL; | 71 fCurrTexture = NULL; |
67 | 72 |
68 fVertexBounds.setLargestInverted(); | 73 fVertexBounds.setLargestInverted(); |
69 } | 74 } |
70 | 75 |
71 GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex
t, | 76 GrDistanceFieldTextContext* GrDistanceFieldTextContext::Create(GrContext* contex
t, |
72 SkGpuDevice* gpuD
evice, | 77 SkGpuDevice* gpuD
evice, |
73 const SkDevicePro
perties& props, | 78 const SkDevicePro
perties& props, |
74 bool enable) { | 79 bool enable) { |
75 GrDistanceFieldTextContext* textContext = SkNEW_ARGS(GrDistanceFieldTextCont
ext, | 80 GrDistanceFieldTextContext* textContext = SkNEW_ARGS(GrDistanceFieldTextCont
ext, |
76 (context, gpuDevice, pr
ops, enable)); | 81 (context, gpuDevice, pr
ops, enable)); |
| 82 textContext->buildWidthAdjustTable(); |
77 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, gpu
Device, props); | 83 textContext->fFallbackTextContext = GrBitmapTextContext::Create(context, gpu
Device, props); |
78 | 84 |
79 return textContext; | 85 return textContext; |
80 } | 86 } |
81 | 87 |
| 88 |
| 89 void GrDistanceFieldTextContext::buildWidthAdjustTable() { |
| 90 int width, height; |
| 91 size_t size; |
| 92 |
| 93 #ifdef SK_GAMMA_CONTRAST |
| 94 SkScalar contrast = SK_GAMMA_CONTRAST; |
| 95 #else |
| 96 SkScalar contrast = 0.5f; |
| 97 #endif |
| 98 SkScalar paintGamma = fDeviceProperties.gamma(); |
| 99 SkScalar deviceGamma = fDeviceProperties.gamma(); |
| 100 |
| 101 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, |
| 102 &width, &height); |
| 103 |
| 104 SkASSERT(kExpectedWidthAdjustTableSize == height); |
| 105 fWidthAdjustTable = SkNEW_ARRAY(SkScalar, height); |
| 106 |
| 107 SkAutoTArray<uint8_t> data((int)size); |
| 108 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get
()); |
| 109 |
| 110 // find the inverse points where we cross 0.5 |
| 111 // binsearch might be better, but we only need to do this once on creation |
| 112 for (int row = 0; row < height; ++row) { |
| 113 uint8_t* rowPtr = data.get() + row*width; |
| 114 for (int col = 0; col < width - 1; ++col) { |
| 115 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { |
| 116 // compute point where a mask value will give us a result of 0.5 |
| 117 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt
r[col]); |
| 118 float borderAlpha = (col + interp) / 255.f; |
| 119 |
| 120 // compute t value for that alpha |
| 121 // this is an approximate inverse for smoothstep() |
| 122 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5
.0f) / 3.0f; |
| 123 |
| 124 // compute distance which gives us that t value |
| 125 float d = 2.0f*0.7071f*t - 0.7071f; |
| 126 |
| 127 fWidthAdjustTable[row] = d; |
| 128 break; |
| 129 } |
| 130 } |
| 131 } |
| 132 } |
| 133 |
| 134 |
82 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { | 135 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { |
83 SkSafeSetNull(fGammaTexture); | 136 SkDELETE_ARRAY(fWidthAdjustTable); |
| 137 fWidthAdjustTable = NULL; |
84 } | 138 } |
85 | 139 |
86 bool GrDistanceFieldTextContext::canDraw(const GrRenderTarget* rt, | 140 bool GrDistanceFieldTextContext::canDraw(const GrRenderTarget* rt, |
87 const GrClip& clip, | 141 const GrClip& clip, |
88 const GrPaint& paint, | 142 const GrPaint& paint, |
89 const SkPaint& skPaint, | 143 const SkPaint& skPaint, |
90 const SkMatrix& viewMatrix) { | 144 const SkMatrix& viewMatrix) { |
91 // TODO: support perspective (need getMaxScale replacement) | 145 // TODO: support perspective (need getMaxScale replacement) |
92 if (viewMatrix.hasPerspective()) { | 146 if (viewMatrix.hasPerspective()) { |
93 return false; | 147 return false; |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
171 } | 225 } |
172 | 226 |
173 fUseLCDText = fSkPaint.isLCDRenderText(); | 227 fUseLCDText = fSkPaint.isLCDRenderText(); |
174 | 228 |
175 fSkPaint.setLCDRenderText(false); | 229 fSkPaint.setLCDRenderText(false); |
176 fSkPaint.setAutohinted(false); | 230 fSkPaint.setAutohinted(false); |
177 fSkPaint.setHinting(SkPaint::kNormal_Hinting); | 231 fSkPaint.setHinting(SkPaint::kNormal_Hinting); |
178 fSkPaint.setSubpixelText(true); | 232 fSkPaint.setSubpixelText(true); |
179 } | 233 } |
180 | 234 |
181 static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache, | |
182 const SkDeviceProperties& deviceProperties, | |
183 GrTexture** gammaTexture) { | |
184 if (NULL == *gammaTexture) { | |
185 int width, height; | |
186 size_t size; | |
187 | |
188 #ifdef SK_GAMMA_CONTRAST | |
189 SkScalar contrast = SK_GAMMA_CONTRAST; | |
190 #else | |
191 SkScalar contrast = 0.5f; | |
192 #endif | |
193 SkScalar paintGamma = deviceProperties.gamma(); | |
194 SkScalar deviceGamma = deviceProperties.gamma(); | |
195 | |
196 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamm
a, | |
197 &width, &height); | |
198 | |
199 SkAutoTArray<uint8_t> data((int)size); | |
200 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data
.get()); | |
201 | |
202 // TODO: Update this to use the cache rather than directly creating a te
xture. | |
203 GrSurfaceDesc desc; | |
204 desc.fFlags = kNone_GrSurfaceFlags; | |
205 desc.fWidth = width; | |
206 desc.fHeight = height; | |
207 desc.fConfig = kAlpha_8_GrPixelConfig; | |
208 | |
209 *gammaTexture = context->getGpu()->createTexture(desc, true, NULL, 0); | |
210 if (NULL == *gammaTexture) { | |
211 return; | |
212 } | |
213 | |
214 (*gammaTexture)->writePixels(0, 0, width, height, | |
215 (*gammaTexture)->config(), data.get(), 0, | |
216 GrContext::kDontFlush_PixelOpsFlag); | |
217 } | |
218 } | |
219 | |
220 void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& cl
ip, | 235 void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& cl
ip, |
221 const GrPaint& paint, | 236 const GrPaint& paint, |
222 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, | 237 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, |
223 const char text[], size_t byteLength
, | 238 const char text[], size_t byteLength
, |
224 SkScalar x, SkScalar y, | 239 SkScalar x, SkScalar y, |
225 const SkIRect& regionClipBounds) { | 240 const SkIRect& regionClipBounds) { |
226 SkASSERT(byteLength == 0 || text != NULL); | 241 SkASSERT(byteLength == 0 || text != NULL); |
227 | 242 |
228 // nothing to draw | 243 // nothing to draw |
229 if (text == NULL || byteLength == 0) { | 244 if (text == NULL || byteLength == 0) { |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
302 | 317 |
303 fViewMatrix = viewMatrix; | 318 fViewMatrix = viewMatrix; |
304 this->init(rt, clip, paint, skPaint, regionClipBounds); | 319 this->init(rt, clip, paint, skPaint, regionClipBounds); |
305 | 320 |
306 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 321 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
307 | 322 |
308 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); | 323 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); |
309 SkGlyphCache* cache = autoCache.getCache(); | 324 SkGlyphCache* cache = autoCache.getCache(); |
310 GrFontScaler* fontScaler = GetGrFontScaler(cache); | 325 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
311 | 326 |
312 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); | |
313 | |
314 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); | 327 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL); |
315 fTotalVertexCount = kVerticesPerGlyph*numGlyphs; | 328 fTotalVertexCount = kVerticesPerGlyph*numGlyphs; |
316 | 329 |
317 const char* stop = text + byteLength; | 330 const char* stop = text + byteLength; |
318 SkTArray<char> fallbackTxt; | 331 SkTArray<char> fallbackTxt; |
319 SkTArray<SkScalar> fallbackPos; | 332 SkTArray<SkScalar> fallbackPos; |
320 | 333 |
321 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | 334 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { |
322 while (text < stop) { | 335 while (text < stop) { |
323 const char* lastText = text; | 336 const char* lastText = text; |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
431 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; | 444 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; |
432 | 445 |
433 // see if we need to create a new effect | 446 // see if we need to create a new effect |
434 if (textureUniqueID != fEffectTextureUniqueID || | 447 if (textureUniqueID != fEffectTextureUniqueID || |
435 filteredColor != fEffectColor || | 448 filteredColor != fEffectColor || |
436 flags != fEffectFlags || | 449 flags != fEffectFlags || |
437 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) { | 450 !fCachedGeometryProcessor->viewMatrix().cheapEqualTo(fViewMatrix)) { |
438 GrColor color = fPaint.getColor(); | 451 GrColor color = fPaint.getColor(); |
439 if (fUseLCDText) { | 452 if (fUseLCDText) { |
440 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); | 453 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); |
| 454 |
| 455 float redCorrection = |
| 456 fWidthAdjustTable[GrColorUnpackR(colorNoPreMul) >> kWidthAdjustL
umShift]; |
| 457 float greenCorrection = |
| 458 fWidthAdjustTable[GrColorUnpackG(colorNoPreMul) >> kWidthAdjustL
umShift]; |
| 459 float blueCorrection = |
| 460 fWidthAdjustTable[GrColorUnpackB(colorNoPreMul) >> kWidthAdjustL
umShift]; |
| 461 GrDistanceFieldLCDTextureEffect::WidthAdjust widthAdjust = |
| 462 GrDistanceFieldLCDTextureEffect::WidthAdjust::Make(redCorrection
, |
| 463 greenCorrecti
on, |
| 464 blueCorrectio
n); |
441 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Crea
te(color, | 465 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Crea
te(color, |
442
fViewMatrix, | 466
fViewMatrix, |
443
fCurrTexture, | 467
fCurrTexture, |
444
params, | 468
params, |
445
fGammaTexture, | 469
widthAdjust, |
446
gammaParams, | |
447
colorNoPreMul, | |
448
flags)); | 470
flags)); |
449 } else { | 471 } else { |
450 flags |= kColorAttr_DistanceFieldEffectFlag; | 472 flags |= kColorAttr_DistanceFieldEffectFlag; |
451 bool opaque = GrColorIsOpaque(color); | 473 bool opaque = GrColorIsOpaque(color); |
452 #ifdef SK_GAMMA_APPLY_TO_A8 | 474 #ifdef SK_GAMMA_APPLY_TO_A8 |
453 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie
s.gamma(), | 475 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie
s.gamma(), |
454 filteredColor); | 476 filteredColor); |
| 477 float correction = fWidthAdjustTable[lum >> kWidthAdjustLumShift]; |
455 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
color, | 478 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
color, |
456
fViewMatrix, | 479
fViewMatrix, |
457
fCurrTexture, | 480
fCurrTexture, |
458
params, | 481
params, |
459
fGammaTexture, | 482
correction, |
460
gammaParams, | |
461
lum/255.f, | |
462
flags, | 483
flags, |
463
opaque)); | 484
opaque)); |
464 #else | 485 #else |
465 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
color, | 486 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
color, |
466
fViewMatrix, | 487
fViewMatrix, |
467
fCurrTexture, | 488
fCurrTexture, |
468
params, | 489
params, |
469
flags, | 490
flags, |
470
opaque)); | 491
opaque)); |
471 #endif | 492 #endif |
(...skipping 260 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
732 } | 753 } |
733 } | 754 } |
734 | 755 |
735 inline void GrDistanceFieldTextContext::finish() { | 756 inline void GrDistanceFieldTextContext::finish() { |
736 this->flush(); | 757 this->flush(); |
737 fTotalVertexCount = 0; | 758 fTotalVertexCount = 0; |
738 | 759 |
739 GrTextContext::finish(); | 760 GrTextContext::finish(); |
740 } | 761 } |
741 | 762 |
OLD | NEW |