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