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 "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 fEffectColor = GrColor_ILLEGAL; | 74 fEffectColor = GrColor_ILLEGAL; |
75 fEffectFlags = 0; | 75 fEffectFlags = 0; |
76 | 76 |
77 fVertices = NULL; | 77 fVertices = NULL; |
78 fMaxVertices = 0; | 78 fMaxVertices = 0; |
79 | 79 |
80 fVertexBounds.setLargestInverted(); | 80 fVertexBounds.setLargestInverted(); |
81 } | 81 } |
82 | 82 |
83 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { | 83 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() { |
84 this->flushGlyphs(); | 84 this->flush(); |
85 SkSafeSetNull(fGammaTexture); | 85 SkSafeSetNull(fGammaTexture); |
86 } | 86 } |
87 | 87 |
88 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) { | 88 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) { |
89 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) { | 89 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) { |
90 return false; | 90 return false; |
91 } | 91 } |
92 | 92 |
93 // rasterizers and mask filters modify alpha, which doesn't | 93 // rasterizers and mask filters modify alpha, which doesn't |
94 // translate well to distance | 94 // translate well to distance |
(...skipping 12 matching lines...) Expand all Loading... |
107 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) { | 107 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) { |
108 return false; | 108 return false; |
109 } | 109 } |
110 | 110 |
111 // distance fields cannot represent color fonts | 111 // distance fields cannot represent color fonts |
112 SkScalerContext::Rec rec; | 112 SkScalerContext::Rec rec; |
113 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); | 113 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec); |
114 return rec.getFormat() != SkMask::kARGB32_Format; | 114 return rec.getFormat() != SkMask::kARGB32_Format; |
115 } | 115 } |
116 | 116 |
| 117 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
& skPaint) { |
| 118 GrTextContext::init(paint, skPaint); |
| 119 |
| 120 fStrike = NULL; |
| 121 |
| 122 const SkMatrix& ctm = fContext->getMatrix(); |
| 123 |
| 124 // getMaxScale doesn't support perspective, so neither do we at the moment |
| 125 SkASSERT(!ctm.hasPerspective()); |
| 126 SkScalar maxScale = ctm.getMaxScale(); |
| 127 SkScalar textSize = fSkPaint.getTextSize(); |
| 128 SkScalar scaledTextSize = textSize; |
| 129 // if we have non-unity scale, we need to choose our base text size |
| 130 // based on the SkPaint's text size multiplied by the max scale factor |
| 131 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? |
| 132 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { |
| 133 scaledTextSize *= maxScale; |
| 134 } |
| 135 |
| 136 fCurrVertex = 0; |
| 137 |
| 138 fVertices = NULL; |
| 139 |
| 140 if (scaledTextSize <= kSmallDFFontLimit) { |
| 141 fTextRatio = textSize / kSmallDFFontSize; |
| 142 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize)); |
| 143 } else if (scaledTextSize <= kMediumDFFontLimit) { |
| 144 fTextRatio = textSize / kMediumDFFontSize; |
| 145 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize)); |
| 146 } else { |
| 147 fTextRatio = textSize / kLargeDFFontSize; |
| 148 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize)); |
| 149 } |
| 150 |
| 151 fUseLCDText = fSkPaint.isLCDRenderText(); |
| 152 |
| 153 fSkPaint.setLCDRenderText(false); |
| 154 fSkPaint.setAutohinted(false); |
| 155 fSkPaint.setHinting(SkPaint::kNormal_Hinting); |
| 156 fSkPaint.setSubpixelText(true); |
| 157 |
| 158 } |
| 159 |
| 160 static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache, |
| 161 const SkDeviceProperties& deviceProperties, |
| 162 GrTexture** gammaTexture) { |
| 163 if (NULL == *gammaTexture) { |
| 164 int width, height; |
| 165 size_t size; |
| 166 |
| 167 #ifdef SK_GAMMA_CONTRAST |
| 168 SkScalar contrast = SK_GAMMA_CONTRAST; |
| 169 #else |
| 170 SkScalar contrast = 0.5f; |
| 171 #endif |
| 172 SkScalar paintGamma = deviceProperties.getGamma(); |
| 173 SkScalar deviceGamma = deviceProperties.getGamma(); |
| 174 |
| 175 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamm
a, |
| 176 &width, &height); |
| 177 |
| 178 SkAutoTArray<uint8_t> data((int)size); |
| 179 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data
.get()); |
| 180 |
| 181 // TODO: Update this to use the cache rather than directly creating a te
xture. |
| 182 GrTextureDesc desc; |
| 183 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; |
| 184 desc.fWidth = width; |
| 185 desc.fHeight = height; |
| 186 desc.fConfig = kAlpha_8_GrPixelConfig; |
| 187 |
| 188 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0); |
| 189 if (NULL == *gammaTexture) { |
| 190 return; |
| 191 } |
| 192 |
| 193 context->writeTexturePixels(*gammaTexture, |
| 194 0, 0, width, height, |
| 195 (*gammaTexture)->config(), data.get(), 0, |
| 196 GrContext::kDontFlush_PixelOpsFlag); |
| 197 } |
| 198 } |
| 199 |
| 200 void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& s
kPaint, |
| 201 const char text[], size_t byteLength, |
| 202 SkScalar x, SkScalar y) { |
| 203 SkASSERT(byteLength == 0 || text != NULL); |
| 204 |
| 205 // nothing to draw or can't draw |
| 206 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/ |
| 207 || fSkPaint.getRasterizer()) { |
| 208 return; |
| 209 } |
| 210 |
| 211 this->init(paint, skPaint); |
| 212 |
| 213 SkScalar sizeRatio = fTextRatio; |
| 214 |
| 215 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 216 |
| 217 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); |
| 218 SkGlyphCache* cache = autoCache.getCache(); |
| 219 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
| 220 |
| 221 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); |
| 222 |
| 223 // need to measure first |
| 224 // TODO - generate positions and pre-load cache as well? |
| 225 const char* stop = text + byteLength; |
| 226 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { |
| 227 SkFixed stopX = 0; |
| 228 SkFixed stopY = 0; |
| 229 |
| 230 const char* textPtr = text; |
| 231 while (textPtr < stop) { |
| 232 // don't need x, y here, since all subpixel variants will have the |
| 233 // same advance |
| 234 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0); |
| 235 |
| 236 stopX += glyph.fAdvanceX; |
| 237 stopY += glyph.fAdvanceY; |
| 238 } |
| 239 SkASSERT(textPtr == stop); |
| 240 |
| 241 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio; |
| 242 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio; |
| 243 |
| 244 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { |
| 245 alignX = SkScalarHalf(alignX); |
| 246 alignY = SkScalarHalf(alignY); |
| 247 } |
| 248 |
| 249 x -= alignX; |
| 250 y -= alignY; |
| 251 } |
| 252 |
| 253 SkFixed fx = SkScalarToFixed(x); |
| 254 SkFixed fy = SkScalarToFixed(y); |
| 255 SkFixed fixedScale = SkScalarToFixed(sizeRatio); |
| 256 while (text < stop) { |
| 257 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 258 |
| 259 if (glyph.fWidth) { |
| 260 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), |
| 261 glyph.getSubXFixed(), |
| 262 glyph.getSubYFixed()), |
| 263 fx, |
| 264 fy, |
| 265 fontScaler); |
| 266 } |
| 267 |
| 268 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale); |
| 269 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale); |
| 270 } |
| 271 |
| 272 this->finish(); |
| 273 } |
| 274 |
| 275 void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint
& skPaint, |
| 276 const char text[], size_t byteLengt
h, |
| 277 const SkScalar pos[], int scalarsPe
rPosition, |
| 278 const SkPoint& offset) { |
| 279 |
| 280 SkASSERT(byteLength == 0 || text != NULL); |
| 281 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
| 282 |
| 283 // nothing to draw |
| 284 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/)
{ |
| 285 return; |
| 286 } |
| 287 |
| 288 this->init(paint, skPaint); |
| 289 |
| 290 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 291 |
| 292 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); |
| 293 SkGlyphCache* cache = autoCache.getCache(); |
| 294 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
| 295 |
| 296 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); |
| 297 |
| 298 const char* stop = text + byteLength; |
| 299 |
| 300 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { |
| 301 while (text < stop) { |
| 302 // the last 2 parameters are ignored |
| 303 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 304 |
| 305 if (glyph.fWidth) { |
| 306 SkScalar x = offset.x() + pos[0]; |
| 307 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; |
| 308 |
| 309 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), |
| 310 glyph.getSubXFixed(), |
| 311 glyph.getSubYFixed()), |
| 312 SkScalarToFixed(x), |
| 313 SkScalarToFixed(y), |
| 314 fontScaler); |
| 315 } |
| 316 pos += scalarsPerPosition; |
| 317 } |
| 318 } else { |
| 319 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 :
0; |
| 320 while (text < stop) { |
| 321 // the last 2 parameters are ignored |
| 322 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 323 |
| 324 if (glyph.fWidth) { |
| 325 SkScalar x = offset.x() + pos[0]; |
| 326 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; |
| 327 |
| 328 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), |
| 329 glyph.getSubXFixed(), |
| 330 glyph.getSubYFixed()), |
| 331 SkScalarToFixed(x) - (glyph.fAdvanceX >> align
Shift), |
| 332 SkScalarToFixed(y) - (glyph.fAdvanceY >> align
Shift), |
| 333 fontScaler); |
| 334 } |
| 335 pos += scalarsPerPosition; |
| 336 } |
| 337 } |
| 338 |
| 339 this->finish(); |
| 340 } |
| 341 |
117 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { | 342 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
118 unsigned r = SkColorGetR(c); | 343 unsigned r = SkColorGetR(c); |
119 unsigned g = SkColorGetG(c); | 344 unsigned g = SkColorGetG(c); |
120 unsigned b = SkColorGetB(c); | 345 unsigned b = SkColorGetB(c); |
121 return GrColorPackRGBA(r, g, b, 0xff); | 346 return GrColorPackRGBA(r, g, b, 0xff); |
122 } | 347 } |
123 | 348 |
124 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo
r) { | 349 void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColo
r) { |
125 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_
FilterMode); | 350 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_
FilterMode); |
126 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNon
e_FilterMode); | 351 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNon
e_FilterMode); |
127 | 352 |
128 uint32_t textureUniqueID = fCurrTexture->getUniqueID(); | 353 uint32_t textureUniqueID = fCurrTexture->getUniqueID(); |
129 const SkMatrix& ctm = fContext->getMatrix(); | 354 const SkMatrix& ctm = fContext->getMatrix(); |
130 | 355 |
131 // set up any flags | 356 // set up any flags |
132 uint32_t flags = 0; | 357 uint32_t flags = 0; |
133 flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; | 358 flags |= ctm.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0; |
134 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0; | 359 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0; |
135 flags |= fUseLCDText && ctm.rectStaysRect() ? | 360 flags |= fUseLCDText && ctm.rectStaysRect() ? |
136 kRectToRect_DistanceFieldEffectFlag : 0; | 361 kRectToRect_DistanceFieldEffectFlag : 0; |
137 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.fPixelGeometry); | 362 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.fPixelGeometry); |
138 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; | 363 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0; |
139 | 364 |
140 // see if we need to create a new effect | 365 // see if we need to create a new effect |
141 if (textureUniqueID != fEffectTextureUniqueID || | 366 if (textureUniqueID != fEffectTextureUniqueID || |
142 filteredColor != fEffectColor || | 367 filteredColor != fEffectColor || |
143 flags != fEffectFlags) { | 368 flags != fEffectFlags) { |
144 if (fUseLCDText) { | 369 if (fUseLCDText) { |
145 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); | 370 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); |
146 fCachedGeometryProcessor.reset( | 371 fCachedGeometryProcessor.reset(GrDistanceFieldLCDTextureEffect::Crea
te(fCurrTexture, |
147 GrDistanceFieldLCDTextureEffect::Create(fCurrTexture, | 372
params, |
148 params, | 373
fGammaTexture, |
149 fGammaTexture, | 374
gammaParams, |
150 gammaParams, | 375
colorNoPreMul, |
151 colorNoPreMul, | 376
flags)); |
152 flags)); | |
153 } else { | 377 } else { |
154 #ifdef SK_GAMMA_APPLY_TO_A8 | 378 #ifdef SK_GAMMA_APPLY_TO_A8 |
155 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie
s.getGamma(), | 379 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDevicePropertie
s.getGamma(), |
156 filteredColor); | 380 filteredColor); |
157 fCachedGeometryProcessor.reset( | 381 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
fCurrTexture, |
158 GrDistanceFieldTextureEffect::Create(fCurrTexture, | 382
params, |
159 params, | 383
fGammaTexture, |
160 fGammaTexture, | 384
gammaParams, |
161 gammaParams, | 385
lum/255.f, |
162 lum/255.f, | 386
flags)); |
163 flags)); | |
164 #else | 387 #else |
165 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
fCurrTexture, | 388 fCachedGeometryProcessor.reset(GrDistanceFieldTextureEffect::Create(
fCurrTexture, |
166
params, flags)); | 389
params, flags)); |
167 #endif | 390 #endif |
168 } | 391 } |
169 fEffectTextureUniqueID = textureUniqueID; | 392 fEffectTextureUniqueID = textureUniqueID; |
170 fEffectColor = filteredColor; | 393 fEffectColor = filteredColor; |
171 fEffectFlags = flags; | 394 fEffectFlags = flags; |
172 } | 395 } |
173 | 396 |
174 } | 397 } |
175 | 398 |
176 void GrDistanceFieldTextContext::flushGlyphs() { | 399 void GrDistanceFieldTextContext::appendGlyph(GrGlyph::PackedID packed, |
| 400 SkFixed vx, SkFixed vy, |
| 401 GrFontScaler* scaler) { |
177 if (NULL == fDrawTarget) { | 402 if (NULL == fDrawTarget) { |
178 return; | 403 return; |
179 } | 404 } |
180 | 405 |
181 GrDrawState* drawState = fDrawTarget->drawState(); | |
182 GrDrawState::AutoRestoreEffects are(drawState); | |
183 | |
184 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa
rget()); | |
185 | |
186 if (fCurrVertex > 0) { | |
187 // setup our sampler state for our text texture/atlas | |
188 SkASSERT(SkIsAlign4(fCurrVertex)); | |
189 | |
190 // get our current color | |
191 SkColor filteredColor; | |
192 SkColorFilter* colorFilter = fSkPaint.getColorFilter(); | |
193 if (colorFilter) { | |
194 filteredColor = colorFilter->filterColor(fSkPaint.getColor()); | |
195 } else { | |
196 filteredColor = fSkPaint.getColor(); | |
197 } | |
198 this->setupCoverageEffect(filteredColor); | |
199 | |
200 // Effects could be stored with one of the cache objects (atlas?) | |
201 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); | |
202 | |
203 // Set draw state | |
204 if (fUseLCDText) { | |
205 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); | |
206 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || | |
207 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || | |
208 fPaint.numColorStages()) { | |
209 GrPrintf("LCD Text will not draw correctly.\n"); | |
210 } | |
211 SkASSERT(!drawState->hasColorVertexAttribute()); | |
212 // We don't use the GrPaint's color in this case because it's been p
remultiplied by | |
213 // alpha. Instead we feed in a non-premultiplied color, and multiply
its alpha by | |
214 // the mask texture color. The end result is that we get | |
215 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstCo
lor | |
216 int a = SkColorGetA(fSkPaint.getColor()); | |
217 // paintAlpha | |
218 drawState->setColor(SkColorSetARGB(a, a, a, a)); | |
219 // paintColor | |
220 drawState->setBlendConstant(colorNoPreMul); | |
221 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); | |
222 } else { | |
223 // set back to normal in case we took LCD path previously. | |
224 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlen
dCoeff()); | |
225 // We're using per-vertex color. | |
226 SkASSERT(drawState->hasColorVertexAttribute()); | |
227 } | |
228 int nGlyphs = fCurrVertex / 4; | |
229 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); | |
230 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, | |
231 nGlyphs, | |
232 4, 6, &fVertexBounds); | |
233 fDrawTarget->resetVertexSource(); | |
234 fVertices = NULL; | |
235 fMaxVertices = 0; | |
236 fCurrVertex = 0; | |
237 SkSafeSetNull(fCurrTexture); | |
238 fVertexBounds.setLargestInverted(); | |
239 } | |
240 } | |
241 | |
242 void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed, | |
243 SkFixed vx, SkFixed vy, | |
244 GrFontScaler* scaler) { | |
245 if (NULL == fDrawTarget) { | |
246 return; | |
247 } | |
248 | |
249 if (NULL == fStrike) { | 406 if (NULL == fStrike) { |
250 fStrike = fContext->getFontCache()->getStrike(scaler, true); | 407 fStrike = fContext->getFontCache()->getStrike(scaler, true); |
251 } | 408 } |
252 | 409 |
253 GrGlyph* glyph = fStrike->getGlyph(packed, scaler); | 410 GrGlyph* glyph = fStrike->getGlyph(packed, scaler); |
254 if (NULL == glyph || glyph->fBounds.isEmpty()) { | 411 if (NULL == glyph || glyph->fBounds.isEmpty()) { |
255 return; | 412 return; |
256 } | 413 } |
257 | 414 |
258 SkScalar sx = SkFixedToScalar(vx); | 415 SkScalar sx = SkFixedToScalar(vx); |
259 SkScalar sy = SkFixedToScalar(vy); | 416 SkScalar sy = SkFixedToScalar(vy); |
260 /* | 417 /* |
261 // not valid, need to find a different solution for this | 418 // not valid, need to find a different solution for this |
262 vx += SkIntToFixed(glyph->fBounds.fLeft); | 419 vx += SkIntToFixed(glyph->fBounds.fLeft); |
(...skipping 25 matching lines...) Expand all Loading... |
288 goto HAS_ATLAS; | 445 goto HAS_ATLAS; |
289 } | 446 } |
290 | 447 |
291 if (c_DumpFontCache) { | 448 if (c_DumpFontCache) { |
292 #ifdef SK_DEVELOPER | 449 #ifdef SK_DEVELOPER |
293 fContext->getFontCache()->dump(); | 450 fContext->getFontCache()->dump(); |
294 #endif | 451 #endif |
295 } | 452 } |
296 | 453 |
297 // before we purge the cache, we must flush any accumulated draws | 454 // before we purge the cache, we must flush any accumulated draws |
298 this->flushGlyphs(); | 455 this->flush(); |
299 fContext->flush(); | 456 fContext->flush(); |
300 | 457 |
301 // we should have an unused plot now | 458 // we should have an unused plot now |
302 if (fContext->getFontCache()->freeUnusedPlot(fStrike) && | 459 if (fContext->getFontCache()->freeUnusedPlot(fStrike) && |
303 fStrike->addGlyphToAtlas(glyph, scaler)) { | 460 fStrike->addGlyphToAtlas(glyph, scaler)) { |
304 goto HAS_ATLAS; | 461 goto HAS_ATLAS; |
305 } | 462 } |
306 } | 463 } |
307 | 464 |
308 if (NULL == glyph->fPath) { | 465 if (NULL == glyph->fPath) { |
(...skipping 19 matching lines...) Expand all Loading... |
328 | 485 |
329 HAS_ATLAS: | 486 HAS_ATLAS: |
330 SkASSERT(glyph->fPlot); | 487 SkASSERT(glyph->fPlot); |
331 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); | 488 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); |
332 glyph->fPlot->setDrawToken(drawToken); | 489 glyph->fPlot->setDrawToken(drawToken); |
333 | 490 |
334 GrTexture* texture = glyph->fPlot->texture(); | 491 GrTexture* texture = glyph->fPlot->texture(); |
335 SkASSERT(texture); | 492 SkASSERT(texture); |
336 | 493 |
337 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) { | 494 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) { |
338 this->flushGlyphs(); | 495 this->flush(); |
339 fCurrTexture = texture; | 496 fCurrTexture = texture; |
340 fCurrTexture->ref(); | 497 fCurrTexture->ref(); |
341 } | 498 } |
342 | 499 |
343 bool useColorVerts = !fUseLCDText; | 500 bool useColorVerts = !fUseLCDText; |
344 | 501 |
345 if (NULL == fVertices) { | 502 if (NULL == fVertices) { |
346 // If we need to reserve vertices allow the draw target to suggest | 503 // If we need to reserve vertices allow the draw target to suggest |
347 // a number of verts to reserve and whether to perform a flush. | 504 // a number of verts to reserve and whether to perform a flush. |
348 fMaxVertices = kMinRequestedVerts; | 505 fMaxVertices = kMinRequestedVerts; |
349 if (useColorVerts) { | 506 if (useColorVerts) { |
350 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttri
bs>( | 507 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttri
bs>( |
351 SK_ARRAY_COUNT(gTextVertexWi
thColorAttribs), | 508 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSize); |
352 kTextVAColorSize); | |
353 } else { | 509 } else { |
354 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( | 510 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( |
355 SK_ARRAY_COUNT(gTextVertexAt
tribs), | 511 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize); |
356 kTextVASize); | |
357 } | 512 } |
358 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL); | 513 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL); |
359 if (flush) { | 514 if (flush) { |
360 this->flushGlyphs(); | 515 this->flush(); |
361 fContext->flush(); | 516 fContext->flush(); |
362 if (useColorVerts) { | 517 if (useColorVerts) { |
363 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorA
ttribs>( | 518 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorA
ttribs>( |
364 SK_ARRAY_COUNT(gTextVertexWi
thColorAttribs), | 519 SK_ARRAY_COUNT(gTextVertexWithColorAttribs), kTextVAColorSiz
e); |
365 kTextVAColorSize); | |
366 } else { | 520 } else { |
367 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( | 521 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( |
368 SK_ARRAY_COUNT(gTextVertexAt
tribs), | 522 SK_ARRAY_COUNT(gTextVertexAttribs), kTextVASize); |
369 kTextVASize); | |
370 } | 523 } |
371 } | 524 } |
372 fMaxVertices = kDefaultRequestedVerts; | 525 fMaxVertices = kDefaultRequestedVerts; |
373 // ignore return, no point in flushing again. | 526 // ignore return, no point in flushing again. |
374 fDrawTarget->geometryHints(&fMaxVertices, NULL); | 527 fDrawTarget->geometryHints(&fMaxVertices, NULL); |
375 | 528 |
376 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads(); | 529 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads(); |
377 if (fMaxVertices < kMinRequestedVerts) { | 530 if (fMaxVertices < kMinRequestedVerts) { |
378 fMaxVertices = kDefaultRequestedVerts; | 531 fMaxVertices = kDefaultRequestedVerts; |
379 } else if (fMaxVertices > maxQuadVertices) { | 532 } else if (fMaxVertices > maxQuadVertices) { |
380 // don't exceed the limit of the index buffer | 533 // don't exceed the limit of the index buffer |
381 fMaxVertices = maxQuadVertices; | 534 fMaxVertices = maxQuadVertices; |
382 } | 535 } |
383 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices, | 536 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices, |
384 0, | 537 0, |
385 &fVertices, | 538 &fVertices, |
386 NULL); | 539 NULL); |
387 GrAlwaysAssert(success); | 540 GrAlwaysAssert(success); |
388 } | 541 } |
389 | 542 |
390 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); | 543 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); |
391 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); | 544 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); |
392 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldIn
set); | 545 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldIn
set); |
393 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceField
Inset); | 546 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceField
Inset); |
394 | 547 |
395 SkScalar scale = fTextRatio; | 548 SkScalar scale = fTextRatio; |
396 dx *= scale; | 549 dx *= scale; |
397 dy *= scale; | 550 dy *= scale; |
398 sx += dx; | 551 sx += dx; |
399 sy += dy; | 552 sy += dy; |
400 width *= scale; | 553 width *= scale; |
401 height *= scale; | 554 height *= scale; |
402 | 555 |
403 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset); | 556 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset); |
404 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset); | 557 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset); |
405 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset); | 558 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset); |
406 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset)
; | 559 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset)
; |
407 | 560 |
408 SkRect r; | 561 SkRect r; |
409 r.fLeft = sx; | 562 r.fLeft = sx; |
410 r.fTop = sy; | 563 r.fTop = sy; |
411 r.fRight = sx + width; | 564 r.fRight = sx + width; |
412 r.fBottom = sy + height; | 565 r.fBottom = sy + height; |
413 | 566 |
414 fVertexBounds.joinNonEmptyArg(r); | 567 fVertexBounds.joinNonEmptyArg(r); |
415 | 568 |
416 size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint)) | 569 size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint)) |
417 : (2 * sizeof(SkPoint) + sizeof(GrColor)); | 570 : (2 * sizeof(SkPoint) + sizeof(GrColor)); |
418 | 571 |
419 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride()); | 572 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride()); |
420 | 573 |
421 SkPoint* positions = reinterpret_cast<SkPoint*>( | 574 SkPoint* positions = reinterpret_cast<SkPoint*>( |
422 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex); | 575 reinterpret_cast<intptr_t>(fVertices) + vertSize
* fCurrVertex); |
423 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize); | 576 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize); |
424 | 577 |
425 // The texture coords are last in both the with and without color vertex lay
outs. | 578 // The texture coords are last in both the with and without color vertex lay
outs. |
426 SkPoint* textureCoords = reinterpret_cast<SkPoint*>( | 579 SkPoint* textureCoords = reinterpret_cast<SkPoint*>( |
427 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint))
; | 580 reinterpret_cast<intptr_t>(positions) + vertSize
- sizeof(SkPoint)); |
428 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFix
edX(tx)), | 581 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFix
edX(tx)), |
429 SkFixedToFloat(texture->texturePriv().normalizeFix
edY(ty)), | 582 SkFixedToFloat(texture->texturePriv().normalizeFix
edY(ty)), |
430 SkFixedToFloat(texture->texturePriv().normalizeFix
edX(tx + tw)), | 583 SkFixedToFloat(texture->texturePriv().normalizeFix
edX(tx + tw)), |
431 SkFixedToFloat(texture->texturePriv().normalizeFix
edY(ty + th)), | 584 SkFixedToFloat(texture->texturePriv().normalizeFix
edY(ty + th)), |
432 vertSize); | 585 vertSize); |
433 if (useColorVerts) { | 586 if (useColorVerts) { |
434 if (0xFF == GrColorUnpackA(fPaint.getColor())) { | 587 if (0xFF == GrColorUnpackA(fPaint.getColor())) { |
435 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaqu
e_Hint, true); | 588 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaqu
e_Hint, true); |
436 } | 589 } |
437 // color comes after position. | 590 // color comes after position. |
438 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1); | 591 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1); |
439 for (int i = 0; i < 4; ++i) { | 592 for (int i = 0; i < 4; ++i) { |
440 *colors = fPaint.getColor(); | 593 *colors = fPaint.getColor(); |
441 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(color
s) + vertSize); | 594 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(color
s) + vertSize); |
442 } | 595 } |
443 } | 596 } |
444 | 597 |
445 fCurrVertex += 4; | 598 fCurrVertex += 4; |
446 } | 599 } |
447 | 600 |
448 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint
& skPaint) { | 601 void GrDistanceFieldTextContext::flush() { |
449 GrTextContext::init(paint, skPaint); | 602 if (NULL == fDrawTarget) { |
450 | 603 return; |
451 fStrike = NULL; | |
452 | |
453 const SkMatrix& ctm = fContext->getMatrix(); | |
454 | |
455 // getMaxScale doesn't support perspective, so neither do we at the moment | |
456 SkASSERT(!ctm.hasPerspective()); | |
457 SkScalar maxScale = ctm.getMaxScale(); | |
458 SkScalar textSize = fSkPaint.getTextSize(); | |
459 SkScalar scaledTextSize = textSize; | |
460 // if we have non-unity scale, we need to choose our base text size | |
461 // based on the SkPaint's text size multiplied by the max scale factor | |
462 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? | |
463 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { | |
464 scaledTextSize *= maxScale; | |
465 } | 604 } |
466 | 605 |
467 fCurrVertex = 0; | 606 GrDrawState* drawState = fDrawTarget->drawState(); |
| 607 GrDrawState::AutoRestoreEffects are(drawState); |
468 | 608 |
469 fVertices = NULL; | 609 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTa
rget()); |
470 | 610 |
471 if (scaledTextSize <= kSmallDFFontLimit) { | 611 if (fCurrVertex > 0) { |
472 fTextRatio = textSize / kSmallDFFontSize; | 612 // setup our sampler state for our text texture/atlas |
473 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize)); | 613 SkASSERT(SkIsAlign4(fCurrVertex)); |
474 } else if (scaledTextSize <= kMediumDFFontLimit) { | 614 |
475 fTextRatio = textSize / kMediumDFFontSize; | 615 // get our current color |
476 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize)); | 616 SkColor filteredColor; |
477 } else { | 617 SkColorFilter* colorFilter = fSkPaint.getColorFilter(); |
478 fTextRatio = textSize / kLargeDFFontSize; | 618 if (colorFilter) { |
479 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize)); | 619 filteredColor = colorFilter->filterColor(fSkPaint.getColor()); |
| 620 } else { |
| 621 filteredColor = fSkPaint.getColor(); |
| 622 } |
| 623 this->setupCoverageEffect(filteredColor); |
| 624 |
| 625 // Effects could be stored with one of the cache objects (atlas?) |
| 626 drawState->setGeometryProcessor(fCachedGeometryProcessor.get()); |
| 627 |
| 628 // Set draw state |
| 629 if (fUseLCDText) { |
| 630 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); |
| 631 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || |
| 632 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || |
| 633 fPaint.numColorStages()) { |
| 634 GrPrintf("LCD Text will not draw correctly.\n"); |
| 635 } |
| 636 SkASSERT(!drawState->hasColorVertexAttribute()); |
| 637 // We don't use the GrPaint's color in this case because it's been p
remultiplied by |
| 638 // alpha. Instead we feed in a non-premultiplied color, and multiply
its alpha by |
| 639 // the mask texture color. The end result is that we get |
| 640 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstCo
lor |
| 641 int a = SkColorGetA(fSkPaint.getColor()); |
| 642 // paintAlpha |
| 643 drawState->setColor(SkColorSetARGB(a, a, a, a)); |
| 644 // paintColor |
| 645 drawState->setBlendConstant(colorNoPreMul); |
| 646 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); |
| 647 } else { |
| 648 // set back to normal in case we took LCD path previously. |
| 649 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlen
dCoeff()); |
| 650 // We're using per-vertex color. |
| 651 SkASSERT(drawState->hasColorVertexAttribute()); |
| 652 } |
| 653 int nGlyphs = fCurrVertex / 4; |
| 654 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); |
| 655 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, |
| 656 nGlyphs, |
| 657 4, 6, &fVertexBounds); |
| 658 fDrawTarget->resetVertexSource(); |
| 659 fVertices = NULL; |
| 660 fMaxVertices = 0; |
| 661 fCurrVertex = 0; |
| 662 SkSafeSetNull(fCurrTexture); |
| 663 fVertexBounds.setLargestInverted(); |
480 } | 664 } |
481 | |
482 fUseLCDText = fSkPaint.isLCDRenderText(); | |
483 | |
484 fSkPaint.setLCDRenderText(false); | |
485 fSkPaint.setAutohinted(false); | |
486 fSkPaint.setHinting(SkPaint::kNormal_Hinting); | |
487 fSkPaint.setSubpixelText(true); | |
488 | |
489 } | 665 } |
490 | 666 |
491 inline void GrDistanceFieldTextContext::finish() { | 667 inline void GrDistanceFieldTextContext::finish() { |
492 this->flushGlyphs(); | 668 this->flush(); |
493 | 669 |
494 GrTextContext::finish(); | 670 GrTextContext::finish(); |
495 } | 671 } |
496 | 672 |
497 static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache, | |
498 const SkDeviceProperties& deviceProperties, | |
499 GrTexture** gammaTexture) { | |
500 if (NULL == *gammaTexture) { | |
501 int width, height; | |
502 size_t size; | |
503 | |
504 #ifdef SK_GAMMA_CONTRAST | |
505 SkScalar contrast = SK_GAMMA_CONTRAST; | |
506 #else | |
507 SkScalar contrast = 0.5f; | |
508 #endif | |
509 SkScalar paintGamma = deviceProperties.getGamma(); | |
510 SkScalar deviceGamma = deviceProperties.getGamma(); | |
511 | |
512 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamm
a, | |
513 &width, &height); | |
514 | |
515 SkAutoTArray<uint8_t> data((int)size); | |
516 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data
.get()); | |
517 | |
518 // TODO: Update this to use the cache rather than directly creating a te
xture. | |
519 GrTextureDesc desc; | |
520 desc.fFlags = kDynamicUpdate_GrTextureFlagBit; | |
521 desc.fWidth = width; | |
522 desc.fHeight = height; | |
523 desc.fConfig = kAlpha_8_GrPixelConfig; | |
524 | |
525 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0); | |
526 if (NULL == *gammaTexture) { | |
527 return; | |
528 } | |
529 | |
530 context->writeTexturePixels(*gammaTexture, | |
531 0, 0, width, height, | |
532 (*gammaTexture)->config(), data.get(), 0, | |
533 GrContext::kDontFlush_PixelOpsFlag); | |
534 } | |
535 } | |
536 | |
537 void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& s
kPaint, | |
538 const char text[], size_t byteLength, | |
539 SkScalar x, SkScalar y) { | |
540 SkASSERT(byteLength == 0 || text != NULL); | |
541 | |
542 // nothing to draw or can't draw | |
543 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/ | |
544 || fSkPaint.getRasterizer()) { | |
545 return; | |
546 } | |
547 | |
548 this->init(paint, skPaint); | |
549 | |
550 SkScalar sizeRatio = fTextRatio; | |
551 | |
552 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | |
553 | |
554 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); | |
555 SkGlyphCache* cache = autoCache.getCache(); | |
556 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
557 | |
558 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); | |
559 | |
560 // need to measure first | |
561 // TODO - generate positions and pre-load cache as well? | |
562 const char* stop = text + byteLength; | |
563 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | |
564 SkFixed stopX = 0; | |
565 SkFixed stopY = 0; | |
566 | |
567 const char* textPtr = text; | |
568 while (textPtr < stop) { | |
569 // don't need x, y here, since all subpixel variants will have the | |
570 // same advance | |
571 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0); | |
572 | |
573 stopX += glyph.fAdvanceX; | |
574 stopY += glyph.fAdvanceY; | |
575 } | |
576 SkASSERT(textPtr == stop); | |
577 | |
578 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio; | |
579 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio; | |
580 | |
581 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { | |
582 alignX = SkScalarHalf(alignX); | |
583 alignY = SkScalarHalf(alignY); | |
584 } | |
585 | |
586 x -= alignX; | |
587 y -= alignY; | |
588 } | |
589 | |
590 SkFixed fx = SkScalarToFixed(x); | |
591 SkFixed fy = SkScalarToFixed(y); | |
592 SkFixed fixedScale = SkScalarToFixed(sizeRatio); | |
593 while (text < stop) { | |
594 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
595 | |
596 if (glyph.fWidth) { | |
597 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
598 glyph.getSubXFixed(), | |
599 glyph.getSubYFixed()), | |
600 fx, | |
601 fy, | |
602 fontScaler); | |
603 } | |
604 | |
605 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale); | |
606 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale); | |
607 } | |
608 | |
609 this->finish(); | |
610 } | |
611 | |
612 void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint
& skPaint, | |
613 const char text[], size_t byteLengt
h, | |
614 const SkScalar pos[], int scalarsPe
rPosition, | |
615 const SkPoint& offset) { | |
616 | |
617 SkASSERT(byteLength == 0 || text != NULL); | |
618 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | |
619 | |
620 // nothing to draw | |
621 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/)
{ | |
622 return; | |
623 } | |
624 | |
625 this->init(paint, skPaint); | |
626 | |
627 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | |
628 | |
629 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL); | |
630 SkGlyphCache* cache = autoCache.getCache(); | |
631 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
632 | |
633 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture); | |
634 | |
635 const char* stop = text + byteLength; | |
636 | |
637 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | |
638 while (text < stop) { | |
639 // the last 2 parameters are ignored | |
640 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
641 | |
642 if (glyph.fWidth) { | |
643 SkScalar x = offset.x() + pos[0]; | |
644 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
645 | |
646 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
647 glyph.getSubXFixed(), | |
648 glyph.getSubYFixed()), | |
649 SkScalarToFixed(x), | |
650 SkScalarToFixed(y), | |
651 fontScaler); | |
652 } | |
653 pos += scalarsPerPosition; | |
654 } | |
655 } else { | |
656 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 :
0; | |
657 while (text < stop) { | |
658 // the last 2 parameters are ignored | |
659 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
660 | |
661 if (glyph.fWidth) { | |
662 SkScalar x = offset.x() + pos[0]; | |
663 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
664 | |
665 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), | |
666 glyph.getSubXFixed(), | |
667 glyph.getSubYFixed()), | |
668 SkScalarToFixed(x) - (glyph.fAdvanceX >> a
lignShift), | |
669 SkScalarToFixed(y) - (glyph.fAdvanceY >> a
lignShift), | |
670 fontScaler); | |
671 } | |
672 pos += scalarsPerPosition; | |
673 } | |
674 } | |
675 | |
676 this->finish(); | |
677 } | |
OLD | NEW |