Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 Google Inc. |
| 3 * | 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
| 6 */ | 6 */ |
| 7 | 7 |
| 8 #include "GrStencilAndCoverTextContext.h" | 8 #include "GrStencilAndCoverTextContext.h" |
| 9 #include "GrDrawTarget.h" | 9 #include "GrDrawTarget.h" |
| 10 #include "GrFontScaler.h" | |
| 11 #include "GrGpu.h" | 10 #include "GrGpu.h" |
| 12 #include "GrPath.h" | 11 #include "GrPath.h" |
| 13 #include "GrTextStrike.h" | 12 #include "GrPathRange.h" |
| 14 #include "GrTextStrike_impl.h" | |
| 15 #include "SkAutoKern.h" | 13 #include "SkAutoKern.h" |
| 16 #include "SkDraw.h" | 14 #include "SkDraw.h" |
| 17 #include "SkDrawProcs.h" | 15 #include "SkDrawProcs.h" |
| 18 #include "SkGlyphCache.h" | 16 #include "SkGlyphCache.h" |
| 19 #include "SkGpuDevice.h" | 17 #include "SkGpuDevice.h" |
| 20 #include "SkPath.h" | 18 #include "SkPath.h" |
| 21 #include "SkTextMapStateProc.h" | 19 #include "SkTextMapStateProc.h" |
| 22 | 20 |
| 23 static const int kMaxReservedGlyphs = 64; | 21 class GrStencilAndCoverTextContext::GlyphPathRange : public GrCacheable { |
| 22 static const int kMaxGlyphCount = 1 << 16; // Glyph IDs are uint16_t's | |
| 23 static const int kGlyphGroupSize = 16; // Glyphs get tracked in groups of 16 | |
| 24 static const bool kIsWrapped = false; | |
| 25 | |
| 26 public: | |
| 27 static GlyphPathRange* Create(GrContext* context, | |
| 28 SkGlyphCache* cache, | |
| 29 const SkStrokeRec& stroke) { | |
| 30 static const GrResourceKey::ResourceType gGlyphPathRangeType = | |
| 31 GrResourceKey::GenerateResourceType(); | |
|
bsalomon
2014/07/17 17:27:28
I think the type should come from GrPathRange itse
Chris Dalton
2014/07/17 18:15:19
Acknowledged.
| |
| 32 static const GrCacheID::Domain gGlyphPathRangeDomain = GrCacheID::Genera teDomain(); | |
| 33 | |
| 34 GrCacheID::Key key; | |
| 35 key.fData32[0] = cache->getDescriptor().getChecksum(); | |
| 36 key.fData32[1] = cache->getScalerContext()->getTypeface()->uniqueID(); | |
| 37 key.fData64[1] = GrPath::ComputeStrokeKey(stroke); | |
| 38 | |
| 39 GrResourceKey resourceKey(GrCacheID(gGlyphPathRangeDomain, key), gGlyphP athRangeType, 0); | |
| 40 SkAutoTUnref<GlyphPathRange> glyphs( | |
| 41 static_cast<GlyphPathRange*>(context->findAndRefCachedResource(resou rceKey))); | |
| 42 | |
| 43 if (NULL == glyphs || | |
| 44 !glyphs->fDesc->equals(cache->getDescriptor() /*checksum collision*/ )) { | |
| 45 GrGpu* const gpu = context->getGpu(); | |
| 46 // We reserve a range of kMaxGlyphCount paths because of fallbacks f onts. We | |
| 47 // can't know exactly how many glyphs we might need without preloadi ng every | |
| 48 // fallback, which we don't want to do at this point. | |
| 49 SkAutoTUnref<GrPathRange> pathRange(gpu->createPathRange(kMaxGlyphCo unt, stroke)); | |
| 50 glyphs.reset(SkNEW_ARGS(GlyphPathRange, (cache->getDescriptor(), pat hRange))); | |
| 51 context->addResourceToCache(resourceKey, glyphs); | |
| 52 } | |
| 53 | |
| 54 return glyphs.detach(); | |
| 55 } | |
| 56 | |
| 57 const GrPathRange* pathRange() const { return fPathRange.get(); } | |
| 58 | |
| 59 void preloadGlyph(uint16_t glyphID, SkGlyphCache* cache) { | |
| 60 const uint16_t groupIndex = glyphID / kGlyphGroupSize; | |
| 61 const uint16_t groupByte = groupIndex >> 3; | |
| 62 const uint8_t groupBit = 1 << (groupIndex & 7); | |
| 63 | |
| 64 const bool hasGlyph = fLoadedGlyphs[groupByte] & groupBit; | |
| 65 if (hasGlyph) { | |
| 66 return; | |
| 67 } | |
| 68 | |
| 69 // We track which glyphs are loaded in groups of kGlyphGroupSize. To | |
| 70 // mark a glyph loaded we need to load the entire group. | |
| 71 const uint16_t groupFirstID = groupIndex * kGlyphGroupSize; | |
| 72 const uint16_t groupLastID = groupFirstID + kGlyphGroupSize - 1; | |
| 73 SkPath skPath; | |
| 74 for (int id = groupFirstID; id <= groupLastID; ++id) { | |
| 75 const SkGlyph& skGlyph = cache->getGlyphIDMetrics(id); | |
| 76 if (const SkPath* skPath = cache->findPath(skGlyph)) { | |
| 77 fPathRange->initAt(id, *skPath); | |
| 78 } // GrGpu::drawPaths will silently ignore undefined paths. | |
| 79 } | |
| 80 | |
| 81 fLoadedGlyphs[groupByte] |= groupBit; | |
| 82 this->didChangeGpuMemorySize(); | |
| 83 } | |
| 84 | |
| 85 // GrCacheable overrides | |
| 86 virtual size_t gpuMemorySize() const SK_OVERRIDE { return fPathRange->gpuMem orySize(); } | |
| 87 virtual bool isValidOnGpu() const SK_OVERRIDE { return fPathRange->isValidOn Gpu(); } | |
| 88 | |
| 89 private: | |
| 90 GlyphPathRange(const SkDescriptor& desc, GrPathRange* pathRange) | |
| 91 : fDesc(desc.copy()) | |
| 92 , fPathRange(pathRange) { | |
| 93 memset(fLoadedGlyphs, 0, sizeof(fLoadedGlyphs)); | |
| 94 } | |
| 95 | |
| 96 ~GlyphPathRange() { | |
| 97 SkDescriptor::Free(fDesc); | |
| 98 } | |
| 99 | |
| 100 static const int kMaxGroupCount = (kMaxGlyphCount + (kGlyphGroupSize - 1)) / kGlyphGroupSize; | |
| 101 SkDescriptor* const fDesc; | |
| 102 uint8_t fLoadedGlyphs[(kMaxGroupCount + 7) >> 3]; // One bit per glyph group | |
| 103 SkRefPtr<GrPathRange> fPathRange; | |
| 104 | |
| 105 typedef GrCacheable INHERITED; | |
| 106 }; | |
| 107 | |
| 24 | 108 |
| 25 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( | 109 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext( |
| 26 GrContext* context, const SkDeviceProperties& properties) | 110 GrContext* context, const SkDeviceProperties& properties) |
| 27 : GrTextContext(context, properties) | 111 : GrTextContext(context, properties) |
| 28 , fStroke(SkStrokeRec::kFill_InitStyle) { | 112 , fStroke(SkStrokeRec::kFill_InitStyle) |
| 113 , fPendingGlyphCount(0) { | |
| 29 } | 114 } |
| 30 | 115 |
| 31 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { | 116 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { |
| 32 } | 117 } |
| 33 | 118 |
| 34 void GrStencilAndCoverTextContext::drawText(const GrPaint& paint, | 119 void GrStencilAndCoverTextContext::drawText(const GrPaint& paint, |
| 35 const SkPaint& skPaint, | 120 const SkPaint& skPaint, |
| 36 const char text[], | 121 const char text[], |
| 37 size_t byteLength, | 122 size_t byteLength, |
| 38 SkScalar x, SkScalar y) { | 123 SkScalar x, SkScalar y) { |
| (...skipping 27 matching lines...) Expand all Loading... | |
| 66 if (fNeedsDeviceSpaceGlyphs) { | 151 if (fNeedsDeviceSpaceGlyphs) { |
| 67 SkPoint loc; | 152 SkPoint loc; |
| 68 fGlyphTransform.mapXY(x, y, &loc); | 153 fGlyphTransform.mapXY(x, y, &loc); |
| 69 x = loc.fX; | 154 x = loc.fX; |
| 70 y = loc.fY; | 155 y = loc.fY; |
| 71 glyphCacheTransform = &fGlyphTransform; | 156 glyphCacheTransform = &fGlyphTransform; |
| 72 } | 157 } |
| 73 | 158 |
| 74 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 159 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 75 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform ); | 160 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, glyphCacheTransform ); |
| 76 SkGlyphCache* cache = autoCache.getCache(); | 161 fGlyphCache = autoCache.getCache(); |
| 77 GrFontScaler* scaler = GetGrFontScaler(cache); | 162 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); |
| 78 GrTextStrike* strike = | |
| 79 fContext->getFontCache()->getStrike(scaler, true); | |
| 80 | 163 |
| 81 const char* stop = text + byteLength; | 164 const char* stop = text + byteLength; |
| 82 | 165 |
| 83 // Measure first if needed. | 166 // Measure first if needed. |
| 84 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | 167 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { |
| 85 SkFixed stopX = 0; | 168 SkFixed stopX = 0; |
| 86 SkFixed stopY = 0; | 169 SkFixed stopY = 0; |
| 87 | 170 |
| 88 const char* textPtr = text; | 171 const char* textPtr = text; |
| 89 while (textPtr < stop) { | 172 while (textPtr < stop) { |
| 90 // We don't need x, y here, since all subpixel variants will have th e | 173 // We don't need x, y here, since all subpixel variants will have th e |
| 91 // same advance. | 174 // same advance. |
| 92 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0); | 175 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0); |
| 93 | 176 |
| 94 stopX += glyph.fAdvanceX; | 177 stopX += glyph.fAdvanceX; |
| 95 stopY += glyph.fAdvanceY; | 178 stopY += glyph.fAdvanceY; |
| 96 } | 179 } |
| 97 SkASSERT(textPtr == stop); | 180 SkASSERT(textPtr == stop); |
| 98 | 181 |
| 99 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; | 182 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; |
| 100 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; | 183 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; |
| 101 | 184 |
| 102 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { | 185 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { |
| 103 alignX = SkScalarHalf(alignX); | 186 alignX = SkScalarHalf(alignX); |
| 104 alignY = SkScalarHalf(alignY); | 187 alignY = SkScalarHalf(alignY); |
| 105 } | 188 } |
| 106 | 189 |
| 107 x -= alignX; | 190 x -= alignX; |
| 108 y -= alignY; | 191 y -= alignY; |
| 109 } | 192 } |
| 110 | 193 |
| 111 SkAutoKern autokern; | 194 SkAutoKern autokern; |
| 112 | 195 |
| 113 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); | 196 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); |
| 114 | 197 |
| 115 SkFixed fx = SkScalarToFixed(x); | 198 SkFixed fx = SkScalarToFixed(x); |
| 116 SkFixed fy = SkScalarToFixed(y); | 199 SkFixed fy = SkScalarToFixed(y); |
| 117 while (text < stop) { | 200 while (text < stop) { |
| 118 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 201 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 119 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); | 202 fx += SkFixedMul_portable(autokern.adjust(glyph), fixedSizeRatio); |
| 120 if (glyph.fWidth) { | 203 if (glyph.fWidth) { |
| 121 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | 204 this->appendGlyph(glyph.getGlyphID(), SkFixedToScalar(fx), SkFixedTo Scalar(fy)); |
| 122 glyph.getSubXFixed(), | |
| 123 glyph.getSubYFixed()), | |
| 124 SkPoint::Make( | |
| 125 SkFixedToScalar(fx), | |
| 126 SkFixedToScalar(fy)), | |
| 127 strike, | |
| 128 scaler); | |
| 129 } | 205 } |
| 130 | 206 |
| 131 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); | 207 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedSizeRatio); |
| 132 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); | 208 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedSizeRatio); |
| 133 } | 209 } |
| 134 | 210 |
| 135 this->finish(); | 211 this->finish(); |
| 136 } | 212 } |
| 137 | 213 |
| 138 void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, | 214 void GrStencilAndCoverTextContext::drawPosText(const GrPaint& paint, |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 157 // glyphs. That already uses glyph cache without device transforms. Device | 233 // glyphs. That already uses glyph cache without device transforms. Device |
| 158 // transform is not part of SkPaint::measureText API, and thus we use the | 234 // transform is not part of SkPaint::measureText API, and thus we use the |
| 159 // same glyphs as what were measured. | 235 // same glyphs as what were measured. |
| 160 fGlyphTransform.reset(); | 236 fGlyphTransform.reset(); |
| 161 | 237 |
| 162 this->init(paint, skPaint, byteLength); | 238 this->init(paint, skPaint, byteLength); |
| 163 | 239 |
| 164 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 240 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); |
| 165 | 241 |
| 166 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL); | 242 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL); |
| 167 SkGlyphCache* cache = autoCache.getCache(); | 243 fGlyphCache = autoCache.getCache(); |
| 168 GrFontScaler* scaler = GetGrFontScaler(cache); | 244 fGlyphs = GlyphPathRange::Create(fContext, fGlyphCache, fStroke); |
| 169 GrTextStrike* strike = | |
| 170 fContext->getFontCache()->getStrike(scaler, true); | |
| 171 | 245 |
| 172 const char* stop = text + byteLength; | 246 const char* stop = text + byteLength; |
| 173 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); | 247 SkTextAlignProcScalar alignProc(fSkPaint.getTextAlign()); |
| 174 SkTextMapStateProc tmsProc(SkMatrix::I(), constY, scalarsPerPosition); | 248 SkTextMapStateProc tmsProc(SkMatrix::I(), constY, scalarsPerPosition); |
| 175 | 249 |
| 176 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { | 250 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { |
| 177 while (text < stop) { | 251 while (text < stop) { |
| 178 SkPoint loc; | 252 SkPoint loc; |
| 179 tmsProc(pos, &loc); | 253 tmsProc(pos, &loc); |
| 180 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 254 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 181 if (glyph.fWidth) { | 255 if (glyph.fWidth) { |
| 182 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | 256 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); |
| 183 glyph.getSubXFixed(), | |
| 184 glyph.getSubYFixed()), | |
| 185 loc, | |
| 186 strike, | |
| 187 scaler); | |
| 188 } | 257 } |
| 189 pos += scalarsPerPosition; | 258 pos += scalarsPerPosition; |
| 190 } | 259 } |
| 191 } else { | 260 } else { |
| 192 while (text < stop) { | 261 while (text < stop) { |
| 193 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); | 262 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); |
| 194 if (glyph.fWidth) { | 263 if (glyph.fWidth) { |
| 195 SkPoint tmsLoc; | 264 SkPoint tmsLoc; |
| 196 tmsProc(pos, &tmsLoc); | 265 tmsProc(pos, &tmsLoc); |
| 197 SkPoint loc; | 266 SkPoint loc; |
| 198 alignProc(tmsLoc, glyph, &loc); | 267 alignProc(tmsLoc, glyph, &loc); |
| 199 | 268 |
| 200 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(), | 269 this->appendGlyph(glyph.getGlyphID(), loc.x(), loc.y()); |
| 201 glyph.getSubXFixed(), | |
| 202 glyph.getSubYFixed()), | |
| 203 loc, | |
| 204 strike, | |
| 205 scaler); | |
| 206 | |
| 207 } | 270 } |
| 208 pos += scalarsPerPosition; | 271 pos += scalarsPerPosition; |
| 209 } | 272 } |
| 210 } | 273 } |
| 211 | 274 |
| 212 this->finish(); | 275 this->finish(); |
| 213 } | 276 } |
| 214 | 277 |
| 215 bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) { | 278 bool GrStencilAndCoverTextContext::canDraw(const SkPaint& paint) { |
| 216 if (paint.getRasterizer()) { | 279 if (paint.getRasterizer()) { |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 298 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 361 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
| 299 kZero_StencilOp, | 362 kZero_StencilOp, |
| 300 kZero_StencilOp, | 363 kZero_StencilOp, |
| 301 kNotEqual_StencilFunc, | 364 kNotEqual_StencilFunc, |
| 302 0xffff, | 365 0xffff, |
| 303 0x0000, | 366 0x0000, |
| 304 0xffff); | 367 0xffff); |
| 305 | 368 |
| 306 *fDrawTarget->drawState()->stencil() = kStencilPass; | 369 *fDrawTarget->drawState()->stencil() = kStencilPass; |
| 307 | 370 |
| 308 size_t reserveAmount; | 371 SkASSERT(0 == fPendingGlyphCount); |
| 309 switch (skPaint.getTextEncoding()) { | |
| 310 default: | |
| 311 SkASSERT(false); | |
| 312 case SkPaint::kUTF8_TextEncoding: | |
| 313 reserveAmount = textByteLength; | |
| 314 break; | |
| 315 case SkPaint::kUTF16_TextEncoding: | |
| 316 reserveAmount = textByteLength / 2; | |
| 317 break; | |
| 318 case SkPaint::kUTF32_TextEncoding: | |
| 319 case SkPaint::kGlyphID_TextEncoding: | |
| 320 reserveAmount = textByteLength / 4; | |
| 321 break; | |
| 322 } | |
| 323 fPaths.setReserve(reserveAmount); | |
| 324 fTransforms.setReserve(reserveAmount); | |
| 325 } | 372 } |
| 326 | 373 |
| 327 inline void GrStencilAndCoverTextContext::appendGlyph(GrGlyph::PackedID glyphID, | 374 inline void GrStencilAndCoverTextContext::appendGlyph(uint16_t glyphID, float x, float y) { |
| 328 const SkPoint& pos, | 375 if (fPendingGlyphCount >= kGlyphBufferSize) { |
| 329 GrTextStrike* strike, | 376 this->flush(); |
| 330 GrFontScaler* scaler) { | 377 SkASSERT(0 == fPendingGlyphCount); |
| 331 GrGlyph* glyph = strike->getGlyph(glyphID, scaler); | 378 } |
| 332 if (NULL == glyph || glyph->fBounds.isEmpty()) { | 379 |
| 380 fGlyphs->preloadGlyph(glyphID, fGlyphCache); | |
| 381 | |
| 382 fIndexBuffer[fPendingGlyphCount] = glyphID; | |
| 383 fTransformBuffer[6 * fPendingGlyphCount + 0] = fTextRatio; | |
| 384 fTransformBuffer[6 * fPendingGlyphCount + 1] = 0; | |
| 385 fTransformBuffer[6 * fPendingGlyphCount + 2] = x; | |
| 386 fTransformBuffer[6 * fPendingGlyphCount + 3] = 0; | |
| 387 fTransformBuffer[6 * fPendingGlyphCount + 4] = fTextRatio; | |
| 388 fTransformBuffer[6 * fPendingGlyphCount + 5] = y; | |
| 389 | |
| 390 ++fPendingGlyphCount; | |
| 391 } | |
| 392 | |
| 393 void GrStencilAndCoverTextContext::flush() { | |
| 394 if (0 == fPendingGlyphCount) { | |
| 333 return; | 395 return; |
| 334 } | 396 } |
| 335 | 397 |
| 336 if (scaler->getGlyphPath(glyph->glyphID(), &fTmpPath)) { | 398 fDrawTarget->drawPaths(fGlyphs->pathRange(), fIndexBuffer, fPendingGlyphCoun t, |
| 337 if (!fTmpPath.isEmpty()) { | 399 fTransformBuffer, kAffine_GrTransformFormat, |
| 338 *fPaths.append() = fContext->createPath(fTmpPath, fStroke); | 400 SkPath::kWinding_FillType); |
| 339 SkMatrix* t = fTransforms.append(); | 401 |
| 340 t->setTranslate(pos.fX, pos.fY); | 402 fPendingGlyphCount = 0; |
| 341 t->preScale(fTextRatio, fTextRatio); | |
| 342 } | |
| 343 } | |
| 344 } | 403 } |
| 345 | 404 |
| 346 void GrStencilAndCoverTextContext::finish() { | 405 void GrStencilAndCoverTextContext::finish() { |
| 347 if (fPaths.count() > 0) { | 406 this->flush(); |
| 348 fDrawTarget->drawPaths(static_cast<size_t>(fPaths.count()), | |
| 349 fPaths.begin(), fTransforms.begin(), | |
| 350 SkPath::kWinding_FillType, fStroke.getStyle()); | |
| 351 | 407 |
| 352 for (int i = 0; i < fPaths.count(); ++i) { | 408 SkSafeUnref(fGlyphs); |
| 353 fPaths[i]->unref(); | 409 fGlyphs = NULL; |
| 354 } | 410 fGlyphCache = NULL; |
| 355 if (fPaths.count() > kMaxReservedGlyphs) { | |
| 356 fPaths.reset(); | |
| 357 fTransforms.reset(); | |
| 358 } else { | |
| 359 fPaths.rewind(); | |
| 360 fTransforms.rewind(); | |
| 361 } | |
| 362 } | |
| 363 fTmpPath.reset(); | |
| 364 | 411 |
| 365 fDrawTarget->drawState()->stencil()->setDisabled(); | 412 fDrawTarget->drawState()->stencil()->setDisabled(); |
| 366 fStateRestore.set(NULL); | 413 fStateRestore.set(NULL); |
| 367 if (fNeedsDeviceSpaceGlyphs) { | 414 if (fNeedsDeviceSpaceGlyphs) { |
| 368 fContext->setMatrix(fGlyphTransform); | 415 fContext->setMatrix(fGlyphTransform); |
| 369 } | 416 } |
| 370 GrTextContext::finish(); | 417 GrTextContext::finish(); |
| 371 } | 418 } |
| 372 | 419 |
| OLD | NEW |