| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2015 Google Inc. | 2 * Copyright 2015 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 #include "GrAtlasTextContext.h" | 7 #include "GrAtlasTextContext.h" |
| 8 | 8 |
| 9 #include "GrBlurUtils.h" | 9 #include "GrBlurUtils.h" |
| 10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
| (...skipping 28 matching lines...) Expand all Loading... |
| 39 static const int kSmallDFFontSize = 32; | 39 static const int kSmallDFFontSize = 32; |
| 40 static const int kSmallDFFontLimit = 32; | 40 static const int kSmallDFFontLimit = 32; |
| 41 static const int kMediumDFFontSize = 72; | 41 static const int kMediumDFFontSize = 72; |
| 42 static const int kMediumDFFontLimit = 72; | 42 static const int kMediumDFFontLimit = 72; |
| 43 static const int kLargeDFFontSize = 162; | 43 static const int kLargeDFFontSize = 162; |
| 44 #ifdef SK_BUILD_FOR_ANDROID | 44 #ifdef SK_BUILD_FOR_ANDROID |
| 45 static const int kLargeDFFontLimit = 384; | 45 static const int kLargeDFFontLimit = 384; |
| 46 #else | 46 #else |
| 47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; | 47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; |
| 48 #endif | 48 #endif |
| 49 | |
| 50 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) | |
| 51 }; | 49 }; |
| 52 | 50 |
| 53 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) | 51 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) |
| 54 : INHERITED(context, surfaceProps) | 52 : INHERITED(context, surfaceProps) |
| 55 , fDistanceAdjustTable(new DistanceAdjustTable) { | 53 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { |
| 56 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 54 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
| 57 // vertexStride | 55 // vertexStride |
| 58 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && | 56 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && |
| 59 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, | 57 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, |
| 60 "vertex_attribute_changed"); | 58 "vertex_attribute_changed"); |
| 61 fCurrStrike = nullptr; | 59 fCurrStrike = nullptr; |
| 62 fCache = context->getTextBlobCache(); | 60 fCache = context->getTextBlobCache(); |
| 63 } | 61 } |
| 64 | 62 |
| 65 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable() { | |
| 66 | |
| 67 // This is used for an approximation of the mask gamma hack, used by raster
and bitmap | |
| 68 // text. The mask gamma hack is based off of guessing what the blend color i
s going to | |
| 69 // be, and adjusting the mask so that when run through the linear blend will | |
| 70 // produce the value closest to the desired result. However, in practice thi
s means | |
| 71 // that the 'adjusted' mask is just increasing or decreasing the coverage of | |
| 72 // the mask depending on what it is thought it will blit against. For black
(on | |
| 73 // assumed white) this means that coverages are decreased (on a curve). For
white (on | |
| 74 // assumed black) this means that coverages are increased (on a a curve). At | |
| 75 // middle (perceptual) gray (which could be blit against anything) the cover
ages | |
| 76 // remain the same. | |
| 77 // | |
| 78 // The idea here is that instead of determining the initial (real) coverage
and | |
| 79 // then adjusting that coverage, we determine an adjusted coverage directly
by | |
| 80 // essentially manipulating the geometry (in this case, the distance to the
glyph | |
| 81 // edge). So for black (on assumed white) this thins a bit; for white (on | |
| 82 // assumed black) this fake bolds the geometry a bit. | |
| 83 // | |
| 84 // The distance adjustment is calculated by determining the actual coverage
value which | |
| 85 // when fed into in the mask gamma table gives us an 'adjusted coverage' val
ue of 0.5. This | |
| 86 // actual coverage value (assuming it's between 0 and 1) corresponds to a di
stance from the | |
| 87 // actual edge. So by subtracting this distance adjustment and computing wit
hout the | |
| 88 // the coverage adjustment we should get 0.5 coverage at the same point. | |
| 89 // | |
| 90 // This has several implications: | |
| 91 // For non-gray lcd smoothed text, each subpixel essentially is using a | |
| 92 // slightly different geometry. | |
| 93 // | |
| 94 // For black (on assumed white) this may not cover some pixels which wer
e | |
| 95 // previously covered; however those pixels would have been only slightl
y | |
| 96 // covered and that slight coverage would have been decreased anyway. Al
so, some pixels | |
| 97 // which were previously fully covered may no longer be fully covered. | |
| 98 // | |
| 99 // For white (on assumed black) this may cover some pixels which weren't | |
| 100 // previously covered at all. | |
| 101 | |
| 102 int width, height; | |
| 103 size_t size; | |
| 104 | |
| 105 #ifdef SK_GAMMA_CONTRAST | |
| 106 SkScalar contrast = SK_GAMMA_CONTRAST; | |
| 107 #else | |
| 108 SkScalar contrast = 0.5f; | |
| 109 #endif | |
| 110 SkScalar paintGamma = SK_GAMMA_EXPONENT; | |
| 111 SkScalar deviceGamma = SK_GAMMA_EXPONENT; | |
| 112 | |
| 113 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, | |
| 114 &width, &height); | |
| 115 | |
| 116 SkASSERT(kExpectedDistanceAdjustTableSize == height); | |
| 117 fTable = new SkScalar[height]; | |
| 118 | |
| 119 SkAutoTArray<uint8_t> data((int)size); | |
| 120 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get
()); | |
| 121 | |
| 122 // find the inverse points where we cross 0.5 | |
| 123 // binsearch might be better, but we only need to do this once on creation | |
| 124 for (int row = 0; row < height; ++row) { | |
| 125 uint8_t* rowPtr = data.get() + row*width; | |
| 126 for (int col = 0; col < width - 1; ++col) { | |
| 127 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { | |
| 128 // compute point where a mask value will give us a result of 0.5 | |
| 129 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt
r[col]); | |
| 130 float borderAlpha = (col + interp) / 255.f; | |
| 131 | |
| 132 // compute t value for that alpha | |
| 133 // this is an approximate inverse for smoothstep() | |
| 134 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5
.0f) / 3.0f; | |
| 135 | |
| 136 // compute distance which gives us that t value | |
| 137 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D
istanceFieldAAFactor | |
| 138 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor
; | |
| 139 | |
| 140 fTable[row] = d; | |
| 141 break; | |
| 142 } | |
| 143 } | |
| 144 } | |
| 145 } | |
| 146 | 63 |
| 147 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 64 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
| 148 const SkSurfaceProps& surfaceProp
s) { | 65 const SkSurfaceProps& surfaceProp
s) { |
| 149 return new GrAtlasTextContext(context, surfaceProps); | 66 return new GrAtlasTextContext(context, surfaceProps); |
| 150 } | 67 } |
| 151 | 68 |
| 152 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { | 69 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { |
| 153 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || | 70 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || |
| 154 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 71 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
| 155 } | 72 } |
| (...skipping 1004 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1160 gTextContext->createDrawTextBlob(clip, grPaint, skPaint, viewMatrix,
text, | 1077 gTextContext->createDrawTextBlob(clip, grPaint, skPaint, viewMatrix,
text, |
| 1161 static_cast<size_t>(textLen), 0, 0,
noClip)); | 1078 static_cast<size_t>(textLen), 0, 0,
noClip)); |
| 1162 | 1079 |
| 1163 SkScalar transX = static_cast<SkScalar>(random->nextU()); | 1080 SkScalar transX = static_cast<SkScalar>(random->nextU()); |
| 1164 SkScalar transY = static_cast<SkScalar>(random->nextU()); | 1081 SkScalar transY = static_cast<SkScalar>(random->nextU()); |
| 1165 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; | 1082 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; |
| 1166 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); | 1083 return gTextContext->createBatch(blob, info, textLen, 0, 0, color, transX, t
ransY, skPaint); |
| 1167 } | 1084 } |
| 1168 | 1085 |
| 1169 #endif | 1086 #endif |
| OLD | NEW |