| 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 "GrAtlas.h" | 9 #include "GrAtlas.h" |
| 10 #include "GrBatch.h" | 10 #include "GrBatch.h" |
| 11 #include "GrBatchFontCache.h" | 11 #include "GrBatchFontCache.h" |
| 12 #include "GrBatchTarget.h" | 12 #include "GrBatchTarget.h" |
| 13 #include "GrDefaultGeoProcFactory.h" | 13 #include "GrDefaultGeoProcFactory.h" |
| 14 #include "GrDrawTarget.h" | 14 #include "GrDrawTarget.h" |
| 15 #include "GrFontScaler.h" | 15 #include "GrFontScaler.h" |
| 16 #include "GrIndexBuffer.h" | 16 #include "GrIndexBuffer.h" |
| 17 #include "GrStrokeInfo.h" | 17 #include "GrStrokeInfo.h" |
| 18 #include "GrTextBlobCache.h" | 18 #include "GrTextBlobCache.h" |
| 19 #include "GrTexturePriv.h" | 19 #include "GrTexturePriv.h" |
| 20 | 20 |
| 21 #include "SkAutoKern.h" | 21 #include "SkAutoKern.h" |
| 22 #include "SkColorPriv.h" | 22 #include "SkColorPriv.h" |
| 23 #include "SkColorFilter.h" |
| 24 #include "SkDistanceFieldGen.h" |
| 23 #include "SkDraw.h" | 25 #include "SkDraw.h" |
| 24 #include "SkDrawFilter.h" | 26 #include "SkDrawFilter.h" |
| 25 #include "SkDrawProcs.h" | 27 #include "SkDrawProcs.h" |
| 26 #include "SkGlyphCache.h" | 28 #include "SkGlyphCache.h" |
| 27 #include "SkGpuDevice.h" | 29 #include "SkGpuDevice.h" |
| 28 #include "SkGr.h" | 30 #include "SkGr.h" |
| 29 #include "SkPath.h" | 31 #include "SkPath.h" |
| 30 #include "SkRTConf.h" | 32 #include "SkRTConf.h" |
| 31 #include "SkStrokeRec.h" | 33 #include "SkStrokeRec.h" |
| 32 #include "SkTextBlob.h" | 34 #include "SkTextBlob.h" |
| 33 #include "SkTextMapStateProc.h" | 35 #include "SkTextMapStateProc.h" |
| 34 | 36 |
| 35 #include "effects/GrBitmapTextGeoProc.h" | 37 #include "effects/GrBitmapTextGeoProc.h" |
| 36 #include "effects/GrSimpleTextureEffect.h" | 38 #include "effects/GrDistanceFieldGeoProc.h" |
| 37 | 39 |
| 38 namespace { | 40 namespace { |
| 39 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | 41 static const size_t kLCDTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
| 40 | 42 |
| 41 // position + local coord | 43 // position + local coord |
| 42 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); | 44 static const size_t kColorTextVASize = sizeof(SkPoint) + sizeof(SkIPoint16); |
| 43 | 45 |
| 44 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
(SkIPoint16); | 46 static const size_t kGrayTextVASize = sizeof(SkPoint) + sizeof(GrColor) + sizeof
(SkIPoint16); |
| 45 | 47 |
| 48 static const int kMinDFFontSize = 18; |
| 49 static const int kSmallDFFontSize = 32; |
| 50 static const int kSmallDFFontLimit = 32; |
| 51 static const int kMediumDFFontSize = 72; |
| 52 static const int kMediumDFFontLimit = 72; |
| 53 static const int kLargeDFFontSize = 162; |
| 54 |
| 55 SkDEBUGCODE(static const int kExpectedDistanceAdjustTableSize = 8;) |
| 56 static const int kDistanceAdjustLumShift = 5; |
| 57 |
| 46 static const int kVerticesPerGlyph = 4; | 58 static const int kVerticesPerGlyph = 4; |
| 47 static const int kIndicesPerGlyph = 6; | 59 static const int kIndicesPerGlyph = 6; |
| 48 | 60 |
| 49 static size_t get_vertex_stride(GrMaskFormat maskFormat) { | 61 static size_t get_vertex_stride(GrMaskFormat maskFormat) { |
| 50 switch (maskFormat) { | 62 switch (maskFormat) { |
| 51 case kA8_GrMaskFormat: | 63 case kA8_GrMaskFormat: |
| 52 return kGrayTextVASize; | 64 return kGrayTextVASize; |
| 53 case kARGB_GrMaskFormat: | 65 case kARGB_GrMaskFormat: |
| 54 return kColorTextVASize; | 66 return kColorTextVASize; |
| 55 default: | 67 default: |
| 56 return kLCDTextVASize; | 68 return kLCDTextVASize; |
| 57 } | 69 } |
| 58 } | 70 } |
| 59 | 71 |
| 72 static size_t get_vertex_stride_df(GrMaskFormat maskFormat, bool useLCDText) { |
| 73 SkASSERT(maskFormat == kA8_GrMaskFormat); |
| 74 if (useLCDText) { |
| 75 return kLCDTextVASize; |
| 76 } else { |
| 77 return kGrayTextVASize; |
| 78 } |
| 79 } |
| 80 |
| 81 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { |
| 82 unsigned r = SkColorGetR(c); |
| 83 unsigned g = SkColorGetG(c); |
| 84 unsigned b = SkColorGetB(c); |
| 85 return GrColorPackRGBA(r, g, b, 0xff); |
| 86 } |
| 87 |
| 60 }; | 88 }; |
| 61 | 89 |
| 62 // TODO | 90 // TODO |
| 63 // Gamma slotting to preserve color | 91 // Distance field text in textblobs |
| 64 // Better reuse on regeneration | |
| 65 // Telemetry tests | |
| 66 // possibly consider having a regeneration ratio on the textblob itself for anim
ated textblobs | |
| 67 | 92 |
| 68 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, | 93 GrAtlasTextContext::GrAtlasTextContext(GrContext* context, |
| 69 SkGpuDevice* gpuDevice, | 94 SkGpuDevice* gpuDevice, |
| 70 const SkDeviceProperties& properties) | 95 const SkDeviceProperties& properties, |
| 71 : INHERITED(context, gpuDevice, properties) { | 96 bool enableDistanceFields) |
| 97 : INHERITED(context, gpuDevice, properties) |
| 98 , fDistanceAdjustTable(SkNEW_ARGS(DistanceAdjustTable, (properties.gamma()))
) { |
| 72 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest | 99 // We overallocate vertices in our textblobs based on the assumption that A8
has the greatest |
| 73 // vertexStride | 100 // vertexStride |
| 74 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >=
kLCDTextVASize, | 101 SK_COMPILE_ASSERT(kGrayTextVASize >= kColorTextVASize && kGrayTextVASize >=
kLCDTextVASize, |
| 75 vertex_attribute_changed); | 102 vertex_attribute_changed); |
| 76 fCurrStrike = NULL; | 103 fCurrStrike = NULL; |
| 77 fCache = context->getTextBlobCache(); | 104 fCache = context->getTextBlobCache(); |
| 105 |
| 106 #if SK_FORCE_DISTANCE_FIELD_TEXT |
| 107 fEnableDFRendering = true; |
| 108 #else |
| 109 fEnableDFRendering = enableDistanceFields; |
| 110 #endif |
| 111 } |
| 112 |
| 113 void GrAtlasTextContext::DistanceAdjustTable::buildDistanceAdjustTable(float gam
ma) { |
| 114 |
| 115 // This is used for an approximation of the mask gamma hack, used by raster
and bitmap |
| 116 // text. The mask gamma hack is based off of guessing what the blend color i
s going to |
| 117 // be, and adjusting the mask so that when run through the linear blend will |
| 118 // produce the value closest to the desired result. However, in practice thi
s means |
| 119 // that the 'adjusted' mask is just increasing or decreasing the coverage of |
| 120 // the mask depending on what it is thought it will blit against. For black
(on |
| 121 // assumed white) this means that coverages are decreased (on a curve). For
white (on |
| 122 // assumed black) this means that coverages are increased (on a a curve). At |
| 123 // middle (perceptual) gray (which could be blit against anything) the cover
ages |
| 124 // remain the same. |
| 125 // |
| 126 // The idea here is that instead of determining the initial (real) coverage
and |
| 127 // then adjusting that coverage, we determine an adjusted coverage directly
by |
| 128 // essentially manipulating the geometry (in this case, the distance to the
glyph |
| 129 // edge). So for black (on assumed white) this thins a bit; for white (on |
| 130 // assumed black) this fake bolds the geometry a bit. |
| 131 // |
| 132 // The distance adjustment is calculated by determining the actual coverage
value which |
| 133 // when fed into in the mask gamma table gives us an 'adjusted coverage' val
ue of 0.5. This |
| 134 // actual coverage value (assuming it's between 0 and 1) corresponds to a di
stance from the |
| 135 // actual edge. So by subtracting this distance adjustment and computing wit
hout the |
| 136 // the coverage adjustment we should get 0.5 coverage at the same point. |
| 137 // |
| 138 // This has several implications: |
| 139 // For non-gray lcd smoothed text, each subpixel essentially is using a |
| 140 // slightly different geometry. |
| 141 // |
| 142 // For black (on assumed white) this may not cover some pixels which wer
e |
| 143 // previously covered; however those pixels would have been only slightl
y |
| 144 // covered and that slight coverage would have been decreased anyway. Al
so, some pixels |
| 145 // which were previously fully covered may no longer be fully covered. |
| 146 // |
| 147 // For white (on assumed black) this may cover some pixels which weren't |
| 148 // previously covered at all. |
| 149 |
| 150 int width, height; |
| 151 size_t size; |
| 152 |
| 153 #ifdef SK_GAMMA_CONTRAST |
| 154 SkScalar contrast = SK_GAMMA_CONTRAST; |
| 155 #else |
| 156 SkScalar contrast = 0.5f; |
| 157 #endif |
| 158 SkScalar paintGamma = gamma; |
| 159 SkScalar deviceGamma = gamma; |
| 160 |
| 161 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma, |
| 162 &width, &height); |
| 163 |
| 164 SkASSERT(kExpectedDistanceAdjustTableSize == height); |
| 165 fTable = SkNEW_ARRAY(SkScalar, height); |
| 166 |
| 167 SkAutoTArray<uint8_t> data((int)size); |
| 168 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get
()); |
| 169 |
| 170 // find the inverse points where we cross 0.5 |
| 171 // binsearch might be better, but we only need to do this once on creation |
| 172 for (int row = 0; row < height; ++row) { |
| 173 uint8_t* rowPtr = data.get() + row*width; |
| 174 for (int col = 0; col < width - 1; ++col) { |
| 175 if (rowPtr[col] <= 127 && rowPtr[col + 1] >= 128) { |
| 176 // compute point where a mask value will give us a result of 0.5 |
| 177 float interp = (127.5f - rowPtr[col]) / (rowPtr[col + 1] - rowPt
r[col]); |
| 178 float borderAlpha = (col + interp) / 255.f; |
| 179 |
| 180 // compute t value for that alpha |
| 181 // this is an approximate inverse for smoothstep() |
| 182 float t = borderAlpha*(borderAlpha*(4.0f*borderAlpha - 6.0f) + 5
.0f) / 3.0f; |
| 183 |
| 184 // compute distance which gives us that t value |
| 185 const float kDistanceFieldAAFactor = 0.65f; // should match SK_D
istanceFieldAAFactor |
| 186 float d = 2.0f*kDistanceFieldAAFactor*t - kDistanceFieldAAFactor
; |
| 187 |
| 188 fTable[row] = d; |
| 189 break; |
| 190 } |
| 191 } |
| 192 } |
| 78 } | 193 } |
| 79 | 194 |
| 80 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, | 195 GrAtlasTextContext* GrAtlasTextContext::Create(GrContext* context, |
| 81 SkGpuDevice* gpuDevice, | 196 SkGpuDevice* gpuDevice, |
| 82 const SkDeviceProperties& props)
{ | 197 const SkDeviceProperties& props, |
| 83 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props)); | 198 bool enableDistanceFields) { |
| 199 return SkNEW_ARGS(GrAtlasTextContext, (context, gpuDevice, props, enableDist
anceFields)); |
| 84 } | 200 } |
| 85 | 201 |
| 86 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, | 202 bool GrAtlasTextContext::canDraw(const GrRenderTarget*, |
| 87 const GrClip&, | 203 const GrClip&, |
| 88 const GrPaint&, | 204 const GrPaint&, |
| 89 const SkPaint& skPaint, | 205 const SkPaint& skPaint, |
| 90 const SkMatrix& viewMatrix) { | 206 const SkMatrix& viewMatrix) { |
| 91 return !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); | 207 return this->canDrawAsDistanceFields(skPaint, viewMatrix) || |
| 208 !SkDraw::ShouldDrawTextAsPaths(skPaint, viewMatrix); |
| 92 } | 209 } |
| 93 | 210 |
| 94 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { | 211 GrColor GrAtlasTextContext::ComputeCanonicalColor(const SkPaint& paint, bool lcd
) { |
| 95 GrColor canonicalColor = paint.computeLuminanceColor(); | 212 GrColor canonicalColor = paint.computeLuminanceColor(); |
| 96 if (lcd) { | 213 if (lcd) { |
| 97 // This is the correct computation, but there are tons of cases where LC
D can be overridden. | 214 // This is the correct computation, but there are tons of cases where LC
D can be overridden. |
| 98 // For now we just regenerate if any run in a textblob has LCD. | 215 // For now we just regenerate if any run in a textblob has LCD. |
| 99 // TODO figure out where all of these overrides are and see if we can in
corporate that logic | 216 // TODO figure out where all of these overrides are and see if we can in
corporate that logic |
| 100 // at a higher level *OR* use sRGB | 217 // at a higher level *OR* use sRGB |
| 101 SkASSERT(false); | 218 SkASSERT(false); |
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 196 } | 313 } |
| 197 #endif | 314 #endif |
| 198 (*outTransX) = transX; | 315 (*outTransX) = transX; |
| 199 (*outTransY) = transY; | 316 (*outTransY) = transY; |
| 200 return false; | 317 return false; |
| 201 } | 318 } |
| 202 | 319 |
| 203 | 320 |
| 204 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, | 321 inline SkGlyphCache* GrAtlasTextContext::setupCache(BitmapTextBlob::Run* run, |
| 205 const SkPaint& skPaint, | 322 const SkPaint& skPaint, |
| 206 const SkMatrix& viewMatrix)
{ | 323 const SkMatrix* viewMatrix, |
| 207 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, &v
iewMatrix, false); | 324 bool noGamma) { |
| 325 skPaint.getScalerContextDescriptor(&run->fDescriptor, &fDeviceProperties, vi
ewMatrix, noGamma); |
| 208 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); | 326 run->fTypeface.reset(SkSafeRef(skPaint.getTypeface())); |
| 209 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; | 327 return SkGlyphCache::DetachCache(run->fTypeface, run->fDescriptor.getDesc())
; |
| 210 } | 328 } |
| 211 | 329 |
| 212 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, | 330 void GrAtlasTextContext::drawTextBlob(GrRenderTarget* rt, const GrClip& clip, |
| 213 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, | 331 const SkPaint& skPaint, const SkMatrix& vi
ewMatrix, |
| 214 const SkTextBlob* blob, SkScalar x, SkScal
ar y, | 332 const SkTextBlob* blob, SkScalar x, SkScal
ar y, |
| 215 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { | 333 SkDrawFilter* drawFilter, const SkIRect& c
lipBounds) { |
| 216 SkAutoTUnref<BitmapTextBlob> cacheBlob; | 334 SkAutoTUnref<BitmapTextBlob> cacheBlob; |
| 217 SkMaskFilter::BlurRec blurRec; | 335 SkMaskFilter::BlurRec blurRec; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 278 } | 396 } |
| 279 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, blob, x, y, | 397 this->regenerateTextBlob(cacheBlob, skPaint, grPaint.getColor(), viewMat
rix, blob, x, y, |
| 280 drawFilter, clipRect); | 398 drawFilter, clipRect); |
| 281 } | 399 } |
| 282 | 400 |
| 283 cacheBlob->fPaintColor = skPaint.getColor(); | 401 cacheBlob->fPaintColor = skPaint.getColor(); |
| 284 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, | 402 this->flush(fContext->getTextTarget(), blob, cacheBlob, rt, skPaint, grPaint
, drawFilter, |
| 285 clip, viewMatrix, clipBounds, x, y, transX, transY); | 403 clip, viewMatrix, clipBounds, x, y, transX, transY); |
| 286 } | 404 } |
| 287 | 405 |
| 406 inline bool GrAtlasTextContext::canDrawAsDistanceFields(const SkPaint& skPaint, |
| 407 const SkMatrix& viewMatr
ix) { |
| 408 // TODO: support perspective (need getMaxScale replacement) |
| 409 if (viewMatrix.hasPerspective()) { |
| 410 return false; |
| 411 } |
| 412 |
| 413 SkScalar maxScale = viewMatrix.getMaxScale(); |
| 414 SkScalar scaledTextSize = maxScale*skPaint.getTextSize(); |
| 415 // Hinted text looks far better at small resolutions |
| 416 // Scaling up beyond 2x yields undesireable artifacts |
| 417 if (scaledTextSize < kMinDFFontSize || scaledTextSize > 2 * kLargeDFFontSize
) { |
| 418 return false; |
| 419 } |
| 420 |
| 421 if (!fEnableDFRendering && !skPaint.isDistanceFieldTextTEMP() && |
| 422 scaledTextSize < kLargeDFFontSize) { |
| 423 return false; |
| 424 } |
| 425 |
| 426 // rasterizers and mask filters modify alpha, which doesn't |
| 427 // translate well to distance |
| 428 if (skPaint.getRasterizer() || skPaint.getMaskFilter() || |
| 429 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) { |
| 430 return false; |
| 431 } |
| 432 |
| 433 // TODO: add some stroking support |
| 434 if (skPaint.getStyle() != SkPaint::kFill_Style) { |
| 435 return false; |
| 436 } |
| 437 |
| 438 return true; |
| 439 } |
| 440 |
| 288 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, | 441 void GrAtlasTextContext::regenerateTextBlob(BitmapTextBlob* cacheBlob, |
| 289 const SkPaint& skPaint, GrColor colo
r, | 442 const SkPaint& skPaint, GrColor colo
r, |
| 290 const SkMatrix& viewMatrix, | 443 const SkMatrix& viewMatrix, |
| 291 const SkTextBlob* blob, SkScalar x,
SkScalar y, | 444 const SkTextBlob* blob, SkScalar x,
SkScalar y, |
| 292 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { | 445 SkDrawFilter* drawFilter, const SkIR
ect& clipRect) { |
| 293 cacheBlob->fViewMatrix = viewMatrix; | 446 cacheBlob->fViewMatrix = viewMatrix; |
| 294 cacheBlob->fX = x; | 447 cacheBlob->fX = x; |
| 295 cacheBlob->fY = y; | 448 cacheBlob->fY = y; |
| 296 | 449 |
| 297 // Regenerate textblob | 450 // Regenerate textblob |
| 298 SkPaint runPaint = skPaint; | 451 SkPaint runPaint = skPaint; |
| 299 SkTextBlob::RunIterator it(blob); | 452 SkTextBlob::RunIterator it(blob); |
| 300 for (int run = 0; !it.done(); it.next(), run++) { | 453 for (int run = 0; !it.done(); it.next(), run++) { |
| 301 int glyphCount = it.glyphCount(); | 454 int glyphCount = it.glyphCount(); |
| 302 size_t textLen = glyphCount * sizeof(uint16_t); | 455 size_t textLen = glyphCount * sizeof(uint16_t); |
| 303 const SkPoint& offset = it.offset(); | 456 const SkPoint& offset = it.offset(); |
| 304 // applyFontToPaint() always overwrites the exact same attributes, | 457 // applyFontToPaint() always overwrites the exact same attributes, |
| 305 // so it is safe to not re-seed the paint for this reason. | 458 // so it is safe to not re-seed the paint for this reason. |
| 306 it.applyFontToPaint(&runPaint); | 459 it.applyFontToPaint(&runPaint); |
| 307 | 460 |
| 308 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { | 461 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
| 309 // A false return from filter() means we should abort the current dr
aw. | 462 // A false return from filter() means we should abort the current dr
aw. |
| 310 runPaint = skPaint; | 463 runPaint = skPaint; |
| 311 continue; | 464 continue; |
| 312 } | 465 } |
| 313 | 466 |
| 314 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); | 467 runPaint.setFlags(fGpuDevice->filterTextFlags(runPaint)); |
| 315 | 468 |
| 316 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint,
viewMatrix); | 469 SkGlyphCache* cache = this->setupCache(&cacheBlob->fRuns[run], runPaint,
&viewMatrix, |
| 470 false); |
| 317 | 471 |
| 318 // setup vertex / glyphIndex for the new run | 472 // setup vertex / glyphIndex for the new run |
| 319 if (run > 0) { | 473 if (run > 0) { |
| 320 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); | 474 PerSubRunInfo& newRun = cacheBlob->fRuns[run].fSubRunInfo.back(); |
| 321 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(
); | 475 PerSubRunInfo& lastRun = cacheBlob->fRuns[run - 1].fSubRunInfo.back(
); |
| 322 | 476 |
| 323 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; | 477 newRun.fVertexStartIndex = lastRun.fVertexEndIndex; |
| 324 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; | 478 newRun.fVertexEndIndex = lastRun.fVertexEndIndex; |
| 325 | 479 |
| 326 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; | 480 newRun.fGlyphStartIndex = lastRun.fGlyphEndIndex; |
| 327 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; | 481 newRun.fGlyphEndIndex = lastRun.fGlyphEndIndex; |
| 328 } | 482 } |
| 329 | 483 |
| 330 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { | 484 if (SkDraw::ShouldDrawTextAsPaths(runPaint, viewMatrix)) { |
| 331 cacheBlob->fRuns[run].fDrawAsPaths = true; | 485 cacheBlob->fRuns[run].fDrawAsPaths = true; |
| 332 continue; | 486 continue; |
| 333 } | 487 } |
| 334 cacheBlob->fRuns[run].fDrawAsPaths = false; | 488 cacheBlob->fRuns[run].fDrawAsPaths = false; |
| 335 | 489 |
| 336 switch (it.positioning()) { | 490 switch (it.positioning()) { |
| 337 case SkTextBlob::kDefault_Positioning: | 491 case SkTextBlob::kDefault_Positioning: |
| 338 this->internalDrawText(cacheBlob, run, cache, runPaint, color, v
iewMatrix, | 492 this->internalDrawBMPText(cacheBlob, run, cache, runPaint, color
, viewMatrix, |
| 339 (const char *)it.glyphs(), textLen, | 493 (const char *)it.glyphs(), textLen, |
| 340 x + offset.x(), y + offset.y(), clipRect)
; | 494 x + offset.x(), y + offset.y(), clipRe
ct); |
| 341 break; | 495 break; |
| 342 case SkTextBlob::kHorizontal_Positioning: | 496 case SkTextBlob::kHorizontal_Positioning: |
| 343 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color
, viewMatrix, | 497 this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, co
lor, viewMatrix, |
| 344 (const char*)it.glyphs(), textLen, it.
pos(), 1, | 498 (const char*)it.glyphs(), textLen,
it.pos(), 1, |
| 345 SkPoint::Make(x, y + offset.y()), clip
Rect); | 499 SkPoint::Make(x, y + offset.y()), c
lipRect); |
| 346 break; | 500 break; |
| 347 case SkTextBlob::kFull_Positioning: | 501 case SkTextBlob::kFull_Positioning: |
| 348 this->internalDrawPosText(cacheBlob, run, cache, runPaint, color
, viewMatrix, | 502 this->internalDrawBMPPosText(cacheBlob, run, cache, runPaint, co
lor, viewMatrix, |
| 349 (const char*)it.glyphs(), textLen, it.
pos(), 2, | 503 (const char*)it.glyphs(), textLen,
it.pos(), 2, |
| 350 SkPoint::Make(x, y), clipRect); | 504 SkPoint::Make(x, y), clipRect); |
| 351 break; | 505 break; |
| 352 } | 506 } |
| 353 | 507 |
| 354 if (drawFilter) { | 508 if (drawFilter) { |
| 355 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 509 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
| 356 runPaint = skPaint; | 510 runPaint = skPaint; |
| 357 } | 511 } |
| 358 | 512 |
| 359 SkGlyphCache::AttachCache(cache); | 513 SkGlyphCache::AttachCache(cache); |
| 360 } | 514 } |
| 361 } | 515 } |
| 362 | 516 |
| 517 inline void GrAtlasTextContext::initDistanceFieldPaint(SkPaint* skPaint, SkScala
r* textRatio, |
| 518 const SkMatrix& viewMatri
x) { |
| 519 // getMaxScale doesn't support perspective, so neither do we at the moment |
| 520 SkASSERT(!viewMatrix.hasPerspective()); |
| 521 SkScalar maxScale = viewMatrix.getMaxScale(); |
| 522 SkScalar textSize = skPaint->getTextSize(); |
| 523 SkScalar scaledTextSize = textSize; |
| 524 // if we have non-unity scale, we need to choose our base text size |
| 525 // based on the SkPaint's text size multiplied by the max scale factor |
| 526 // TODO: do we need to do this if we're scaling down (i.e. maxScale < 1)? |
| 527 if (maxScale > 0 && !SkScalarNearlyEqual(maxScale, SK_Scalar1)) { |
| 528 scaledTextSize *= maxScale; |
| 529 } |
| 530 |
| 531 if (scaledTextSize <= kSmallDFFontLimit) { |
| 532 *textRatio = textSize / kSmallDFFontSize; |
| 533 skPaint->setTextSize(SkIntToScalar(kSmallDFFontSize)); |
| 534 } else if (scaledTextSize <= kMediumDFFontLimit) { |
| 535 *textRatio = textSize / kMediumDFFontSize; |
| 536 skPaint->setTextSize(SkIntToScalar(kMediumDFFontSize)); |
| 537 } else { |
| 538 *textRatio = textSize / kLargeDFFontSize; |
| 539 skPaint->setTextSize(SkIntToScalar(kLargeDFFontSize)); |
| 540 } |
| 541 |
| 542 skPaint->setLCDRenderText(false); |
| 543 skPaint->setAutohinted(false); |
| 544 skPaint->setHinting(SkPaint::kNormal_Hinting); |
| 545 skPaint->setSubpixelText(true); |
| 546 } |
| 547 |
| 548 inline void GrAtlasTextContext::fallbackDrawPosText(GrRenderTarget* rt, const Gr
Clip& clip, |
| 549 const GrPaint& paint, |
| 550 const SkPaint& skPaint, |
| 551 const SkMatrix& viewMatrix, |
| 552 const SkTDArray<char>& fallb
ackTxt, |
| 553 const SkTDArray<SkScalar>& f
allbackPos, |
| 554 int scalarsPerPosition, |
| 555 const SkPoint& offset, |
| 556 const SkIRect& clipRect) { |
| 557 int glyphCount = fallbackTxt.count(); |
| 558 SkASSERT(glyphCount); |
| 559 // TODO currently we have to create a whole new blob for fallback text. Thi
s is because |
| 560 // they have a different descriptor and we currently only have one descripto
r per run. |
| 561 // We should fix this and allow an override descriptor on each subrun |
| 562 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); |
| 563 blob->fViewMatrix = viewMatrix; |
| 564 |
| 565 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMatrix
, false); |
| 566 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(), view
Matrix, |
| 567 fallbackTxt.begin(), fallbackTxt.count(), |
| 568 fallbackPos.begin(), scalarsPerPosition, offset
, clipRect); |
| 569 SkGlyphCache::AttachCache(cache); |
| 570 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip); |
| 571 } |
| 572 |
| 573 inline GrAtlasTextContext::BitmapTextBlob* |
| 574 GrAtlasTextContext::setupDFBlob(int glyphCount, const SkPaint& origPaint, |
| 575 const SkMatrix& viewMatrix, SkGlyphCache** cache
, |
| 576 SkPaint* dfPaint, SkScalar* textRatio) { |
| 577 BitmapTextBlob* blob = fCache->createBlob(glyphCount, 1, kGrayTextVASize); |
| 578 |
| 579 *dfPaint = origPaint; |
| 580 this->initDistanceFieldPaint(dfPaint, textRatio, viewMatrix); |
| 581 blob->fViewMatrix = viewMatrix; |
| 582 blob->fRuns[0].fSubRunInfo.back().fUseLCDText = origPaint.isLCDRenderText(); |
| 583 blob->fRuns[0].fSubRunInfo.back().fDrawAsDistanceFields = true; |
| 584 |
| 585 *cache = this->setupCache(&blob->fRuns[0], *dfPaint, NULL, true); |
| 586 return blob; |
| 587 } |
| 588 |
| 363 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, | 589 void GrAtlasTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip, |
| 364 const GrPaint& paint, const SkPaint& skPaint
, | 590 const GrPaint& paint, const SkPaint& skPaint
, |
| 365 const SkMatrix& viewMatrix, | 591 const SkMatrix& viewMatrix, |
| 366 const char text[], size_t byteLength, | 592 const char text[], size_t byteLength, |
| 367 SkScalar x, SkScalar y, const SkIRect& regio
nClipBounds) { | 593 SkScalar x, SkScalar y, const SkIRect& regio
nClipBounds) { |
| 368 int glyphCount = skPaint.countText(text, byteLength); | 594 int glyphCount = skPaint.countText(text, byteLength); |
| 369 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); | 595 SkIRect clipRect; |
| 370 blob->fViewMatrix = viewMatrix; | 596 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
| 371 blob->fX = x; | 597 |
| 372 blob->fY = y; | 598 // setup cache |
| 599 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { |
| 600 SkPaint dfPaint; |
| 601 SkScalar textRatio; |
| 602 SkGlyphCache* cache; |
| 603 SkAutoTUnref<BitmapTextBlob> blob(this->setupDFBlob(glyphCount, skPaint,
viewMatrix, &cache, |
| 604 &dfPaint, &textRatio
)); |
| 605 |
| 606 SkTDArray<char> fallbackTxt; |
| 607 SkTDArray<SkScalar> fallbackPos; |
| 608 SkPoint offset; |
| 609 this->internalDrawDFText(blob, 0, cache, dfPaint, paint.getColor(), view
Matrix, text, |
| 610 byteLength, x, y, clipRect, textRatio, &fallbac
kTxt, &fallbackPos, |
| 611 &offset, skPaint); |
| 612 SkGlyphCache::AttachCache(cache); |
| 613 this->flush(fContext->getTextTarget(), blob, rt, dfPaint, paint, clip); |
| 614 if (fallbackTxt.count()) { |
| 615 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fall
backTxt, |
| 616 fallbackPos, 2, offset, clipRect); |
| 617 } |
| 618 } else { |
| 619 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra
yTextVASize)); |
| 620 blob->fViewMatrix = viewMatrix; |
| 621 |
| 622 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); |
| 623 this->internalDrawBMPText(blob, 0, cache, skPaint, paint.getColor(), vie
wMatrix, text, |
| 624 byteLength, x, y, clipRect); |
| 625 SkGlyphCache::AttachCache(cache); |
| 626 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip); |
| 627 } |
| 628 } |
| 629 |
| 630 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, |
| 631 const GrPaint& paint, const SkPaint& skPa
int, |
| 632 const SkMatrix& viewMatrix, |
| 633 const char text[], size_t byteLength, |
| 634 const SkScalar pos[], int scalarsPerPosit
ion, |
| 635 const SkPoint& offset, const SkIRect& reg
ionClipBounds) { |
| 636 int glyphCount = skPaint.countText(text, byteLength); |
| 373 | 637 |
| 374 SkIRect clipRect; | 638 SkIRect clipRect; |
| 375 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | 639 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); |
| 376 | 640 |
| 377 // setup cache | 641 if (this->canDrawAsDistanceFields(skPaint, viewMatrix)) { |
| 378 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; | 642 SkPaint dfPaint; |
| 379 this->internalDrawText(blob, 0, cache, skPaint, paint.getColor(), viewMatrix
, text, byteLength, | 643 SkScalar textRatio; |
| 380 x, y, clipRect); | 644 SkGlyphCache* cache; |
| 381 SkGlyphCache::AttachCache(cache); | 645 SkAutoTUnref<BitmapTextBlob> blob(this->setupDFBlob(glyphCount, skPaint,
viewMatrix, &cache, |
| 646 &dfPaint, &textRatio
)); |
| 382 | 647 |
| 383 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM
atrix); | 648 SkTDArray<char> fallbackTxt; |
| 649 SkTDArray<SkScalar> fallbackPos; |
| 650 this->internalDrawDFPosText(blob, 0, cache, dfPaint, paint.getColor(), v
iewMatrix, text, |
| 651 byteLength, pos, scalarsPerPosition, offset,
clipRect, |
| 652 textRatio, &fallbackTxt, &fallbackPos); |
| 653 SkGlyphCache::AttachCache(cache); |
| 654 this->flush(fContext->getTextTarget(), blob, rt, dfPaint, paint, clip); |
| 655 if (fallbackTxt.count()) { |
| 656 this->fallbackDrawPosText(rt, clip, paint, skPaint, viewMatrix, fall
backTxt, |
| 657 fallbackPos, scalarsPerPosition, offset, c
lipRect); |
| 658 } |
| 659 } else { |
| 660 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGra
yTextVASize)); |
| 661 blob->fViewMatrix = viewMatrix; |
| 662 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, &viewMa
trix, false); |
| 663 this->internalDrawBMPPosText(blob, 0, cache, skPaint, paint.getColor(),
viewMatrix, text, |
| 664 byteLength, pos, scalarsPerPosition, offset
, clipRect); |
| 665 SkGlyphCache::AttachCache(cache); |
| 666 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip); |
| 667 } |
| 384 } | 668 } |
| 385 | 669 |
| 386 void GrAtlasTextContext::internalDrawText(BitmapTextBlob* blob, int runIndex, | 670 void GrAtlasTextContext::internalDrawBMPText(BitmapTextBlob* blob, int runIndex, |
| 387 SkGlyphCache* cache, const SkPaint& sk
Paint, | 671 SkGlyphCache* cache, const SkPaint&
skPaint, |
| 388 GrColor color, | 672 GrColor color, |
| 389 const SkMatrix& viewMatrix, | 673 const SkMatrix& viewMatrix, |
| 390 const char text[], size_t byteLength, | 674 const char text[], size_t byteLengt
h, |
| 391 SkScalar x, SkScalar y, const SkIRect&
clipRect) { | 675 SkScalar x, SkScalar y, const SkIRe
ct& clipRect) { |
| 392 SkASSERT(byteLength == 0 || text != NULL); | 676 SkASSERT(byteLength == 0 || text != NULL); |
| 393 | 677 |
| 394 // nothing to draw | 678 // nothing to draw |
| 395 if (text == NULL || byteLength == 0) { | 679 if (text == NULL || byteLength == 0) { |
| 396 return; | 680 return; |
| 397 } | 681 } |
| 398 | 682 |
| 399 fCurrStrike = NULL; | 683 fCurrStrike = NULL; |
| 400 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | 684 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); |
| 401 | 685 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 449 | 733 |
| 450 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); | 734 Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX); |
| 451 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); | 735 Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY); |
| 452 | 736 |
| 453 while (text < stop) { | 737 while (text < stop) { |
| 454 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy
Mask); | 738 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fy
Mask); |
| 455 | 739 |
| 456 fx += autokern.adjust(glyph); | 740 fx += autokern.adjust(glyph); |
| 457 | 741 |
| 458 if (glyph.fWidth) { | 742 if (glyph.fWidth) { |
| 459 this->appendGlyph(blob, | 743 this->bmpAppendGlyph(blob, |
| 460 runIndex, | 744 runIndex, |
| 461 GrGlyph::Pack(glyph.getGlyphID(), | 745 GrGlyph::Pack(glyph.getGlyphID(), |
| 462 glyph.getSubXFixed(), | 746 glyph.getSubXFixed(), |
| 463 glyph.getSubYFixed(), | 747 glyph.getSubYFixed(), |
| 464 GrGlyph::kCoverage_MaskStyle), | 748 GrGlyph::kCoverage_MaskStyle), |
| 465 Sk48Dot16FloorToInt(fx), | 749 Sk48Dot16FloorToInt(fx), |
| 466 Sk48Dot16FloorToInt(fy), | 750 Sk48Dot16FloorToInt(fy), |
| 467 color, | 751 color, |
| 468 fontScaler, | 752 fontScaler, |
| 469 clipRect); | 753 clipRect); |
| 470 } | 754 } |
| 471 | 755 |
| 472 fx += glyph.fAdvanceX; | 756 fx += glyph.fAdvanceX; |
| 473 fy += glyph.fAdvanceY; | 757 fy += glyph.fAdvanceY; |
| 474 } | 758 } |
| 475 } | 759 } |
| 476 | 760 |
| 477 void GrAtlasTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip, | 761 void GrAtlasTextContext::internalDrawBMPPosText(BitmapTextBlob* blob, int runInd
ex, |
| 478 const GrPaint& paint, const SkPaint& skPa
int, | 762 SkGlyphCache* cache, const SkPai
nt& skPaint, |
| 479 const SkMatrix& viewMatrix, | 763 GrColor color, |
| 480 const char text[], size_t byteLength, | 764 const SkMatrix& viewMatrix, |
| 481 const SkScalar pos[], int scalarsPerPosit
ion, | 765 const char text[], size_t byteLe
ngth, |
| 482 const SkPoint& offset, const SkIRect& reg
ionClipBounds) { | 766 const SkScalar pos[], int scalar
sPerPosition, |
| 483 int glyphCount = skPaint.countText(text, byteLength); | 767 const SkPoint& offset, const SkI
Rect& clipRect) { |
| 484 SkAutoTUnref<BitmapTextBlob> blob(fCache->createBlob(glyphCount, 1, kGrayTex
tVASize)); | |
| 485 blob->fViewMatrix = viewMatrix; | |
| 486 | |
| 487 SkIRect clipRect; | |
| 488 clip.getConservativeBounds(rt->width(), rt->height(), &clipRect); | |
| 489 | |
| 490 // setup cache | |
| 491 SkGlyphCache* cache = this->setupCache(&blob->fRuns[0], skPaint, viewMatrix)
; | |
| 492 this->internalDrawPosText(blob, 0, cache, skPaint, paint.getColor(), viewMat
rix, text, | |
| 493 byteLength, pos, scalarsPerPosition, offset, clipR
ect); | |
| 494 SkGlyphCache::AttachCache(cache); | |
| 495 | |
| 496 this->flush(fContext->getTextTarget(), blob, rt, skPaint, paint, clip, viewM
atrix); | |
| 497 } | |
| 498 | |
| 499 void GrAtlasTextContext::internalDrawPosText(BitmapTextBlob* blob, int runIndex, | |
| 500 SkGlyphCache* cache, const SkPaint&
skPaint, | |
| 501 GrColor color, | |
| 502 const SkMatrix& viewMatrix, | |
| 503 const char text[], size_t byteLengt
h, | |
| 504 const SkScalar pos[], int scalarsPe
rPosition, | |
| 505 const SkPoint& offset, const SkIRec
t& clipRect) { | |
| 506 SkASSERT(byteLength == 0 || text != NULL); | 768 SkASSERT(byteLength == 0 || text != NULL); |
| 507 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 769 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
| 508 | 770 |
| 509 // nothing to draw | 771 // nothing to draw |
| 510 if (text == NULL || byteLength == 0) { | 772 if (text == NULL || byteLength == 0) { |
| 511 return; | 773 return; |
| 512 } | 774 } |
| 513 | 775 |
| 514 fCurrStrike = NULL; | 776 fCurrStrike = NULL; |
| 515 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); | 777 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 541 while (text < stop) { | 803 while (text < stop) { |
| 542 SkPoint tmsLoc; | 804 SkPoint tmsLoc; |
| 543 tmsProc(pos, &tmsLoc); | 805 tmsProc(pos, &tmsLoc); |
| 544 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); | 806 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + halfSampleX); |
| 545 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); | 807 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + halfSampleY); |
| 546 | 808 |
| 547 const SkGlyph& glyph = glyphCacheProc(cache, &text, | 809 const SkGlyph& glyph = glyphCacheProc(cache, &text, |
| 548 fx & fxMask, fy & fyMask); | 810 fx & fxMask, fy & fyMask); |
| 549 | 811 |
| 550 if (glyph.fWidth) { | 812 if (glyph.fWidth) { |
| 551 this->appendGlyph(blob, | 813 this->bmpAppendGlyph(blob, |
| 552 runIndex, | 814 runIndex, |
| 553 GrGlyph::Pack(glyph.getGlyphID(), | 815 GrGlyph::Pack(glyph.getGlyphID(), |
| 554 glyph.getSubXFixed(), | 816 glyph.getSubXFixed(), |
| 555 glyph.getSubYFixed(), | 817 glyph.getSubYFixed(), |
| 556 GrGlyph::kCoverage_MaskStyle
), | 818 GrGlyph::kCoverage_MaskSt
yle), |
| 557 Sk48Dot16FloorToInt(fx), | 819 Sk48Dot16FloorToInt(fx), |
| 558 Sk48Dot16FloorToInt(fy), | 820 Sk48Dot16FloorToInt(fy), |
| 559 color, | 821 color, |
| 560 fontScaler, | 822 fontScaler, |
| 561 clipRect); | 823 clipRect); |
| 562 } | 824 } |
| 563 pos += scalarsPerPosition; | 825 pos += scalarsPerPosition; |
| 564 } | 826 } |
| 565 } else { | 827 } else { |
| 566 while (text < stop) { | 828 while (text < stop) { |
| 567 const char* currentText = text; | 829 const char* currentText = text; |
| 568 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); | 830 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); |
| 569 | 831 |
| 570 if (metricGlyph.fWidth) { | 832 if (metricGlyph.fWidth) { |
| 571 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) | 833 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) |
| 572 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) | 834 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) |
| 573 SkPoint tmsLoc; | 835 SkPoint tmsLoc; |
| 574 tmsProc(pos, &tmsLoc); | 836 tmsProc(pos, &tmsLoc); |
| 575 SkPoint alignLoc; | 837 SkPoint alignLoc; |
| 576 alignProc(tmsLoc, metricGlyph, &alignLoc); | 838 alignProc(tmsLoc, metricGlyph, &alignLoc); |
| 577 | 839 |
| 578 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); | 840 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + halfSampleX); |
| 579 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); | 841 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + halfSampleY); |
| 580 | 842 |
| 581 // have to call again, now that we've been "aligned" | 843 // have to call again, now that we've been "aligned" |
| 582 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, | 844 const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, |
| 583 fx & fxMask, fy & fyMa
sk); | 845 fx & fxMask, fy & fyMa
sk); |
| 584 // the assumption is that the metrics haven't changed | 846 // the assumption is that the metrics haven't changed |
| 585 SkASSERT(prevAdvX == glyph.fAdvanceX); | 847 SkASSERT(prevAdvX == glyph.fAdvanceX); |
| 586 SkASSERT(prevAdvY == glyph.fAdvanceY); | 848 SkASSERT(prevAdvY == glyph.fAdvanceY); |
| 587 SkASSERT(glyph.fWidth); | 849 SkASSERT(glyph.fWidth); |
| 588 | 850 |
| 589 this->appendGlyph(blob, | 851 this->bmpAppendGlyph(blob, |
| 590 runIndex, | 852 runIndex, |
| 591 GrGlyph::Pack(glyph.getGlyphID(), | 853 GrGlyph::Pack(glyph.getGlyphID(), |
| 592 glyph.getSubXFixed(), | 854 glyph.getSubXFixed(), |
| 593 glyph.getSubYFixed(), | 855 glyph.getSubYFixed(), |
| 594 GrGlyph::kCoverage_MaskStyle
), | 856 GrGlyph::kCoverage_MaskSt
yle), |
| 595 Sk48Dot16FloorToInt(fx), | 857 Sk48Dot16FloorToInt(fx), |
| 596 Sk48Dot16FloorToInt(fy), | 858 Sk48Dot16FloorToInt(fy), |
| 597 color, | 859 color, |
| 598 fontScaler, | 860 fontScaler, |
| 599 clipRect); | 861 clipRect); |
| 600 } | 862 } |
| 601 pos += scalarsPerPosition; | 863 pos += scalarsPerPosition; |
| 602 } | 864 } |
| 603 } | 865 } |
| 604 } else { // not subpixel | 866 } else { // not subpixel |
| 605 | 867 |
| 606 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { | 868 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { |
| 607 while (text < stop) { | 869 while (text < stop) { |
| 608 // the last 2 parameters are ignored | 870 // the last 2 parameters are ignored |
| 609 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 871 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 610 | 872 |
| 611 if (glyph.fWidth) { | 873 if (glyph.fWidth) { |
| 612 SkPoint tmsLoc; | 874 SkPoint tmsLoc; |
| 613 tmsProc(pos, &tmsLoc); | 875 tmsProc(pos, &tmsLoc); |
| 614 | 876 |
| 615 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf);
//halfSampleX; | 877 Sk48Dot16 fx = SkScalarTo48Dot16(tmsLoc.fX + SK_ScalarHalf);
//halfSampleX; |
| 616 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf);
//halfSampleY; | 878 Sk48Dot16 fy = SkScalarTo48Dot16(tmsLoc.fY + SK_ScalarHalf);
//halfSampleY; |
| 617 this->appendGlyph(blob, | 879 this->bmpAppendGlyph(blob, |
| 618 runIndex, | 880 runIndex, |
| 619 GrGlyph::Pack(glyph.getGlyphID(), | 881 GrGlyph::Pack(glyph.getGlyphID(), |
| 620 glyph.getSubXFixed(), | 882 glyph.getSubXFixed(), |
| 621 glyph.getSubYFixed(), | 883 glyph.getSubYFixed(), |
| 622 GrGlyph::kCoverage_MaskStyle
), | 884 GrGlyph::kCoverage_MaskSt
yle), |
| 623 Sk48Dot16FloorToInt(fx), | 885 Sk48Dot16FloorToInt(fx), |
| 624 Sk48Dot16FloorToInt(fy), | 886 Sk48Dot16FloorToInt(fy), |
| 625 color, | 887 color, |
| 626 fontScaler, | 888 fontScaler, |
| 627 clipRect); | 889 clipRect); |
| 628 } | 890 } |
| 629 pos += scalarsPerPosition; | 891 pos += scalarsPerPosition; |
| 630 } | 892 } |
| 631 } else { | 893 } else { |
| 632 while (text < stop) { | 894 while (text < stop) { |
| 633 // the last 2 parameters are ignored | 895 // the last 2 parameters are ignored |
| 634 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 896 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 635 | 897 |
| 636 if (glyph.fWidth) { | 898 if (glyph.fWidth) { |
| 637 SkPoint tmsLoc; | 899 SkPoint tmsLoc; |
| 638 tmsProc(pos, &tmsLoc); | 900 tmsProc(pos, &tmsLoc); |
| 639 | 901 |
| 640 SkPoint alignLoc; | 902 SkPoint alignLoc; |
| 641 alignProc(tmsLoc, glyph, &alignLoc); | 903 alignProc(tmsLoc, glyph, &alignLoc); |
| 642 | 904 |
| 643 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf
); //halfSampleX; | 905 Sk48Dot16 fx = SkScalarTo48Dot16(alignLoc.fX + SK_ScalarHalf
); //halfSampleX; |
| 644 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf
); //halfSampleY; | 906 Sk48Dot16 fy = SkScalarTo48Dot16(alignLoc.fY + SK_ScalarHalf
); //halfSampleY; |
| 645 this->appendGlyph(blob, | 907 this->bmpAppendGlyph(blob, |
| 646 runIndex, | 908 runIndex, |
| 647 GrGlyph::Pack(glyph.getGlyphID(), | 909 GrGlyph::Pack(glyph.getGlyphID(), |
| 648 glyph.getSubXFixed(), | 910 glyph.getSubXFixed(), |
| 649 glyph.getSubYFixed(), | 911 glyph.getSubYFixed(), |
| 650 GrGlyph::kCoverage_MaskStyle
), | 912 GrGlyph::kCoverage_MaskSt
yle), |
| 651 Sk48Dot16FloorToInt(fx), | 913 Sk48Dot16FloorToInt(fx), |
| 652 Sk48Dot16FloorToInt(fy), | 914 Sk48Dot16FloorToInt(fy), |
| 653 color, | 915 color, |
| 654 fontScaler, | 916 fontScaler, |
| 655 clipRect); | 917 clipRect); |
| 656 } | 918 } |
| 657 pos += scalarsPerPosition; | 919 pos += scalarsPerPosition; |
| 658 } | 920 } |
| 659 } | 921 } |
| 660 } | 922 } |
| 661 } | 923 } |
| 662 | 924 |
| 663 void GrAtlasTextContext::appendGlyph(BitmapTextBlob* blob, int runIndex, GrGlyph
::PackedID packed, | 925 |
| 664 int vx, int vy, GrColor color, GrFontScaler
* scaler, | 926 void GrAtlasTextContext::internalDrawDFText(BitmapTextBlob* blob, int runIndex, |
| 665 const SkIRect& clipRect) { | 927 SkGlyphCache* cache, const SkPaint&
skPaint, |
| 666 if (NULL == fCurrStrike) { | 928 GrColor color, |
| 929 const SkMatrix& viewMatrix, |
| 930 const char text[], size_t byteLength
, |
| 931 SkScalar x, SkScalar y, const SkIRec
t& clipRect, |
| 932 SkScalar textRatio, |
| 933 SkTDArray<char>* fallbackTxt, |
| 934 SkTDArray<SkScalar>* fallbackPos, |
| 935 SkPoint* offset, |
| 936 const SkPaint& origPaint) { |
| 937 SkASSERT(byteLength == 0 || text != NULL); |
| 938 |
| 939 // nothing to draw |
| 940 if (text == NULL || byteLength == 0) { |
| 941 return; |
| 942 } |
| 943 |
| 944 SkDrawCacheProc glyphCacheProc = origPaint.getDrawCacheProc(); |
| 945 SkAutoDescriptor desc; |
| 946 origPaint.getScalerContextDescriptor(&desc, &fDeviceProperties, NULL, true); |
| 947 SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(origPaint.getTypefa
ce(), |
| 948 desc.getDesc()); |
| 949 |
| 950 SkTArray<SkScalar> positions; |
| 951 |
| 952 const char* textPtr = text; |
| 953 SkFixed stopX = 0; |
| 954 SkFixed stopY = 0; |
| 955 SkFixed origin = 0; |
| 956 switch (origPaint.getTextAlign()) { |
| 957 case SkPaint::kRight_Align: origin = SK_Fixed1; break; |
| 958 case SkPaint::kCenter_Align: origin = SK_FixedHalf; break; |
| 959 case SkPaint::kLeft_Align: origin = 0; break; |
| 960 } |
| 961 |
| 962 SkAutoKern autokern; |
| 963 const char* stop = text + byteLength; |
| 964 while (textPtr < stop) { |
| 965 // don't need x, y here, since all subpixel variants will have the |
| 966 // same advance |
| 967 const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr, 0, 0); |
| 968 |
| 969 SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph); |
| 970 positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width))); |
| 971 |
| 972 SkFixed height = glyph.fAdvanceY; |
| 973 positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)))
; |
| 974 |
| 975 stopX += width; |
| 976 stopY += height; |
| 977 } |
| 978 SkASSERT(textPtr == stop); |
| 979 |
| 980 // now adjust starting point depending on alignment |
| 981 SkScalar alignX = SkFixedToScalar(stopX); |
| 982 SkScalar alignY = SkFixedToScalar(stopY); |
| 983 if (origPaint.getTextAlign() == SkPaint::kCenter_Align) { |
| 984 alignX = SkScalarHalf(alignX); |
| 985 alignY = SkScalarHalf(alignY); |
| 986 } else if (origPaint.getTextAlign() == SkPaint::kLeft_Align) { |
| 987 alignX = 0; |
| 988 alignY = 0; |
| 989 } |
| 990 x -= alignX; |
| 991 y -= alignY; |
| 992 *offset = SkPoint::Make(x, y); |
| 993 |
| 994 this->internalDrawDFPosText(blob, runIndex, cache, skPaint, color, viewMatri
x, text, byteLength, |
| 995 positions.begin(), 2, *offset, clipRect, textRat
io, fallbackTxt, |
| 996 fallbackPos); |
| 997 SkGlyphCache::AttachCache(origPaintCache); |
| 998 } |
| 999 |
| 1000 void GrAtlasTextContext::internalDrawDFPosText(BitmapTextBlob* blob, int runInde
x, |
| 1001 SkGlyphCache* cache, const SkPain
t& skPaint, |
| 1002 GrColor color, |
| 1003 const SkMatrix& viewMatrix, |
| 1004 const char text[], size_t byteLen
gth, |
| 1005 const SkScalar pos[], int scalars
PerPosition, |
| 1006 const SkPoint& offset, const SkIR
ect& clipRect, |
| 1007 SkScalar textRatio, |
| 1008 SkTDArray<char>* fallbackTxt, |
| 1009 SkTDArray<SkScalar>* fallbackPos)
{ |
| 1010 |
| 1011 SkASSERT(byteLength == 0 || text != NULL); |
| 1012 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
| 1013 |
| 1014 // nothing to draw |
| 1015 if (text == NULL || byteLength == 0) { |
| 1016 return; |
| 1017 } |
| 1018 |
| 1019 fCurrStrike = NULL; |
| 1020 |
| 1021 SkDrawCacheProc glyphCacheProc = skPaint.getDrawCacheProc(); |
| 1022 GrFontScaler* fontScaler = GetGrFontScaler(cache); |
| 1023 |
| 1024 const char* stop = text + byteLength; |
| 1025 |
| 1026 if (SkPaint::kLeft_Align == skPaint.getTextAlign()) { |
| 1027 while (text < stop) { |
| 1028 const char* lastText = text; |
| 1029 // the last 2 parameters are ignored |
| 1030 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 1031 |
| 1032 if (glyph.fWidth) { |
| 1033 SkScalar x = offset.x() + pos[0]; |
| 1034 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; |
| 1035 |
| 1036 if (!this->dfAppendGlyph(blob, |
| 1037 runIndex, |
| 1038 GrGlyph::Pack(glyph.getGlyphID(), |
| 1039 glyph.getSubXFixed(), |
| 1040 glyph.getSubYFixed(), |
| 1041 GrGlyph::kDistance_MaskSt
yle), |
| 1042 x, y, color, fontScaler, clipRect, |
| 1043 textRatio, viewMatrix)) { |
| 1044 // couldn't append, send to fallback |
| 1045 fallbackTxt->append(SkToInt(text-lastText), lastText); |
| 1046 *fallbackPos->append() = pos[0]; |
| 1047 if (2 == scalarsPerPosition) { |
| 1048 *fallbackPos->append() = pos[1]; |
| 1049 } |
| 1050 } |
| 1051 } |
| 1052 pos += scalarsPerPosition; |
| 1053 } |
| 1054 } else { |
| 1055 SkScalar alignMul = SkPaint::kCenter_Align == skPaint.getTextAlign() ? S
K_ScalarHalf |
| 1056 : S
K_Scalar1; |
| 1057 while (text < stop) { |
| 1058 const char* lastText = text; |
| 1059 // the last 2 parameters are ignored |
| 1060 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); |
| 1061 |
| 1062 if (glyph.fWidth) { |
| 1063 SkScalar x = offset.x() + pos[0]; |
| 1064 SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0)
; |
| 1065 |
| 1066 SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul
* textRatio; |
| 1067 SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul
* textRatio; |
| 1068 |
| 1069 if (!this->dfAppendGlyph(blob, |
| 1070 runIndex, |
| 1071 GrGlyph::Pack(glyph.getGlyphID(), |
| 1072 glyph.getSubXFixed(), |
| 1073 glyph.getSubYFixed(), |
| 1074 GrGlyph::kDistance_MaskSt
yle), |
| 1075 x - advanceX, y - advanceY, color, |
| 1076 fontScaler, |
| 1077 clipRect, |
| 1078 textRatio, |
| 1079 viewMatrix)) { |
| 1080 // couldn't append, send to fallback |
| 1081 fallbackTxt->append(SkToInt(text-lastText), lastText); |
| 1082 *fallbackPos->append() = pos[0]; |
| 1083 if (2 == scalarsPerPosition) { |
| 1084 *fallbackPos->append() = pos[1]; |
| 1085 } |
| 1086 } |
| 1087 } |
| 1088 pos += scalarsPerPosition; |
| 1089 } |
| 1090 } |
| 1091 } |
| 1092 |
| 1093 void GrAtlasTextContext::bmpAppendGlyph(BitmapTextBlob* blob, int runIndex, |
| 1094 GrGlyph::PackedID packed, |
| 1095 int vx, int vy, GrColor color, GrFontSca
ler* scaler, |
| 1096 const SkIRect& clipRect) { |
| 1097 if (!fCurrStrike) { |
| 667 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); | 1098 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); |
| 668 } | 1099 } |
| 669 | 1100 |
| 670 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); | 1101 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); |
| 671 if (NULL == glyph || glyph->fBounds.isEmpty()) { | 1102 if (!glyph || glyph->fBounds.isEmpty()) { |
| 672 return; | 1103 return; |
| 673 } | 1104 } |
| 674 | 1105 |
| 675 int x = vx + glyph->fBounds.fLeft; | 1106 int x = vx + glyph->fBounds.fLeft; |
| 676 int y = vy + glyph->fBounds.fTop; | 1107 int y = vy + glyph->fBounds.fTop; |
| 677 | 1108 |
| 678 // keep them as ints until we've done the clip-test | 1109 // keep them as ints until we've done the clip-test |
| 679 int width = glyph->fBounds.width(); | 1110 int width = glyph->fBounds.width(); |
| 680 int height = glyph->fBounds.height(); | 1111 int height = glyph->fBounds.height(); |
| 681 | 1112 |
| 682 #if 0 | 1113 #if 0 |
| 683 // Not checking the clip bounds might introduce a performance regression. H
owever, its not | 1114 // Not checking the clip bounds might introduce a performance regression. H
owever, its not |
| 684 // clear if this is still true today with the larger tiles we use in Chrome.
For repositionable | 1115 // clear if this is still true today with the larger tiles we use in Chrome.
For repositionable |
| 685 // blobs, we want to make sure we have all of the glyphs, so clipping them o
ut is not ideal. | 1116 // blobs, we want to make sure we have all of the glyphs, so clipping them o
ut is not ideal. |
| 686 // We could store the cliprect in the key, but then we'd lose the ability to
do integer scrolls | 1117 // We could store the cliprect in the key, but then we'd lose the ability to
do integer scrolls |
| 687 // TODO verify this | 1118 // TODO verify this |
| 688 // check if we clipped out | 1119 // check if we clipped out |
| 689 if (clipRect.quickReject(x, y, x + width, y + height)) { | 1120 if (clipRect.quickReject(x, y, x + width, y + height)) { |
| 690 return; | 1121 return; |
| 691 } | 1122 } |
| 692 #endif | 1123 #endif |
| 693 | 1124 |
| 694 // If the glyph is too large we fall back to paths | 1125 // If the glyph is too large we fall back to paths |
| 695 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { | 1126 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { |
| 696 if (NULL == glyph->fPath) { | 1127 this->appendGlyphPath(blob, glyph, scaler, vx, vy); |
| 697 SkPath* path = SkNEW(SkPath); | |
| 698 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { | |
| 699 // flag the glyph as being dead? | |
| 700 SkDELETE(path); | |
| 701 return; | |
| 702 } | |
| 703 glyph->fPath = path; | |
| 704 } | |
| 705 SkASSERT(glyph->fPath); | |
| 706 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, vx, v
y)); | |
| 707 return; | 1128 return; |
| 708 } | 1129 } |
| 709 | 1130 |
| 710 Run& run = blob->fRuns[runIndex]; | 1131 Run& run = blob->fRuns[runIndex]; |
| 711 | 1132 |
| 712 GrMaskFormat format = glyph->fMaskFormat; | 1133 GrMaskFormat format = glyph->fMaskFormat; |
| 713 | 1134 |
| 714 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); | 1135 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); |
| 715 if (run.fInitialized && subRun->fMaskFormat != format) { | 1136 if (run.fInitialized && subRun->fMaskFormat != format) { |
| 716 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back(); | 1137 PerSubRunInfo* newSubRun = &run.fSubRunInfo.push_back(); |
| 717 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex; | 1138 newSubRun->fGlyphStartIndex = subRun->fGlyphEndIndex; |
| 718 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex; | 1139 newSubRun->fGlyphEndIndex = subRun->fGlyphEndIndex; |
| 719 | 1140 |
| 720 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex; | 1141 newSubRun->fVertexStartIndex = subRun->fVertexEndIndex; |
| 721 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex; | 1142 newSubRun->fVertexEndIndex = subRun->fVertexEndIndex; |
| 722 | 1143 |
| 723 subRun = newSubRun; | 1144 subRun = newSubRun; |
| 724 } | 1145 } |
| 725 | 1146 |
| 726 run.fInitialized = true; | 1147 run.fInitialized = true; |
| 727 subRun->fMaskFormat = format; | |
| 728 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed; | |
| 729 | 1148 |
| 730 size_t vertexStride = get_vertex_stride(format); | 1149 size_t vertexStride = get_vertex_stride(format); |
| 731 | 1150 |
| 732 SkRect r; | 1151 SkRect r; |
| 733 r.fLeft = SkIntToScalar(x); | 1152 r.fLeft = SkIntToScalar(x); |
| 734 r.fTop = SkIntToScalar(y); | 1153 r.fTop = SkIntToScalar(y); |
| 735 r.fRight = r.fLeft + SkIntToScalar(width); | 1154 r.fRight = r.fLeft + SkIntToScalar(width); |
| 736 r.fBottom = r.fTop + SkIntToScalar(height); | 1155 r.fBottom = r.fTop + SkIntToScalar(height); |
| 1156 subRun->fMaskFormat = format; |
| 1157 this->appendGlyphCommon(blob, &run, subRun, r, color, vertexStride, kA8_GrMa
skFormat == format, |
| 1158 packed); |
| 1159 } |
| 737 | 1160 |
| 738 run.fVertexBounds.joinNonEmptyArg(r); | 1161 bool GrAtlasTextContext::dfAppendGlyph(BitmapTextBlob* blob, int runIndex, |
| 739 run.fColor = color; | 1162 GrGlyph::PackedID packed, |
| 1163 SkScalar sx, SkScalar sy, GrColor color, |
| 1164 GrFontScaler* scaler, |
| 1165 const SkIRect& clipRect, |
| 1166 SkScalar textRatio, const SkMatrix& viewM
atrix) { |
| 1167 if (!fCurrStrike) { |
| 1168 fCurrStrike = fContext->getBatchFontCache()->getStrike(scaler); |
| 1169 } |
| 1170 |
| 1171 GrGlyph* glyph = fCurrStrike->getGlyph(packed, scaler); |
| 1172 if (!glyph || glyph->fBounds.isEmpty()) { |
| 1173 return true; |
| 1174 } |
| 1175 |
| 1176 // fallback to color glyph support |
| 1177 if (kA8_GrMaskFormat != glyph->fMaskFormat) { |
| 1178 return false; |
| 1179 } |
| 1180 |
| 1181 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset); |
| 1182 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset); |
| 1183 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2 * SK_DistanceField
Inset); |
| 1184 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2 * SK_DistanceFie
ldInset); |
| 1185 |
| 1186 SkScalar scale = textRatio; |
| 1187 dx *= scale; |
| 1188 dy *= scale; |
| 1189 width *= scale; |
| 1190 height *= scale; |
| 1191 sx += dx; |
| 1192 sy += dy; |
| 1193 SkRect glyphRect = SkRect::MakeXYWH(sx, sy, width, height); |
| 1194 |
| 1195 #if 0 |
| 1196 // check if we clipped out |
| 1197 SkRect dstRect; |
| 1198 viewMatrix.mapRect(&dstRect, glyphRect); |
| 1199 if (clipRect.quickReject(SkScalarTruncToInt(dstRect.left()), |
| 1200 SkScalarTruncToInt(dstRect.top()), |
| 1201 SkScalarTruncToInt(dstRect.right()), |
| 1202 SkScalarTruncToInt(dstRect.bottom()))) { |
| 1203 return true; |
| 1204 } |
| 1205 #endif |
| 1206 |
| 1207 // TODO combine with the above |
| 1208 // If the glyph is too large we fall back to paths |
| 1209 if (fCurrStrike->glyphTooLargeForAtlas(glyph)) { |
| 1210 this->appendGlyphPath(blob, glyph, scaler, SkScalarRoundToInt(sx - dx), |
| 1211 SkScalarRoundToInt(sy - dy)); |
| 1212 return true; |
| 1213 } |
| 1214 |
| 1215 Run& run = blob->fRuns[runIndex]; |
| 1216 |
| 1217 PerSubRunInfo* subRun = &run.fSubRunInfo.back(); |
| 1218 SkASSERT(glyph->fMaskFormat == kA8_GrMaskFormat); |
| 1219 subRun->fMaskFormat = kA8_GrMaskFormat; |
| 1220 |
| 1221 size_t vertexStride = get_vertex_stride_df(kA8_GrMaskFormat, subRun->fUseLCD
Text); |
| 1222 |
| 1223 bool useColorVerts = !subRun->fUseLCDText; |
| 1224 this->appendGlyphCommon(blob, &run, subRun, glyphRect, color, vertexStride,
useColorVerts, |
| 1225 packed); |
| 1226 return true; |
| 1227 } |
| 1228 |
| 1229 inline void GrAtlasTextContext::appendGlyphPath(BitmapTextBlob* blob, GrGlyph* g
lyph, |
| 1230 GrFontScaler* scaler, int x, int
y) { |
| 1231 if (NULL == glyph->fPath) { |
| 1232 SkPath* path = SkNEW(SkPath); |
| 1233 if (!scaler->getGlyphPath(glyph->glyphID(), path)) { |
| 1234 // flag the glyph as being dead? |
| 1235 SkDELETE(path); |
| 1236 return; |
| 1237 } |
| 1238 glyph->fPath = path; |
| 1239 } |
| 1240 SkASSERT(glyph->fPath); |
| 1241 blob->fBigGlyphs.push_back(BitmapTextBlob::BigGlyph(*glyph->fPath, x, y)); |
| 1242 } |
| 1243 |
| 1244 inline void GrAtlasTextContext::appendGlyphCommon(BitmapTextBlob* blob, Run* run
, |
| 1245 Run::SubRunInfo* subRun, |
| 1246 const SkRect& positions, GrCol
or color, |
| 1247 size_t vertexStride, bool useV
ertexColor, |
| 1248 GrGlyph::PackedID packed) { |
| 1249 blob->fGlyphIDs[subRun->fGlyphEndIndex] = packed; |
| 1250 run->fVertexBounds.joinNonEmptyArg(positions); |
| 1251 run->fColor = color; |
| 740 | 1252 |
| 741 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert
exEndIndex); | 1253 intptr_t vertex = reinterpret_cast<intptr_t>(blob->fVertices + subRun->fVert
exEndIndex); |
| 742 | 1254 |
| 743 // V0 | 1255 // V0 |
| 744 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); | 1256 SkPoint* position = reinterpret_cast<SkPoint*>(vertex); |
| 745 position->set(r.fLeft, r.fTop); | 1257 position->set(positions.fLeft, positions.fTop); |
| 746 if (kA8_GrMaskFormat == format) { | 1258 if (useVertexColor) { |
| 747 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 1259 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
| 748 *colorPtr = color; | 1260 *colorPtr = color; |
| 749 } | 1261 } |
| 750 vertex += vertexStride; | 1262 vertex += vertexStride; |
| 1263 |
| 751 // V1 | 1264 // V1 |
| 752 position = reinterpret_cast<SkPoint*>(vertex); | 1265 position = reinterpret_cast<SkPoint*>(vertex); |
| 753 position->set(r.fLeft, r.fBottom); | 1266 position->set(positions.fLeft, positions.fBottom); |
| 754 if (kA8_GrMaskFormat == format) { | 1267 if (useVertexColor) { |
| 755 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 1268 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
| 756 *colorPtr = color; | 1269 *colorPtr = color; |
| 757 } | 1270 } |
| 758 vertex += vertexStride; | 1271 vertex += vertexStride; |
| 759 | 1272 |
| 760 // V2 | 1273 // V2 |
| 761 position = reinterpret_cast<SkPoint*>(vertex); | 1274 position = reinterpret_cast<SkPoint*>(vertex); |
| 762 position->set(r.fRight, r.fBottom); | 1275 position->set(positions.fRight, positions.fBottom); |
| 763 if (kA8_GrMaskFormat == format) { | 1276 if (useVertexColor) { |
| 764 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 1277 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
| 765 *colorPtr = color; | 1278 *colorPtr = color; |
| 766 } | 1279 } |
| 767 vertex += vertexStride; | 1280 vertex += vertexStride; |
| 768 | 1281 |
| 769 // V3 | 1282 // V3 |
| 770 position = reinterpret_cast<SkPoint*>(vertex); | 1283 position = reinterpret_cast<SkPoint*>(vertex); |
| 771 position->set(r.fRight, r.fTop); | 1284 position->set(positions.fRight, positions.fTop); |
| 772 if (kA8_GrMaskFormat == format) { | 1285 if (useVertexColor) { |
| 773 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; | 1286 SkColor* colorPtr = reinterpret_cast<SkColor*>(vertex + sizeof(SkPoint))
; |
| 774 *colorPtr = color; | 1287 *colorPtr = color; |
| 775 } | 1288 } |
| 776 | 1289 |
| 777 subRun->fGlyphEndIndex++; | 1290 subRun->fGlyphEndIndex++; |
| 778 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; | 1291 subRun->fVertexEndIndex += vertexStride * kVerticesPerGlyph; |
| 779 } | 1292 } |
| 780 | 1293 |
| 781 class BitmapTextBatch : public GrBatch { | 1294 class BitmapTextBatch : public GrBatch { |
| 782 public: | 1295 public: |
| 1296 typedef GrAtlasTextContext::DistanceAdjustTable DistanceAdjustTable; |
| 783 typedef GrAtlasTextContext::BitmapTextBlob Blob; | 1297 typedef GrAtlasTextContext::BitmapTextBlob Blob; |
| 784 typedef Blob::Run Run; | 1298 typedef Blob::Run Run; |
| 785 typedef Run::SubRunInfo TextInfo; | 1299 typedef Run::SubRunInfo TextInfo; |
| 786 struct Geometry { | 1300 struct Geometry { |
| 787 Blob* fBlob; | 1301 Blob* fBlob; |
| 788 int fRun; | 1302 int fRun; |
| 789 int fSubRun; | 1303 int fSubRun; |
| 790 GrColor fColor; | 1304 GrColor fColor; |
| 791 SkScalar fTransX; | 1305 SkScalar fTransX; |
| 792 SkScalar fTransY; | 1306 SkScalar fTransY; |
| 793 }; | 1307 }; |
| 794 | 1308 |
| 795 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, | 1309 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, |
| 796 GrBatchFontCache* fontCache) { | 1310 GrBatchFontCache* fontCache) { |
| 797 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache)); | 1311 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache)); |
| 798 } | 1312 } |
| 799 | 1313 |
| 1314 static BitmapTextBatch* Create(GrMaskFormat maskFormat, int glyphCount, |
| 1315 GrBatchFontCache* fontCache, |
| 1316 DistanceAdjustTable* distanceAdjustTable, |
| 1317 SkColor filteredColor, bool useLCDText, |
| 1318 bool useBGR, float gamma) { |
| 1319 return SkNEW_ARGS(BitmapTextBatch, (maskFormat, glyphCount, fontCache, d
istanceAdjustTable, |
| 1320 filteredColor, useLCDText, useBGR, g
amma)); |
| 1321 } |
| 1322 |
| 800 const char* name() const override { return "BitmapTextBatch"; } | 1323 const char* name() const override { return "BitmapTextBatch"; } |
| 801 | 1324 |
| 802 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { | 1325 void getInvariantOutputColor(GrInitInvariantOutput* out) const override { |
| 803 if (kARGB_GrMaskFormat == fMaskFormat) { | 1326 if (kARGB_GrMaskFormat == fMaskFormat) { |
| 804 out->setUnknownFourComponents(); | 1327 out->setUnknownFourComponents(); |
| 805 } else { | 1328 } else { |
| 806 out->setKnownFourComponents(fBatch.fColor); | 1329 out->setKnownFourComponents(fBatch.fColor); |
| 807 } | 1330 } |
| 808 } | 1331 } |
| 809 | 1332 |
| 810 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { | 1333 void getInvariantOutputCoverage(GrInitInvariantOutput* out) const override { |
| 811 if (kARGB_GrMaskFormat != fMaskFormat) { | 1334 if (!fUseDistanceFields) { |
| 812 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) { | 1335 // Bitmap Text |
| 1336 if (kARGB_GrMaskFormat != fMaskFormat) { |
| 1337 if (GrPixelConfigIsAlphaOnly(fPixelConfig)) { |
| 1338 out->setUnknownSingleComponent(); |
| 1339 } else if (GrPixelConfigIsOpaque(fPixelConfig)) { |
| 1340 out->setUnknownOpaqueFourComponents(); |
| 1341 out->setUsingLCDCoverage(); |
| 1342 } else { |
| 1343 out->setUnknownFourComponents(); |
| 1344 out->setUsingLCDCoverage(); |
| 1345 } |
| 1346 } else { |
| 1347 out->setKnownSingleComponent(0xff); |
| 1348 } |
| 1349 } else { |
| 1350 // Distance fields |
| 1351 if (!fUseLCDText) { |
| 813 out->setUnknownSingleComponent(); | 1352 out->setUnknownSingleComponent(); |
| 814 } else if (GrPixelConfigIsOpaque(fPixelConfig)) { | |
| 815 out->setUnknownOpaqueFourComponents(); | |
| 816 out->setUsingLCDCoverage(); | |
| 817 } else { | 1353 } else { |
| 818 out->setUnknownFourComponents(); | 1354 out->setUnknownFourComponents(); |
| 819 out->setUsingLCDCoverage(); | 1355 out->setUsingLCDCoverage(); |
| 820 } | 1356 } |
| 821 } else { | |
| 822 out->setKnownSingleComponent(0xff); | |
| 823 } | 1357 } |
| 824 } | 1358 } |
| 825 | 1359 |
| 826 void initBatchTracker(const GrPipelineInfo& init) override { | 1360 void initBatchTracker(const GrPipelineInfo& init) override { |
| 827 // Handle any color overrides | 1361 // Handle any color overrides |
| 828 if (init.fColorIgnored) { | 1362 if (init.fColorIgnored) { |
| 829 fBatch.fColor = GrColor_ILLEGAL; | 1363 fBatch.fColor = GrColor_ILLEGAL; |
| 830 } else if (GrColor_ILLEGAL != init.fOverrideColor) { | 1364 } else if (GrColor_ILLEGAL != init.fOverrideColor) { |
| 831 fBatch.fColor = init.fOverrideColor; | 1365 fBatch.fColor = init.fOverrideColor; |
| 832 } | 1366 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 845 SkDebugf("Cannot invert viewmatrix\n"); | 1379 SkDebugf("Cannot invert viewmatrix\n"); |
| 846 return; | 1380 return; |
| 847 } | 1381 } |
| 848 | 1382 |
| 849 GrTexture* texture = fFontCache->getTexture(fMaskFormat); | 1383 GrTexture* texture = fFontCache->getTexture(fMaskFormat); |
| 850 if (!texture) { | 1384 if (!texture) { |
| 851 SkDebugf("Could not allocate backing texture for atlas\n"); | 1385 SkDebugf("Could not allocate backing texture for atlas\n"); |
| 852 return; | 1386 return; |
| 853 } | 1387 } |
| 854 | 1388 |
| 855 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kNone
_FilterMode); | 1389 SkAutoTUnref<const GrGeometryProcessor> gp; |
| 1390 if (fUseDistanceFields) { |
| 1391 gp.reset(this->setupDfProcessor(this->viewMatrix(), fFilteredColor,
this->color(), |
| 1392 texture)); |
| 1393 } else { |
| 1394 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::k
None_FilterMode); |
| 856 | 1395 |
| 857 // This will be ignored in the non A8 case | 1396 // This will be ignored in the non A8 case |
| 858 bool opaqueVertexColors = GrColorIsOpaque(this->color()); | 1397 bool opaqueVertexColors = GrColorIsOpaque(this->color()); |
| 859 SkAutoTUnref<const GrGeometryProcessor> gp( | 1398 gp.reset(GrBitmapTextGeoProc::Create(this->color(), |
| 860 GrBitmapTextGeoProc::Create(this->color(), | 1399 texture, |
| 861 texture, | 1400 params, |
| 862 params, | 1401 fMaskFormat, |
| 863 fMaskFormat, | 1402 opaqueVertexColors, |
| 864 opaqueVertexColors, | 1403 localMatrix)); |
| 865 localMatrix)); | 1404 } |
| 866 | 1405 |
| 867 size_t vertexStride = gp->getVertexStride(); | 1406 size_t vertexStride = gp->getVertexStride(); |
| 868 SkASSERT(vertexStride == get_vertex_stride(fMaskFormat)); | 1407 SkASSERT(vertexStride == (fUseDistanceFields ? |
| 1408 get_vertex_stride_df(fMaskFormat, fUseLCDText)
: |
| 1409 get_vertex_stride(fMaskFormat))); |
| 869 | 1410 |
| 870 this->initDraw(batchTarget, gp, pipeline); | 1411 this->initDraw(batchTarget, gp, pipeline); |
| 871 | 1412 |
| 872 int glyphCount = this->numGlyphs(); | 1413 int glyphCount = this->numGlyphs(); |
| 873 int instanceCount = fInstanceCount; | 1414 int instanceCount = fInstanceCount; |
| 874 const GrVertexBuffer* vertexBuffer; | 1415 const GrVertexBuffer* vertexBuffer; |
| 875 int firstVertex; | 1416 int firstVertex; |
| 876 | 1417 |
| 877 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, | 1418 void* vertices = batchTarget->vertexPool()->makeSpace(vertexStride, |
| 878 glyphCount * kVert
icesPerGlyph, | 1419 glyphCount * kVert
icesPerGlyph, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 901 | 1442 |
| 902 int instancesToFlush = 0; | 1443 int instancesToFlush = 0; |
| 903 for (int i = 0; i < instanceCount; i++) { | 1444 for (int i = 0; i < instanceCount; i++) { |
| 904 Geometry& args = fGeoData[i]; | 1445 Geometry& args = fGeoData[i]; |
| 905 Blob* blob = args.fBlob; | 1446 Blob* blob = args.fBlob; |
| 906 Run& run = blob->fRuns[args.fRun]; | 1447 Run& run = blob->fRuns[args.fRun]; |
| 907 TextInfo& info = run.fSubRunInfo[args.fSubRun]; | 1448 TextInfo& info = run.fSubRunInfo[args.fSubRun]; |
| 908 | 1449 |
| 909 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); | 1450 uint64_t currentAtlasGen = fFontCache->atlasGeneration(fMaskFormat); |
| 910 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas
Gen; | 1451 bool regenerateTextureCoords = info.fAtlasGeneration != currentAtlas
Gen; |
| 911 bool regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColo
r != args.fColor; | 1452 bool regenerateColors; |
| 1453 if (fUseDistanceFields) { |
| 1454 regenerateColors = fUseLCDText && run.fColor != args.fColor; |
| 1455 } else { |
| 1456 regenerateColors = kA8_GrMaskFormat == fMaskFormat && run.fColor
!= args.fColor; |
| 1457 } |
| 912 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.
f; | 1458 bool regeneratePositions = args.fTransX != 0.f || args.fTransY != 0.
f; |
| 913 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 1459 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 914 | 1460 |
| 915 // We regenerate both texture coords and colors in the blob itself,
and update the | 1461 // We regenerate both texture coords and colors in the blob itself,
and update the |
| 916 // atlas generation. If we don't end up purging any unused plots, w
e can avoid | 1462 // atlas generation. If we don't end up purging any unused plots, w
e can avoid |
| 917 // regenerating the coords. We could take a finer grained approach
to updating texture | 1463 // regenerating the coords. We could take a finer grained approach
to updating texture |
| 918 // coords but its not clear if the extra bookkeeping would offset an
y gains. | 1464 // coords but its not clear if the extra bookkeeping would offset an
y gains. |
| 919 // To avoid looping over the glyphs twice, we do one loop and condit
ionally update color | 1465 // To avoid looping over the glyphs twice, we do one loop and condit
ionally update color |
| 920 // or coords as needed. One final note, if we have to break a run f
or an atlas eviction | 1466 // or coords as needed. One final note, if we have to break a run f
or an atlas eviction |
| 921 // then we can't really trust the atlas has all of the correct data.
Atlas evictions | 1467 // then we can't really trust the atlas has all of the correct data.
Atlas evictions |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1022 // to avoid even the initial copy of the struct, we have a getter for the fi
rst item which | 1568 // to avoid even the initial copy of the struct, we have a getter for the fi
rst item which |
| 1023 // is used to seed the batch with its initial geometry. After seeding, the
client should call | 1569 // is used to seed the batch with its initial geometry. After seeding, the
client should call |
| 1024 // init() so the Batch can initialize itself | 1570 // init() so the Batch can initialize itself |
| 1025 Geometry& geometry() { return fGeoData[0]; } | 1571 Geometry& geometry() { return fGeoData[0]; } |
| 1026 void init() { | 1572 void init() { |
| 1027 fBatch.fColor = fGeoData[0].fColor; | 1573 fBatch.fColor = fGeoData[0].fColor; |
| 1028 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix; | 1574 fBatch.fViewMatrix = fGeoData[0].fBlob->fViewMatrix; |
| 1029 } | 1575 } |
| 1030 | 1576 |
| 1031 private: | 1577 private: |
| 1032 BitmapTextBatch(GrMaskFormat maskFormat, | 1578 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f
ontCache) |
| 1033 int glyphCount, GrBatchFontCache* fontCache) | |
| 1034 : fMaskFormat(maskFormat) | 1579 : fMaskFormat(maskFormat) |
| 1035 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) | 1580 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) |
| 1036 , fFontCache(fontCache) { | 1581 , fFontCache(fontCache) |
| 1582 , fUseDistanceFields(false) { |
| 1037 this->initClassID<BitmapTextBatch>(); | 1583 this->initClassID<BitmapTextBatch>(); |
| 1038 fBatch.fNumGlyphs = glyphCount; | 1584 fBatch.fNumGlyphs = glyphCount; |
| 1039 fInstanceCount = 1; | 1585 fInstanceCount = 1; |
| 1040 fAllocatedCount = kMinAllocated; | 1586 fAllocatedCount = kMinAllocated; |
| 1041 } | 1587 } |
| 1042 | 1588 |
| 1589 BitmapTextBatch(GrMaskFormat maskFormat, int glyphCount, GrBatchFontCache* f
ontCache, |
| 1590 DistanceAdjustTable* distanceAdjustTable, SkColor filteredCo
lor, |
| 1591 bool useLCDText, bool useBGR, float gamma) |
| 1592 : fMaskFormat(maskFormat) |
| 1593 , fPixelConfig(fontCache->getPixelConfig(maskFormat)) |
| 1594 , fFontCache(fontCache) |
| 1595 , fDistanceAdjustTable(SkRef(distanceAdjustTable)) |
| 1596 , fFilteredColor(filteredColor) |
| 1597 , fUseDistanceFields(true) |
| 1598 , fUseLCDText(useLCDText) |
| 1599 , fUseBGR(useBGR) |
| 1600 , fGamma(gamma) { |
| 1601 this->initClassID<BitmapTextBatch>(); |
| 1602 fBatch.fNumGlyphs = glyphCount; |
| 1603 fInstanceCount = 1; |
| 1604 fAllocatedCount = kMinAllocated; |
| 1605 SkASSERT(fMaskFormat == kA8_GrMaskFormat); |
| 1606 } |
| 1607 |
| 1043 ~BitmapTextBatch() { | 1608 ~BitmapTextBatch() { |
| 1044 for (int i = 0; i < fInstanceCount; i++) { | 1609 for (int i = 0; i < fInstanceCount; i++) { |
| 1045 fGeoData[i].fBlob->unref(); | 1610 fGeoData[i].fBlob->unref(); |
| 1046 } | 1611 } |
| 1047 } | 1612 } |
| 1048 | 1613 |
| 1049 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS
tride) { | 1614 void regenerateTextureCoords(GrGlyph* glyph, intptr_t vertex, size_t vertexS
tride) { |
| 1050 int width = glyph->fBounds.width(); | 1615 int width = glyph->fBounds.width(); |
| 1051 int height = glyph->fBounds.height(); | 1616 int height = glyph->fBounds.height(); |
| 1052 int u0 = glyph->fAtlasLocation.fX; | |
| 1053 int v0 = glyph->fAtlasLocation.fY; | |
| 1054 int u1 = u0 + width; | |
| 1055 int v1 = v0 + height; | |
| 1056 | 1617 |
| 1057 // we assume texture coords are the last vertex attribute, this is a bit
fragile. | 1618 int u0, v0, u1, v1; |
| 1058 // TODO pass in this offset or something | 1619 if (fUseDistanceFields) { |
| 1620 u0 = glyph->fAtlasLocation.fX + SK_DistanceFieldInset; |
| 1621 v0 = glyph->fAtlasLocation.fY + SK_DistanceFieldInset; |
| 1622 u1 = u0 + width - 2 * SK_DistanceFieldInset; |
| 1623 v1 = v0 + height - 2 * SK_DistanceFieldInset; |
| 1624 } else { |
| 1625 u0 = glyph->fAtlasLocation.fX; |
| 1626 v0 = glyph->fAtlasLocation.fY; |
| 1627 u1 = u0 + width; |
| 1628 v1 = v0 + height; |
| 1629 } |
| 1630 |
| 1059 SkIPoint16* textureCoords; | 1631 SkIPoint16* textureCoords; |
| 1060 // V0 | 1632 // V0 |
| 1061 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | 1633 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
| 1062 textureCoords->set(u0, v0); | 1634 textureCoords->set(u0, v0); |
| 1063 vertex += vertexStride; | 1635 vertex += vertexStride; |
| 1064 | 1636 |
| 1065 // V1 | 1637 // V1 |
| 1066 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); | 1638 textureCoords = reinterpret_cast<SkIPoint16*>(vertex); |
| 1067 textureCoords->set(u0, v1); | 1639 textureCoords->set(u0, v1); |
| 1068 vertex += vertexStride; | 1640 vertex += vertexStride; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1126 } | 1698 } |
| 1127 | 1699 |
| 1128 GrColor color() const { return fBatch.fColor; } | 1700 GrColor color() const { return fBatch.fColor; } |
| 1129 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } | 1701 const SkMatrix& viewMatrix() const { return fBatch.fViewMatrix; } |
| 1130 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } | 1702 bool usesLocalCoords() const { return fBatch.fUsesLocalCoords; } |
| 1131 int numGlyphs() const { return fBatch.fNumGlyphs; } | 1703 int numGlyphs() const { return fBatch.fNumGlyphs; } |
| 1132 | 1704 |
| 1133 bool onCombineIfPossible(GrBatch* t) override { | 1705 bool onCombineIfPossible(GrBatch* t) override { |
| 1134 BitmapTextBatch* that = t->cast<BitmapTextBatch>(); | 1706 BitmapTextBatch* that = t->cast<BitmapTextBatch>(); |
| 1135 | 1707 |
| 1136 if (this->fMaskFormat != that->fMaskFormat) { | 1708 if (fUseDistanceFields != that->fUseDistanceFields) { |
| 1137 return false; | 1709 return false; |
| 1138 } | 1710 } |
| 1139 | 1711 |
| 1140 if (this->fMaskFormat != kA8_GrMaskFormat && this->color() != that->colo
r()) { | 1712 if (!fUseDistanceFields) { |
| 1141 return false; | 1713 // Bitmap Text |
| 1142 } | 1714 if (fMaskFormat != that->fMaskFormat) { |
| 1715 return false; |
| 1716 } |
| 1143 | 1717 |
| 1144 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that->vi
ewMatrix())) { | 1718 // TODO we can often batch across LCD text if we have dual source bl
ending and don't |
| 1145 return false; | 1719 // have to use the blend constant |
| 1720 if (fMaskFormat != kA8_GrMaskFormat && this->color() != that->color(
)) { |
| 1721 return false; |
| 1722 } |
| 1723 |
| 1724 if (this->usesLocalCoords() && !this->viewMatrix().cheapEqualTo(that
->viewMatrix())) { |
| 1725 return false; |
| 1726 } |
| 1727 } else { |
| 1728 // Distance Fields |
| 1729 SkASSERT(this->fMaskFormat == that->fMaskFormat && |
| 1730 this->fMaskFormat == kA8_GrMaskFormat); |
| 1731 |
| 1732 if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) { |
| 1733 return false; |
| 1734 } |
| 1735 |
| 1736 if (fFilteredColor != that->fFilteredColor) { |
| 1737 return false; |
| 1738 } |
| 1739 |
| 1740 if (fUseLCDText != that->fUseLCDText) { |
| 1741 return false; |
| 1742 } |
| 1743 |
| 1744 if (fUseBGR != that->fUseBGR) { |
| 1745 return false; |
| 1746 } |
| 1747 |
| 1748 if (fGamma != that->fGamma) { |
| 1749 return false; |
| 1750 } |
| 1751 |
| 1752 // TODO see note above |
| 1753 if (fUseLCDText && this->color() != that->color()) { |
| 1754 return false; |
| 1755 } |
| 1146 } | 1756 } |
| 1147 | 1757 |
| 1148 fBatch.fNumGlyphs += that->numGlyphs(); | 1758 fBatch.fNumGlyphs += that->numGlyphs(); |
| 1149 | 1759 |
| 1150 // copy that->geoData(). We do this manually for performance reasons | 1760 // copy that->geoData(). We do this manually for performance reasons |
| 1151 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData(); | 1761 SkAutoSTMalloc<kMinAllocated, Geometry>* otherGeoData = that->geoData(); |
| 1152 int otherInstanceCount = that->instanceCount(); | 1762 int otherInstanceCount = that->instanceCount(); |
| 1153 int allocSize = otherInstanceCount + fInstanceCount; | 1763 int allocSize = otherInstanceCount + fInstanceCount; |
| 1154 if (allocSize > fAllocatedCount) { | 1764 if (allocSize > fAllocatedCount) { |
| 1155 while (allocSize > fAllocatedCount) { | 1765 while (allocSize > fAllocatedCount) { |
| 1156 fAllocatedCount = fAllocatedCount << 1; | 1766 fAllocatedCount = fAllocatedCount << 1; |
| 1157 } | 1767 } |
| 1158 fGeoData.realloc(fAllocatedCount); | 1768 fGeoData.realloc(fAllocatedCount); |
| 1159 } | 1769 } |
| 1160 | 1770 |
| 1161 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(), | 1771 memcpy(&fGeoData[fInstanceCount], otherGeoData->get(), |
| 1162 otherInstanceCount * sizeof(Geometry)); | 1772 otherInstanceCount * sizeof(Geometry)); |
| 1163 int total = fInstanceCount + otherInstanceCount; | 1773 int total = fInstanceCount + otherInstanceCount; |
| 1164 for (int i = fInstanceCount; i < total; i++) { | 1774 for (int i = fInstanceCount; i < total; i++) { |
| 1165 fGeoData[i].fBlob->ref(); | 1775 fGeoData[i].fBlob->ref(); |
| 1166 } | 1776 } |
| 1167 fInstanceCount = total; | 1777 fInstanceCount = total; |
| 1168 return true; | 1778 return true; |
| 1169 } | 1779 } |
| 1170 | 1780 |
| 1781 // TODO just use class params |
| 1782 // TODO trying to figure out why lcd is so whack |
| 1783 GrGeometryProcessor* setupDfProcessor(const SkMatrix& viewMatrix, SkColor fi
lteredColor, |
| 1784 GrColor color, GrTexture* texture) { |
| 1785 GrTextureParams params(SkShader::kClamp_TileMode, GrTextureParams::kBile
rp_FilterMode); |
| 1786 |
| 1787 // set up any flags |
| 1788 uint32_t flags = 0; |
| 1789 flags |= viewMatrix.isSimilarity() ? kSimilarity_DistanceFieldEffectFlag
: 0; |
| 1790 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0; |
| 1791 flags |= fUseLCDText && viewMatrix.rectStaysRect() ? |
| 1792 kRectToRect_DistanceFieldEffectFlag : 0; |
| 1793 flags |= fUseLCDText && fUseBGR ? kBGR_DistanceFieldEffectFlag : 0; |
| 1794 |
| 1795 // see if we need to create a new effect |
| 1796 if (fUseLCDText) { |
| 1797 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredCol
or); |
| 1798 |
| 1799 float redCorrection = |
| 1800 (*fDistanceAdjustTable)[GrColorUnpackR(colorNoPreMul) >> kDistan
ceAdjustLumShift]; |
| 1801 float greenCorrection = |
| 1802 (*fDistanceAdjustTable)[GrColorUnpackG(colorNoPreMul) >> kDistan
ceAdjustLumShift]; |
| 1803 float blueCorrection = |
| 1804 (*fDistanceAdjustTable)[GrColorUnpackB(colorNoPreMul) >> kDistan
ceAdjustLumShift]; |
| 1805 GrDistanceFieldLCDTextGeoProc::DistanceAdjust widthAdjust = |
| 1806 GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(redCorrectio
n, |
| 1807 greenCorrect
ion, |
| 1808 blueCorrecti
on); |
| 1809 |
| 1810 return GrDistanceFieldLCDTextGeoProc::Create(color, |
| 1811 viewMatrix, |
| 1812 texture, |
| 1813 params, |
| 1814 widthAdjust, |
| 1815 flags); |
| 1816 } else { |
| 1817 flags |= kColorAttr_DistanceFieldEffectFlag; |
| 1818 bool opaque = GrColorIsOpaque(color); |
| 1819 #ifdef SK_GAMMA_APPLY_TO_A8 |
| 1820 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fGamma, filtered
Color); |
| 1821 float correction = (*fDistanceAdjustTable)[lum >> kDistanceAdjustLum
Shift]; |
| 1822 return GrDistanceFieldA8TextGeoProc::Create(color, |
| 1823 viewMatrix, |
| 1824 texture, |
| 1825 params, |
| 1826 correction, |
| 1827 flags, |
| 1828 opaque); |
| 1829 #else |
| 1830 return GrDistanceFieldA8TextGeoProc::Create(color, |
| 1831 viewMatrix, |
| 1832 texture, |
| 1833 params, |
| 1834 flags, |
| 1835 opaque); |
| 1836 #endif |
| 1837 } |
| 1838 |
| 1839 } |
| 1840 |
| 1171 struct BatchTracker { | 1841 struct BatchTracker { |
| 1172 GrColor fColor; | 1842 GrColor fColor; |
| 1173 SkMatrix fViewMatrix; | 1843 SkMatrix fViewMatrix; |
| 1174 bool fUsesLocalCoords; | 1844 bool fUsesLocalCoords; |
| 1175 bool fColorIgnored; | 1845 bool fColorIgnored; |
| 1176 bool fCoverageIgnored; | 1846 bool fCoverageIgnored; |
| 1177 int fNumGlyphs; | 1847 int fNumGlyphs; |
| 1178 }; | 1848 }; |
| 1179 | 1849 |
| 1180 BatchTracker fBatch; | 1850 BatchTracker fBatch; |
| 1181 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData; | 1851 SkAutoSTMalloc<kMinAllocated, Geometry> fGeoData; |
| 1182 int fInstanceCount; | 1852 int fInstanceCount; |
| 1183 int fAllocatedCount; | 1853 int fAllocatedCount; |
| 1184 GrMaskFormat fMaskFormat; | 1854 GrMaskFormat fMaskFormat; |
| 1185 GrPixelConfig fPixelConfig; | 1855 GrPixelConfig fPixelConfig; |
| 1186 GrBatchFontCache* fFontCache; | 1856 GrBatchFontCache* fFontCache; |
| 1857 |
| 1858 // Distance field properties |
| 1859 SkAutoTUnref<DistanceAdjustTable> fDistanceAdjustTable; |
| 1860 SkColor fFilteredColor; |
| 1861 bool fUseDistanceFields; |
| 1862 bool fUseLCDText; |
| 1863 bool fUseBGR; |
| 1864 float fGamma; |
| 1187 }; | 1865 }; |
| 1188 | 1866 |
| 1189 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons
t SkPaint& skPaint, | 1867 void GrAtlasTextContext::flushRunAsPaths(const SkTextBlob::RunIterator& it, cons
t SkPaint& skPaint, |
| 1190 SkDrawFilter* drawFilter, const SkMatri
x& viewMatrix, | 1868 SkDrawFilter* drawFilter, const SkMatri
x& viewMatrix, |
| 1191 const SkIRect& clipBounds, SkScalar x,
SkScalar y) { | 1869 const SkIRect& clipBounds, SkScalar x,
SkScalar y) { |
| 1192 SkPaint runPaint = skPaint; | 1870 SkPaint runPaint = skPaint; |
| 1193 | 1871 |
| 1194 size_t textLen = it.glyphCount() * sizeof(uint16_t); | 1872 size_t textLen = it.glyphCount() * sizeof(uint16_t); |
| 1195 const SkPoint& offset = it.offset(); | 1873 const SkPoint& offset = it.offset(); |
| 1196 | 1874 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1214 break; | 1892 break; |
| 1215 case SkTextBlob::kFull_Positioning: | 1893 case SkTextBlob::kFull_Positioning: |
| 1216 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs
(), | 1894 this->drawPosTextAsPath(runPaint, viewMatrix, (const char*)it.glyphs
(), |
| 1217 textLen, it.pos(), 2, SkPoint::Make(x, y), c
lipBounds); | 1895 textLen, it.pos(), 2, SkPoint::Make(x, y), c
lipBounds); |
| 1218 break; | 1896 break; |
| 1219 } | 1897 } |
| 1220 } | 1898 } |
| 1221 | 1899 |
| 1222 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
* pipelineBuilder, | 1900 inline void GrAtlasTextContext::flushRun(GrDrawTarget* target, GrPipelineBuilder
* pipelineBuilder, |
| 1223 BitmapTextBlob* cacheBlob, int run, GrC
olor color, | 1901 BitmapTextBlob* cacheBlob, int run, GrC
olor color, |
| 1224 uint8_t paintAlpha, SkScalar transX, Sk
Scalar transY) { | 1902 SkScalar transX, SkScalar transY, const
SkPaint& skPaint) { |
| 1225 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub
Run++) { | 1903 for (int subRun = 0; subRun < cacheBlob->fRuns[run].fSubRunInfo.count(); sub
Run++) { |
| 1226 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; | 1904 const PerSubRunInfo& info = cacheBlob->fRuns[run].fSubRunInfo[subRun]; |
| 1227 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; | 1905 int glyphCount = info.fGlyphEndIndex - info.fGlyphStartIndex; |
| 1228 if (0 == glyphCount) { | 1906 if (0 == glyphCount) { |
| 1229 continue; | 1907 continue; |
| 1230 } | 1908 } |
| 1231 | 1909 |
| 1232 GrMaskFormat format = info.fMaskFormat; | 1910 GrMaskFormat format = info.fMaskFormat; |
| 1233 GrColor subRunColor = kARGB_GrMaskFormat == format ? | 1911 GrColor subRunColor; |
| 1234 SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha,
paintAlpha) : | 1912 if (kARGB_GrMaskFormat == format) { |
| 1235 color; | 1913 uint8_t paintAlpha = skPaint.getAlpha(); |
| 1914 subRunColor = SkColorSetARGB(paintAlpha, paintAlpha, paintAlpha, pai
ntAlpha); |
| 1915 } else { |
| 1916 subRunColor = color; |
| 1917 } |
| 1236 | 1918 |
| 1237 SkAutoTUnref<BitmapTextBatch> batch(BitmapTextBatch::Create(format, glyp
hCount, | 1919 SkAutoTUnref<BitmapTextBatch> batch; |
| 1238 fContext->getBatchFo
ntCache())); | 1920 if (info.fDrawAsDistanceFields) { |
| 1921 SkColor filteredColor; |
| 1922 SkColorFilter* colorFilter = skPaint.getColorFilter(); |
| 1923 if (colorFilter) { |
| 1924 filteredColor = colorFilter->filterColor(skPaint.getColor()); |
| 1925 } else { |
| 1926 filteredColor = skPaint.getColor(); |
| 1927 } |
| 1928 bool useBGR = SkPixelGeometryIsBGR(fDeviceProperties.pixelGeometry()
); |
| 1929 float gamma = fDeviceProperties.gamma(); |
| 1930 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge
tBatchFontCache(), |
| 1931 fDistanceAdjustTable, filteredCo
lor, |
| 1932 info.fUseLCDText, useBGR, |
| 1933 gamma)); |
| 1934 } else { |
| 1935 batch.reset(BitmapTextBatch::Create(format, glyphCount, fContext->ge
tBatchFontCache())); |
| 1936 } |
| 1239 BitmapTextBatch::Geometry& geometry = batch->geometry(); | 1937 BitmapTextBatch::Geometry& geometry = batch->geometry(); |
| 1240 geometry.fBlob = SkRef(cacheBlob); | 1938 geometry.fBlob = SkRef(cacheBlob); |
| 1241 geometry.fRun = run; | 1939 geometry.fRun = run; |
| 1242 geometry.fSubRun = subRun; | 1940 geometry.fSubRun = subRun; |
| 1243 geometry.fColor = subRunColor; | 1941 geometry.fColor = subRunColor; |
| 1244 geometry.fTransX = transX; | 1942 geometry.fTransX = transX; |
| 1245 geometry.fTransY = transY; | 1943 geometry.fTransY = transY; |
| 1246 batch->init(); | 1944 batch->init(); |
| 1247 | 1945 |
| 1248 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex
Bounds); | 1946 target->drawBatch(pipelineBuilder, batch, &cacheBlob->fRuns[run].fVertex
Bounds); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1277 const SkMatrix& viewMatrix, | 1975 const SkMatrix& viewMatrix, |
| 1278 const SkIRect& clipBounds, | 1976 const SkIRect& clipBounds, |
| 1279 SkScalar x, SkScalar y, | 1977 SkScalar x, SkScalar y, |
| 1280 SkScalar transX, SkScalar transY) { | 1978 SkScalar transX, SkScalar transY) { |
| 1281 // We loop through the runs of the blob, flushing each. If any run is too l
arge, then we flush | 1979 // We loop through the runs of the blob, flushing each. If any run is too l
arge, then we flush |
| 1282 // it as paths | 1980 // it as paths |
| 1283 GrPipelineBuilder pipelineBuilder; | 1981 GrPipelineBuilder pipelineBuilder; |
| 1284 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 1982 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1285 | 1983 |
| 1286 GrColor color = grPaint.getColor(); | 1984 GrColor color = grPaint.getColor(); |
| 1287 uint8_t paintAlpha = skPaint.getAlpha(); | |
| 1288 | 1985 |
| 1289 SkTextBlob::RunIterator it(blob); | 1986 SkTextBlob::RunIterator it(blob); |
| 1290 for (int run = 0; !it.done(); it.next(), run++) { | 1987 for (int run = 0; !it.done(); it.next(), run++) { |
| 1291 if (cacheBlob->fRuns[run].fDrawAsPaths) { | 1988 if (cacheBlob->fRuns[run].fDrawAsPaths) { |
| 1292 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound
s, x, y); | 1989 this->flushRunAsPaths(it, skPaint, drawFilter, viewMatrix, clipBound
s, x, y); |
| 1293 continue; | 1990 continue; |
| 1294 } | 1991 } |
| 1295 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); | 1992 cacheBlob->fRuns[run].fVertexBounds.offset(transX, transY); |
| 1296 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, transX, transY); | 1993 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, transX,
transY, skPaint); |
| 1297 } | 1994 } |
| 1298 | 1995 |
| 1299 // Now flush big glyphs | 1996 // Now flush big glyphs |
| 1300 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); | 1997 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, transX, transY); |
| 1301 } | 1998 } |
| 1302 | 1999 |
| 1303 void GrAtlasTextContext::flush(GrDrawTarget* target, | 2000 void GrAtlasTextContext::flush(GrDrawTarget* target, |
| 1304 BitmapTextBlob* cacheBlob, | 2001 BitmapTextBlob* cacheBlob, |
| 1305 GrRenderTarget* rt, | 2002 GrRenderTarget* rt, |
| 1306 const SkPaint& skPaint, | 2003 const SkPaint& skPaint, |
| 1307 const GrPaint& grPaint, | 2004 const GrPaint& grPaint, |
| 1308 const GrClip& clip, | 2005 const GrClip& clip) { |
| 1309 const SkMatrix& viewMatrix) { | |
| 1310 GrPipelineBuilder pipelineBuilder; | 2006 GrPipelineBuilder pipelineBuilder; |
| 1311 pipelineBuilder.setFromPaint(grPaint, rt, clip); | 2007 pipelineBuilder.setFromPaint(grPaint, rt, clip); |
| 1312 | 2008 |
| 1313 GrColor color = grPaint.getColor(); | 2009 GrColor color = grPaint.getColor(); |
| 1314 uint8_t paintAlpha = skPaint.getAlpha(); | |
| 1315 for (int run = 0; run < cacheBlob->fRunCount; run++) { | 2010 for (int run = 0; run < cacheBlob->fRunCount; run++) { |
| 1316 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, paintAlp
ha, 0, 0); | 2011 this->flushRun(target, &pipelineBuilder, cacheBlob, run, color, 0, 0, sk
Paint); |
| 1317 } | 2012 } |
| 1318 | 2013 |
| 1319 // Now flush big glyphs | 2014 // Now flush big glyphs |
| 1320 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); | 2015 this->flushBigGlyphs(cacheBlob, rt, grPaint, clip, 0, 0); |
| 1321 } | 2016 } |
| OLD | NEW |