| 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 |