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