blob: a7299393bdaa729da726e916e97e86c29d43b2e0 [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"
17#include "GrTextStrike.h"
18#include "GrTextStrike_impl.h"
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +000019#include "SkDistanceFieldGen.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000020#include "SkDraw.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000021#include "SkGpuDevice.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000022#include "SkPath.h"
23#include "SkRTConf.h"
24#include "SkStrokeRec.h"
25#include "effects/GrDistanceFieldTextureEffect.h"
26
27static const int kGlyphCoordsAttributeIndex = 1;
28
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +000029static const int kSmallDFFontSize = 32;
30static const int kSmallDFFontLimit = 32;
31static const int kMediumDFFontSize = 64;
32static const int kMediumDFFontLimit = 64;
33static const int kLargeDFFontSize = 128;
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000034
jvanverth@google.comd830d132013-11-11 20:54:09 +000035SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
36 "Dump the contents of the font cache before every purge.");
37
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000038GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000039 const SkDeviceProperties& properties,
40 bool enable)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000041 : GrTextContext(context, properties) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000042#if SK_FORCE_DISTANCEFIELD_FONTS
43 fEnableDFRendering = true;
44#else
45 fEnableDFRendering = enable;
46#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +000047 fStrike = NULL;
jvanverth2d2a68c2014-06-10 06:42:56 -070048 fGammaTexture = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000049
50 fCurrTexture = NULL;
51 fCurrVertex = 0;
52
53 fVertices = NULL;
54 fMaxVertices = 0;
55}
56
57GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
58 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070059 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000060}
61
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000062bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000063 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000064 return false;
65 }
66
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000067 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000068 // translate well to distance
69 if (paint.getRasterizer() || paint.getMaskFilter() ||
70 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
71 return false;
72 }
73
74 // TODO: add some stroking support
75 if (paint.getStyle() != SkPaint::kFill_Style) {
76 return false;
77 }
78
79 // TODO: choose an appropriate maximum scale for distance fields and
80 // enable perspective
81 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
82 return false;
83 }
84
85 // distance fields cannot represent color fonts
86 SkScalerContext::Rec rec;
87 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
88 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000089}
90
jvanverth@google.comd830d132013-11-11 20:54:09 +000091static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
92 unsigned r = SkColorGetR(c);
93 unsigned g = SkColorGetG(c);
94 unsigned b = SkColorGetB(c);
95 return GrColorPackRGBA(r, g, b, 0xff);
96}
97
98void GrDistanceFieldTextContext::flushGlyphs() {
99 if (NULL == fDrawTarget) {
100 return;
101 }
102
103 GrDrawState* drawState = fDrawTarget->drawState();
104 GrDrawState::AutoRestoreEffects are(drawState);
105 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
106
107 if (fCurrVertex > 0) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000108 fContext->getFontCache()->updateTextures();
109
jvanverth@google.comd830d132013-11-11 20:54:09 +0000110 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000111 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000112 SkASSERT(fCurrTexture);
113 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700114 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000115
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000116 // Effects could be stored with one of the cache objects (atlas?)
jvanverth2d2a68c2014-06-10 06:42:56 -0700117 SkColor filteredColor;
118 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
119 if (NULL != colorFilter) {
120 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
121 } else {
122 filteredColor = fSkPaint.getColor();
123 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000124 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700125 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000126 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
127 fDeviceProperties.fGeometry.getLayout();
128 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
129 fCurrTexture,
130 params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700131 fGammaTexture,
132 gammaParams,
133 colorNoPreMul,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000134 fContext->getMatrix().rectStaysRect() &&
135 fContext->getMatrix().isSimilarity(),
136 useBGR),
137 kGlyphCoordsAttributeIndex)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000138
jvanverth@google.comd830d132013-11-11 20:54:09 +0000139 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
140 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
141 fPaint.numColorStages()) {
142 GrPrintf("LCD Text will not draw correctly.\n");
143 }
144 // We don't use the GrPaint's color in this case because it's been premultiplied by
145 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
146 // the mask texture color. The end result is that we get
147 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000148 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000149 // paintAlpha
150 drawState->setColor(SkColorSetARGB(a, a, a, a));
151 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700152 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000153 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
154 } else {
jvanverth2d2a68c2014-06-10 06:42:56 -0700155#ifdef SK_GAMMA_APPLY_TO_A8
156 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
157 filteredColor);
158 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
159 fCurrTexture, params,
160 fGammaTexture, gammaParams,
161 lum/255.f,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000162 fContext->getMatrix().isSimilarity()),
163 kGlyphCoordsAttributeIndex)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700164#else
165 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
166 fCurrTexture, params,
167 fContext->getMatrix().isSimilarity()),
168 kGlyphCoordsAttributeIndex)->unref();
169#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000170 // set back to normal in case we took LCD path previously.
171 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
172 drawState->setColor(fPaint.getColor());
173 }
174
175 int nGlyphs = fCurrVertex / 4;
176 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
177 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
178 nGlyphs,
179 4, 6);
180 fDrawTarget->resetVertexSource();
181 fVertices = NULL;
182 fMaxVertices = 0;
183 fCurrVertex = 0;
184 SkSafeSetNull(fCurrTexture);
185 }
186}
187
188namespace {
189
190// position + texture coord
191extern const GrVertexAttrib gTextVertexAttribs[] = {
192 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000193 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
jvanverth@google.comd830d132013-11-11 20:54:09 +0000194};
195
196};
197
198void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000199 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000200 GrFontScaler* scaler) {
201 if (NULL == fDrawTarget) {
202 return;
203 }
204 if (NULL == fStrike) {
205 fStrike = fContext->getFontCache()->getStrike(scaler, true);
206 }
207
208 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
209 if (NULL == glyph || glyph->fBounds.isEmpty()) {
210 return;
211 }
212
213 SkScalar sx = SkFixedToScalar(vx);
214 SkScalar sy = SkFixedToScalar(vy);
215/*
216 // not valid, need to find a different solution for this
217 vx += SkIntToFixed(glyph->fBounds.fLeft);
218 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000219
jvanverth@google.comd830d132013-11-11 20:54:09 +0000220 // keep them as ints until we've done the clip-test
221 GrFixed width = glyph->fBounds.width();
222 GrFixed height = glyph->fBounds.height();
223
224 // check if we clipped out
225 if (true || NULL == glyph->fPlot) {
226 int x = vx >> 16;
227 int y = vy >> 16;
228 if (fClipRect.quickReject(x, y, x + width, y + height)) {
229// SkCLZ(3); // so we can set a break-point in the debugger
230 return;
231 }
232 }
233*/
234 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000235 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000236 goto HAS_ATLAS;
237 }
238
239 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000240 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
241 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000242 goto HAS_ATLAS;
243 }
244
245 if (c_DumpFontCache) {
246#ifdef SK_DEVELOPER
247 fContext->getFontCache()->dump();
248#endif
249 }
250
251 // before we purge the cache, we must flush any accumulated draws
252 this->flushGlyphs();
253 fContext->flush();
254
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000255 // we should have an unused plot now
256 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
257 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000258 goto HAS_ATLAS;
259 }
260
261 if (NULL == glyph->fPath) {
262 SkPath* path = SkNEW(SkPath);
263 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
264 // flag the glyph as being dead?
265 delete path;
266 return;
267 }
268 glyph->fPath = path;
269 }
270
271 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000272 SkMatrix ctm;
273 ctm.setScale(fTextRatio, fTextRatio);
274 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000275 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000276 am.setPreConcat(fContext, ctm, &tmpPaint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000277 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
278 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
279 return;
280 }
281
282HAS_ATLAS:
283 SkASSERT(glyph->fPlot);
284 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
285 glyph->fPlot->setDrawToken(drawToken);
286
287 GrTexture* texture = glyph->fPlot->texture();
288 SkASSERT(texture);
289
290 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
291 this->flushGlyphs();
292 fCurrTexture = texture;
293 fCurrTexture->ref();
294 }
295
296 if (NULL == fVertices) {
297 // If we need to reserve vertices allow the draw target to suggest
298 // a number of verts to reserve and whether to perform a flush.
299 fMaxVertices = kMinRequestedVerts;
300 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
301 SK_ARRAY_COUNT(gTextVertexAttribs));
302 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
303 if (flush) {
304 this->flushGlyphs();
305 fContext->flush();
306 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
307 SK_ARRAY_COUNT(gTextVertexAttribs));
308 }
309 fMaxVertices = kDefaultRequestedVerts;
310 // ignore return, no point in flushing again.
311 fDrawTarget->geometryHints(&fMaxVertices, NULL);
312
313 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
314 if (fMaxVertices < kMinRequestedVerts) {
315 fMaxVertices = kDefaultRequestedVerts;
316 } else if (fMaxVertices > maxQuadVertices) {
317 // don't exceed the limit of the index buffer
318 fMaxVertices = maxQuadVertices;
319 }
320 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
321 0,
322 GrTCast<void**>(&fVertices),
323 NULL);
324 GrAlwaysAssert(success);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000325 SkASSERT(2*sizeof(SkPoint) == fDrawTarget->getDrawState().getVertexSize());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000326 }
327
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000328 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
329 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
330 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
331 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000332
333 SkScalar scale = fTextRatio;
334 dx *= scale;
335 dy *= scale;
336 sx += dx;
337 sy += dy;
338 width *= scale;
339 height *= scale;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000340
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000341 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
342 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
343 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
344 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000345
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000346 static const size_t kVertexSize = 2 * sizeof(SkPoint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000347 fVertices[2*fCurrVertex].setRectFan(sx,
348 sy,
349 sx + width,
350 sy + height,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000351 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000352 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
353 SkFixedToFloat(texture->normalizeFixedY(ty)),
354 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
355 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000356 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000357 fCurrVertex += 4;
358}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000359
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000360inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
361 GrTextContext::init(paint, skPaint);
362
363 fStrike = NULL;
364
365 fCurrTexture = NULL;
366 fCurrVertex = 0;
367
368 fVertices = NULL;
369 fMaxVertices = 0;
370
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000371 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
372 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
373 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
374 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
375 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
376 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
377 } else {
378 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
379 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
380 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000381
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000382 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000383
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000384 fSkPaint.setLCDRenderText(false);
385 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700386 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000387 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700388
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000389}
390
391inline void GrDistanceFieldTextContext::finish() {
392 flushGlyphs();
393
394 GrTextContext::finish();
395}
396
jvanverth2d2a68c2014-06-10 06:42:56 -0700397static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
398 const SkDeviceProperties& deviceProperties,
399 GrTexture** gammaTexture) {
400 if (NULL == *gammaTexture) {
401 int width, height;
402 size_t size;
403
404#ifdef SK_GAMMA_CONTRAST
405 SkScalar contrast = SK_GAMMA_CONTRAST;
406#else
407 SkScalar contrast = 0.5f;
408#endif
409 SkScalar paintGamma = deviceProperties.fGamma;
410 SkScalar deviceGamma = deviceProperties.fGamma;
411
412 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
413 &width, &height);
414
415 SkAutoTArray<uint8_t> data((int)size);
416 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
417
418 // TODO: Update this to use the cache rather than directly creating a texture.
419 GrTextureDesc desc;
420 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
421 desc.fWidth = width;
422 desc.fHeight = height;
423 desc.fConfig = kAlpha_8_GrPixelConfig;
424
425 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
426 if (NULL == *gammaTexture) {
427 return;
428 }
429
430 context->writeTexturePixels(*gammaTexture,
431 0, 0, width, height,
432 (*gammaTexture)->config(), data.get(), 0,
433 GrContext::kDontFlush_PixelOpsFlag);
434 }
435}
436
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000437void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
438 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000439 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000440 SkASSERT(byteLength == 0 || text != NULL);
441
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000442 // nothing to draw or can't draw
443 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
444 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000445 return;
446 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000447
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000448 this->init(paint, skPaint);
449
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000450 SkScalar sizeRatio = fTextRatio;
451
452 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
453
jvanverth2d2a68c2014-06-10 06:42:56 -0700454 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
455 SkGlyphCache* cache = autoCache.getCache();
456 GrFontScaler* fontScaler = GetGrFontScaler(cache);
457
458 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000459
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000460 // need to measure first
461 // TODO - generate positions and pre-load cache as well?
462 const char* stop = text + byteLength;
463 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
464 SkFixed stopX = 0;
465 SkFixed stopY = 0;
466
467 const char* textPtr = text;
468 while (textPtr < stop) {
469 // don't need x, y here, since all subpixel variants will have the
470 // same advance
471 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
472
473 stopX += glyph.fAdvanceX;
474 stopY += glyph.fAdvanceY;
475 }
476 SkASSERT(textPtr == stop);
477
478 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
479 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
480
481 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
482 alignX = SkScalarHalf(alignX);
483 alignY = SkScalarHalf(alignY);
484 }
485
486 x -= alignX;
487 y -= alignY;
488 }
489
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000490 SkFixed fx = SkScalarToFixed(x);
491 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000492 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
493 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000494 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000495
496 if (glyph.fWidth) {
497 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
498 glyph.getSubXFixed(),
499 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000500 fx,
501 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000502 fontScaler);
503 }
504
505 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
506 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
507 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000508
509 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000510}
511
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000512void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
513 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000514 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000515 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000516
517 SkASSERT(byteLength == 0 || text != NULL);
518 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
519
520 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000521 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000522 return;
523 }
524
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000525 this->init(paint, skPaint);
526
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000527 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
528
jvanverth2d2a68c2014-06-10 06:42:56 -0700529 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
530 SkGlyphCache* cache = autoCache.getCache();
531 GrFontScaler* fontScaler = GetGrFontScaler(cache);
532
533 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000534
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000535 const char* stop = text + byteLength;
536
537 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
538 while (text < stop) {
539 // the last 2 parameters are ignored
540 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
541
542 if (glyph.fWidth) {
543 SkScalar x = pos[0];
544 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
545
546 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
547 glyph.getSubXFixed(),
548 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000549 SkScalarToFixed(x),
550 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000551 fontScaler);
552 }
553 pos += scalarsPerPosition;
554 }
555 } else {
556 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
557 while (text < stop) {
558 // the last 2 parameters are ignored
559 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
560
561 if (glyph.fWidth) {
562 SkScalar x = pos[0];
563 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000564
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000565 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
566 glyph.getSubXFixed(),
567 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000568 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
569 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000570 fontScaler);
571 }
572 pos += scalarsPerPosition;
573 }
574 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000575
576 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000577}