| 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 |