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