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 19 matching lines...) Expand all Loading... |
30 template<typename Key, typename Val> static void delete_hash_map_entry(const Key
&, Val* val) { | 30 template<typename Key, typename Val> static void delete_hash_map_entry(const Key
&, Val* val) { |
31 SkASSERT(*val); | 31 SkASSERT(*val); |
32 delete *val; | 32 delete *val; |
33 } | 33 } |
34 | 34 |
35 template<typename T> static void delete_hash_table_entry(T* val) { | 35 template<typename T> static void delete_hash_table_entry(T* val) { |
36 SkASSERT(*val); | 36 SkASSERT(*val); |
37 delete *val; | 37 delete *val; |
38 } | 38 } |
39 | 39 |
40 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context) | 40 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext() |
41 : INHERITED(context) | 41 : fFallbackTextContext(nullptr) |
42 , fFallbackTextContext(nullptr) | |
43 , fCacheSize(0) { | 42 , fCacheSize(0) { |
44 } | 43 } |
45 | 44 |
46 GrStencilAndCoverTextContext* | 45 GrStencilAndCoverTextContext* |
47 GrStencilAndCoverTextContext::Create(GrContext* context) { | 46 GrStencilAndCoverTextContext::Create() { |
48 GrStencilAndCoverTextContext* textContext = | 47 GrStencilAndCoverTextContext* textContext = new GrStencilAndCoverTextContext
(); |
49 new GrStencilAndCoverTextContext(context); | 48 textContext->fFallbackTextContext = GrAtlasTextContext::Create(); |
50 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context); | |
51 | 49 |
52 return textContext; | 50 return textContext; |
53 } | 51 } |
54 | 52 |
55 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { | 53 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { |
56 delete fFallbackTextContext; | 54 delete fFallbackTextContext; |
57 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>); | 55 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>); |
58 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>); | 56 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>); |
59 } | 57 } |
60 | 58 |
61 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { | 59 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { |
62 if (skPaint.getRasterizer()) { | 60 if (skPaint.getRasterizer()) { |
63 return false; | 61 return false; |
64 } | 62 } |
65 if (skPaint.getMaskFilter()) { | 63 if (skPaint.getMaskFilter()) { |
66 return false; | 64 return false; |
67 } | 65 } |
68 if (SkPathEffect* pe = skPaint.getPathEffect()) { | 66 if (SkPathEffect* pe = skPaint.getPathEffect()) { |
69 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { | 67 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { |
70 return false; | 68 return false; |
71 } | 69 } |
72 } | 70 } |
73 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. | 71 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. |
74 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); | 72 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); |
75 } | 73 } |
76 | 74 |
77 void GrStencilAndCoverTextContext::drawText(GrDrawContext* dc, | 75 void GrStencilAndCoverTextContext::drawText(GrContext* context, GrDrawContext* d
c, |
78 const GrClip& clip, const GrPaint& p
aint, | 76 const GrClip& clip, const GrPaint& p
aint, |
79 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, | 77 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, |
80 const SkSurfaceProps& props, | 78 const SkSurfaceProps& props, |
81 const char text[], size_t byteLength
, | 79 const char text[], size_t byteLength
, |
82 SkScalar x, SkScalar y, const SkIRec
t& clipBounds) { | 80 SkScalar x, SkScalar y, const SkIRec
t& clipBounds) { |
83 if (fContext->abandoned()) { | 81 if (context->abandoned()) { |
84 return; | 82 return; |
85 } else if (this->canDraw(skPaint, viewMatrix)) { | 83 } else if (this->canDraw(skPaint, viewMatrix)) { |
86 TextRun run(skPaint); | 84 TextRun run(skPaint); |
87 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; | 85 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; |
88 run.setText(text, byteLength, x, y); | 86 run.setText(text, byteLength, x, y); |
89 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, p
rops, 0, 0, | 87 run.draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, pr
ops, 0, 0, |
90 clipBounds, fFallbackTextContext, skPaint); | 88 clipBounds, fFallbackTextContext, skPaint); |
91 return; | 89 return; |
92 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props)) { | 90 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props, |
93 fFallbackTextContext->drawText(dc, clip, paint, skPaint, viewMatrix, pro
ps, text, | 91 *context->caps()->shaderCaps())) { |
| 92 fFallbackTextContext->drawText(context, dc, clip, paint, skPaint, viewMa
trix, props, text, |
94 byteLength, x, y, clipBounds); | 93 byteLength, x, y, clipBounds); |
95 return; | 94 return; |
96 } | 95 } |
97 | 96 |
98 // fall back to drawing as a path | 97 // fall back to drawing as a path |
99 GrTextUtils::DrawTextAsPath(fContext, dc, clip, skPaint, viewMatrix, text, b
yteLength, x, y, | 98 GrTextUtils::DrawTextAsPath(context, dc, clip, skPaint, viewMatrix, text, by
teLength, x, y, |
100 clipBounds); | 99 clipBounds); |
101 } | 100 } |
102 | 101 |
103 void GrStencilAndCoverTextContext::drawPosText(GrDrawContext* dc, | 102 void GrStencilAndCoverTextContext::drawPosText(GrContext* context, GrDrawContext
* dc, |
104 const GrClip& clip, | 103 const GrClip& clip, |
105 const GrPaint& paint, | 104 const GrPaint& paint, |
106 const SkPaint& skPaint, | 105 const SkPaint& skPaint, |
107 const SkMatrix& viewMatrix, | 106 const SkMatrix& viewMatrix, |
108 const SkSurfaceProps& props, | 107 const SkSurfaceProps& props, |
109 const char text[], | 108 const char text[], |
110 size_t byteLength, | 109 size_t byteLength, |
111 const SkScalar pos[], | 110 const SkScalar pos[], |
112 int scalarsPerPosition, | 111 int scalarsPerPosition, |
113 const SkPoint& offset, | 112 const SkPoint& offset, |
114 const SkIRect& clipBounds) { | 113 const SkIRect& clipBounds) { |
115 if (fContext->abandoned()) { | 114 if (context->abandoned()) { |
116 return; | 115 return; |
117 } else if (this->canDraw(skPaint, viewMatrix)) { | 116 } else if (this->canDraw(skPaint, viewMatrix)) { |
118 TextRun run(skPaint); | 117 TextRun run(skPaint); |
119 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; | 118 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; |
120 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); | 119 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); |
121 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, p
rops, 0, 0, | 120 run.draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, pr
ops, 0, 0, |
122 clipBounds, fFallbackTextContext, skPaint); | 121 clipBounds, fFallbackTextContext, skPaint); |
123 return; | 122 return; |
124 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props)) { | 123 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix, props, |
125 fFallbackTextContext->drawPosText(dc, clip, paint, skPaint, viewMatrix,
props, | 124 *context->caps()->shaderCaps())) { |
| 125 fFallbackTextContext->drawPosText(context, dc, clip, paint, skPaint, vie
wMatrix, props, |
126 text, byteLength, pos, | 126 text, byteLength, pos, |
127 scalarsPerPosition, offset, clipBounds
); | 127 scalarsPerPosition, offset, clipBounds
); |
128 return; | 128 return; |
129 } | 129 } |
130 | 130 |
131 // fall back to drawing as a path | 131 // fall back to drawing as a path |
132 GrTextUtils::DrawPosTextAsPath(fContext, dc, props, clip, skPaint, viewMatri
x, text, | 132 GrTextUtils::DrawPosTextAsPath(context, dc, props, clip, skPaint, viewMatrix
, text, |
133 byteLength, pos, scalarsPerPosition, offset,
clipBounds); | 133 byteLength, pos, scalarsPerPosition, offset,
clipBounds); |
134 } | 134 } |
135 | 135 |
136 void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrDrawContext* dc, | 136 void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrContext* context, |
| 137 GrDrawContext* dc, |
137 const GrClip& clip, cons
t SkPaint& skPaint, | 138 const GrClip& clip, cons
t SkPaint& skPaint, |
138 const SkMatrix& viewMatr
ix, | 139 const SkMatrix& viewMatr
ix, |
139 const SkSurfaceProps& pr
ops, | 140 const SkSurfaceProps& pr
ops, |
140 const SkTextBlob* blob, | 141 const SkTextBlob* blob, |
141 SkScalar x, SkScalar y, | 142 SkScalar x, SkScalar y, |
142 SkDrawFilter* drawFilter
, | 143 SkDrawFilter* drawFilter
, |
143 const SkIRect& clipBound
s) { | 144 const SkIRect& clipBound
s) { |
144 SkPaint runPaint = skPaint; | 145 SkPaint runPaint = skPaint; |
145 | 146 |
146 SkTextBlobRunIterator it(blob); | 147 SkTextBlobRunIterator it(blob); |
147 for (;!it.done(); it.next()) { | 148 for (;!it.done(); it.next()) { |
148 size_t textLen = it.glyphCount() * sizeof(uint16_t); | 149 size_t textLen = it.glyphCount() * sizeof(uint16_t); |
149 const SkPoint& offset = it.offset(); | 150 const SkPoint& offset = it.offset(); |
150 | 151 |
151 // applyFontToPaint() always overwrites the exact same attributes, | 152 // applyFontToPaint() always overwrites the exact same attributes, |
152 // so it is safe to not re-seed the paint for this reason. | 153 // so it is safe to not re-seed the paint for this reason. |
153 it.applyFontToPaint(&runPaint); | 154 it.applyFontToPaint(&runPaint); |
154 | 155 |
155 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { | 156 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
156 // A false return from filter() means we should abort the current dr
aw. | 157 // A false return from filter() means we should abort the current dr
aw. |
157 runPaint = skPaint; | 158 runPaint = skPaint; |
158 continue; | 159 continue; |
159 } | 160 } |
160 | 161 |
161 runPaint.setFlags(FilterTextFlags(props, runPaint)); | 162 runPaint.setFlags(FilterTextFlags(props, runPaint)); |
162 | 163 |
163 GrPaint grPaint; | 164 GrPaint grPaint; |
164 if (!SkPaintToGrPaint(fContext, runPaint, viewMatrix, &grPaint)) { | 165 if (!SkPaintToGrPaint(context, runPaint, viewMatrix, &grPaint)) { |
165 return; | 166 return; |
166 } | 167 } |
167 | 168 |
168 switch (it.positioning()) { | 169 switch (it.positioning()) { |
169 case SkTextBlob::kDefault_Positioning: | 170 case SkTextBlob::kDefault_Positioning: |
170 this->drawText(dc, clip, grPaint, runPaint, viewMatrix, props, | 171 this->drawText(context, dc, clip, grPaint, runPaint, viewMatrix,
props, |
171 (const char *)it.glyphs(), | 172 (const char *)it.glyphs(), |
172 textLen, x + offset.x(), y + offset.y(), clipBoun
ds); | 173 textLen, x + offset.x(), y + offset.y(), clipBoun
ds); |
173 break; | 174 break; |
174 case SkTextBlob::kHorizontal_Positioning: | 175 case SkTextBlob::kHorizontal_Positioning: |
175 this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, props
, | 176 this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatr
ix, props, |
176 (const char*)it.glyphs(), | 177 (const char*)it.glyphs(), |
177 textLen, it.pos(), 1, SkPoint::Make(x, y + off
set.y()), | 178 textLen, it.pos(), 1, SkPoint::Make(x, y + off
set.y()), |
178 clipBounds); | 179 clipBounds); |
179 break; | 180 break; |
180 case SkTextBlob::kFull_Positioning: | 181 case SkTextBlob::kFull_Positioning: |
181 this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, props
, | 182 this->drawPosText(context, dc, clip, grPaint, runPaint, viewMatr
ix, props, |
182 (const char*)it.glyphs(), | 183 (const char*)it.glyphs(), |
183 textLen, it.pos(), 2, SkPoint::Make(x, y), cli
pBounds); | 184 textLen, it.pos(), 2, SkPoint::Make(x, y), cli
pBounds); |
184 break; | 185 break; |
185 } | 186 } |
186 | 187 |
187 if (drawFilter) { | 188 if (drawFilter) { |
188 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. | 189 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
189 runPaint = skPaint; | 190 runPaint = skPaint; |
190 } | 191 } |
191 } | 192 } |
192 } | 193 } |
193 | 194 |
194 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, | 195 void GrStencilAndCoverTextContext::drawTextBlob(GrContext* context, GrDrawContex
t* dc, |
195 const GrClip& clip, const SkPain
t& skPaint, | 196 const GrClip& clip, const SkPain
t& skPaint, |
196 const SkMatrix& viewMatrix, | 197 const SkMatrix& viewMatrix, |
197 const SkSurfaceProps& props, | 198 const SkSurfaceProps& props, |
198 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, | 199 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, |
199 SkDrawFilter* drawFilter, | 200 SkDrawFilter* drawFilter, |
200 const SkIRect& clipBounds) { | 201 const SkIRect& clipBounds) { |
201 if (fContext->abandoned()) { | 202 if (context->abandoned()) { |
202 return; | 203 return; |
203 } | 204 } |
204 | 205 |
205 if (!this->internalCanDraw(skPaint)) { | 206 if (!this->internalCanDraw(skPaint)) { |
206 fFallbackTextContext->drawTextBlob(dc, clip, skPaint, viewMatrix, props,
skBlob, x, y, | 207 fFallbackTextContext->drawTextBlob(context, dc, clip, skPaint, viewMatri
x, props, skBlob, |
207 drawFilter, clipBounds); | 208 x, y, drawFilter, clipBounds); |
208 return; | 209 return; |
209 } | 210 } |
210 | 211 |
211 if (drawFilter || skPaint.getPathEffect()) { | 212 if (drawFilter || skPaint.getPathEffect()) { |
212 // This draw can't be cached. | 213 // This draw can't be cached. |
213 this->uncachedDrawTextBlob(dc, clip, skPaint, viewMatrix, props, skBlob,
x, y, drawFilter, | 214 this->uncachedDrawTextBlob(context, dc, clip, skPaint, viewMatrix, props
, skBlob, x, y, |
214 clipBounds); | 215 drawFilter, clipBounds); |
215 return; | 216 return; |
216 } | 217 } |
217 | 218 |
218 GrPaint paint; | 219 GrPaint paint; |
219 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { | 220 if (!SkPaintToGrPaint(context, skPaint, viewMatrix, &paint)) { |
220 return; | 221 return; |
221 } | 222 } |
222 | 223 |
223 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); | 224 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); |
224 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); | 225 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); |
225 | 226 |
226 TextBlob::Iter iter(blob); | 227 TextBlob::Iter iter(blob); |
227 for (TextRun* run = iter.get(); run; run = iter.next()) { | 228 for (TextRun* run = iter.get(); run; run = iter.next()) { |
228 run->draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix,
props, x, y, | 229 run->draw(context, dc, &pipelineBuilder, paint.getColor(), viewMatrix, p
rops, x, y, |
229 clipBounds, fFallbackTextContext, skPaint); | 230 clipBounds, fFallbackTextContext, skPaint); |
230 run->releaseGlyphCache(); | 231 run->releaseGlyphCache(); |
231 } | 232 } |
232 } | 233 } |
233 | 234 |
234 const GrStencilAndCoverTextContext::TextBlob& | 235 const GrStencilAndCoverTextContext::TextBlob& |
235 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, | 236 GrStencilAndCoverTextContext::findOrCreateTextBlob(const SkTextBlob* skBlob, |
236 const SkPaint& skPaint) { | 237 const SkPaint& skPaint) { |
237 // The font-related parameters are baked into the text blob and will overrid
e this skPaint, so | 238 // The font-related parameters are baked into the text blob and will overrid
e this skPaint, so |
238 // the only remaining properties that can affect a TextBlob are the ones rel
ated to stroke. | 239 // the only remaining properties that can affect a TextBlob are the ones rel
ated to stroke. |
(...skipping 374 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 dc->drawPathBatch(*pipelineBuilder, batch); | 614 dc->drawPathBatch(*pipelineBuilder, batch); |
614 } | 615 } |
615 | 616 |
616 if (fFallbackTextBlob) { | 617 if (fFallbackTextBlob) { |
617 SkPaint fallbackSkPaint(originalSkPaint); | 618 SkPaint fallbackSkPaint(originalSkPaint); |
618 fStroke.applyToPaint(&fallbackSkPaint); | 619 fStroke.applyToPaint(&fallbackSkPaint); |
619 if (!fStroke.isFillStyle()) { | 620 if (!fStroke.isFillStyle()) { |
620 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); | 621 fallbackSkPaint.setStrokeWidth(fStroke.getWidth() * fTextRatio); |
621 } | 622 } |
622 | 623 |
623 fallbackTextContext->drawTextBlob(dc, pipelineBuilder->clip(), fallbackS
kPaint, viewMatrix, | 624 fallbackTextContext->drawTextBlob(ctx, dc, pipelineBuilder->clip(), fall
backSkPaint, |
624 props, fFallbackTextBlob, x, y, nullpt
r, clipBounds); | 625 viewMatrix, props, fFallbackTextBlob,
x, y, nullptr, |
| 626 clipBounds); |
625 } | 627 } |
626 } | 628 } |
627 | 629 |
628 SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const { | 630 SkGlyphCache* GrStencilAndCoverTextContext::TextRun::getGlyphCache() const { |
629 if (!fDetachedGlyphCache) { | 631 if (!fDetachedGlyphCache) { |
630 fDetachedGlyphCache = fFont.detachCache(nullptr, nullptr, true /*ignoreG
amma*/); | 632 fDetachedGlyphCache = fFont.detachCache(nullptr, nullptr, true /*ignoreG
amma*/); |
631 } | 633 } |
632 return fDetachedGlyphCache; | 634 return fDetachedGlyphCache; |
633 } | 635 } |
634 | 636 |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
695 } | 697 } |
696 | 698 |
697 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeed
ed(int *count) { | 699 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeed
ed(int *count) { |
698 *count = fCount; | 700 *count = fCount; |
699 if (fCount) { | 701 if (fCount) { |
700 this->flush(); | 702 this->flush(); |
701 return fBuilder->build(); | 703 return fBuilder->build(); |
702 } | 704 } |
703 return nullptr; | 705 return nullptr; |
704 } | 706 } |
OLD | NEW |