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 "SkPath.h" | 20 #include "SkPath.h" |
21 #include "SkTextMapStateProc.h" | 21 #include "SkTextMapStateProc.h" |
22 #include "SkTextFormatParams.h" | 22 #include "SkTextFormatParams.h" |
23 | 23 |
24 #include "batches/GrDrawPathBatch.h" | 24 #include "batches/GrDrawPathBatch.h" |
25 | 25 |
26 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, | 26 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, |
27 const SkSurfaceProps&
surfaceProps) | 27 const SkSurfaceProps&
surfaceProps) |
28 : INHERITED(context, surfaceProps) | 28 : INHERITED(context, surfaceProps) { |
29 , fDraw(nullptr) | |
30 , fStroke(SkStrokeRec::kFill_InitStyle) { | |
31 } | 29 } |
32 | 30 |
33 GrStencilAndCoverTextContext* | 31 GrStencilAndCoverTextContext* |
34 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { | 32 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { |
35 GrStencilAndCoverTextContext* textContext = | 33 GrStencilAndCoverTextContext* textContext = |
36 new GrStencilAndCoverTextContext(context, surfaceProps); | 34 new GrStencilAndCoverTextContext(context, surfaceProps); |
37 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); | 35 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); |
38 | 36 |
39 return textContext; | 37 return textContext; |
40 } | 38 } |
(...skipping 23 matching lines...) Expand all Loading... |
64 | 62 |
65 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, | 63 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, GrRenderTarget*
rt, |
66 const GrClip& clip, | 64 const GrClip& clip, |
67 const GrPaint& paint, | 65 const GrPaint& paint, |
68 const SkPaint& skPaint, | 66 const SkPaint& skPaint, |
69 const SkMatrix& viewMatrix, | 67 const SkMatrix& viewMatrix, |
70 const char text[], | 68 const char text[], |
71 size_t byteLength, | 69 size_t byteLength, |
72 SkScalar x, SkScalar y, | 70 SkScalar x, SkScalar y, |
73 const SkIRect& regionClipBounds) { | 71 const SkIRect& regionClipBounds) { |
| 72 TextRun run(skPaint); |
| 73 run.setText(text, byteLength, x, y, fContext, &fSurfaceProps); |
| 74 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); |
| 75 } |
| 76 |
| 77 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, |
| 78 const GrClip& clip, |
| 79 const GrPaint& paint, |
| 80 const SkPaint& skPaint, |
| 81 const SkMatrix& viewMatrix, |
| 82 const char text[], |
| 83 size_t byteLength, |
| 84 const SkScalar pos[], |
| 85 int scalarsPerPosition, |
| 86 const SkPoint& offset, |
| 87 const SkIRect& regionClipBounds
) { |
| 88 TextRun run(skPaint); |
| 89 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset, fContext,
&fSurfaceProps); |
| 90 run.draw(dc, rt, clip, paint, viewMatrix, regionClipBounds, fFallbackTextCon
text, skPaint); |
| 91 } |
| 92 |
| 93 ////////////////////////////////////////////////////////////////////////////////
//////////////////// |
| 94 |
| 95 GrStencilAndCoverTextContext::TextRun::TextRun(const SkPaint& fontAndStroke) |
| 96 : fStroke(fontAndStroke), |
| 97 fFont(fontAndStroke) { |
| 98 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. |
| 99 |
| 100 // Setting to "fill" ensures that no strokes get baked into font outlines. (
We use the GPU path |
| 101 // rendering API for stroking). |
| 102 fFont.setStyle(SkPaint::kFill_Style); |
| 103 |
| 104 if (fFont.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getStyle
()) { |
| 105 // Instead of letting fake bold get baked into the glyph outlines, do it
with GPU stroke. |
| 106 SkScalar fakeBoldScale = SkScalarInterpFunc(fFont.getTextSize(), |
| 107 kStdFakeBoldInterpKeys, |
| 108 kStdFakeBoldInterpValues, |
| 109 kStdFakeBoldInterpLength); |
| 110 SkScalar extra = SkScalarMul(fFont.getTextSize(), fakeBoldScale); |
| 111 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extr
a : extra, |
| 112 true /*strokeAndFill*/); |
| 113 |
| 114 fFont.setFakeBoldText(false); |
| 115 } |
| 116 |
| 117 if (!fFont.getPathEffect() && !fStroke.isDashed()) { |
| 118 // We can draw the glyphs from canonically sized paths. |
| 119 fTextRatio = fFont.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; |
| 120 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fFont.getTextS
ize(); |
| 121 |
| 122 // Compensate for the glyphs being scaled by fTextRatio. |
| 123 if (!fStroke.isFillStyle()) { |
| 124 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, |
| 125 SkStrokeRec::kStrokeAndFill_Style == fStroke.
getStyle()); |
| 126 } |
| 127 |
| 128 fFont.setLinearText(true); |
| 129 fFont.setLCDRenderText(false); |
| 130 fFont.setAutohinted(false); |
| 131 fFont.setHinting(SkPaint::kNo_Hinting); |
| 132 fFont.setSubpixelText(true); |
| 133 fFont.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)); |
| 134 |
| 135 fUsingRawGlyphPaths = SK_Scalar1 == fFont.getTextScaleX() && |
| 136 0 == fFont.getTextSkewX() && |
| 137 !fFont.isFakeBoldText() && |
| 138 !fFont.isVerticalText(); |
| 139 } else { |
| 140 fTextRatio = fTextInverseRatio = 1.0f; |
| 141 fUsingRawGlyphPaths = false; |
| 142 } |
| 143 |
| 144 // When drawing from canonically sized paths, the actual local coords are fT
extRatio * coords. |
| 145 fLocalMatrix.setScale(fTextRatio, fTextRatio); |
| 146 } |
| 147 |
| 148 GrStencilAndCoverTextContext::TextRun::~TextRun() { |
| 149 } |
| 150 |
| 151 void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t by
teLength, |
| 152 SkScalar x, SkScalar y, GrCo
ntext* ctx, |
| 153 const SkSurfaceProps* surfac
eProps) { |
74 SkASSERT(byteLength == 0 || text != nullptr); | 154 SkASSERT(byteLength == 0 || text != nullptr); |
75 | 155 |
76 if (text == nullptr || byteLength == 0 /*|| fRC->isEmpty()*/) { | 156 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
77 return; | 157 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
78 } | |
79 | 158 |
80 this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBound
s); | 159 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
| 160 GrPathRendering::kTranslate_PathTransfor
mType, |
| 161 fFont.countText(text, byteLength))); |
81 | 162 |
82 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 163 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
83 | 164 |
84 const char* stop = text + byteLength; | 165 const char* stop = text + byteLength; |
85 | 166 |
86 // Measure first if needed. | 167 // Measure first if needed. |
87 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { | 168 if (fFont.getTextAlign() != SkPaint::kLeft_Align) { |
88 SkFixed stopX = 0; | 169 SkFixed stopX = 0; |
89 SkFixed stopY = 0; | 170 SkFixed stopY = 0; |
90 | 171 |
91 const char* textPtr = text; | 172 const char* textPtr = text; |
92 while (textPtr < stop) { | 173 while (textPtr < stop) { |
93 // We don't need x, y here, since all subpixel variants will have th
e | 174 // We don't need x, y here, since all subpixel variants will have th
e |
94 // same advance. | 175 // same advance. |
95 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0); | 176 const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr, 0, 0); |
96 | 177 |
97 stopX += glyph.fAdvanceX; | 178 stopX += glyph.fAdvanceX; |
98 stopY += glyph.fAdvanceY; | 179 stopY += glyph.fAdvanceY; |
99 } | 180 } |
100 SkASSERT(textPtr == stop); | 181 SkASSERT(textPtr == stop); |
101 | 182 |
102 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; | 183 SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio; |
103 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; | 184 SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio; |
104 | 185 |
105 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { | 186 if (fFont.getTextAlign() == SkPaint::kCenter_Align) { |
106 alignX = SkScalarHalf(alignX); | 187 alignX = SkScalarHalf(alignX); |
107 alignY = SkScalarHalf(alignY); | 188 alignY = SkScalarHalf(alignY); |
108 } | 189 } |
109 | 190 |
110 x -= alignX; | 191 x -= alignX; |
111 y -= alignY; | 192 y -= alignY; |
112 } | 193 } |
113 | 194 |
114 SkAutoKern autokern; | 195 SkAutoKern autokern; |
115 | 196 |
116 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); | 197 SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio); |
117 | 198 |
118 SkFixed fx = SkScalarToFixed(x); | 199 SkFixed fx = SkScalarToFixed(x); |
119 SkFixed fy = SkScalarToFixed(y); | 200 SkFixed fy = SkScalarToFixed(y); |
120 while (text < stop) { | 201 while (text < stop) { |
121 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 202 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
122 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); | 203 fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio); |
123 if (glyph.fWidth) { | 204 if (glyph.fWidth) { |
124 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy))); | 205 this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedT
oScalar(fy))); |
125 } | 206 } |
126 | 207 |
127 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); | 208 fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio); |
128 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); | 209 fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio); |
129 } | 210 } |
130 | |
131 this->finish(dc); | |
132 } | 211 } |
133 | 212 |
134 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, GrRenderTarg
et* rt, | 213 void GrStencilAndCoverTextContext::TextRun::setPosText(const char text[], size_t
byteLength, |
135 const GrClip& clip, | 214 const SkScalar pos[], int
scalarsPerPosition, |
136 const GrPaint& paint, | 215 const SkPoint& offset, Gr
Context* ctx, |
137 const SkPaint& skPaint, | 216 const SkSurfaceProps* sur
faceProps) { |
138 const SkMatrix& viewMatrix, | |
139 const char text[], | |
140 size_t byteLength, | |
141 const SkScalar pos[], | |
142 int scalarsPerPosition, | |
143 const SkPoint& offset, | |
144 const SkIRect& regionClipBounds
) { | |
145 SkASSERT(byteLength == 0 || text != nullptr); | 217 SkASSERT(byteLength == 0 || text != nullptr); |
146 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); | 218 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); |
147 | 219 |
148 // nothing to draw | 220 SkAutoGlyphCacheNoGamma autoGlyphCache(fFont, surfaceProps, nullptr); |
149 if (text == nullptr || byteLength == 0/* || fRC->isEmpty()*/) { | 221 SkGlyphCache* glyphCache = autoGlyphCache.getCache(); |
150 return; | |
151 } | |
152 | 222 |
153 this->init(rt, clip, paint, skPaint, byteLength, viewMatrix, regionClipBound
s); | 223 fDraw.reset(GrPathRangeDraw::Create(this->createGlyphs(ctx, glyphCache), |
| 224 GrPathRendering::kTranslate_PathTransfor
mType, |
| 225 fFont.countText(text, byteLength))); |
154 | 226 |
155 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); | 227 SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc(); |
156 | 228 |
157 const char* stop = text + byteLength; | 229 const char* stop = text + byteLength; |
158 | 230 |
159 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); | 231 SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition); |
160 SkTextAlignProc alignProc(fSkPaint.getTextAlign()); | 232 SkTextAlignProc alignProc(fFont.getTextAlign()); |
161 while (text < stop) { | 233 while (text < stop) { |
162 const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0); | 234 const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0); |
163 if (glyph.fWidth) { | 235 if (glyph.fWidth) { |
164 SkPoint tmsLoc; | 236 SkPoint tmsLoc; |
165 tmsProc(pos, &tmsLoc); | 237 tmsProc(pos, &tmsLoc); |
166 SkPoint loc; | 238 SkPoint loc; |
167 alignProc(tmsLoc, glyph, &loc); | 239 alignProc(tmsLoc, glyph, &loc); |
168 | 240 |
169 this->appendGlyph(glyph, loc); | 241 this->appendGlyph(glyph, loc); |
170 } | 242 } |
171 pos += scalarsPerPosition; | 243 pos += scalarsPerPosition; |
172 } | 244 } |
173 | |
174 this->finish(dc); | |
175 } | 245 } |
176 | 246 |
177 static GrPathRange* get_gr_glyphs(GrContext* ctx, | 247 GrPathRange* GrStencilAndCoverTextContext::TextRun::createGlyphs(GrContext* ctx, |
178 const SkTypeface* typeface, | 248 SkGlyphCache* g
lyphCache) { |
179 const SkDescriptor* desc, | 249 SkTypeface* typeface = fUsingRawGlyphPaths ? fFont.getTypeface() |
180 const GrStrokeInfo& stroke) { | 250 : glyphCache->getScalerContext()-
>getTypeface(); |
| 251 const SkDescriptor* desc = fUsingRawGlyphPaths ? nullptr : &glyphCache->getD
escriptor(); |
181 | 252 |
182 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDom
ain(); | 253 static const GrUniqueKey::Domain kPathGlyphDomain = GrUniqueKey::GenerateDom
ain(); |
183 int strokeDataCount = stroke.computeUniqueKeyFragmentData32Cnt(); | 254 int strokeDataCount = fStroke.computeUniqueKeyFragmentData32Cnt(); |
184 GrUniqueKey glyphKey; | 255 GrUniqueKey glyphKey; |
185 GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCoun
t); | 256 GrUniqueKey::Builder builder(&glyphKey, kPathGlyphDomain, 2 + strokeDataCoun
t); |
186 reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0; | 257 reinterpret_cast<uint32_t&>(builder[0]) = desc ? desc->getChecksum() : 0; |
187 reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() :
0; | 258 reinterpret_cast<uint32_t&>(builder[1]) = typeface ? typeface->uniqueID() :
0; |
188 if (strokeDataCount > 0) { | 259 if (strokeDataCount > 0) { |
189 stroke.asUniqueKeyFragment(&builder[2]); | 260 fStroke.asUniqueKeyFragment(&builder[2]); |
190 } | 261 } |
191 builder.finish(); | 262 builder.finish(); |
192 | 263 |
193 SkAutoTUnref<GrPathRange> glyphs( | 264 SkAutoTUnref<GrPathRange> glyphs( |
194 static_cast<GrPathRange*>( | 265 static_cast<GrPathRange*>( |
195 ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey))); | 266 ctx->resourceProvider()->findAndRefResourceByUniqueKey(glyphKey))); |
196 if (nullptr == glyphs) { | 267 if (nullptr == glyphs) { |
197 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, strok
e)); | 268 glyphs.reset(ctx->resourceProvider()->createGlyphs(typeface, desc, fStro
ke)); |
198 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); | 269 ctx->resourceProvider()->assignUniqueKeyToResource(glyphKey, glyphs); |
199 } else { | 270 } else { |
200 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); | 271 SkASSERT(nullptr == desc || glyphs->isEqualTo(*desc)); |
201 } | 272 } |
202 | 273 |
203 return glyphs.detach(); | 274 return glyphs.detach(); |
204 } | 275 } |
205 | 276 |
206 void GrStencilAndCoverTextContext::init(GrRenderTarget* rt, | 277 inline void GrStencilAndCoverTextContext::TextRun::appendGlyph(const SkGlyph& gl
yph, |
207 const GrClip& clip, | 278 const SkPoint& po
s) { |
208 const GrPaint& paint, | |
209 const SkPaint& skPaint, | |
210 size_t textByteLength, | |
211 const SkMatrix& viewMatrix, | |
212 const SkIRect& regionClipBounds) { | |
213 fClip = clip; | |
214 | |
215 fRenderTarget.reset(SkRef(rt)); | |
216 | |
217 fRegionClipBounds = regionClipBounds; | |
218 fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(),
&fClipRect); | |
219 | |
220 fPaint = paint; | |
221 fSkPaint = skPaint; | |
222 | |
223 // Don't bake strokes into the glyph outlines. We will stroke the glyphs usi
ng the GPU instead. | |
224 fStroke = GrStrokeInfo(fSkPaint); | |
225 fSkPaint.setStyle(SkPaint::kFill_Style); | |
226 | |
227 SkASSERT(!fStroke.isHairlineStyle()); // Hairlines are not supported. | |
228 | |
229 if (fSkPaint.isFakeBoldText() && SkStrokeRec::kStroke_Style != fStroke.getSt
yle()) { | |
230 // Instead of baking fake bold into the glyph outlines, do it with the G
PU stroke. | |
231 SkScalar fakeBoldScale = SkScalarInterpFunc(fSkPaint.getTextSize(), | |
232 kStdFakeBoldInterpKeys, | |
233 kStdFakeBoldInterpValues, | |
234 kStdFakeBoldInterpLength); | |
235 SkScalar extra = SkScalarMul(fSkPaint.getTextSize(), fakeBoldScale); | |
236 fStroke.setStrokeStyle(fStroke.needToApply() ? fStroke.getWidth() + extr
a : extra, | |
237 true /*strokeAndFill*/); | |
238 | |
239 fSkPaint.setFakeBoldText(false); | |
240 } | |
241 | |
242 bool canUseRawPaths; | |
243 if (!fStroke.isDashed()) { | |
244 // We can draw the glyphs from canonically sized paths. | |
245 fTextRatio = fSkPaint.getTextSize() / SkPaint::kCanonicalTextSizeForPath
s; | |
246 fTextInverseRatio = SkPaint::kCanonicalTextSizeForPaths / fSkPaint.getTe
xtSize(); | |
247 | |
248 // Compensate for the glyphs being scaled by fTextRatio. | |
249 if (!fStroke.isFillStyle()) { | |
250 fStroke.setStrokeStyle(fStroke.getWidth() / fTextRatio, | |
251 SkStrokeRec::kStrokeAndFill_Style == fStroke.
getStyle()); | |
252 } | |
253 | |
254 fSkPaint.setLinearText(true); | |
255 fSkPaint.setLCDRenderText(false); | |
256 fSkPaint.setAutohinted(false); | |
257 fSkPaint.setHinting(SkPaint::kNo_Hinting); | |
258 fSkPaint.setSubpixelText(true); | |
259 fSkPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths))
; | |
260 | |
261 canUseRawPaths = SK_Scalar1 == fSkPaint.getTextScaleX() && | |
262 0 == fSkPaint.getTextSkewX() && | |
263 !fSkPaint.isFakeBoldText() && | |
264 !fSkPaint.isVerticalText(); | |
265 } else { | |
266 fTextRatio = fTextInverseRatio = 1.0f; | |
267 canUseRawPaths = false; | |
268 } | |
269 | |
270 fViewMatrix = viewMatrix; | |
271 fViewMatrix.preScale(fTextRatio, fTextRatio); | |
272 fLocalMatrix.setScale(fTextRatio, fTextRatio); | |
273 | |
274 fGlyphCache = fSkPaint.detachCache(&fSurfaceProps, nullptr, true /*ignoreGam
ma*/); | |
275 fGlyphs = canUseRawPaths ? | |
276 get_gr_glyphs(fContext, fSkPaint.getTypeface(), nullptr, fStro
ke) : | |
277 get_gr_glyphs(fContext, fGlyphCache->getScalerContext()->getTy
peface(), | |
278 &fGlyphCache->getDescriptor(), fStroke); | |
279 } | |
280 | |
281 inline void GrStencilAndCoverTextContext::appendGlyph(const SkGlyph& glyph, cons
t SkPoint& pos) { | |
282 // Stick the glyphs we can't draw into the fallback arrays. | 279 // Stick the glyphs we can't draw into the fallback arrays. |
283 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { | 280 if (SkMask::kARGB32_Format == glyph.fMaskFormat) { |
284 fFallbackIndices.push_back(glyph.getGlyphID()); | 281 fFallbackIndices.push_back(glyph.getGlyphID()); |
285 fFallbackPositions.push_back(pos); | 282 fFallbackPositions.push_back(pos); |
286 } else { | 283 } else { |
287 // TODO: infer the reserve count from the text length. | |
288 if (!fDraw) { | |
289 fDraw = GrPathRangeDraw::Create(fGlyphs, | |
290 GrPathRendering::kTranslate_PathTran
sformType, | |
291 64); | |
292 } | |
293 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; | 284 float translate[] = { fTextInverseRatio * pos.x(), fTextInverseRatio * p
os.y() }; |
294 fDraw->append(glyph.getGlyphID(), translate); | 285 fDraw->append(glyph.getGlyphID(), translate); |
295 } | 286 } |
296 } | 287 } |
297 | 288 |
298 void GrStencilAndCoverTextContext::flush(GrDrawContext* dc) { | 289 void GrStencilAndCoverTextContext::TextRun::draw(GrDrawContext* dc, |
299 if (fDraw) { | 290 GrRenderTarget* rt, |
300 SkASSERT(fDraw->count()); | 291 const GrClip& clip, |
| 292 const GrPaint& paint, |
| 293 const SkMatrix& viewMatrix, |
| 294 const SkIRect& regionClipBounds
, |
| 295 GrTextContext* fallbackTextCont
ext, |
| 296 const SkPaint& originalSkPaint)
const { |
| 297 SkASSERT(fDraw); |
301 | 298 |
302 // We should only be flushing about once every run. However, if this im
pacts performance | 299 if (fDraw->count()) { |
303 // we could move the creation of the GrPipelineBuilder earlier. | 300 GrPipelineBuilder pipelineBuilder(paint, rt, clip); |
304 GrPipelineBuilder pipelineBuilder(fPaint, fRenderTarget, fClip); | 301 SkASSERT(rt->isStencilBufferMultisampled() || !paint.isAntiAlias()); |
305 SkASSERT(fRenderTarget->isStencilBufferMultisampled() || !fPaint.isAntiA
lias()); | 302 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, paint.isA
ntiAlias()); |
306 pipelineBuilder.setState(GrPipelineBuilder::kHWAntialias_Flag, fPaint.is
AntiAlias()); | |
307 | 303 |
308 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, | 304 GR_STATIC_CONST_SAME_STENCIL(kStencilPass, |
309 kZero_StencilOp, | 305 kZero_StencilOp, |
310 kKeep_StencilOp, | 306 kKeep_StencilOp, |
311 kNotEqual_StencilFunc, | 307 kNotEqual_StencilFunc, |
312 0xffff, | 308 0xffff, |
313 0x0000, | 309 0x0000, |
314 0xffff); | 310 0xffff); |
315 | 311 |
316 *pipelineBuilder.stencil() = kStencilPass; | 312 *pipelineBuilder.stencil() = kStencilPass; |
317 | 313 |
318 dc->drawPathsFromRange(&pipelineBuilder, fViewMatrix, fLocalMatrix, fPai
nt.getColor(), | 314 SkMatrix drawMatrix(viewMatrix); |
319 fDraw, GrPathRendering::kWinding_FillType); | 315 drawMatrix.preScale(fTextRatio, fTextRatio); |
320 fDraw->unref(); | 316 |
321 fDraw = nullptr; | 317 dc->drawPathsFromRange(&pipelineBuilder, drawMatrix, fLocalMatrix, paint
.getColor(), fDraw, |
| 318 GrPathRendering::kWinding_FillType); |
322 } | 319 } |
323 | 320 |
324 if (fFallbackIndices.count()) { | 321 if (fFallbackIndices.count()) { |
325 SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); | 322 SkASSERT(fFallbackPositions.count() == fFallbackIndices.count()); |
326 | 323 |
327 SkPaint fallbackSkPaint(fSkPaint); | 324 enum { kPreservedFlags = SkPaint::kFakeBoldText_Flag | SkPaint::kLinearT
ext_Flag | |
| 325 SkPaint::kLCDRenderText_Flag | SkPaint::kAutoHi
nting_Flag }; |
| 326 |
| 327 SkPaint fallbackSkPaint(originalSkPaint); |
328 fStroke.applyToPaint(&fallbackSkPaint); | 328 fStroke.applyToPaint(&fallbackSkPaint); |
329 if (!fStroke.isFillStyle()) { | 329 if (!fStroke.isFillStyle()) { |
330 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); | 330 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
331 } | 331 } |
332 fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already
been accounted for. | 332 fallbackSkPaint.setTextAlign(SkPaint::kLeft_Align); // Align has already
been accounted for. |
333 fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); | 333 fallbackSkPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); |
| 334 fallbackSkPaint.setHinting(fFont.getHinting()); |
| 335 fallbackSkPaint.setFlags((fFont.getFlags() & kPreservedFlags) | |
| 336 (originalSkPaint.getFlags() & ~kPreservedFlags)
); |
334 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if
non-bitmap color | 337 // No need for subpixel positioning with bitmap glyphs. TODO: revisit if
non-bitmap color |
335 // glyphs show up and https://code.google.com/p/skia/issues/detail?id=44
08 gets resolved. | 338 // glyphs show up and https://code.google.com/p/skia/issues/detail?id=44
08 gets resolved. |
336 fallbackSkPaint.setSubpixelText(false); | 339 fallbackSkPaint.setSubpixelText(false); |
337 fallbackSkPaint.setTextSize(fSkPaint.getTextSize() * fTextRatio); | 340 fallbackSkPaint.setTextSize(fFont.getTextSize() * fTextRatio); |
338 | 341 |
339 SkMatrix fallbackMatrix(fViewMatrix); | 342 fallbackTextContext->drawPosText(dc, rt, clip, paint, fallbackSkPaint, v
iewMatrix, |
340 fallbackMatrix.preScale(fTextInverseRatio, fTextInverseRatio); | 343 (char*)fFallbackIndices.begin(), |
341 | 344 sizeof(uint16_t) * fFallbackIndices.cou
nt(), |
342 fFallbackTextContext->drawPosText(dc, fRenderTarget, fClip, fPaint, fall
backSkPaint, | 345 fFallbackPositions[0].asScalars(), 2, S
kPoint::Make(0, 0), |
343 fallbackMatrix, (char*)fFallbackIndice
s.begin(), | 346 regionClipBounds); |
344 sizeof(uint16_t) * fFallbackIndices.co
unt(), | |
345 fFallbackPositions[0].asScalars(), 2,
SkPoint::Make(0, 0), | |
346 fRegionClipBounds); | |
347 fFallbackIndices.reset(); | |
348 fFallbackPositions.reset(); | |
349 } | 347 } |
350 } | 348 } |
351 | |
352 void GrStencilAndCoverTextContext::finish(GrDrawContext* dc) { | |
353 this->flush(dc); | |
354 | |
355 SkASSERT(!fDraw); | |
356 SkASSERT(!fFallbackIndices.count()); | |
357 SkASSERT(!fFallbackPositions.count()); | |
358 | |
359 fGlyphs->unref(); | |
360 fGlyphs = nullptr; | |
361 | |
362 SkGlyphCache::AttachCache(fGlyphCache); | |
363 fGlyphCache = nullptr; | |
364 } | |
OLD | NEW |