| 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 "GrDrawContext.h" | 9 #include "GrDrawContext.h" |
| 10 #include "GrDrawTarget.h" | 10 #include "GrDrawTarget.h" |
| (...skipping 16 matching lines...) Expand all Loading... |
| 27 #include "SkGpuDevice.h" | 27 #include "SkGpuDevice.h" |
| 28 #include "SkGrPriv.h" | 28 #include "SkGrPriv.h" |
| 29 #include "SkPath.h" | 29 #include "SkPath.h" |
| 30 #include "SkRTConf.h" | 30 #include "SkRTConf.h" |
| 31 #include "SkStrokeRec.h" | 31 #include "SkStrokeRec.h" |
| 32 #include "SkTextBlob.h" | 32 #include "SkTextBlob.h" |
| 33 #include "SkTextMapStateProc.h" | 33 #include "SkTextMapStateProc.h" |
| 34 | 34 |
| 35 #include "batches/GrAtlasTextBatch.h" | 35 #include "batches/GrAtlasTextBatch.h" |
| 36 | 36 |
| 37 namespace { | |
| 38 static const int kMinDFFontSize = 18; | |
| 39 static const int kSmallDFFontSize = 32; | |
| 40 static const int kSmallDFFontLimit = 32; | |
| 41 static const int kMediumDFFontSize = 72; | |
| 42 static const int kMediumDFFontLimit = 72; | |
| 43 static const int kLargeDFFontSize = 162; | |
| 44 #ifdef SK_BUILD_FOR_ANDROID | |
| 45 static const int kLargeDFFontLimit = 384; | |
| 46 #else | |
| 47 static const int kLargeDFFontLimit = 2 * kLargeDFFontSize; | |
| 48 #endif | |
| 49 }; | |
| 50 | |
| 51 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) | 37 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, const SkSurfaceProps&
surfaceProps) |
| 52 : INHERITED(context, surfaceProps) | 38 : INHERITED(context, surfaceProps) |
| 53 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { | 39 , fDistanceAdjustTable(new GrDistanceFieldAdjustTable) { |
| 54 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 40 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
| 55 // vertexStride | 41 // vertexStride |
| 56 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && | 42 static_assert(GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kColorTex
tVASize && |
| 57 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, | 43 GrAtlasTextBlob::kGrayTextVASize >= GrAtlasTextBlob::kLCDTextV
ASize, |
| 58 "vertex_attribute_changed"); | 44 "vertex_attribute_changed"); |
| 59 fCurrStrike = nullptr; | 45 fCurrStrike = nullptr; |
| 60 fCache = context->getTextBlobCache(); | 46 fCache = context->getTextBlobCache(); |
| 61 } | 47 } |
| 62 | 48 |
| 63 | 49 |
| 64 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 50 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
| 65 const SkSurfaceProps& surfaceProp
s) { | 51 const SkSurfaceProps& surfaceProp
s) { |
| 66 return new GrAtlasTextContext(context, surfaceProps); | 52 return new GrAtlasTextContext(context, surfaceProps); |
| 67 } | 53 } |
| 68 | 54 |
| 69 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { | 55 bool GrAtlasTextContext::canDraw(const SkPaint& skPaint, const SkMatrix& viewMat
rix) { |
| 70 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || | 56 return GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfacePro
ps, |
| 57 *fContext->caps()->shaderCaps())
|| |
| 71 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 58 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
| 72 } | 59 } |
| 73 | 60 |
| 74 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { | 61 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { |
| 75 GrColor canonicalColor = paint.computeLuminanceColor(); | 62 GrColor canonicalColor = paint.computeLuminanceColor(); |
| 76 if (lcd) { | 63 if (lcd) { |
| 77 // This is the correct computation, but there are tons of cases where LC
D can be overridden. | 64 // This is the correct computation, but there are tons of cases where LC
D can be overridden. |
| 78 // For now we just regenerate if any run in a textblob has LCD. | 65 // For now we just regenerate if any run in a textblob has LCD. |
| 79 // TODO figure out where all of these overrides are and see if we can in
corporate that logic | 66 // TODO figure out where all of these overrides are and see if we can in
corporate that logic |
| 80 // at a higher level *OR* use sRGB | 67 // at a higher level *OR* use sRGB |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBlob::kGrayTextV
ASize)); | 179 cacheBlob.reset(fCache->createBlob(blob, GrAtlasTextBlob::kGrayTextV
ASize)); |
| 193 } | 180 } |
| 194 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, | 181 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, |
| 195 blob, x, y, drawFilter); | 182 blob, x, y, drawFilter); |
| 196 } | 183 } |
| 197 | 184 |
| 198 cacheBlob->flushCached(fContext, dc, blob, fSurfaceProps, fDistanceAdjustTab
le, skPaint, | 185 cacheBlob->flushCached(fContext, dc, blob, fSurfaceProps, fDistanceAdjustTab
le, skPaint, |
| 199 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); | 186 grPaint, drawFilter, clip, viewMatrix, clipBounds, x,
y, transX, transY); |
| 200 } | 187 } |
| 201 | 188 |
| 202 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, | |
| 203 const SkMatrix& viewMatr
ix) { | |
| 204 // TODO: support perspective (need getMaxScale replacement) | |
| 205 if (viewMatrix.hasPerspective()) { | |
| 206 return false; | |
| 207 } | |
| 208 | |
| 209 SkScalar maxScale = viewMatrix.getMaxScale(); | |
| 210 SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); | |
| 211 // Hinted text looks far better at small resolutions | |
| 212 // Scaling up beyond 2x yields undesireable artifacts | |
| 213 if (scaledTextSize < kMinDFFontSize || scaledTextSize > kLargeDFFontLimit) { | |
| 214 return false; | |
| 215 } | |
| 216 | |
| 217 bool useDFT = fSurfaceProps.isUseDeviceIndependentFonts(); | |
| 218 #if SK_FORCE_DISTANCE_FIELD_TEXT | |
| 219 useDFT = true; | |
| 220 #endif | |
| 221 | |
| 222 if (!useDFT && scaledTextSize < kLargeDFFontSize) { | |
| 223 return false; | |
| 224 } | |
| 225 | |
| 226 // rasterizers and mask filters modify alpha, which doesn't | |
| 227 // translate well to distance | |
| 228 if (skPaint.getRasterizer() || skPaint.getMaskFilter() || | |
| 229 !fContext->caps()->shaderCaps()->shaderDerivativeSupport()) { | |
| 230 return false; | |
| 231 } | |
| 232 | |
| 233 // TODO: add some stroking support | |
| 234 if (skPaint.getStyle() != SkPaint::kFill_Style) { | |
| 235 return false; | |
| 236 } | |
| 237 | |
| 238 return true; | |
| 239 } | |
| 240 | |
| 241 void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, | 189 void GrAtlasTextContext::regenerateTextBlob(GrAtlasTextBlob* cacheBlob, |
| 242 const SkPaint& skPaint, GrColor colo
r, | 190 const SkPaint& skPaint, GrColor colo
r, |
| 243 const SkMatrix& viewMatrix, | 191 const SkMatrix& viewMatrix, |
| 244 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 192 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
| 245 SkDrawFilter* drawFilter) { | 193 SkDrawFilter* drawFilter) { |
| 246 // The color here is the GrPaint color, and it is used to determine whether
we | 194 // The color here is the GrPaint color, and it is used to determine whether
we |
| 247 // have to regenerate LCD text blobs. | 195 // have to regenerate LCD text blobs. |
| 248 // We use this color vs the SkPaint color because it has the colorfilter app
lied. | 196 // We use this color vs the SkPaint color because it has the colorfilter app
lied. |
| 249 cacheBlob->fPaintColor = color; | 197 cacheBlob->fPaintColor = color; |
| 250 cacheBlob->fViewMatrix = viewMatrix; | 198 cacheBlob->fViewMatrix = viewMatrix; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 265 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { | 213 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
| 266 // A false return from filter() means we should abort the current dr
aw. | 214 // A false return from filter() means we should abort the current dr
aw. |
| 267 runPaint = skPaint; | 215 runPaint = skPaint; |
| 268 continue; | 216 continue; |
| 269 } | 217 } |
| 270 | 218 |
| 271 runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); | 219 runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); |
| 272 | 220 |
| 273 cacheBlob->push_back_run(run); | 221 cacheBlob->push_back_run(run); |
| 274 | 222 |
| 275 if (this->canDrawAsDistanceFields(runPaint, viewMatrix)) { | 223 if (GrTextUtils::CanDrawAsDistanceFields(runPaint, viewMatrix, fSurfaceP
rops, |
| 224 *fContext->caps()->shaderCaps()
)) { |
| 276 switch (it.positioning()) { | 225 switch (it.positioning()) { |
| 277 case SkTextBlob::kDefault_Positioning: { | 226 case SkTextBlob::kDefault_Positioning: { |
| 278 this->internalDrawDFText(cacheBlob, run, runPaint, color, vi
ewMatrix, | 227 GrTextUtils::DrawDFText(cacheBlob, run, fContext->getBatchFo
ntCache(), |
| 279 (const char *)it.glyphs(), textLen, | 228 fSurfaceProps, runPaint, color, view
Matrix, |
| 280 x + offset.x(), y + offset.y()); | 229 (const char *)it.glyphs(), textLen, |
| 230 x + offset.x(), y + offset.y()); |
| 281 break; | 231 break; |
| 282 } | 232 } |
| 283 case SkTextBlob::kHorizontal_Positioning: { | 233 case SkTextBlob::kHorizontal_Positioning: { |
| 284 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); | 234 SkPoint dfOffset = SkPoint::Make(x, y + offset.y()); |
| 285 this->internalDrawDFPosText(cacheBlob, run, runPaint, color,
viewMatrix, | 235 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBatc
hFontCache(), |
| 286 (const char*)it.glyphs(), textLe
n, it.pos(), | 236 fSurfaceProps, runPaint, color, v
iewMatrix, |
| 287 1, dfOffset); | 237 (const char*)it.glyphs(), textLen
, it.pos(), |
| 238 1, dfOffset); |
| 288 break; | 239 break; |
| 289 } | 240 } |
| 290 case SkTextBlob::kFull_Positioning: { | 241 case SkTextBlob::kFull_Positioning: { |
| 291 SkPoint dfOffset = SkPoint::Make(x, y); | 242 SkPoint dfOffset = SkPoint::Make(x, y); |
| 292 this->internalDrawDFPosText(cacheBlob, run, runPaint, color,
viewMatrix, | 243 GrTextUtils::DrawDFPosText(cacheBlob, run, fContext->getBat
chFontCache(), |
| 293 (const char*)it.glyphs(), textLe
n, it.pos(), | 244 fSurfaceProps, runPaint, color, v
iewMatrix, |
| 294 2, dfOffset); | 245 (const char*)it.glyphs(), textLen
, it.pos(), |
| 246 2, dfOffset); |
| 295 break; | 247 break; |
| 296 } | 248 } |
| 297 } | 249 } |
| 298 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { | 250 } else if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
| 299 cacheBlob->fRuns[run].fDrawAsPaths = true; | 251 cacheBlob->fRuns[run].fDrawAsPaths = true; |
| 300 } else { | 252 } else { |
| 301 switch (it.positioning()) { | 253 switch (it.positioning()) { |
| 302 case SkTextBlob::kDefault_Positioning: | 254 case SkTextBlob::kDefault_Positioning: |
| 303 GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchF
ontCache(), | 255 GrTextUtils::DrawBmpText(cacheBlob, run, fContext->getBatchF
ontCache(), |
| 304 fSurfaceProps, runPaint, color, vie
wMatrix, | 256 fSurfaceProps, runPaint, color, vie
wMatrix, |
| (...skipping 15 matching lines...) Expand all Loading... |
| 320 } | 272 } |
| 321 } | 273 } |
| 322 | 274 |
| 323 if (drawFilter) { | 275 if (drawFilter) { |
| 324 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 276 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
| 325 runPaint = skPaint; | 277 runPaint = skPaint; |
| 326 } | 278 } |
| 327 } | 279 } |
| 328 } | 280 } |
| 329 | 281 |
| 330 inline void GrAtlasTextContext::initDistanceFieldPaint(GrAtlasTextBlob* blob, | |
| 331 SkPaint* skPaint, | |
| 332 SkScalar* textRatio, | |
| 333 const SkMatrix& viewMatri
x) { | |
| 334 // getMaxScale doesn't support perspective, so neither do we at the moment | |
| 335 SkASSERT(!viewMatrix.hasPerspective()); | |
| 336 SkScalar maxScale = viewMatrix.getMaxScale(); | |
| 337 SkScalar textSize = skPaint->getTextSize(); | |
| 338 SkScalar scaledTextSize = textSize; | |
| 339 // if we have non-unity scale, we need to choose our base text size | |
| 340 // based on the SkPaint's text size multiplied by the max scale factor | |
| 341 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? | |
| 342 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { | |
| 343 scaledTextSize *= maxScale; | |
| 344 } | |
| 345 | |
| 346 // We have three sizes of distance field text, and within each size 'bucket'
there is a floor | |
| 347 // and ceiling. A scale outside of this range would require regenerating th
e distance fields | |
| 348 SkScalar dfMaskScaleFloor; | |
| 349 SkScalar dfMaskScaleCeil; | |
| 350 if (scaledTextSize <= kSmallDFFontLimit) { | |
| 351 dfMaskScaleFloor = kMinDFFontSize; | |
| 352 dfMaskScaleCeil = kSmallDFFontLimit; | |
| 353 *textRatio = textSize / kSmallDFFontSize; | |
| 354 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); | |
| 355 } else if (scaledTextSize <= kMediumDFFontLimit) { | |
| 356 dfMaskScaleFloor = kSmallDFFontLimit; | |
| 357 dfMaskScaleCeil = kMediumDFFontLimit; | |
| 358 *textRatio = textSize / kMediumDFFontSize; | |
| 359 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); | |
| 360 } else { | |
| 361 dfMaskScaleFloor = kMediumDFFontLimit; | |
| 362 dfMaskScaleCeil = kLargeDFFontLimit; | |
| 363 *textRatio = textSize / kLargeDFFontSize; | |
| 364 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); | |
| 365 } | |
| 366 | |
| 367 // Because there can be multiple runs in the blob, we want the overall maxMi
nScale, and | |
| 368 // minMaxScale to make regeneration decisions. Specifically, we want the ma
ximum minimum scale | |
| 369 // we can tolerate before we'd drop to a lower mip size, and the minimum max
imum scale we can | |
| 370 // tolerate before we'd have to move to a large mip size. When we actually
test these values | |
| 371 // we look at the delta in scale between the new viewmatrix and the old view
matrix, and test | |
| 372 // against these values to decide if we can reuse or not(ie, will a given sc
ale change our mip | |
| 373 // level) | |
| 374 SkASSERT(dfMaskScaleFloor <= scaledTextSize && scaledTextSize <= dfMaskScale
Ceil); | |
| 375 blob->fMaxMinScale = SkMaxScalar(dfMaskScaleFloor / scaledTextSize, blob->fM
axMinScale); | |
| 376 blob->fMinMaxScale = SkMinScalar(dfMaskScaleCeil / scaledTextSize, blob->fMi
nMaxScale); | |
| 377 | |
| 378 skPaint->setLCDRenderText(false); | |
| 379 skPaint->setAutohinted(false); | |
| 380 skPaint->setHinting(SkPaint::kNormal_Hinting); | |
| 381 skPaint->setSubpixelText(true); | |
| 382 } | |
| 383 | |
| 384 inline void GrAtlasTextContext::fallbackDrawPosText(GrAtlasTextBlob* blob, | |
| 385 int runIndex, | |
| 386 GrColor color, | |
| 387 const SkPaint& skPaint, | |
| 388 const SkMatrix& viewMatrix, | |
| 389 const SkTDArray<char>& fallb
ackTxt, | |
| 390 const SkTDArray<SkScalar>& f
allbackPos, | |
| 391 int scalarsPerPosition, | |
| 392 const SkPoint& offset) { | |
| 393 SkASSERT(fallbackTxt.count()); | |
| 394 Run& run = blob->fRuns[runIndex]; | |
| 395 // Push back a new subrun to fill and set the override descriptor | |
| 396 run.push_back(); | |
| 397 run.fOverrideDescriptor.reset(new SkAutoDescriptor); | |
| 398 GrTextUtils::DrawBmpPosText(blob, runIndex, fContext->getBatchFontCache(), f
SurfaceProps, | |
| 399 skPaint, color, viewMatrix, fallbackTxt.begin(),
fallbackTxt.count(), | |
| 400 fallbackPos.begin(), scalarsPerPosition, offset)
; | |
| 401 } | |
| 402 | |
| 403 inline GrAtlasTextBlob* | 282 inline GrAtlasTextBlob* |
| 404 GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, const SkPaint& skPa
int, | 283 GrAtlasTextContext::createDrawTextBlob(const GrPaint& paint, const SkPaint& skPa
int, |
| 405 const SkMatrix& viewMatrix, | 284 const SkMatrix& viewMatrix, |
| 406 const char text[], size_t byteLength, | 285 const char text[], size_t byteLength, |
| 407 SkScalar x, SkScalar y) { | 286 SkScalar x, SkScalar y) { |
| 408 int glyphCount = skPaint.countText(text, byteLength); | 287 int glyphCount = skPaint.countText(text, byteLength); |
| 409 | 288 |
| 410 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); | 289 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); |
| 411 blob->fViewMatrix = viewMatrix; | 290 blob->fViewMatrix = viewMatrix; |
| 412 | 291 |
| 413 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { | 292 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfaceProps, |
| 414 this->internalDrawDFText(blob, 0, skPaint, paint.getColor(), viewMatrix,
text, | 293 *fContext->caps()->shaderCaps())) { |
| 415 byteLength, x, y); | 294 GrTextUtils::DrawDFText(blob, 0, fContext->getBatchFontCache(), fSurface
Props, |
| 295 skPaint, paint.getColor(), viewMatrix, text, |
| 296 byteLength, x, y); |
| 416 } else { | 297 } else { |
| 417 GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), fSurfac
eProps, skPaint, | 298 GrTextUtils::DrawBmpText(blob, 0, fContext->getBatchFontCache(), fSurfac
eProps, skPaint, |
| 418 paint.getColor(), viewMatrix, text, byteLength,
x, y); | 299 paint.getColor(), viewMatrix, text, byteLength,
x, y); |
| 419 } | 300 } |
| 420 return blob; | 301 return blob; |
| 421 } | 302 } |
| 422 | 303 |
| 423 inline GrAtlasTextBlob* | 304 inline GrAtlasTextBlob* |
| 424 GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& s
kPaint, | 305 GrAtlasTextContext::createDrawPosTextBlob(const GrPaint& paint, const SkPaint& s
kPaint, |
| 425 const SkMatrix& viewMatrix, | 306 const SkMatrix& viewMatrix, |
| 426 const char text[], size_t byteLength, | 307 const char text[], size_t byteLength, |
| 427 const SkScalar pos[], int scalarsPerPo
sition, | 308 const SkScalar pos[], int scalarsPerPo
sition, |
| 428 const SkPoint& offset) { | 309 const SkPoint& offset) { |
| 429 int glyphCount = skPaint.countText(text, byteLength); | 310 int glyphCount = skPaint.countText(text, byteLength); |
| 430 | 311 |
| 431 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); | 312 GrAtlasTextBlob* blob = fCache->createBlob(glyphCount, 1, GrAtlasTextBlob::k
GrayTextVASize); |
| 432 blob->fViewMatrix = viewMatrix; | 313 blob->fViewMatrix = viewMatrix; |
| 433 | 314 |
| 434 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { | 315 if (GrTextUtils::CanDrawAsDistanceFields(skPaint, viewMatrix, fSurfaceProps, |
| 435 this->internalDrawDFPosText(blob, 0, skPaint, paint.getColor(), viewMatr
ix, text, | 316 *fContext->caps()->shaderCaps())) { |
| 436 byteLength, pos, scalarsPerPosition, offset)
; | 317 GrTextUtils::DrawDFPosText(blob, 0, fContext->getBatchFontCache(), fSurf
aceProps, |
| 318 skPaint, paint.getColor(), viewMatrix, text, |
| 319 byteLength, pos, scalarsPerPosition, offset); |
| 437 } else { | 320 } else { |
| 438 GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), fSur
faceProps, skPaint, | 321 GrTextUtils::DrawBmpPosText(blob, 0, fContext->getBatchFontCache(), fSur
faceProps, skPaint, |
| 439 paint.getColor(), viewMatrix, text, | 322 paint.getColor(), viewMatrix, text, |
| 440 byteLength, pos, scalarsPerPosition, offset)
; | 323 byteLength, pos, scalarsPerPosition, offset)
; |
| 441 } | 324 } |
| 442 return blob; | 325 return blob; |
| 443 } | 326 } |
| 444 | 327 |
| 445 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, | 328 void GrAtlasTextContext::onDrawText(GrDrawContext* dc, |
| 446 const GrClip& clip, | 329 const GrClip& clip, |
| (...skipping 17 matching lines...) Expand all Loading... |
| 464 SkAutoTUnref<GrAtlasTextBlob> blob( | 347 SkAutoTUnref<GrAtlasTextBlob> blob( |
| 465 this->createDrawPosTextBlob(paint, skPaint, viewMatrix, | 348 this->createDrawPosTextBlob(paint, skPaint, viewMatrix, |
| 466 text, byteLength, | 349 text, byteLength, |
| 467 pos, scalarsPerPosition, | 350 pos, scalarsPerPosition, |
| 468 offset)); | 351 offset)); |
| 469 | 352 |
| 470 blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPa
int, paint, clip, | 353 blob->flushThrowaway(fContext, dc, fSurfaceProps, fDistanceAdjustTable, skPa
int, paint, clip, |
| 471 regionClipBounds); | 354 regionClipBounds); |
| 472 } | 355 } |
| 473 | 356 |
| 474 void GrAtlasTextContext::internalDrawDFText(GrAtlasTextBlob* blob, int runIndex, | |
| 475 const SkPaint& skPaint, GrColor colo
r, | |
| 476 const SkMatrix& viewMatrix, | |
| 477 const char text[], size_t byteLength
, | |
| 478 SkScalar x, SkScalar y) { | |
| 479 SkASSERT(byteLength == 0 || text != nullptr); | |
| 480 | |
| 481 // nothing to draw | |
| 482 if (text == nullptr || byteLength == 0) { | |
| 483 return; | |
| 484 } | |
| 485 | |
| 486 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | |
| 487 SkAutoDescriptor desc; | |
| 488 skPaint.getScalerContextDescriptor(&desc, fSurfaceProps, nullptr, true); | |
| 489 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface
(), | |
| 490 desc.getDesc()); | |
| 491 | |
| 492 SkTArray<SkScalar> positions; | |
| 493 | |
| 494 const char* textPtr = text; | |
| 495 SkFixed stopX = 0; | |
| 496 SkFixed stopY = 0; | |
| 497 SkFixed origin = 0; | |
| 498 switch (skPaint.getTextAlign()) { | |
| 499 case SkPaint::kRight_Align: origin = SK_Fixed1; break; | |
| 500 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; | |
| 501 case SkPaint::kLeft_Align: origin = 0; break; | |
| 502 } | |
| 503 | |
| 504 SkAutoKern autokern; | |
| 505 const char* stop = text + byteLength; | |
| 506 while (textPtr < stop) { | |
| 507 // don't need x, y here, since all subpixel variants will have the | |
| 508 // same advance | |
| 509 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0); | |
| 510 | |
| 511 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); | |
| 512 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); | |
| 513 | |
| 514 SkFixed height = glyph.fAdvanceY; | |
| 515 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)))
; | |
| 516 | |
| 517 stopX += width; | |
| 518 stopY += height; | |
| 519 } | |
| 520 SkASSERT(textPtr == stop); | |
| 521 | |
| 522 SkGlyphCache::AttachCache(origPaintCache); | |
| 523 | |
| 524 // now adjust starting point depending on alignment | |
| 525 SkScalar alignX = SkFixedToScalar(stopX); | |
| 526 SkScalar alignY = SkFixedToScalar(stopY); | |
| 527 if (skPaint.getTextAlign() == SkPaint::kCenter_Align) { | |
| 528 alignX = SkScalarHalf(alignX); | |
| 529 alignY = SkScalarHalf(alignY); | |
| 530 } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) { | |
| 531 alignX = 0; | |
| 532 alignY = 0; | |
| 533 } | |
| 534 x -= alignX; | |
| 535 y -= alignY; | |
| 536 SkPoint offset = SkPoint::Make(x, y); | |
| 537 | |
| 538 this->internalDrawDFPosText(blob, runIndex, skPaint, color, viewMatrix, text
, byteLength, | |
| 539 positions.begin(), 2, offset); | |
| 540 } | |
| 541 | |
| 542 void GrAtlasTextContext::internalDrawDFPosText(GrAtlasTextBlob* blob, int runInd
ex, | |
| 543 const SkPaint& origPaint, | |
| 544 GrColor color, | |
| 545 const SkMatrix& viewMatrix, | |
| 546 const char text[], size_t byteLen
gth, | |
| 547 const SkScalar pos[], int scalars
PerPosition, | |
| 548 const SkPoint& offset) { | |
| 549 | |
| 550 SkASSERT(byteLength == 0 || text != nullptr); | |
| 551 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | |
| 552 | |
| 553 // nothing to draw | |
| 554 if (text == nullptr || byteLength == 0) { | |
| 555 return; | |
| 556 } | |
| 557 | |
| 558 SkTDArray<char> fallbackTxt; | |
| 559 SkTDArray<SkScalar> fallbackPos; | |
| 560 | |
| 561 // Setup distance field paint and text ratio | |
| 562 SkScalar textRatio; | |
| 563 SkPaint dfPaint(origPaint); | |
| 564 this->initDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix); | |
| 565 blob->setHasDistanceField(); | |
| 566 blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText()); | |
| 567 | |
| 568 fCurrStrike = nullptr; | |
| 569 | |
| 570 SkGlyphCache* cache = blob->setupCache(runIndex, fSurfaceProps, dfPaint, nul
lptr, true); | |
| 571 SkDrawCacheProc glyphCacheProc = dfPaint.getDrawCacheProc(); | |
| 572 GrFontScaler* fontScaler = GetGrFontScaler(cache); | |
| 573 | |
| 574 const char* stop = text + byteLength; | |
| 575 | |
| 576 if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) { | |
| 577 while (text < stop) { | |
| 578 const char* lastText = text; | |
| 579 // the last 2 parameters are ignored | |
| 580 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
| 581 | |
| 582 if (glyph.fWidth) { | |
| 583 SkScalar x = offset.x() + pos[0]; | |
| 584 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
| 585 | |
| 586 if (!this->dfAppendGlyph(blob, | |
| 587 runIndex, | |
| 588 glyph, | |
| 589 x, y, color, fontScaler, | |
| 590 textRatio, viewMatrix)) { | |
| 591 // couldn't append, send to fallback | |
| 592 fallbackTxt.append(SkToInt(text-lastText), lastText); | |
| 593 *fallbackPos.append() = pos[0]; | |
| 594 if (2 == scalarsPerPosition) { | |
| 595 *fallbackPos.append() = pos[1]; | |
| 596 } | |
| 597 } | |
| 598 } | |
| 599 pos += scalarsPerPosition; | |
| 600 } | |
| 601 } else { | |
| 602 SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? S
K_ScalarHalf | |
| 603 : S
K_Scalar1; | |
| 604 while (text < stop) { | |
| 605 const char* lastText = text; | |
| 606 // the last 2 parameters are ignored | |
| 607 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | |
| 608 | |
| 609 if (glyph.fWidth) { | |
| 610 SkScalar x = offset.x() + pos[0]; | |
| 611 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; | |
| 612 | |
| 613 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul
* textRatio; | |
| 614 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul
* textRatio; | |
| 615 | |
| 616 if (!this->dfAppendGlyph(blob, | |
| 617 runIndex, | |
| 618 glyph, | |
| 619 x - advanceX, y - advanceY, color, | |
| 620 fontScaler, | |
| 621 textRatio, | |
| 622 viewMatrix)) { | |
| 623 // couldn't append, send to fallback | |
| 624 fallbackTxt.append(SkToInt(text-lastText), lastText); | |
| 625 *fallbackPos.append() = pos[0]; | |
| 626 if (2 == scalarsPerPosition) { | |
| 627 *fallbackPos.append() = pos[1]; | |
| 628 } | |
| 629 } | |
| 630 } | |
| 631 pos += scalarsPerPosition; | |
| 632 } | |
| 633 } | |
| 634 | |
| 635 SkGlyphCache::AttachCache(cache); | |
| 636 if (fallbackTxt.count()) { | |
| 637 this->fallbackDrawPosText(blob, runIndex, origPaint.getColor(), origPain
t, viewMatrix, | |
| 638 fallbackTxt, fallbackPos, scalarsPerPosition,
offset); | |
| 639 } | |
| 640 } | |
| 641 | |
| 642 bool GrAtlasTextContext::dfAppendGlyph(GrAtlasTextBlob* blob, int runIndex, | |
| 643 const SkGlyph& skGlyph, | |
| 644 SkScalar sx, SkScalar sy, GrColor color, | |
| 645 GrFontScaler* scaler, | |
| 646 SkScalar textRatio, const SkMatrix& viewM
atrix) { | |
| 647 if (!fCurrStrike) { | |
| 648 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); | |
| 649 } | |
| 650 | |
| 651 GrGlyph::PackedID id = GrGlyph::Pack(skGlyph.getGlyphID(), | |
| 652 skGlyph.getSubXFixed(), | |
| 653 skGlyph.getSubYFixed(), | |
| 654 GrGlyph::kDistance_MaskStyle); | |
| 655 GrGlyph* glyph = fCurrStrike->getGlyph(skGlyph, id, scaler); | |
| 656 if (!glyph) { | |
| 657 return true; | |
| 658 } | |
| 659 | |
| 660 // fallback to color glyph support | |
| 661 if (kA8_GrMaskFormat != glyph->fMaskFormat) { | |
| 662 return false; | |
| 663 } | |
| 664 | |
| 665 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); | |
| 666 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); | |
| 667 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField
Inset); | |
| 668 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie
ldInset); | |
| 669 | |
| 670 SkScalar scale = textRatio; | |
| 671 dx *= scale; | |
| 672 dy *= scale; | |
| 673 width *= scale; | |
| 674 height *= scale; | |
| 675 sx += dx; | |
| 676 sy += dy; | |
| 677 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); | |
| 678 | |
| 679 blob->appendGlyph(runIndex, glyphRect, color, fCurrStrike, glyph, scaler, sk
Glyph, | |
| 680 sx - dx, sy - dy, scale, true); | |
| 681 return true; | |
| 682 } | |
| 683 | |
| 684 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 357 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
| 685 | 358 |
| 686 #ifdef GR_TEST_UTILS | 359 #ifdef GR_TEST_UTILS |
| 687 | 360 |
| 688 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { | 361 DRAW_BATCH_TEST_DEFINE(TextBlobBatch) { |
| 689 static uint32_t gContextID = SK_InvalidGenID; | 362 static uint32_t gContextID = SK_InvalidGenID; |
| 690 static GrAtlasTextContext* gTextContext = nullptr; | 363 static GrAtlasTextContext* gTextContext = nullptr; |
| 691 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); | 364 static SkSurfaceProps gSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType
); |
| 692 | 365 |
| 693 if (context->uniqueID() != gContextID) { | 366 if (context->uniqueID() != gContextID) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 728 | 401 |
| 729 SkScalar transX = static_cast<SkScalar>(random->nextU()); | 402 SkScalar transX = static_cast<SkScalar>(random->nextU()); |
| 730 SkScalar transY = static_cast<SkScalar>(random->nextU()); | 403 SkScalar transY = static_cast<SkScalar>(random->nextU()); |
| 731 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; | 404 const GrAtlasTextBlob::Run::SubRunInfo& info = blob->fRuns[0].fSubRunInfo[0]
; |
| 732 return blob->createBatch(info, textLen, 0, 0, color, transX, transY, skPaint
, | 405 return blob->createBatch(info, textLen, 0, 0, color, transX, transY, skPaint
, |
| 733 gSurfaceProps, gTextContext->dfAdjustTable(), | 406 gSurfaceProps, gTextContext->dfAdjustTable(), |
| 734 context->getBatchFontCache()); | 407 context->getBatchFontCache()); |
| 735 } | 408 } |
| 736 | 409 |
| 737 #endif | 410 #endif |
| OLD | NEW |