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 "GrTextUtils.h" |
15 #include "SkAutoKern.h" | 16 #include "SkAutoKern.h" |
16 #include "SkDraw.h" | 17 #include "SkDraw.h" |
17 #include "SkDrawProcs.h" | 18 #include "SkDrawProcs.h" |
18 #include "SkGlyphCache.h" | 19 #include "SkGlyphCache.h" |
19 #include "SkGpuDevice.h" | 20 #include "SkGpuDevice.h" |
20 #include "SkGrPriv.h" | 21 #include "SkGrPriv.h" |
| 22 #include "SkDrawFilter.h" |
21 #include "SkPath.h" | 23 #include "SkPath.h" |
22 #include "SkTextBlobRunIterator.h" | 24 #include "SkTextBlobRunIterator.h" |
23 #include "SkTextMapStateProc.h" | 25 #include "SkTextMapStateProc.h" |
24 #include "SkTextFormatParams.h" | 26 #include "SkTextFormatParams.h" |
25 | 27 |
26 #include "batches/GrDrawPathBatch.h" | 28 #include "batches/GrDrawPathBatch.h" |
27 | 29 |
28 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) { |
29 SkASSERT(*val); | 31 SkASSERT(*val); |
30 delete *val; | 32 delete *val; |
31 } | 33 } |
32 | 34 |
33 template<typename T> static void delete_hash_table_entry(T* val) { | 35 template<typename T> static void delete_hash_table_entry(T* val) { |
34 SkASSERT(*val); | 36 SkASSERT(*val); |
35 delete *val; | 37 delete *val; |
36 } | 38 } |
37 | 39 |
38 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, | 40 GrStencilAndCoverTextContext::GrStencilAndCoverTextContext(GrContext* context, |
39 const SkSurfaceProps&
surfaceProps) | 41 const SkSurfaceProps&
surfaceProps) |
40 : INHERITED(context, surfaceProps), | 42 : INHERITED(context, surfaceProps) |
41 fCacheSize(0) { | 43 , fFallbackTextContext(nullptr) |
| 44 , fCacheSize(0) { |
42 } | 45 } |
43 | 46 |
44 GrStencilAndCoverTextContext* | 47 GrStencilAndCoverTextContext* |
45 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { | 48 GrStencilAndCoverTextContext::Create(GrContext* context, const SkSurfaceProps& s
urfaceProps) { |
46 GrStencilAndCoverTextContext* textContext = | 49 GrStencilAndCoverTextContext* textContext = |
47 new GrStencilAndCoverTextContext(context, surfaceProps); | 50 new GrStencilAndCoverTextContext(context, surfaceProps); |
48 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); | 51 textContext->fFallbackTextContext = GrAtlasTextContext::Create(context, surf
aceProps); |
49 | 52 |
50 return textContext; | 53 return textContext; |
51 } | 54 } |
52 | 55 |
53 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { | 56 GrStencilAndCoverTextContext::~GrStencilAndCoverTextContext() { |
| 57 delete fFallbackTextContext; |
54 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>); | 58 fBlobIdCache.foreach(delete_hash_map_entry<uint32_t, TextBlob*>); |
55 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>); | 59 fBlobKeyCache.foreach(delete_hash_table_entry<TextBlob*>); |
56 } | 60 } |
57 | 61 |
58 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { | 62 bool GrStencilAndCoverTextContext::internalCanDraw(const SkPaint& skPaint) { |
59 if (skPaint.getRasterizer()) { | 63 if (skPaint.getRasterizer()) { |
60 return false; | 64 return false; |
61 } | 65 } |
62 if (skPaint.getMaskFilter()) { | 66 if (skPaint.getMaskFilter()) { |
63 return false; | 67 return false; |
64 } | 68 } |
65 if (SkPathEffect* pe = skPaint.getPathEffect()) { | 69 if (SkPathEffect* pe = skPaint.getPathEffect()) { |
66 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { | 70 if (pe->asADash(nullptr) != SkPathEffect::kDash_DashType) { |
67 return false; | 71 return false; |
68 } | 72 } |
69 } | 73 } |
70 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. | 74 // No hairlines. They would require new paths with customized strokes for ev
ery new draw matrix. |
71 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); | 75 return SkPaint::kStroke_Style != skPaint.getStyle() || 0 != skPaint.getStrok
eWidth(); |
72 } | 76 } |
73 | 77 |
74 void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* dc, | 78 void GrStencilAndCoverTextContext::drawText(GrDrawContext* dc, |
75 const GrClip& clip, | 79 const GrClip& clip, const GrPaint& p
aint, |
76 const GrPaint& paint, | 80 const SkPaint& skPaint, const SkMatr
ix& viewMatrix, |
77 const SkPaint& skPaint, | 81 const char text[], size_t byteLength
, |
78 const SkMatrix& viewMatrix, | 82 SkScalar x, SkScalar y, const SkIRec
t& clipBounds) { |
79 const char text[], | 83 if (fContext->abandoned()) { |
80 size_t byteLength, | 84 return; |
81 SkScalar x, SkScalar y, | 85 } else if (this->canDraw(skPaint, viewMatrix)) { |
82 const SkIRect& clipBounds) { | 86 TextRun run(skPaint); |
83 TextRun run(skPaint); | 87 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; |
84 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); | 88 run.setText(text, byteLength, x, y); |
85 run.setText(text, byteLength, x, y); | 89 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0
, 0, clipBounds, |
86 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0,
clipBounds, | 90 fFallbackTextContext, skPaint); |
87 fFallbackTextContext, skPaint); | 91 return; |
| 92 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix)) { |
| 93 fFallbackTextContext->drawText(dc, clip, paint, skPaint, viewMatrix, tex
t, |
| 94 byteLength, x, y, clipBounds); |
| 95 return; |
| 96 } |
| 97 |
| 98 // fall back to drawing as a path |
| 99 GrTextUtils::DrawTextAsPath(fContext, dc, clip, skPaint, viewMatrix, text, b
yteLength, x, y, |
| 100 clipBounds); |
88 } | 101 } |
89 | 102 |
90 void GrStencilAndCoverTextContext::onDrawPosText(GrDrawContext* dc, | 103 void GrStencilAndCoverTextContext::drawPosText(GrDrawContext* dc, |
91 const GrClip& clip, | 104 const GrClip& clip, |
92 const GrPaint& paint, | 105 const GrPaint& paint, |
93 const SkPaint& skPaint, | 106 const SkPaint& skPaint, |
94 const SkMatrix& viewMatrix, | 107 const SkMatrix& viewMatrix, |
95 const char text[], | 108 const char text[], |
96 size_t byteLength, | 109 size_t byteLength, |
97 const SkScalar pos[], | 110 const SkScalar pos[], |
98 int scalarsPerPosition, | 111 int scalarsPerPosition, |
99 const SkPoint& offset, | 112 const SkPoint& offset, |
100 const SkIRect& clipBounds) { | 113 const SkIRect& clipBounds) { |
101 TextRun run(skPaint); | 114 if (fContext->abandoned()) { |
102 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); | 115 return; |
103 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); | 116 } else if (this->canDraw(skPaint, viewMatrix)) { |
104 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0, 0,
clipBounds, | 117 TextRun run(skPaint); |
105 fFallbackTextContext, skPaint); | 118 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip)
; |
| 119 run.setPosText(text, byteLength, pos, scalarsPerPosition, offset); |
| 120 run.draw(fContext, dc, &pipelineBuilder, paint.getColor(), viewMatrix, 0
, 0, clipBounds, |
| 121 fFallbackTextContext, skPaint); |
| 122 return; |
| 123 } else if (fFallbackTextContext->canDraw(skPaint, viewMatrix)) { |
| 124 fFallbackTextContext->drawPosText(dc, clip, paint, skPaint, viewMatrix, |
| 125 text, byteLength, pos, |
| 126 scalarsPerPosition, offset, clipBounds
); |
| 127 return; |
| 128 } |
| 129 |
| 130 // fall back to drawing as a path |
| 131 GrTextUtils::DrawPosTextAsPath(fContext, dc, fSurfaceProps, clip, skPaint, v
iewMatrix, text, |
| 132 byteLength, pos, scalarsPerPosition, offset,
clipBounds); |
| 133 } |
| 134 |
| 135 void GrStencilAndCoverTextContext::uncachedDrawTextBlob(GrDrawContext* dc, |
| 136 const GrClip& clip, cons
t SkPaint& skPaint, |
| 137 const SkMatrix& viewMatr
ix, |
| 138 const SkTextBlob* blob, |
| 139 SkScalar x, SkScalar y, |
| 140 SkDrawFilter* drawFilter
, |
| 141 const SkIRect& clipBound
s) { |
| 142 SkPaint runPaint = skPaint; |
| 143 |
| 144 SkTextBlobRunIterator it(blob); |
| 145 for (;!it.done(); it.next()) { |
| 146 size_t textLen = it.glyphCount() * sizeof(uint16_t); |
| 147 const SkPoint& offset = it.offset(); |
| 148 |
| 149 // applyFontToPaint() always overwrites the exact same attributes, |
| 150 // so it is safe to not re-seed the paint for this reason. |
| 151 it.applyFontToPaint(&runPaint); |
| 152 |
| 153 if (drawFilter && !drawFilter->filter(&runPaint, SkDrawFilter::kText_Typ
e)) { |
| 154 // A false return from filter() means we should abort the current dr
aw. |
| 155 runPaint = skPaint; |
| 156 continue; |
| 157 } |
| 158 |
| 159 runPaint.setFlags(FilterTextFlags(fSurfaceProps, runPaint)); |
| 160 |
| 161 GrPaint grPaint; |
| 162 if (!SkPaintToGrPaint(fContext, runPaint, viewMatrix, &grPaint)) { |
| 163 return; |
| 164 } |
| 165 |
| 166 switch (it.positioning()) { |
| 167 case SkTextBlob::kDefault_Positioning: |
| 168 this->drawText(dc, clip, grPaint, runPaint, viewMatrix, (const c
har *)it.glyphs(), |
| 169 textLen, x + offset.x(), y + offset.y(), clipBoun
ds); |
| 170 break; |
| 171 case SkTextBlob::kHorizontal_Positioning: |
| 172 this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, (cons
t char*)it.glyphs(), |
| 173 textLen, it.pos(), 1, SkPoint::Make(x, y + off
set.y()), |
| 174 clipBounds); |
| 175 break; |
| 176 case SkTextBlob::kFull_Positioning: |
| 177 this->drawPosText(dc, clip, grPaint, runPaint, viewMatrix, (cons
t char*)it.glyphs(), |
| 178 textLen, it.pos(), 2, SkPoint::Make(x, y), cli
pBounds); |
| 179 break; |
| 180 } |
| 181 |
| 182 if (drawFilter) { |
| 183 // A draw filter may change the paint arbitrarily, so we must re-see
d in this case. |
| 184 runPaint = skPaint; |
| 185 } |
| 186 } |
106 } | 187 } |
107 | 188 |
108 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, | 189 void GrStencilAndCoverTextContext::drawTextBlob(GrDrawContext* dc, |
109 const GrClip& clip, const SkPain
t& skPaint, | 190 const GrClip& clip, const SkPain
t& skPaint, |
110 const SkMatrix& viewMatrix, | 191 const SkMatrix& viewMatrix, |
111 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, | 192 const SkTextBlob* skBlob, SkScal
ar x, SkScalar y, |
112 SkDrawFilter* drawFilter, | 193 SkDrawFilter* drawFilter, |
113 const SkIRect& clipBounds) { | 194 const SkIRect& clipBounds) { |
| 195 if (fContext->abandoned()) { |
| 196 return; |
| 197 } |
| 198 |
114 if (!this->internalCanDraw(skPaint)) { | 199 if (!this->internalCanDraw(skPaint)) { |
115 fFallbackTextContext->drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob
, x, y, | 200 fFallbackTextContext->drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob
, x, y, |
116 drawFilter, clipBounds); | 201 drawFilter, clipBounds); |
117 return; | 202 return; |
118 } | 203 } |
119 | 204 |
120 if (drawFilter || skPaint.getPathEffect()) { | 205 if (drawFilter || skPaint.getPathEffect()) { |
121 // This draw can't be cached. | 206 // This draw can't be cached. |
122 INHERITED::drawTextBlob(dc, clip, skPaint, viewMatrix, skBlob, x, y, dra
wFilter, | 207 this->uncachedDrawTextBlob(dc, clip, skPaint, viewMatrix, skBlob, x, y,
drawFilter, |
123 clipBounds); | 208 clipBounds); |
124 return; | 209 return; |
125 } | 210 } |
126 | 211 |
127 if (fContext->abandoned()) { | |
128 return; | |
129 } | |
130 | |
131 GrPaint paint; | 212 GrPaint paint; |
132 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { | 213 if (!SkPaintToGrPaint(fContext, skPaint, viewMatrix, &paint)) { |
133 return; | 214 return; |
134 } | 215 } |
135 | 216 |
136 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); | 217 const TextBlob& blob = this->findOrCreateTextBlob(skBlob, skPaint); |
137 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); | 218 GrPipelineBuilder pipelineBuilder(paint, dc->accessRenderTarget(), clip); |
138 | 219 |
139 TextBlob::Iter iter(blob); | 220 TextBlob::Iter iter(blob); |
140 for (TextRun* run = iter.get(); run; run = iter.next()) { | 221 for (TextRun* run = iter.get(); run; run = iter.next()) { |
(...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
607 } | 688 } |
608 | 689 |
609 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeed
ed(int *count) { | 690 const SkTextBlob* GrStencilAndCoverTextContext::FallbackBlobBuilder::buildIfNeed
ed(int *count) { |
610 *count = fCount; | 691 *count = fCount; |
611 if (fCount) { | 692 if (fCount) { |
612 this->flush(); | 693 this->flush(); |
613 return fBuilder->build(); | 694 return fBuilder->build(); |
614 } | 695 } |
615 return nullptr; | 696 return nullptr; |
616 } | 697 } |
OLD | NEW |