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 "GrAtlasTextContext.h" | 9 #include "GrAtlasTextContext.h" |
10 #include "GrDrawContext.h" | 10 #include "GrDrawContext.h" |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
74 const GrClip& clip, | 74 const GrClip& clip, |
75 const GrPaint& paint, | 75 const GrPaint& paint, |
76 const SkPaint& skPaint, | 76 const SkPaint& skPaint, |
77 const SkMatrix& viewMatrix, | 77 const SkMatrix& viewMatrix, |
78 const char text[], | 78 const char text[], |
79 size_t byteLength, | 79 size_t byteLength, |
80 SkScalar x, SkScalar y, | 80 SkScalar x, SkScalar y, |
81 const SkIRect& clipBounds) { | 81 const SkIRect& clipBounds) { |
82 TextRun run(skPaint); | 82 TextRun run(skPaint); |
83 GrPipelineBuilder pipelineBuilder(paint, rt, clip); | 83 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
84 run.setText(text, byteLength, x, y, fContext, &fSurfaceProps); | 84 run.setText(text, byteLength, x, y); |
85 run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBound
s, | 85 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0,
clipBounds, |
86 fFallbackTextContext, skPaint); | 86 fFallbackTextContext, skPaint); |
87 } | 87 } |
88 | 88 |
89 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, | 89 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, |
90 const GrClip& clip, | 90 const GrClip& clip, |
91 const GrPaint& paint, | 91 const GrPaint& paint, |
92 const SkPaint& skPaint, | 92 const SkPaint& skPaint, |
93 const SkMatrix& viewMatrix, | 93 const SkMatrix& viewMatrix, |
94 const char text[], | 94 const char text[], |
95 size_t byteLength, | 95 size_t byteLength, |
96 const SkScalar pos[], | 96 const SkScalar pos[], |
97 int scalarsPerPosition, | 97 int scalarsPerPosition, |
98 const SkPoint& offset, | 98 const SkPoint& offset, |
99 const SkIRect& clipBounds) { | 99 const SkIRect& clipBounds) { |
100 TextRun run(skPaint); | 100 TextRun run(skPaint); |
101 GrPipelineBuilder pipelineBuilder(paint, rt, clip); | 101 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
102 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); | 102 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); |
103 run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBound
s, | 103 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0,
clipBounds, |
104 fFallbackTextContext, skPaint); | 104 fFallbackTextContext, skPaint); |
105 } | 105 } |
106 | 106 |
107 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarge
t* rt, | 107 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarge
t* rt, |
108 const GrClip& clip, const SkPain
t& skPaint, | 108 const GrClip& clip, const SkPain
t& skPaint, |
109 const SkMatrix& viewMatrix, | 109 const SkMatrix& viewMatrix, |
110 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, | 110 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, |
111 SkDrawFilter* drawFilter, | 111 SkDrawFilter* drawFilter, |
112 const SkIRect& clipBounds) { | 112 const SkIRect& clipBounds) { |
113 if (!this->internalCanDraw(skPaint)) { | 113 if (!this->internalCanDraw(skPaint)) { |
(...skipping 16 matching lines...) Expand all Loading... |
130 GrPaint paint; | 130 GrPaint paint; |
131 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { | 131 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { |
132 return; | 132 return; |
133 } | 133 } |
134 | 134 |
135 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); | 135 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); |
136 GrPipelineBuilder pipelineBuilder(paint, rt, clip); | 136 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
137 | 137 |
138 TextBlob::Iter iter(blob); | 138 TextBlob::Iter iter(blob); |
139 for (TextRun* run = iter.get(); run; run = iter.next()) { | 139 for (TextRun* run = iter.get(); run; run = iter.next()) { |
140 run->draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clip
Bounds, | 140 run->draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix,
x, y, clipBounds, |
141 fFallbackTextContext, skPaint); | 141 fFallbackTextContext, skPaint); |
| 142 run->releaseGlyphCache(); |
142 } | 143 } |
143 } | 144 } |
144 | 145 |
145 const GrStencilAndCoverTextContext::TextBlob& | 146 const GrStencilAndCoverTextContext::TextBlob& |
146 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, | 147 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
147 const SkPaint& skPaint) { | 148 const SkPaint& skPaint) { |
148 // The font-related parameters are baked into the text blob and will overrid
e this skPaint, so | 149 // The font-related parameters are baked into the text blob and will overrid
e this skPaint, so |
149 // the only remaining properties that can affect a TextBlob are the ones rel
ated to stroke. | 150 // the only remaining properties that can affect a TextBlob are the ones rel
ated to stroke. |
150 if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path. | 151 if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path. |
151 if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) { | 152 if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) { |
152 fLRUList.remove(*found); | 153 fLRUList.remove(*found); |
153 fLRUList.addToTail(*found); | 154 fLRUList.addToTail(*found); |
154 return **found; | 155 return **found; |
155 } | 156 } |
156 TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint, fCont
ext, | 157 TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint); |
157 &fSurfaceProps); | |
158 this->purgeToFit(*blob); | 158 this->purgeToFit(*blob); |
159 fBlobIdCache.set(skBlob->uniqueID(), blob); | 159 fBlobIdCache.set(skBlob->uniqueID(), blob); |
160 fLRUList.addToTail(blob); | 160 fLRUList.addToTail(blob); |
161 fCacheSize += blob->cpuMemorySize(); | 161 fCacheSize += blob->cpuMemorySize(); |
162 return *blob; | 162 return *blob; |
163 } else { | 163 } else { |
164 GrStrokeInfo stroke(skPaint); | 164 GrStrokeInfo stroke(skPaint); |
165 SkSTArray<4, uint32_t, true> key; | 165 SkSTArray<4, uint32_t, true> key; |
166 key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt()); | 166 key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt()); |
167 key[0] = skBlob->uniqueID(); | 167 key[0] = skBlob->uniqueID(); |
168 stroke.asUniqueKeyFragment(&key[1]); | 168 stroke.asUniqueKeyFragment(&key[1]); |
169 if (TextBlob** found = fBlobKeyCache.find(key)) { | 169 if (TextBlob** found = fBlobKeyCache.find(key)) { |
170 fLRUList.remove(*found); | 170 fLRUList.remove(*found); |
171 fLRUList.addToTail(*found); | 171 fLRUList.addToTail(*found); |
172 return **found; | 172 return **found; |
173 } | 173 } |
174 TextBlob* blob = new TextBlob(key, skBlob, skPaint, fContext, &fSurfaceP
rops); | 174 TextBlob* blob = new TextBlob(key, skBlob, skPaint); |
175 this->purgeToFit(*blob); | 175 this->purgeToFit(*blob); |
176 fBlobKeyCache.set(blob); | 176 fBlobKeyCache.set(blob); |
177 fLRUList.addToTail(blob); | 177 fLRUList.addToTail(blob); |
178 fCacheSize += blob->cpuMemorySize(); | 178 fCacheSize += blob->cpuMemorySize(); |
179 return *blob; | 179 return *blob; |
180 } | 180 } |
181 } | 181 } |
182 | 182 |
183 void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) { | 183 void GrStencilAndCoverTextContext::purgeToFit(const TextBlob& blob) { |
184 static const int maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for cac
hing text blobs. | 184 static const size_t maxCacheSize = 4 * 1024 * 1024; // Allow up to 4 MB for
caching text blobs. |
185 | 185 |
186 int maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize(); | 186 size_t maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize(); |
187 while (fCacheSize && fCacheSize > maxSizeForNewBlob) { | 187 while (fCacheSize && fCacheSize > maxSizeForNewBlob) { |
188 TextBlob* lru = fLRUList.head(); | 188 TextBlob* lru = fLRUList.head(); |
189 if (1 == lru->key().count()) { | 189 if (1 == lru->key().count()) { |
190 // 1-length keys are unterstood to be the blob id. | 190 // 1-length keys are unterstood to be the blob id. |
191 fBlobIdCache.remove(lru->key()[0]); | 191 fBlobIdCache.remove(lru->key()[0]); |
192 } else { | 192 } else { |
193 fBlobKeyCache.remove(lru->key()); | 193 fBlobKeyCache.remove(lru->key()); |
194 } | 194 } |
195 fLRUList.remove(lru); | 195 fLRUList.remove(lru); |
196 fCacheSize -= lru->cpuMemorySize(); | 196 fCacheSize -= lru->cpuMemorySize(); |
197 delete lru; | 197 delete lru; |
198 } | 198 } |
199 } | 199 } |
200 | 200 |
201 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 201 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
202 | 202 |
203 void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, cons
t SkPaint& skPaint, | 203 void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, |
204 GrContext* ctx, const SkSurfac
eProps* props) { | 204 const SkPaint& skPaint) { |
205 fCpuMemorySize = sizeof(TextBlob); | 205 fCpuMemorySize = sizeof(TextBlob); |
206 SkPaint runPaint(skPaint); | 206 SkPaint runPaint(skPaint); |
207 for (SkTextBlob::RunIterator iter(skBlob); !iter.done(); iter.next()) { | 207 for (SkTextBlob::RunIterator iter(skBlob); !iter.done(); iter.next()) { |
208 iter.applyFontToPaint(&runPaint); // No need to re-seed the paint. | 208 iter.applyFontToPaint(&runPaint); // No need to re-seed the paint. |
209 TextRun* run = SkNEW_INSERT_AT_LLIST_TAIL(this, TextRun, (runPaint)); | 209 TextRun* run = SkNEW_INSERT_AT_LLIST_TAIL(this, TextRun, (runPaint)); |
210 | 210 |
211 const char* text = reinterpret_cast<const char*>(iter.glyphs()); | 211 const char* text = reinterpret_cast<const char*>(iter.glyphs()); |
212 size_t byteLength = sizeof(uint16_t) * iter.glyphCount(); | 212 size_t byteLength = sizeof(uint16_t) * iter.glyphCount(); |
213 const SkPoint& runOffset = iter.offset(); | 213 const SkPoint& runOffset = iter.offset(); |
214 | 214 |
215 switch (iter.positioning()) { | 215 switch (iter.positioning()) { |
216 case SkTextBlob::kDefault_Positioning: | 216 case SkTextBlob::kDefault_Positioning: |
217 run->setText(text, byteLength, runOffset.fX, runOffset.fY, ctx,
props); | 217 run->setText(text, byteLength, runOffset.fX, runOffset.fY); |
218 break; | 218 break; |
219 case SkTextBlob::kHorizontal_Positioning: | 219 case SkTextBlob::kHorizontal_Positioning: |
220 run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0
, runOffset.fY), | 220 run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0
, runOffset.fY)); |
221 ctx, props); | |
222 break; | 221 break; |
223 case SkTextBlob::kFull_Positioning: | 222 case SkTextBlob::kFull_Positioning: |
224 run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0
, 0), ctx, props); | 223 run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0
, 0)); |
225 break; | 224 break; |
226 } | 225 } |
227 | 226 |
228 fCpuMemorySize += run->cpuMemorySize(); | 227 fCpuMemorySize += run->computeSizeInCache(); |
229 } | 228 } |
230 } | 229 } |
231 | 230 |
232 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 231 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
233 | 232 |
234 class GrStencilAndCoverTextContext::FallbackBlobBuilder { | 233 class GrStencilAndCoverTextContext::FallbackBlobBuilder { |
235 public: | 234 public: |
236 FallbackBlobBuilder() : fBuffIdx(0) {} | 235 FallbackBlobBuilder() : fBuffIdx(0) {} |
237 | 236 |
238 bool isInitialized() const { return SkToBool(fBuilder); } | 237 bool isInitialized() const { return SkToBool(fBuilder); } |
(...skipping 14 matching lines...) Expand all Loading... |
253 int fBuffIdx; | 252 int fBuffIdx; |
254 uint16_t fGlyphIds[kWriteBufferSize]; | 253 uint16_t fGlyphIds[kWriteBufferSize]; |
255 SkPoint fPositions[kWriteBufferSize]; | 254 SkPoint fPositions[kWriteBufferSize]; |
256 }; | 255 }; |
257 | 256 |
258 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 257 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
259 | 258 |
260 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) | 259 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
261 : fStroke(fontAndStroke), | 260 : fStroke(fontAndStroke), |
262 fFont(fontAndStroke), | 261 fFont(fontAndStroke), |
263 fTotalGlyphCount(0) { | 262 fTotalGlyphCount(0), |
| 263 fDetachedGlyphCache(nullptr), |
| 264 fLastDrawnGlyphsID(SK_InvalidUniqueID) { |
264 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. | 265 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
265 | 266 |
266 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path | 267 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path |
267 // rendering API for stroking). | 268 // rendering API for stroking). |
268 fFont.setStyle(SkPaint::kFill_Style); | 269 fFont.setStyle(SkPaint::kFill_Style); |
269 | 270 |
270 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { | 271 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { |
271 // Instead of letting fake bold get baked into the glyph outlines, do it
with GPU stroke. | 272 // Instead of letting fake bold get baked into the glyph outlines, do it
with GPU stroke. |
272 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), | 273 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), |
273 kStdFakeBoldInterpKeys, | 274 kStdFakeBoldInterpKeys, |
(...skipping 26 matching lines...) Expand all Loading... |
300 | 301 |
301 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && | 302 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && |
302 0 == fFont.getTextSkewX() && | 303 0 == fFont.getTextSkewX() && |
303 !fFont.isFakeBoldText() && | 304 !fFont.isFakeBoldText() && |
304 !fFont.isVerticalText(); | 305 !fFont.isVerticalText(); |
305 } else { | 306 } else { |
306 fTextRatio = fTextInverseRatio = 1.0f; | 307 fTextRatio = fTextInverseRatio = 1.0f; |
307 fUsingRawGlyphPaths = false; | 308 fUsingRawGlyphPaths = false; |
308 } | 309 } |
309 | 310 |
| 311 // Generate the key that will be used to cache the GPU glyph path objects. |
| 312 if (fUsingRawGlyphPaths && fStroke.isFillStyle()) { |
| 313 static const GrUniqueKey::Domain kRawFillPathGlyphDomain = GrUniqueKey::
GenerateDomain(); |
| 314 |
| 315 const SkTypeface* typeface = fFont.getTypeface(); |
| 316 GrUniqueKey::Builder builder(&fGlyphPathsKey, kRawFillPathGlyphDomain, 1
); |
| 317 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqueID(
) : 0; |
| 318 } else { |
| 319 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::Generat
eDomain(); |
| 320 |
| 321 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); |
| 322 if (fUsingRawGlyphPaths) { |
| 323 const SkTypeface* typeface = fFont.getTypeface(); |
| 324 GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, 2 +
strokeDataCount); |
| 325 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqu
eID() : 0; |
| 326 reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount; |
| 327 fStroke.asUniqueKeyFragment(&builder[2]); |
| 328 } else { |
| 329 SkGlyphCache* glyphCache = this->getGlyphCache(); |
| 330 const SkTypeface* typeface = glyphCache->getScalerContext()->getType
face(); |
| 331 const SkDescriptor* desc = &glyphCache->getDescriptor(); |
| 332 int descDataCount = (desc->getLength() + 3) / 4; |
| 333 GrUniqueKey::Builder builder(&fGlyphPathsKey, kPathGlyphDomain, |
| 334 2 + strokeDataCount + descDataCount); |
| 335 reinterpret_cast<uint32_t&>(builder[0]) = typeface ? typeface->uniqu
eID() : 0; |
| 336 reinterpret_cast<uint32_t&>(builder[1]) = strokeDataCount | (descDat
aCount << 16); |
| 337 fStroke.asUniqueKeyFragment(&builder[2]); |
| 338 memcpy(&builder[2 + strokeDataCount], desc, desc->getLength()); |
| 339 } |
| 340 } |
| 341 |
310 // When drawing from canonically sized paths, the actual local coords are fT
extRatio * coords. | 342 // When drawing from canonically sized paths, the actual local coords are fT
extRatio * coords. |
311 fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio); | 343 fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio); |
312 } | 344 } |
313 | 345 |
314 GrStencilAndCoverTextContext::TextRun::~TextRun() { | 346 GrStencilAndCoverTextContext::TextRun::~TextRun() { |
| 347 this->releaseGlyphCache(); |
315 } | 348 } |
316 | 349 |
317 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by
teLength, | 350 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by
teLength, |
318 SkScalar x, SkScalar y, GrCo
ntext* ctx, | 351 SkScalar x, SkScalar y) { |
319 const SkSurfaceProps* surfac
eProps) { | |
320 SkASSERT(byteLength == 0 || text != nullptr); | 352 SkASSERT(byteLength == 0 || text != nullptr); |
321 | 353 |
322 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); | 354 SkGlyphCache* glyphCache = this->getGlyphCache(); |
323 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); | 355 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
324 | 356 |
325 fTotalGlyphCount = fFont.countText(text, byteLength); | 357 fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransfor
mType, |
326 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), | 358 fTotalGlyphCount = fFont.countText(text,
byteLength))); |
327 GrPathRendering::kTranslate_PathTransfor
mType, | |
328 fTotalGlyphCount)); | |
329 | |
330 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); | |
331 | 359 |
332 const char* stop = text + byteLength; | 360 const char* stop = text + byteLength; |
333 | 361 |
334 // Measure first if needed. | 362 // Measure first if needed. |
335 if (fFont.getTextAlign() != SkPaint::kLeft_Align) { | 363 if (fFont.getTextAlign() != SkPaint::kLeft_Align) { |
336 SkFixed stopX = 0; | 364 SkFixed stopX = 0; |
337 SkFixed stopY = 0; | 365 SkFixed stopY = 0; |
338 | 366 |
339 const char* textPtr = text; | 367 const char* textPtr = text; |
340 while (textPtr < stop) { | 368 while (textPtr < stop) { |
(...skipping 30 matching lines...) Expand all Loading... |
371 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); | 399 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); |
372 if (glyph.fWidth) { | 400 if (glyph.fWidth) { |
373 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy)), | 401 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy)), |
374 &fallback); | 402 &fallback); |
375 } | 403 } |
376 | 404 |
377 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); | 405 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); |
378 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); | 406 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); |
379 } | 407 } |
380 | 408 |
381 fDraw->loadGlyphPathsIfNeeded(); | |
382 | |
383 fFallbackTextBlob.reset(fallback.buildIfInitialized()); | 409 fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
384 } | 410 } |
385 | 411 |
386 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, | 412 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, |
387 const SkScalar pos[], int
scalarsPerPosition, | 413 const SkScalar pos[], int
scalarsPerPosition, |
388 const SkPoint& offset, Gr
Context* ctx, | 414 const SkPoint& offset) { |
389 const SkSurfaceProps* sur
faceProps) { | |
390 SkASSERT(byteLength == 0 || text != nullptr); | 415 SkASSERT(byteLength == 0 || text != nullptr); |
391 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 416 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
392 | 417 |
393 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); | 418 SkGlyphCache* glyphCache = this->getGlyphCache(); |
394 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); | 419 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
395 | 420 |
396 fTotalGlyphCount = fFont.countText(text, byteLength); | 421 fDraw.reset(GrPathRangeDraw::Create(GrPathRendering::kTranslate_PathTransfor
mType, |
397 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), | 422 fTotalGlyphCount = fFont.countText(text,
byteLength))); |
398 GrPathRendering::kTranslate_PathTransfor
mType, | |
399 fTotalGlyphCount)); | |
400 | |
401 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); | |
402 | 423 |
403 const char* stop = text + byteLength; | 424 const char* stop = text + byteLength; |
404 | 425 |
405 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 426 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
406 SkTextAlignProc alignProc(fFont.getTextAlign()); | 427 SkTextAlignProc alignProc(fFont.getTextAlign()); |
407 FallbackBlobBuilder fallback; | 428 FallbackBlobBuilder fallback; |
408 while (text < stop) { | 429 while (text < stop) { |
409 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); | 430 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
410 if (glyph.fWidth) { | 431 if (glyph.fWidth) { |
411 SkPoint tmsLoc; | 432 SkPoint tmsLoc; |
412 tmsProc(pos, &tmsLoc); | 433 tmsProc(pos, &tmsLoc); |
413 SkPoint loc; | 434 SkPoint loc; |
414 alignProc(tmsLoc, glyph, &loc); | 435 alignProc(tmsLoc, glyph, &loc); |
415 | 436 |
416 this->appendGlyph(glyph, loc, &fallback); | 437 this->appendGlyph(glyph, loc, &fallback); |
417 } | 438 } |
418 pos += scalarsPerPosition; | 439 pos += scalarsPerPosition; |
419 } | 440 } |
420 | 441 |
421 fDraw->loadGlyphPathsIfNeeded(); | |
422 | |
423 fFallbackTextBlob.reset(fallback.buildIfInitialized()); | 442 fFallbackTextBlob.reset(fallback.buildIfInitialized()); |
424 } | 443 } |
425 | 444 |
426 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, | 445 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx)
const { |
427 SkGlyphCache* g
lyphCache) { | 446 GrPathRange* glyphs = static_cast<GrPathRange*>( |
428 SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface() | 447 ctx->resourceProvider()->findAndRefResourceByUniqueKey(fGlyphPathsKe
y)); |
429 : glyphCache->getScalerContext()-
>getTypeface(); | 448 if (nullptr == glyphs) { |
430 const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getD
escriptor(); | 449 if (fUsingRawGlyphPaths) { |
431 | 450 glyphs = ctx->resourceProvider()->createGlyphs(fFont.getTypeface(),
nullptr, fStroke); |
432 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDom
ain(); | 451 } else { |
433 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); | 452 SkGlyphCache* cache = this->getGlyphCache(); |
434 GrUniqueKey glyphKey; | 453 glyphs = ctx->resourceProvider()->createGlyphs(cache->getScalerConte
xt()->getTypeface(), |
435 GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCoun
t); | 454 &cache->getDescriptor
(), |
436 reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0; | 455 fStroke); |
437 reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() :
0; | 456 } |
438 if (strokeDataCount > 0) { | 457 ctx->resourceProvider()->assignUniqueKeyToResource(fGlyphPathsKey, glyph
s); |
439 fStroke.asUniqueKeyFragment(&builder[2]); | |
440 } | 458 } |
441 builder.finish(); | 459 return glyphs; |
442 | |
443 SkAutoTUnref<GrPathRange> glyphs( | |
444 static_cast<GrPathRange*>( | |
445 ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey))); | |
446 if (nullptr == glyphs) { | |
447 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStro
ke)); | |
448 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); | |
449 } else { | |
450 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); | |
451 } | |
452 | |
453 return glyphs.detach(); | |
454 } | 460 } |
455 | 461 |
456 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl
yph, | 462 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl
yph, |
457 const SkPoint& po
s, | 463 const SkPoint& po
s, |
458 FallbackBlobBuild
er* fallback) { | 464 FallbackBlobBuild
er* fallback) { |
459 // Stick the glyphs we can't draw into the fallback text blob. | 465 // Stick the glyphs we can't draw into the fallback text blob. |
460 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | 466 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { |
461 if (!fallback->isInitialized()) { | 467 if (!fallback->isInitialized()) { |
462 fallback->init(fFont, fTextRatio); | 468 fallback->init(fFont, fTextRatio); |
463 } | 469 } |
464 fallback->appendGlyph(glyph.getGlyphID(), pos); | 470 fallback->appendGlyph(glyph.getGlyphID(), pos); |
465 } else { | 471 } else { |
466 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; | 472 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; |
467 fDraw->append(glyph.getGlyphID(), translate); | 473 fDraw->append(glyph.getGlyphID(), translate); |
468 } | 474 } |
469 } | 475 } |
470 | 476 |
471 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, | 477 void GrStencilAndCoverTextContext::TextRun::draw(GrContext* ctx, |
| 478 GrDrawContext* dc, |
472 GrPipelineBuilder* pipelineBuil
der, | 479 GrPipelineBuilder* pipelineBuil
der, |
473 GrColor color, | 480 GrColor color, |
474 const SkMatrix& viewMatrix, | 481 const SkMatrix& viewMatrix, |
475 SkScalar x, SkScalar y, | 482 SkScalar x, SkScalar y, |
476 const SkIRect& clipBounds, | 483 const SkIRect& clipBounds, |
477 GrTextContext* fallbackTextCont
ext, | 484 GrTextContext* fallbackTextCont
ext, |
478 const SkPaint& originalSkPaint)
const { | 485 const SkPaint& originalSkPaint)
const { |
479 SkASSERT(fDraw); | 486 SkASSERT(fDraw); |
480 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() |
| | 487 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() |
| |
481 !fFont.isAntiAlias()); | 488 !fFont.isAntiAlias()); |
482 | 489 |
483 if (fDraw->count()) { | 490 if (fDraw->count()) { |
484 pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.is
AntiAlias()); | 491 pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.is
AntiAlias()); |
485 | 492 |
486 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 493 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
487 kZero_StencilOp, | 494 kZero_StencilOp, |
488 kKeep_StencilOp, | 495 kKeep_StencilOp, |
489 kNotEqual_StencilFunc, | 496 kNotEqual_StencilFunc, |
490 0xffff, | 497 0xffff, |
491 0x0000, | 498 0x0000, |
492 0xffff); | 499 0xffff); |
493 | 500 |
494 *pipelineBuilder->stencil() = kStencilPass; | 501 *pipelineBuilder->stencil() = kStencilPass; |
495 | 502 |
| 503 SkAutoTUnref<GrPathRange> glyphs(this->createGlyphs(ctx)); |
| 504 if (fLastDrawnGlyphsID != glyphs->getUniqueID()) { |
| 505 // Either this is the first draw or the glyphs object was purged sin
ce last draw. |
| 506 glyphs->loadPathsIfNeeded(fDraw->indices(), fDraw->count()); |
| 507 fLastDrawnGlyphsID = glyphs->getUniqueID(); |
| 508 } |
| 509 |
496 SkMatrix drawMatrix(viewMatrix); | 510 SkMatrix drawMatrix(viewMatrix); |
497 drawMatrix.preTranslate(x, y); | 511 drawMatrix.preTranslate(x, y); |
498 drawMatrix.preScale(fTextRatio, fTextRatio); | 512 drawMatrix.preScale(fTextRatio, fTextRatio); |
499 | 513 |
500 SkMatrix& localMatrix = fLocalMatrixTemplate; | 514 SkMatrix& localMatrix = fLocalMatrixTemplate; |
501 localMatrix.setTranslateX(x); | 515 localMatrix.setTranslateX(x); |
502 localMatrix.setTranslateY(y); | 516 localMatrix.setTranslateY(y); |
503 | 517 |
504 dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color,
fDraw, | 518 dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color,
glyphs, fDraw, |
505 GrPathRendering::kWinding_FillType); | 519 GrPathRendering::kWinding_FillType); |
506 } | 520 } |
507 | 521 |
508 if (fFallbackTextBlob) { | 522 if (fFallbackTextBlob) { |
509 SkPaint fallbackSkPaint(originalSkPaint); | 523 SkPaint fallbackSkPaint(originalSkPaint); |
510 fStroke.applyToPaint(&fallbackSkPaint); | 524 fStroke.applyToPaint(&fallbackSkPaint); |
511 if (!fStroke.isFillStyle()) { | 525 if (!fStroke.isFillStyle()) { |
512 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); | 526 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
513 } | 527 } |
514 | 528 |
515 fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget()
, | 529 fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget()
, |
516 pipelineBuilder->clip(), fallbackSkPai
nt, viewMatrix, | 530 pipelineBuilder->clip(), fallbackSkPai
nt, viewMatrix, |
517 fFallbackTextBlob, x, y, nullptr, clip
Bounds); | 531 fFallbackTextBlob, x, y, nullptr, clip
Bounds); |
518 } | 532 } |
519 } | 533 } |
520 | 534 |
521 int GrStencilAndCoverTextContext::TextRun::cpuMemorySize() const { | 535 SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const { |
522 int size = sizeof(TextRun) + fTotalGlyphCount * (sizeof(uint16_t) + 2 * size
of(float)); | 536 if (!fDetachedGlyphCache) { |
| 537 fDetachedGlyphCache = fFont.detachCache(nullptr, nullptr, true /*ignoreG
amma*/); |
| 538 } |
| 539 return fDetachedGlyphCache; |
| 540 } |
| 541 |
| 542 |
| 543 void GrStencilAndCoverTextContext::TextRun::releaseGlyphCache() const { |
| 544 if (fDetachedGlyphCache) { |
| 545 SkGlyphCache::AttachCache(fDetachedGlyphCache); |
| 546 fDetachedGlyphCache = nullptr; |
| 547 } |
| 548 } |
| 549 |
| 550 size_t GrStencilAndCoverTextContext::TextRun::computeSizeInCache() const { |
| 551 size_t size = sizeof(TextRun) + |
| 552 fGlyphPathsKey.size() + |
| 553 fTotalGlyphCount * (sizeof(uint16_t) + 2 * sizeof(float)); |
523 if (fDraw) { | 554 if (fDraw) { |
524 size += sizeof(GrPathRangeDraw); | 555 size += sizeof(GrPathRangeDraw); |
525 } | 556 } |
526 if (fFallbackTextBlob) { | 557 if (fFallbackTextBlob) { |
527 size += sizeof(SkTextBlob); | 558 size += sizeof(SkTextBlob); |
528 } | 559 } |
529 return size; | 560 return size; |
530 } | 561 } |
531 | 562 |
532 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 563 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 fBuffIdx = 0; | 600 fBuffIdx = 0; |
570 } | 601 } |
571 | 602 |
572 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInit
ialized() { | 603 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInit
ialized() { |
573 if (!this->isInitialized()) { | 604 if (!this->isInitialized()) { |
574 return nullptr; | 605 return nullptr; |
575 } | 606 } |
576 this->flush(); | 607 this->flush(); |
577 return fBuilder->build(); | 608 return fBuilder->build(); |
578 } | 609 } |
OLD | NEW |