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" |
11 #include "GrDrawTarget.h" | 11 #include "GrDrawTarget.h" |
12 #include "GrPath.h" | 12 #include "GrPath.h" |
13 #include "GrPathRange.h" | 13 #include "GrPathRange.h" |
14 #include "GrResourceProvider.h" | 14 #include "GrResourceProvider.h" |
15 #include "SkAutoKern.h" | 15 #include "SkAutoKern.h" |
16 #include "SkDraw.h" | 16 #include "SkDraw.h" |
17 #include "SkDrawProcs.h" | 17 #include "SkDrawProcs.h" |
18 #include "SkGlyphCache.h" | 18 #include "SkGlyphCache.h" |
19 #include "SkGpuDevice.h" | 19 #include "SkGpuDevice.h" |
| 20 #include "SkGrPriv.h" |
20 #include "SkPath.h" | 21 #include "SkPath.h" |
21 #include "SkTextMapStateProc.h" | 22 #include "SkTextMapStateProc.h" |
22 #include "SkTextFormatParams.h" | 23 #include "SkTextFormatParams.h" |
23 | 24 |
24 #include "batches/GrDrawPathBatch.h" | 25 #include "batches/GrDrawPathBatch.h" |
25 | 26 |
| 27 template<typename Key, typename Val> static void delete_hash_map_entry(const Key
&, Val* val) { |
| 28 SkASSERT(*val); |
| 29 delete *val; |
| 30 } |
| 31 |
| 32 template<typename T> static void delete_hash_table_entry(T* val) { |
| 33 SkASSERT(*val); |
| 34 delete *val; |
| 35 } |
| 36 |
26 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, | 37 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, |
27 const SkSurfaceProps&
surfaceProps) | 38 const SkSurfaceProps&
surfaceProps) |
28 : INHERITED(context, surfaceProps) { | 39 : INHERITED(context, surfaceProps), |
| 40 fCacheSize(0) { |
29 } | 41 } |
30 | 42 |
31 GrStencilAndCoverTextContext* | 43 GrStencilAndCoverTextContext* |
32 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { | 44 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { |
33 GrStencilAndCoverTextContext* textContext = | 45 GrStencilAndCoverTextContext* textContext = |
34 new GrStencilAndCoverTextContext(context, surfaceProps); | 46 new GrStencilAndCoverTextContext(context, surfaceProps); |
35 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); | 47 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); |
36 | 48 |
37 return textContext; | 49 return textContext; |
38 } | 50 } |
39 | 51 |
40 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { | 52 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { |
| 53 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>); |
| 54 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>); |
41 } | 55 } |
42 | 56 |
43 bool GrStencilAndCoverTextContext::canDraw(const GrRenderTarget* rt, | 57 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { |
44 const GrClip& clip, | |
45 const GrPaint& paint, | |
46 const SkPaint& skPaint, | |
47 const SkMatrix& viewMatrix) { | |
48 if (skPaint.getRasterizer()) { | 58 if (skPaint.getRasterizer()) { |
49 return false; | 59 return false; |
50 } | 60 } |
51 if (skPaint.getMaskFilter()) { | 61 if (skPaint.getMaskFilter()) { |
52 return false; | 62 return false; |
53 } | 63 } |
54 if (SkPathEffect* pe = skPaint.getPathEffect()) { | 64 if (SkPathEffect* pe = skPaint.getPathEffect()) { |
55 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { | 65 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { |
56 return false; | 66 return false; |
57 } | 67 } |
58 } | 68 } |
59 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. | 69 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. |
60 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); | 70 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); |
61 } | 71 } |
62 | 72 |
63 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, | 73 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, |
64 const GrClip& clip, | 74 const GrClip& clip, |
65 const GrPaint& paint, | 75 const GrPaint& paint, |
66 const SkPaint& skPaint, | 76 const SkPaint& skPaint, |
67 const SkMatrix& viewMatrix, | 77 const SkMatrix& viewMatrix, |
68 const char text[], | 78 const char text[], |
69 size_t byteLength, | 79 size_t byteLength, |
70 SkScalar x, SkScalar y, | 80 SkScalar x, SkScalar y, |
71 const SkIRect& regionClipBounds) { | 81 const SkIRect& clipBounds) { |
72 TextRun run(skPaint); | 82 TextRun run(skPaint); |
| 83 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
73 run.setText(text, byteLength, x, y, fContext, &fSurfaceProps); | 84 run.setText(text, byteLength, x, y, fContext, &fSurfaceProps); |
74 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); | 85 run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBound
s, |
| 86 fFallbackTextContext, skPaint); |
75 } | 87 } |
76 | 88 |
77 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, | 89 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, |
78 const GrClip& clip, | 90 const GrClip& clip, |
79 const GrPaint& paint, | 91 const GrPaint& paint, |
80 const SkPaint& skPaint, | 92 const SkPaint& skPaint, |
81 const SkMatrix& viewMatrix, | 93 const SkMatrix& viewMatrix, |
82 const char text[], | 94 const char text[], |
83 size_t byteLength, | 95 size_t byteLength, |
84 const SkScalar pos[], | 96 const SkScalar pos[], |
85 int scalarsPerPosition, | 97 int scalarsPerPosition, |
86 const SkPoint& offset, | 98 const SkPoint& offset, |
87 const SkIRect& regionClipBounds
) { | 99 const SkIRect& clipBounds) { |
88 TextRun run(skPaint); | 100 TextRun run(skPaint); |
| 101 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
89 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); | 102 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); |
90 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); | 103 run.draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0, clipBound
s, |
| 104 fFallbackTextContext, skPaint); |
| 105 } |
| 106 |
| 107 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, GrRenderTarge
t* rt, |
| 108 const GrClip& clip, const SkPain
t& skPaint, |
| 109 const SkMatrix& viewMatrix, |
| 110 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, |
| 111 SkDrawFilter* drawFilter, |
| 112 const SkIRect& clipBounds) { |
| 113 if (!this->internalCanDraw(skPaint)) { |
| 114 fFallbackTextContext->drawTextBlob(dc, rt, clip, skPaint, viewMatrix, sk
Blob, x, y, |
| 115 drawFilter, clipBounds); |
| 116 return; |
| 117 } |
| 118 |
| 119 if (drawFilter || skPaint.getPathEffect()) { |
| 120 // This draw can't be cached. |
| 121 INHERITED::drawTextBlob(dc, rt, clip, skPaint, viewMatrix, skBlob, x, y,
drawFilter, |
| 122 clipBounds); |
| 123 return; |
| 124 } |
| 125 |
| 126 if (fContext->abandoned()) { |
| 127 return; |
| 128 } |
| 129 |
| 130 GrPaint paint; |
| 131 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { |
| 132 return; |
| 133 } |
| 134 |
| 135 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); |
| 136 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
| 137 |
| 138 TextBlob::Iter iter(blob); |
| 139 for (TextRun* run = iter.get(); run; run = iter.next()) { |
| 140 run->draw(dc, &pipelineBuilder, paint.getColor(), viewMatrix, x, y, clip
Bounds, |
| 141 fFallbackTextContext, skPaint); |
| 142 } |
| 143 } |
| 144 |
| 145 const GrStencilAndCoverTextContext::TextBlob& |
| 146 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
| 147 const SkPaint& skPaint) { |
| 148 // 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 if (SkPaint::kFill_Style == skPaint.getStyle()) { // Fast path. |
| 151 if (TextBlob** found = fBlobIdCache.find(skBlob->uniqueID())) { |
| 152 fLRUList.remove(*found); |
| 153 fLRUList.addToTail(*found); |
| 154 return **found; |
| 155 } |
| 156 TextBlob* blob = new TextBlob(skBlob->uniqueID(), skBlob, skPaint, fCont
ext, |
| 157 &fSurfaceProps); |
| 158 this->purgeToFit(*blob); |
| 159 fBlobIdCache.set(skBlob->uniqueID(), blob); |
| 160 fLRUList.addToTail(blob); |
| 161 fCacheSize += blob->cpuMemorySize(); |
| 162 return *blob; |
| 163 } else { |
| 164 GrStrokeInfo stroke(skPaint); |
| 165 SkSTArray<4, uint32_t, true> key; |
| 166 key.reset(1 + stroke.computeUniqueKeyFragmentData32Cnt()); |
| 167 key[0] = skBlob->uniqueID(); |
| 168 stroke.asUniqueKeyFragment(&key[1]); |
| 169 if (TextBlob** found = fBlobKeyCache.find(key)) { |
| 170 fLRUList.remove(*found); |
| 171 fLRUList.addToTail(*found); |
| 172 return **found; |
| 173 } |
| 174 TextBlob* blob = new TextBlob(key, skBlob, skPaint, fContext, &fSurfaceP
rops); |
| 175 this->purgeToFit(*blob); |
| 176 fBlobKeyCache.set(blob); |
| 177 fLRUList.addToTail(blob); |
| 178 fCacheSize += blob->cpuMemorySize(); |
| 179 return *blob; |
| 180 } |
| 181 } |
| 182 |
| 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. |
| 185 |
| 186 int maxSizeForNewBlob = maxCacheSize - blob.cpuMemorySize(); |
| 187 while (fCacheSize && fCacheSize > maxSizeForNewBlob) { |
| 188 TextBlob* lru = fLRUList.head(); |
| 189 if (1 == lru->key().count()) { |
| 190 // 1-length keys are unterstood to be the blob id. |
| 191 fBlobIdCache.remove(lru->key()[0]); |
| 192 } else { |
| 193 fBlobKeyCache.remove(lru->key()); |
| 194 } |
| 195 fLRUList.remove(lru); |
| 196 fCacheSize -= lru->cpuMemorySize(); |
| 197 delete lru; |
| 198 } |
91 } | 199 } |
92 | 200 |
93 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 201 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 202 |
| 203 void GrStencilAndCoverTextContext::TextBlob::init(const SkTextBlob* skBlob, cons
t SkPaint& skPaint, |
| 204 GrContext* ctx, const SkSurfac
eProps* props) { |
| 205 fCpuMemorySize = sizeof(TextBlob); |
| 206 SkPaint runPaint(skPaint); |
| 207 for (SkTextBlob::RunIterator iter(skBlob); !iter.done(); iter.next()) { |
| 208 iter.applyFontToPaint(&runPaint); // No need to re-seed the paint. |
| 209 TextRun* run = SkNEW_INSERT_AT_LLIST_TAIL(this, TextRun, (runPaint)); |
| 210 |
| 211 const char* text = reinterpret_cast<const char*>(iter.glyphs()); |
| 212 size_t byteLength = sizeof(uint16_t) * iter.glyphCount(); |
| 213 const SkPoint& runOffset = iter.offset(); |
| 214 |
| 215 switch (iter.positioning()) { |
| 216 case SkTextBlob::kDefault_Positioning: |
| 217 run->setText(text, byteLength, runOffset.fX, runOffset.fY, ctx,
props); |
| 218 break; |
| 219 case SkTextBlob::kHorizontal_Positioning: |
| 220 run->setPosText(text, byteLength, iter.pos(), 1, SkPoint::Make(0
, runOffset.fY), |
| 221 ctx, props); |
| 222 break; |
| 223 case SkTextBlob::kFull_Positioning: |
| 224 run->setPosText(text, byteLength, iter.pos(), 2, SkPoint::Make(0
, 0), ctx, props); |
| 225 break; |
| 226 } |
| 227 |
| 228 fCpuMemorySize += run->cpuMemorySize(); |
| 229 } |
| 230 } |
| 231 |
| 232 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
94 | 233 |
95 class GrStencilAndCoverTextContext::FallbackBlobBuilder { | 234 class GrStencilAndCoverTextContext::FallbackBlobBuilder { |
96 public: | 235 public: |
97 FallbackBlobBuilder() : fBuffIdx(0) {} | 236 FallbackBlobBuilder() : fBuffIdx(0) {} |
98 | 237 |
99 bool isInitialized() const { return fBuilder; } | 238 bool isInitialized() const { return fBuilder; } |
100 | 239 |
101 void init(const SkPaint& font, SkScalar textRatio); | 240 void init(const SkPaint& font, SkScalar textRatio); |
102 | 241 |
103 void appendGlyph(uint16_t glyphId, const SkPoint& pos); | 242 void appendGlyph(uint16_t glyphId, const SkPoint& pos); |
104 | 243 |
105 const SkTextBlob* buildIfInitialized(); | 244 const SkTextBlob* buildIfInitialized(); |
106 | 245 |
107 private: | 246 private: |
108 enum { kWriteBufferSize = 1024 }; | 247 enum { kWriteBufferSize = 1024 }; |
109 | 248 |
110 void flush(); | 249 void flush(); |
111 | 250 |
112 SkAutoTDelete<SkTextBlobBuilder> fBuilder; | 251 SkAutoTDelete<SkTextBlobBuilder> fBuilder; |
113 SkPaint fFont; | 252 SkPaint fFont; |
114 int fBuffIdx; | 253 int fBuffIdx; |
115 uint16_t fGlyphIds[kWriteBufferSize]; | 254 uint16_t fGlyphIds[kWriteBufferSize]; |
116 SkPoint fPositions[kWriteBufferSize]; | 255 SkPoint fPositions[kWriteBufferSize]; |
117 }; | 256 }; |
118 | 257 |
119 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 258 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
120 | 259 |
121 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) | 260 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
122 : fStroke(fontAndStroke), | 261 : fStroke(fontAndStroke), |
123 fFont(fontAndStroke) { | 262 fFont(fontAndStroke), |
| 263 fTotalGlyphCount(0) { |
124 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. | 264 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
125 | 265 |
126 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path | 266 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path |
127 // rendering API for stroking). | 267 // rendering API for stroking). |
128 fFont.setStyle(SkPaint::kFill_Style); | 268 fFont.setStyle(SkPaint::kFill_Style); |
129 | 269 |
130 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { | 270 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { |
131 // Instead of letting fake bold get baked into the glyph outlines, do it
with GPU stroke. | 271 // Instead of letting fake bold get baked into the glyph outlines, do it
with GPU stroke. |
132 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), | 272 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), |
133 kStdFakeBoldInterpKeys, | 273 kStdFakeBoldInterpKeys, |
(...skipping 27 matching lines...) Expand all Loading... |
161 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && | 301 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && |
162 0 == fFont.getTextSkewX() && | 302 0 == fFont.getTextSkewX() && |
163 !fFont.isFakeBoldText() && | 303 !fFont.isFakeBoldText() && |
164 !fFont.isVerticalText(); | 304 !fFont.isVerticalText(); |
165 } else { | 305 } else { |
166 fTextRatio = fTextInverseRatio = 1.0f; | 306 fTextRatio = fTextInverseRatio = 1.0f; |
167 fUsingRawGlyphPaths = false; | 307 fUsingRawGlyphPaths = false; |
168 } | 308 } |
169 | 309 |
170 // When drawing from canonically sized paths, the actual local coords are fT
extRatio * coords. | 310 // When drawing from canonically sized paths, the actual local coords are fT
extRatio * coords. |
171 fLocalMatrix.setScale(fTextRatio, fTextRatio); | 311 fLocalMatrixTemplate.setScale(fTextRatio, fTextRatio); |
172 } | 312 } |
173 | 313 |
174 GrStencilAndCoverTextContext::TextRun::~TextRun() { | 314 GrStencilAndCoverTextContext::TextRun::~TextRun() { |
175 } | 315 } |
176 | 316 |
177 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by
teLength, | 317 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by
teLength, |
178 SkScalar x, SkScalar y, GrCo
ntext* ctx, | 318 SkScalar x, SkScalar y, GrCo
ntext* ctx, |
179 const SkSurfaceProps* surfac
eProps) { | 319 const SkSurfaceProps* surfac
eProps) { |
180 SkASSERT(byteLength == 0 || text != nullptr); | 320 SkASSERT(byteLength == 0 || text != nullptr); |
181 | 321 |
182 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); | 322 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
183 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); | 323 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
184 | 324 |
| 325 fTotalGlyphCount = fFont.countText(text, byteLength); |
185 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), | 326 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
186 GrPathRendering::kTranslate_PathTransfor
mType, | 327 GrPathRendering::kTranslate_PathTransfor
mType, |
187 fFont.countText(text, byteLength))); | 328 fTotalGlyphCount)); |
188 | 329 |
189 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); | 330 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
190 | 331 |
191 const char* stop = text + byteLength; | 332 const char* stop = text + byteLength; |
192 | 333 |
193 // Measure first if needed. | 334 // Measure first if needed. |
194 if (fFont.getTextAlign() != SkPaint::kLeft_Align) { | 335 if (fFont.getTextAlign() != SkPaint::kLeft_Align) { |
195 SkFixed stopX = 0; | 336 SkFixed stopX = 0; |
196 SkFixed stopY = 0; | 337 SkFixed stopY = 0; |
197 | 338 |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, | 384 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, |
244 const SkScalar pos[], int
scalarsPerPosition, | 385 const SkScalar pos[], int
scalarsPerPosition, |
245 const SkPoint& offset, Gr
Context* ctx, | 386 const SkPoint& offset, Gr
Context* ctx, |
246 const SkSurfaceProps* sur
faceProps) { | 387 const SkSurfaceProps* sur
faceProps) { |
247 SkASSERT(byteLength == 0 || text != nullptr); | 388 SkASSERT(byteLength == 0 || text != nullptr); |
248 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 389 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
249 | 390 |
250 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); | 391 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
251 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); | 392 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
252 | 393 |
| 394 fTotalGlyphCount = fFont.countText(text, byteLength); |
253 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), | 395 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
254 GrPathRendering::kTranslate_PathTransfor
mType, | 396 GrPathRendering::kTranslate_PathTransfor
mType, |
255 fFont.countText(text, byteLength))); | 397 fTotalGlyphCount)); |
256 | 398 |
257 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); | 399 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
258 | 400 |
259 const char* stop = text + byteLength; | 401 const char* stop = text + byteLength; |
260 | 402 |
261 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 403 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
262 SkTextAlignProc alignProc(fFont.getTextAlign()); | 404 SkTextAlignProc alignProc(fFont.getTextAlign()); |
263 FallbackBlobBuilder fallback; | 405 FallbackBlobBuilder fallback; |
264 while (text < stop) { | 406 while (text < stop) { |
265 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); | 407 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
316 fallback->init(fFont, fTextRatio); | 458 fallback->init(fFont, fTextRatio); |
317 } | 459 } |
318 fallback->appendGlyph(glyph.getGlyphID(), pos); | 460 fallback->appendGlyph(glyph.getGlyphID(), pos); |
319 } else { | 461 } else { |
320 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; | 462 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; |
321 fDraw->append(glyph.getGlyphID(), translate); | 463 fDraw->append(glyph.getGlyphID(), translate); |
322 } | 464 } |
323 } | 465 } |
324 | 466 |
325 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, | 467 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
326 GrRenderTarget* rt, | 468 GrPipelineBuilder* pipelineBuil
der, |
327 const GrClip& clip, | 469 GrColor color, |
328 const GrPaint& paint, | |
329 const SkMatrix& viewMatrix, | 470 const SkMatrix& viewMatrix, |
330 const SkIRect& regionClipBounds
, | 471 SkScalar x, SkScalar y, |
| 472 const SkIRect& clipBounds, |
331 GrTextContext* fallbackTextCont
ext, | 473 GrTextContext* fallbackTextCont
ext, |
332 const SkPaint& originalSkPaint)
const { | 474 const SkPaint& originalSkPaint)
const { |
333 SkASSERT(fDraw); | 475 SkASSERT(fDraw); |
| 476 SkASSERT(pipelineBuilder->getRenderTarget()->isStencilBufferMultisampled() |
| |
| 477 !fFont.isAntiAlias()); |
334 | 478 |
335 if (fDraw->count()) { | 479 if (fDraw->count()) { |
336 GrPipelineBuilder pipelineBuilder(paint, rt, clip); | 480 pipelineBuilder->setState(GrPipelineBuilder::kHWAntialias_Flag, fFont.is
AntiAlias()); |
337 SkASSERT(rt->isStencilBufferMultisampled() || !paint.isAntiAlias()); | |
338 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, paint.isA
ntiAlias()); | |
339 | 481 |
340 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 482 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
341 kZero_StencilOp, | 483 kZero_StencilOp, |
342 kKeep_StencilOp, | 484 kKeep_StencilOp, |
343 kNotEqual_StencilFunc, | 485 kNotEqual_StencilFunc, |
344 0xffff, | 486 0xffff, |
345 0x0000, | 487 0x0000, |
346 0xffff); | 488 0xffff); |
347 | 489 |
348 *pipelineBuilder.stencil() = kStencilPass; | 490 *pipelineBuilder->stencil() = kStencilPass; |
349 | 491 |
350 SkMatrix drawMatrix(viewMatrix); | 492 SkMatrix drawMatrix(viewMatrix); |
| 493 drawMatrix.preTranslate(x, y); |
351 drawMatrix.preScale(fTextRatio, fTextRatio); | 494 drawMatrix.preScale(fTextRatio, fTextRatio); |
352 | 495 |
353 dc->drawPathsFromRange(&pipelineBuilder, drawMatrix, fLocalMatrix, paint
.getColor(), fDraw, | 496 SkMatrix& localMatrix = fLocalMatrixTemplate; |
| 497 localMatrix.setTranslateX(x); |
| 498 localMatrix.setTranslateY(y); |
| 499 |
| 500 dc->drawPathsFromRange(pipelineBuilder, drawMatrix, localMatrix, color,
fDraw, |
354 GrPathRendering::kWinding_FillType); | 501 GrPathRendering::kWinding_FillType); |
355 } | 502 } |
356 | 503 |
357 if (fFallbackTextBlob) { | 504 if (fFallbackTextBlob) { |
358 SkPaint fallbackSkPaint(originalSkPaint); | 505 SkPaint fallbackSkPaint(originalSkPaint); |
359 fStroke.applyToPaint(&fallbackSkPaint); | 506 fStroke.applyToPaint(&fallbackSkPaint); |
360 if (!fStroke.isFillStyle()) { | 507 if (!fStroke.isFillStyle()) { |
361 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); | 508 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
362 } | 509 } |
363 | 510 |
364 fallbackTextContext->drawTextBlob(dc, rt, clip, fallbackSkPaint, viewMat
rix, | 511 fallbackTextContext->drawTextBlob(dc, pipelineBuilder->getRenderTarget()
, |
365 fFallbackTextBlob, 0, 0, nullptr, regi
onClipBounds); | 512 pipelineBuilder->clip(), fallbackSkPai
nt, viewMatrix, |
| 513 fFallbackTextBlob, x, y, nullptr, clip
Bounds); |
366 } | 514 } |
367 } | 515 } |
368 | 516 |
| 517 int GrStencilAndCoverTextContext::TextRun::cpuMemorySize() const { |
| 518 int size = sizeof(TextRun) + fTotalGlyphCount * (sizeof(uint16_t) + 2 * size
of(float)); |
| 519 if (fDraw) { |
| 520 size += sizeof(GrPathRangeDraw); |
| 521 } |
| 522 if (fFallbackTextBlob) { |
| 523 size += sizeof(SkTextBlob); |
| 524 } |
| 525 return size; |
| 526 } |
| 527 |
369 ////////////////////////////////////////////////////////////////////////////////
//////////////////// | 528 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
370 | 529 |
371 void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font
, | 530 void GrStencilAndCoverTextContext::FallbackBlobBuilder::init(const SkPaint& font
, |
372 SkScalar textRatio)
{ | 531 SkScalar textRatio)
{ |
373 SkASSERT(!this->isInitialized()); | 532 SkASSERT(!this->isInitialized()); |
374 fBuilder.reset(new SkTextBlobBuilder); | 533 fBuilder.reset(new SkTextBlobBuilder); |
375 fFont = font; | 534 fFont = font; |
376 fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will alread
y account for align. | 535 fFont.setTextAlign(SkPaint::kLeft_Align); // The glyph positions will alread
y account for align. |
377 fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 536 fFont.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
378 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non
-bitmap color glyphs | 537 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if non
-bitmap color glyphs |
(...skipping 27 matching lines...) Expand all Loading... |
406 fBuffIdx = 0; | 565 fBuffIdx = 0; |
407 } | 566 } |
408 | 567 |
409 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInit
ialized() { | 568 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfInit
ialized() { |
410 if (!this->isInitialized()) { | 569 if (!this->isInitialized()) { |
411 return nullptr; | 570 return nullptr; |
412 } | 571 } |
413 this->flush(); | 572 this->flush(); |
414 return fBuilder->build(); | 573 return fBuilder->build(); |
415 } | 574 } |
OLD | NEW |