blob: 034980d455e1b2f48060145b28ebdd6c9083d14c [file] [log] [blame]
jvanverth@google.comd830d132013-11-11 20:54:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrDistanceFieldTextContext.h"
9#include "GrAtlas.h"
jvanverth2d2a68c2014-06-10 06:42:56 -070010#include "SkColorFilter.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000011#include "GrDrawTarget.h"
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000012#include "GrDrawTargetCaps.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000013#include "GrFontScaler.h"
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000014#include "SkGlyphCache.h"
jvanverth2d2a68c2014-06-10 06:42:56 -070015#include "GrGpu.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000016#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070017#include "GrStrokeInfo.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000018#include "GrTextStrike.h"
19#include "GrTextStrike_impl.h"
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +000020#include "SkDistanceFieldGen.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000021#include "SkDraw.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000022#include "SkGpuDevice.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000023#include "SkPath.h"
24#include "SkRTConf.h"
25#include "SkStrokeRec.h"
26#include "effects/GrDistanceFieldTextureEffect.h"
27
jvanverthfeceba52014-07-25 19:03:34 -070028SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29 "Dump the contents of the font cache before every purge.");
30
31static const int kGlyphCoordsNoColorAttributeIndex = 1;
32static const int kGlyphCoordsWithColorAttributeIndex = 2;
jvanverth@google.comd830d132013-11-11 20:54:09 +000033
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +000034static const int kSmallDFFontSize = 32;
35static const int kSmallDFFontLimit = 32;
36static const int kMediumDFFontSize = 64;
37static const int kMediumDFFontLimit = 64;
38static const int kLargeDFFontSize = 128;
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000039
jvanverthfeceba52014-07-25 19:03:34 -070040namespace {
41// position + texture coord
42extern const GrVertexAttrib gTextVertexAttribs[] = {
43 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
44 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
45};
46
47// position + color + texture coord
48extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
49 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
50 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
51 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
52};
53
54};
jvanverth@google.comd830d132013-11-11 20:54:09 +000055
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000056GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000057 const SkDeviceProperties& properties,
58 bool enable)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000059 : GrTextContext(context, properties) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000060#if SK_FORCE_DISTANCEFIELD_FONTS
61 fEnableDFRendering = true;
62#else
63 fEnableDFRendering = enable;
64#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +000065 fStrike = NULL;
jvanverth2d2a68c2014-06-10 06:42:56 -070066 fGammaTexture = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000067
jvanverth@google.comd830d132013-11-11 20:54:09 +000068 fCurrVertex = 0;
jvanverth78f07182014-07-30 06:17:59 -070069 fEffectTextureUniqueID = SK_InvalidUniqueID;
70 fEffectColor = GrColor_ILLEGAL;
71 fEffectFlags = 0;
jvanverth1723bfc2014-07-30 09:16:33 -070072
jvanverth@google.comd830d132013-11-11 20:54:09 +000073 fVertices = NULL;
jvanverth1723bfc2014-07-30 09:16:33 -070074
75 fVertexBounds.setLargestInverted();
jvanverth@google.comd830d132013-11-11 20:54:09 +000076}
77
78GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
79 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070080 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000081}
82
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000083bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000084 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000085 return false;
86 }
87
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000088 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000089 // translate well to distance
90 if (paint.getRasterizer() || paint.getMaskFilter() ||
91 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
92 return false;
93 }
94
95 // TODO: add some stroking support
96 if (paint.getStyle() != SkPaint::kFill_Style) {
97 return false;
98 }
99
100 // TODO: choose an appropriate maximum scale for distance fields and
101 // enable perspective
102 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
103 return false;
104 }
105
106 // distance fields cannot represent color fonts
107 SkScalerContext::Rec rec;
108 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
109 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000110}
111
jvanverth@google.comd830d132013-11-11 20:54:09 +0000112static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
113 unsigned r = SkColorGetR(c);
114 unsigned g = SkColorGetG(c);
115 unsigned b = SkColorGetB(c);
116 return GrColorPackRGBA(r, g, b, 0xff);
117}
118
jvanverth78f07182014-07-30 06:17:59 -0700119void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
120 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
121 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
122
123 GrTexture* currTexture = fStrike->getTexture();
124 SkASSERT(currTexture);
125 uint32_t textureUniqueID = currTexture->getUniqueID();
126
127 // set up any flags
128 uint32_t flags = 0;
129 flags |= fContext->getMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
130 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
131 flags |= fUseLCDText && fContext->getMatrix().rectStaysRect() ?
132 kRectToRect_DistanceFieldEffectFlag : 0;
133 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
134 fDeviceProperties.fGeometry.getLayout();
135 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
136
137 // see if we need to create a new effect
138 if (textureUniqueID != fEffectTextureUniqueID ||
139 filteredColor != fEffectColor ||
140 flags != fEffectFlags) {
141 if (fUseLCDText) {
142 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
143 fCachedEffect.reset(GrDistanceFieldLCDTextureEffect::Create(currTexture,
144 params,
145 fGammaTexture,
146 gammaParams,
147 colorNoPreMul,
148 flags));
149 } else {
150#ifdef SK_GAMMA_APPLY_TO_A8
151 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
152 filteredColor);
153 fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(currTexture,
154 params,
155 fGammaTexture,
156 gammaParams,
157 lum/255.f,
158 flags));
159#else
160 fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(currTexture,
161 params, flags));
162#endif
163 }
164 fEffectTextureUniqueID = textureUniqueID;
165 fEffectColor = filteredColor;
166 fEffectFlags = flags;
167 }
168
169}
170
jvanverth@google.comd830d132013-11-11 20:54:09 +0000171void GrDistanceFieldTextContext::flushGlyphs() {
172 if (NULL == fDrawTarget) {
173 return;
174 }
175
176 GrDrawState* drawState = fDrawTarget->drawState();
177 GrDrawState::AutoRestoreEffects are(drawState);
178 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
179
180 if (fCurrVertex > 0) {
181 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000182 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000183
jvanverth78f07182014-07-30 06:17:59 -0700184 // get our current color
jvanverth2d2a68c2014-06-10 06:42:56 -0700185 SkColor filteredColor;
186 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
187 if (NULL != colorFilter) {
188 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
189 } else {
190 filteredColor = fSkPaint.getColor();
191 }
jvanverth78f07182014-07-30 06:17:59 -0700192 this->setupCoverageEffect(filteredColor);
193
194 // Effects could be stored with one of the cache objects (atlas?)
195 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
196 kGlyphCoordsNoColorAttributeIndex;
197 drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
198
199 // Set draw state
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000200 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700201 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000202 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
203 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
204 fPaint.numColorStages()) {
205 GrPrintf("LCD Text will not draw correctly.\n");
206 }
jvanverthfeceba52014-07-25 19:03:34 -0700207 SkASSERT(!drawState->hasColorVertexAttribute());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000208 // We don't use the GrPaint's color in this case because it's been premultiplied by
209 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
210 // the mask texture color. The end result is that we get
211 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000212 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000213 // paintAlpha
214 drawState->setColor(SkColorSetARGB(a, a, a, a));
215 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700216 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000217 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
218 } else {
219 // set back to normal in case we took LCD path previously.
220 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
jvanverthfeceba52014-07-25 19:03:34 -0700221 //drawState->setColor(fPaint.getColor());
222 // We're using per-vertex color.
223 SkASSERT(drawState->hasColorVertexAttribute());
224 drawState->setColor(0xFFFFFFFF);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000225 }
jvanverth@google.comd830d132013-11-11 20:54:09 +0000226 int nGlyphs = fCurrVertex / 4;
227 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
228 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
229 nGlyphs,
jvanverth1723bfc2014-07-30 09:16:33 -0700230 4, 6, &fVertexBounds);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000231 fCurrVertex = 0;
jvanverth1723bfc2014-07-30 09:16:33 -0700232 fVertexBounds.setLargestInverted();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000233 }
jvanverth1723bfc2014-07-30 09:16:33 -0700234
jvanverthf17bc6c2014-07-25 16:46:53 -0700235 fDrawTarget->resetVertexSource();
236 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237}
238
jvanverth@google.comd830d132013-11-11 20:54:09 +0000239void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000240 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000241 GrFontScaler* scaler) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000242 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
243 if (NULL == glyph || glyph->fBounds.isEmpty()) {
244 return;
245 }
246
247 SkScalar sx = SkFixedToScalar(vx);
248 SkScalar sy = SkFixedToScalar(vy);
249/*
250 // not valid, need to find a different solution for this
251 vx += SkIntToFixed(glyph->fBounds.fLeft);
252 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000253
jvanverth@google.comd830d132013-11-11 20:54:09 +0000254 // keep them as ints until we've done the clip-test
255 GrFixed width = glyph->fBounds.width();
256 GrFixed height = glyph->fBounds.height();
257
258 // check if we clipped out
259 if (true || NULL == glyph->fPlot) {
260 int x = vx >> 16;
261 int y = vy >> 16;
262 if (fClipRect.quickReject(x, y, x + width, y + height)) {
263// SkCLZ(3); // so we can set a break-point in the debugger
264 return;
265 }
266 }
267*/
268 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000269 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000270 goto HAS_ATLAS;
271 }
272
273 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000274 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
275 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000276 goto HAS_ATLAS;
277 }
278
279 if (c_DumpFontCache) {
280#ifdef SK_DEVELOPER
281 fContext->getFontCache()->dump();
282#endif
283 }
284
285 // before we purge the cache, we must flush any accumulated draws
286 this->flushGlyphs();
287 fContext->flush();
288
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000289 // we should have an unused plot now
290 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
291 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000292 goto HAS_ATLAS;
293 }
294
295 if (NULL == glyph->fPath) {
296 SkPath* path = SkNEW(SkPath);
297 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
298 // flag the glyph as being dead?
299 delete path;
300 return;
301 }
302 glyph->fPath = path;
303 }
304
305 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000306 SkMatrix ctm;
307 ctm.setScale(fTextRatio, fTextRatio);
308 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000309 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000310 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700311 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
312 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000313 return;
314 }
315
316HAS_ATLAS:
317 SkASSERT(glyph->fPlot);
318 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
319 glyph->fPlot->setDrawToken(drawToken);
320
321 GrTexture* texture = glyph->fPlot->texture();
322 SkASSERT(texture);
323
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000324 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
325 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
326 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
327 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000328
329 SkScalar scale = fTextRatio;
330 dx *= scale;
331 dy *= scale;
332 sx += dx;
333 sy += dy;
334 width *= scale;
335 height *= scale;
jvanverth1723bfc2014-07-30 09:16:33 -0700336
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000337 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
338 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
339 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
340 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000341
jvanverth1723bfc2014-07-30 09:16:33 -0700342 SkRect r;
343 r.fLeft = SkFixedToFloat(sx);
344 r.fTop = SkFixedToFloat(sy);
345 r.fRight = SkFixedToFloat(sx + width);
346 r.fBottom = SkFixedToFloat(sy + height);
347
348 fVertexBounds.growToInclude(r);
349
jvanverthfeceba52014-07-25 19:03:34 -0700350 size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
351 : (2 * sizeof(SkPoint) + sizeof(GrColor));
jvanverth1723bfc2014-07-30 09:16:33 -0700352
jvanverthfeceba52014-07-25 19:03:34 -0700353 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
jvanverth1723bfc2014-07-30 09:16:33 -0700354
jvanverthf17bc6c2014-07-25 16:46:53 -0700355 SkPoint* positions = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700356 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
jvanverth1723bfc2014-07-30 09:16:33 -0700357 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
358
jvanverthfeceba52014-07-25 19:03:34 -0700359 // The texture coords are last in both the with and without color vertex layouts.
jvanverthf17bc6c2014-07-25 16:46:53 -0700360 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700361 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
jvanverthf17bc6c2014-07-25 16:46:53 -0700362 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
jvanverthfeceba52014-07-25 19:03:34 -0700363 SkFixedToFloat(texture->normalizeFixedY(ty)),
364 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
365 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
366 vertSize);
367 if (!fUseLCDText) {
368 // color comes after position.
369 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
370 for (int i = 0; i < 4; ++i) {
371 *colors = fPaint.getColor();
372 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
373 }
374 }
jvanverth1723bfc2014-07-30 09:16:33 -0700375
jvanverth@google.comd830d132013-11-11 20:54:09 +0000376 fCurrVertex += 4;
377}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000378
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000379inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
380 GrTextContext::init(paint, skPaint);
381
382 fStrike = NULL;
383
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000384 fCurrVertex = 0;
385
386 fVertices = NULL;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000387
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000388 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
389 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
390 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
391 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
392 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
393 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
394 } else {
395 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
396 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
397 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000398
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000399 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000400
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000401 fSkPaint.setLCDRenderText(false);
402 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700403 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000404 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700405
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000406}
407
408inline void GrDistanceFieldTextContext::finish() {
jvanverthfeceba52014-07-25 19:03:34 -0700409 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000410
411 GrTextContext::finish();
412}
413
jvanverth2d2a68c2014-06-10 06:42:56 -0700414static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
415 const SkDeviceProperties& deviceProperties,
416 GrTexture** gammaTexture) {
417 if (NULL == *gammaTexture) {
418 int width, height;
419 size_t size;
420
421#ifdef SK_GAMMA_CONTRAST
422 SkScalar contrast = SK_GAMMA_CONTRAST;
423#else
424 SkScalar contrast = 0.5f;
425#endif
426 SkScalar paintGamma = deviceProperties.fGamma;
427 SkScalar deviceGamma = deviceProperties.fGamma;
428
429 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
430 &width, &height);
431
432 SkAutoTArray<uint8_t> data((int)size);
433 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
434
435 // TODO: Update this to use the cache rather than directly creating a texture.
436 GrTextureDesc desc;
437 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
438 desc.fWidth = width;
439 desc.fHeight = height;
440 desc.fConfig = kAlpha_8_GrPixelConfig;
441
442 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
443 if (NULL == *gammaTexture) {
444 return;
445 }
446
447 context->writeTexturePixels(*gammaTexture,
448 0, 0, width, height,
449 (*gammaTexture)->config(), data.get(), 0,
450 GrContext::kDontFlush_PixelOpsFlag);
451 }
452}
453
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000454void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
455 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000456 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000457 SkASSERT(byteLength == 0 || text != NULL);
458
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000459 // nothing to draw or can't draw
460 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
461 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000462 return;
463 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000464
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000465 this->init(paint, skPaint);
466
jvanverthf17bc6c2014-07-25 16:46:53 -0700467 if (NULL == fDrawTarget) {
468 return;
469 }
470
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000471 SkScalar sizeRatio = fTextRatio;
472
473 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
474
jvanverth2d2a68c2014-06-10 06:42:56 -0700475 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
476 SkGlyphCache* cache = autoCache.getCache();
477 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700478 if (NULL == fStrike) {
479 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
480 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700481
482 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000483
jvanverthf17bc6c2014-07-25 16:46:53 -0700484 // allocate vertices
485 SkASSERT(NULL == fVertices);
jvanverthfeceba52014-07-25 19:03:34 -0700486 if (!fUseLCDText) {
487 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
488 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
489 } else {
490 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
491 SK_ARRAY_COUNT(gTextVertexAttribs));
492 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700493 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
494 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
495 0,
496 &fVertices,
497 NULL);
498 GrAlwaysAssert(success);
499
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000500 // need to measure first
501 // TODO - generate positions and pre-load cache as well?
502 const char* stop = text + byteLength;
503 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
504 SkFixed stopX = 0;
505 SkFixed stopY = 0;
506
507 const char* textPtr = text;
508 while (textPtr < stop) {
509 // don't need x, y here, since all subpixel variants will have the
510 // same advance
511 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
512
513 stopX += glyph.fAdvanceX;
514 stopY += glyph.fAdvanceY;
515 }
516 SkASSERT(textPtr == stop);
517
518 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
519 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
520
521 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
522 alignX = SkScalarHalf(alignX);
523 alignY = SkScalarHalf(alignY);
524 }
525
526 x -= alignX;
527 y -= alignY;
528 }
529
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000530 SkFixed fx = SkScalarToFixed(x);
531 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000532 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
533 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000534 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000535
536 if (glyph.fWidth) {
537 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
538 glyph.getSubXFixed(),
539 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000540 fx,
541 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000542 fontScaler);
543 }
544
545 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
546 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
547 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000548
549 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000550}
551
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000552void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
553 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000554 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000555 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000556
557 SkASSERT(byteLength == 0 || text != NULL);
558 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
559
560 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000561 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000562 return;
563 }
564
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000565 this->init(paint, skPaint);
566
jvanverthf17bc6c2014-07-25 16:46:53 -0700567 if (NULL == fDrawTarget) {
568 return;
569 }
570
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000571 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
572
jvanverth2d2a68c2014-06-10 06:42:56 -0700573 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
574 SkGlyphCache* cache = autoCache.getCache();
575 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700576 if (NULL == fStrike) {
577 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
578 }
579
580 // allocate vertices
581 SkASSERT(NULL == fVertices);
jvanverthfeceba52014-07-25 19:03:34 -0700582 if (!fUseLCDText) {
583 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
584 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
585 } else {
586 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
587 SK_ARRAY_COUNT(gTextVertexAttribs));
588 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700589 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
590 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
591 0,
592 &fVertices,
593 NULL);
594 GrAlwaysAssert(success);
jvanverth2d2a68c2014-06-10 06:42:56 -0700595
596 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000597
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000598 const char* stop = text + byteLength;
599
600 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
601 while (text < stop) {
602 // the last 2 parameters are ignored
603 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
604
605 if (glyph.fWidth) {
606 SkScalar x = pos[0];
607 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
608
609 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
610 glyph.getSubXFixed(),
611 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000612 SkScalarToFixed(x),
613 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000614 fontScaler);
615 }
616 pos += scalarsPerPosition;
617 }
618 } else {
619 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
620 while (text < stop) {
621 // the last 2 parameters are ignored
622 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
623
624 if (glyph.fWidth) {
625 SkScalar x = pos[0];
626 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000627
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000628 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
629 glyph.getSubXFixed(),
630 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000631 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
632 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000633 fontScaler);
634 }
635 pos += scalarsPerPosition;
636 }
637 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000638
639 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000640}