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