blob: 9cf53ce41062e936e8fb27f05c1f330b00802fa4 [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)
jvanverth9c3d24b2014-08-27 11:53:17 -070059 : GrTextContext(context, properties)
60 , fStrike(NULL)
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000061#if SK_FORCE_DISTANCEFIELD_FONTS
jvanverth9c3d24b2014-08-27 11:53:17 -070062 , fEnableDFRendering(true)
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000063#else
jvanverth9c3d24b2014-08-27 11:53:17 -070064 , fEnableDFRendering(true)//enable)
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000065#endif
jvanverth9c3d24b2014-08-27 11:53:17 -070066 , fEffectTextureUniqueID(SK_InvalidUniqueID)
67 , fEffectColor(GrColor_ILLEGAL)
68 , fEffectFlags(0)
69 , fGammaTexture(NULL)
70 , fVertices(NULL)
71 , fVertexCount(0)
72 , fCurrVertex(0) {
jvanverth1723bfc2014-07-30 09:16:33 -070073 fVertexBounds.setLargestInverted();
jvanverth@google.comd830d132013-11-11 20:54:09 +000074}
75
76GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
77 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070078 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000079}
80
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000081bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000082 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000083 return false;
84 }
85
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000086 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000087 // translate well to distance
88 if (paint.getRasterizer() || paint.getMaskFilter() ||
89 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
90 return false;
91 }
92
93 // TODO: add some stroking support
94 if (paint.getStyle() != SkPaint::kFill_Style) {
95 return false;
96 }
97
98 // TODO: choose an appropriate maximum scale for distance fields and
99 // enable perspective
100 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
101 return false;
102 }
103
104 // distance fields cannot represent color fonts
105 SkScalerContext::Rec rec;
106 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
107 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000108}
109
jvanverth@google.comd830d132013-11-11 20:54:09 +0000110static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
111 unsigned r = SkColorGetR(c);
112 unsigned g = SkColorGetG(c);
113 unsigned b = SkColorGetB(c);
114 return GrColorPackRGBA(r, g, b, 0xff);
115}
116
jvanverth78f07182014-07-30 06:17:59 -0700117void GrDistanceFieldTextContext::setupCoverageEffect(const SkColor& filteredColor) {
118 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
119 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
120
jvanverth9c3d24b2014-08-27 11:53:17 -0700121 GrTexture* currTexture = fStrike->getTexture();
122 SkASSERT(currTexture);
123 uint32_t textureUniqueID = currTexture->getUniqueID();
jvanverth78f07182014-07-30 06:17:59 -0700124
125 // set up any flags
126 uint32_t flags = 0;
127 flags |= fContext->getMatrix().isSimilarity() ? kSimilarity_DistanceFieldEffectFlag : 0;
128 flags |= fUseLCDText ? kUseLCD_DistanceFieldEffectFlag : 0;
129 flags |= fUseLCDText && fContext->getMatrix().rectStaysRect() ?
130 kRectToRect_DistanceFieldEffectFlag : 0;
131 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
132 fDeviceProperties.fGeometry.getLayout();
133 flags |= fUseLCDText && useBGR ? kBGR_DistanceFieldEffectFlag : 0;
134
135 // see if we need to create a new effect
136 if (textureUniqueID != fEffectTextureUniqueID ||
137 filteredColor != fEffectColor ||
138 flags != fEffectFlags) {
139 if (fUseLCDText) {
140 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
jvanverth9c3d24b2014-08-27 11:53:17 -0700141 fCachedEffect.reset(GrDistanceFieldLCDTextureEffect::Create(currTexture,
jvanverth78f07182014-07-30 06:17:59 -0700142 params,
143 fGammaTexture,
144 gammaParams,
145 colorNoPreMul,
146 flags));
147 } else {
148#ifdef SK_GAMMA_APPLY_TO_A8
149 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
150 filteredColor);
jvanverth9c3d24b2014-08-27 11:53:17 -0700151 fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(currTexture,
jvanverth78f07182014-07-30 06:17:59 -0700152 params,
153 fGammaTexture,
154 gammaParams,
155 lum/255.f,
156 flags));
157#else
djsollenc59308d2014-08-27 13:06:01 -0700158 fCachedEffect.reset(GrDistanceFieldTextureEffect::Create(fCurrTexture,
jvanverth78f07182014-07-30 06:17:59 -0700159 params, flags));
160#endif
161 }
162 fEffectTextureUniqueID = textureUniqueID;
163 fEffectColor = filteredColor;
164 fEffectFlags = flags;
165 }
166
167}
168
jvanverth@google.comd830d132013-11-11 20:54:09 +0000169void GrDistanceFieldTextContext::flushGlyphs() {
170 if (NULL == fDrawTarget) {
171 return;
172 }
173
174 GrDrawState* drawState = fDrawTarget->drawState();
175 GrDrawState::AutoRestoreEffects are(drawState);
176 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
177
178 if (fCurrVertex > 0) {
179 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000180 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000181
jvanverth78f07182014-07-30 06:17:59 -0700182 // get our current color
jvanverth2d2a68c2014-06-10 06:42:56 -0700183 SkColor filteredColor;
184 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
185 if (NULL != colorFilter) {
186 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
187 } else {
188 filteredColor = fSkPaint.getColor();
189 }
jvanverth78f07182014-07-30 06:17:59 -0700190 this->setupCoverageEffect(filteredColor);
191
192 // Effects could be stored with one of the cache objects (atlas?)
193 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
194 kGlyphCoordsNoColorAttributeIndex;
195 drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
196
197 // Set draw state
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000198 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700199 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000200 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
201 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
202 fPaint.numColorStages()) {
203 GrPrintf("LCD Text will not draw correctly.\n");
204 }
jvanverthfeceba52014-07-25 19:03:34 -0700205 SkASSERT(!drawState->hasColorVertexAttribute());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000206 // We don't use the GrPaint's color in this case because it's been premultiplied by
207 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
208 // the mask texture color. The end result is that we get
209 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000210 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000211 // paintAlpha
212 drawState->setColor(SkColorSetARGB(a, a, a, a));
213 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700214 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000215 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
216 } else {
217 // set back to normal in case we took LCD path previously.
218 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
jvanverthfeceba52014-07-25 19:03:34 -0700219 // We're using per-vertex color.
220 SkASSERT(drawState->hasColorVertexAttribute());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000221 }
jvanverth@google.comd830d132013-11-11 20:54:09 +0000222 int nGlyphs = fCurrVertex / 4;
223 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
224 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
225 nGlyphs,
jvanverth1723bfc2014-07-30 09:16:33 -0700226 4, 6, &fVertexBounds);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000227 fCurrVertex = 0;
jvanverth1723bfc2014-07-30 09:16:33 -0700228 fVertexBounds.setLargestInverted();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000229 }
jvanverth9c3d24b2014-08-27 11:53:17 -0700230
231 fDrawTarget->resetVertexSource();
232 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000233}
234
jvanverth@google.comd830d132013-11-11 20:54:09 +0000235void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000236 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 GrFontScaler* scaler) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000238 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
239 if (NULL == glyph || glyph->fBounds.isEmpty()) {
240 return;
241 }
242
243 SkScalar sx = SkFixedToScalar(vx);
244 SkScalar sy = SkFixedToScalar(vy);
245/*
246 // not valid, need to find a different solution for this
247 vx += SkIntToFixed(glyph->fBounds.fLeft);
248 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000249
jvanverth@google.comd830d132013-11-11 20:54:09 +0000250 // keep them as ints until we've done the clip-test
251 GrFixed width = glyph->fBounds.width();
252 GrFixed height = glyph->fBounds.height();
253
254 // check if we clipped out
255 if (true || NULL == glyph->fPlot) {
256 int x = vx >> 16;
257 int y = vy >> 16;
258 if (fClipRect.quickReject(x, y, x + width, y + height)) {
259// SkCLZ(3); // so we can set a break-point in the debugger
260 return;
261 }
262 }
263*/
264 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000265 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000266 goto HAS_ATLAS;
267 }
268
269 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000270 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
271 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000272 goto HAS_ATLAS;
273 }
274
275 if (c_DumpFontCache) {
276#ifdef SK_DEVELOPER
277 fContext->getFontCache()->dump();
278#endif
279 }
280
jvanverth9c3d24b2014-08-27 11:53:17 -0700281 // flush any accumulated draws to allow us to free up a plot
282 int remainingVertexCount = fVertexCount - fCurrVertex;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000283 this->flushGlyphs();
284 fContext->flush();
285
jvanverth9c3d24b2014-08-27 11:53:17 -0700286 // need to reallocate the vertex buffer for the remaining glyphs
287 fVertexCount = remainingVertexCount;
288 bool success = fDrawTarget->reserveVertexAndIndexSpace(fVertexCount,
289 0,
290 &fVertices,
291 NULL);
292 GrAlwaysAssert(success);
293
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000294 // we should have an unused plot now
295 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
296 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000297 goto HAS_ATLAS;
298 }
299
300 if (NULL == glyph->fPath) {
301 SkPath* path = SkNEW(SkPath);
302 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
303 // flag the glyph as being dead?
304 delete path;
305 return;
306 }
307 glyph->fPath = path;
308 }
309
310 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000311 SkMatrix ctm;
312 ctm.setScale(fTextRatio, fTextRatio);
313 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000314 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000315 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700316 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
317 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000318 return;
319 }
320
321HAS_ATLAS:
322 SkASSERT(glyph->fPlot);
323 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
324 glyph->fPlot->setDrawToken(drawToken);
325
326 GrTexture* texture = glyph->fPlot->texture();
327 SkASSERT(texture);
328
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000329 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
330 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
331 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
332 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000333
334 SkScalar scale = fTextRatio;
335 dx *= scale;
336 dy *= scale;
337 sx += dx;
338 sy += dy;
339 width *= scale;
340 height *= scale;
jvanverth9c3d24b2014-08-27 11:53:17 -0700341
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000342 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
343 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
344 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
345 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000346
jvanverth1723bfc2014-07-30 09:16:33 -0700347 SkRect r;
jvanverth9bcd23b2014-08-01 14:05:19 -0700348 r.fLeft = sx;
349 r.fTop = sy;
350 r.fRight = sx + width;
351 r.fBottom = sy + height;
jvanverth1723bfc2014-07-30 09:16:33 -0700352
353 fVertexBounds.growToInclude(r);
354
jvanverthfeceba52014-07-25 19:03:34 -0700355 size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
356 : (2 * sizeof(SkPoint) + sizeof(GrColor));
jvanverth1723bfc2014-07-30 09:16:33 -0700357
djsollenea81ced2014-08-27 13:07:34 -0700358 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
jvanverth1723bfc2014-07-30 09:16:33 -0700359
jvanverthf17bc6c2014-07-25 16:46:53 -0700360 SkPoint* positions = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700361 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
jvanverth1723bfc2014-07-30 09:16:33 -0700362 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
363
jvanverthfeceba52014-07-25 19:03:34 -0700364 // The texture coords are last in both the with and without color vertex layouts.
jvanverthf17bc6c2014-07-25 16:46:53 -0700365 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700366 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
jvanverthf17bc6c2014-07-25 16:46:53 -0700367 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
jvanverthfeceba52014-07-25 19:03:34 -0700368 SkFixedToFloat(texture->normalizeFixedY(ty)),
369 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
370 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
371 vertSize);
jvanverth9c3d24b2014-08-27 11:53:17 -0700372 if (!fUseLCDText) {
bsalomon62c447d2014-08-08 08:08:50 -0700373 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
374 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
375 }
jvanverthfeceba52014-07-25 19:03:34 -0700376 // color comes after position.
377 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
378 for (int i = 0; i < 4; ++i) {
379 *colors = fPaint.getColor();
380 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
381 }
382 }
jvanverth1723bfc2014-07-30 09:16:33 -0700383
jvanverth@google.comd830d132013-11-11 20:54:09 +0000384 fCurrVertex += 4;
385}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000386
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000387inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
388 GrTextContext::init(paint, skPaint);
389
390 fStrike = NULL;
391
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000392 fCurrVertex = 0;
393
394 fVertices = NULL;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000395
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000396 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
397 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
398 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
399 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
400 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
401 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
402 } else {
403 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
404 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
405 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000406
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000407 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000408
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000409 fSkPaint.setLCDRenderText(false);
410 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700411 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000412 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700413
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000414}
415
416inline void GrDistanceFieldTextContext::finish() {
jvanverthfeceba52014-07-25 19:03:34 -0700417 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000418
419 GrTextContext::finish();
420}
421
jvanverth2d2a68c2014-06-10 06:42:56 -0700422static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
423 const SkDeviceProperties& deviceProperties,
424 GrTexture** gammaTexture) {
425 if (NULL == *gammaTexture) {
426 int width, height;
427 size_t size;
428
429#ifdef SK_GAMMA_CONTRAST
430 SkScalar contrast = SK_GAMMA_CONTRAST;
431#else
432 SkScalar contrast = 0.5f;
433#endif
434 SkScalar paintGamma = deviceProperties.fGamma;
435 SkScalar deviceGamma = deviceProperties.fGamma;
436
437 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
438 &width, &height);
439
440 SkAutoTArray<uint8_t> data((int)size);
441 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
442
443 // TODO: Update this to use the cache rather than directly creating a texture.
444 GrTextureDesc desc;
445 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
446 desc.fWidth = width;
447 desc.fHeight = height;
448 desc.fConfig = kAlpha_8_GrPixelConfig;
449
450 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
451 if (NULL == *gammaTexture) {
452 return;
453 }
454
455 context->writeTexturePixels(*gammaTexture,
456 0, 0, width, height,
457 (*gammaTexture)->config(), data.get(), 0,
458 GrContext::kDontFlush_PixelOpsFlag);
459 }
460}
461
jvanverth9c3d24b2014-08-27 11:53:17 -0700462void GrDistanceFieldTextContext::allocateVertices(const char text[], size_t byteLength) {
463 SkASSERT(NULL == fVertices);
464 if (!fUseLCDText) {
465 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
djsollenea81ced2014-08-27 13:07:34 -0700466 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
jvanverth9c3d24b2014-08-27 11:53:17 -0700467 } else {
468 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
djsollenea81ced2014-08-27 13:07:34 -0700469 SK_ARRAY_COUNT(gTextVertexAttribs));
jvanverth9c3d24b2014-08-27 11:53:17 -0700470 }
471 fVertexCount = 4*fSkPaint.textToGlyphs(text, byteLength, NULL);
472 bool success = fDrawTarget->reserveVertexAndIndexSpace(fVertexCount,
473 0,
474 &fVertices,
475 NULL);
476 GrAlwaysAssert(success);
477}
478
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000479void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
480 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000481 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000482 SkASSERT(byteLength == 0 || text != NULL);
483
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000484 // nothing to draw or can't draw
485 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
486 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000487 return;
488 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000489
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000490 this->init(paint, skPaint);
491
jvanverth9c3d24b2014-08-27 11:53:17 -0700492 if (NULL == fDrawTarget) {
493 return;
494 }
495
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000496 SkScalar sizeRatio = fTextRatio;
497
498 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
499
jvanverth2d2a68c2014-06-10 06:42:56 -0700500 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
501 SkGlyphCache* cache = autoCache.getCache();
502 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverth9c3d24b2014-08-27 11:53:17 -0700503 if (NULL == fStrike) {
504 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
505 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700506
507 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000508
jvanverth9c3d24b2014-08-27 11:53:17 -0700509 this->allocateVertices(text, byteLength);
510
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000511 // need to measure first
512 // TODO - generate positions and pre-load cache as well?
513 const char* stop = text + byteLength;
514 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
515 SkFixed stopX = 0;
516 SkFixed stopY = 0;
517
518 const char* textPtr = text;
519 while (textPtr < stop) {
520 // don't need x, y here, since all subpixel variants will have the
521 // same advance
522 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
523
524 stopX += glyph.fAdvanceX;
525 stopY += glyph.fAdvanceY;
526 }
527 SkASSERT(textPtr == stop);
528
529 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
530 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
531
532 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
533 alignX = SkScalarHalf(alignX);
534 alignY = SkScalarHalf(alignY);
535 }
536
537 x -= alignX;
538 y -= alignY;
539 }
540
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000541 SkFixed fx = SkScalarToFixed(x);
542 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000543 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
544 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000545 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000546
547 if (glyph.fWidth) {
548 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
549 glyph.getSubXFixed(),
550 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000551 fx,
552 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000553 fontScaler);
554 }
555
556 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
557 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
558 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000559
560 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000561}
562
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000563void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
564 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000565 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000566 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000567
568 SkASSERT(byteLength == 0 || text != NULL);
569 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
570
571 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000572 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000573 return;
574 }
575
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000576 this->init(paint, skPaint);
577
jvanverth9c3d24b2014-08-27 11:53:17 -0700578 if (NULL == fDrawTarget) {
579 return;
580 }
581
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000582 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
583
jvanverth2d2a68c2014-06-10 06:42:56 -0700584 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
585 SkGlyphCache* cache = autoCache.getCache();
586 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverth9c3d24b2014-08-27 11:53:17 -0700587 if (NULL == fStrike) {
588 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
589 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700590
591 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000592
jvanverth9c3d24b2014-08-27 11:53:17 -0700593 this->allocateVertices(text, byteLength);
594
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000595 const char* stop = text + byteLength;
596
597 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
598 while (text < stop) {
599 // the last 2 parameters are ignored
600 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
601
602 if (glyph.fWidth) {
603 SkScalar x = pos[0];
604 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
605
606 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
607 glyph.getSubXFixed(),
608 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000609 SkScalarToFixed(x),
610 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000611 fontScaler);
612 }
613 pos += scalarsPerPosition;
614 }
615 } else {
616 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
617 while (text < stop) {
618 // the last 2 parameters are ignored
619 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
620
621 if (glyph.fWidth) {
622 SkScalar x = pos[0];
623 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000624
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000625 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
626 glyph.getSubXFixed(),
627 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000628 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
629 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000630 fontScaler);
631 }
632 pos += scalarsPerPosition;
633 }
634 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000635
636 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000637}