blob: fe6e50fbde0b769debd2a194044dae42c278b018 [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
28static const int kGlyphCoordsAttributeIndex = 1;
29
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +000030static const int kSmallDFFontSize = 32;
31static const int kSmallDFFontLimit = 32;
32static const int kMediumDFFontSize = 64;
33static const int kMediumDFFontLimit = 64;
34static const int kLargeDFFontSize = 128;
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000035
jvanverth@google.comd830d132013-11-11 20:54:09 +000036SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
37 "Dump the contents of the font cache before every purge.");
38
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000039GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000040 const SkDeviceProperties& properties,
41 bool enable)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000042 : GrTextContext(context, properties) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000043#if SK_FORCE_DISTANCEFIELD_FONTS
44 fEnableDFRendering = true;
45#else
46 fEnableDFRendering = enable;
47#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +000048 fStrike = NULL;
jvanverth2d2a68c2014-06-10 06:42:56 -070049 fGammaTexture = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000050
51 fCurrTexture = NULL;
52 fCurrVertex = 0;
53
54 fVertices = NULL;
55 fMaxVertices = 0;
56}
57
58GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
59 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070060 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000061}
62
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000063bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000064 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000065 return false;
66 }
67
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000068 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000069 // translate well to distance
70 if (paint.getRasterizer() || paint.getMaskFilter() ||
71 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
72 return false;
73 }
74
75 // TODO: add some stroking support
76 if (paint.getStyle() != SkPaint::kFill_Style) {
77 return false;
78 }
79
80 // TODO: choose an appropriate maximum scale for distance fields and
81 // enable perspective
82 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
83 return false;
84 }
85
86 // distance fields cannot represent color fonts
87 SkScalerContext::Rec rec;
88 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
89 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000090}
91
jvanverth@google.comd830d132013-11-11 20:54:09 +000092static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
93 unsigned r = SkColorGetR(c);
94 unsigned g = SkColorGetG(c);
95 unsigned b = SkColorGetB(c);
96 return GrColorPackRGBA(r, g, b, 0xff);
97}
98
99void GrDistanceFieldTextContext::flushGlyphs() {
100 if (NULL == fDrawTarget) {
101 return;
102 }
103
104 GrDrawState* drawState = fDrawTarget->drawState();
105 GrDrawState::AutoRestoreEffects are(drawState);
106 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
107
108 if (fCurrVertex > 0) {
109 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000110 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000111 SkASSERT(fCurrTexture);
112 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700113 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000114
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000115 // Effects could be stored with one of the cache objects (atlas?)
jvanverth2d2a68c2014-06-10 06:42:56 -0700116 SkColor filteredColor;
117 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
118 if (NULL != colorFilter) {
119 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
120 } else {
121 filteredColor = fSkPaint.getColor();
122 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000123 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700124 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000125 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
126 fDeviceProperties.fGeometry.getLayout();
127 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
128 fCurrTexture,
129 params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700130 fGammaTexture,
131 gammaParams,
132 colorNoPreMul,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000133 fContext->getMatrix().rectStaysRect() &&
134 fContext->getMatrix().isSimilarity(),
135 useBGR),
136 kGlyphCoordsAttributeIndex)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000137
jvanverth@google.comd830d132013-11-11 20:54:09 +0000138 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
139 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
140 fPaint.numColorStages()) {
141 GrPrintf("LCD Text will not draw correctly.\n");
142 }
143 // We don't use the GrPaint's color in this case because it's been premultiplied by
144 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
145 // the mask texture color. The end result is that we get
146 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000147 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000148 // paintAlpha
149 drawState->setColor(SkColorSetARGB(a, a, a, a));
150 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700151 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000152 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
153 } else {
jvanverth2d2a68c2014-06-10 06:42:56 -0700154#ifdef SK_GAMMA_APPLY_TO_A8
155 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
156 filteredColor);
157 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
158 fCurrTexture, params,
159 fGammaTexture, gammaParams,
160 lum/255.f,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000161 fContext->getMatrix().isSimilarity()),
162 kGlyphCoordsAttributeIndex)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700163#else
164 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
165 fCurrTexture, params,
166 fContext->getMatrix().isSimilarity()),
167 kGlyphCoordsAttributeIndex)->unref();
168#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000169 // set back to normal in case we took LCD path previously.
170 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
171 drawState->setColor(fPaint.getColor());
172 }
173
174 int nGlyphs = fCurrVertex / 4;
175 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
176 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
177 nGlyphs,
178 4, 6);
179 fDrawTarget->resetVertexSource();
180 fVertices = NULL;
181 fMaxVertices = 0;
182 fCurrVertex = 0;
183 SkSafeSetNull(fCurrTexture);
184 }
185}
186
187namespace {
188
189// position + texture coord
190extern const GrVertexAttrib gTextVertexAttribs[] = {
191 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000192 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
jvanverth@google.comd830d132013-11-11 20:54:09 +0000193};
194
195};
196
197void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000198 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000199 GrFontScaler* scaler) {
200 if (NULL == fDrawTarget) {
201 return;
202 }
203 if (NULL == fStrike) {
204 fStrike = fContext->getFontCache()->getStrike(scaler, true);
205 }
206
207 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
208 if (NULL == glyph || glyph->fBounds.isEmpty()) {
209 return;
210 }
211
212 SkScalar sx = SkFixedToScalar(vx);
213 SkScalar sy = SkFixedToScalar(vy);
214/*
215 // not valid, need to find a different solution for this
216 vx += SkIntToFixed(glyph->fBounds.fLeft);
217 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000218
jvanverth@google.comd830d132013-11-11 20:54:09 +0000219 // keep them as ints until we've done the clip-test
220 GrFixed width = glyph->fBounds.width();
221 GrFixed height = glyph->fBounds.height();
222
223 // check if we clipped out
224 if (true || NULL == glyph->fPlot) {
225 int x = vx >> 16;
226 int y = vy >> 16;
227 if (fClipRect.quickReject(x, y, x + width, y + height)) {
228// SkCLZ(3); // so we can set a break-point in the debugger
229 return;
230 }
231 }
232*/
233 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000234 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000235 goto HAS_ATLAS;
236 }
237
238 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000239 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
240 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000241 goto HAS_ATLAS;
242 }
243
244 if (c_DumpFontCache) {
245#ifdef SK_DEVELOPER
246 fContext->getFontCache()->dump();
247#endif
248 }
249
250 // before we purge the cache, we must flush any accumulated draws
251 this->flushGlyphs();
252 fContext->flush();
253
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000254 // we should have an unused plot now
255 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
256 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000257 goto HAS_ATLAS;
258 }
259
260 if (NULL == glyph->fPath) {
261 SkPath* path = SkNEW(SkPath);
262 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
263 // flag the glyph as being dead?
264 delete path;
265 return;
266 }
267 glyph->fPath = path;
268 }
269
270 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000271 SkMatrix ctm;
272 ctm.setScale(fTextRatio, fTextRatio);
273 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000274 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000275 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700276 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
277 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000278 return;
279 }
280
281HAS_ATLAS:
282 SkASSERT(glyph->fPlot);
283 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
284 glyph->fPlot->setDrawToken(drawToken);
285
286 GrTexture* texture = glyph->fPlot->texture();
287 SkASSERT(texture);
288
289 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
290 this->flushGlyphs();
291 fCurrTexture = texture;
292 fCurrTexture->ref();
293 }
294
295 if (NULL == fVertices) {
296 // If we need to reserve vertices allow the draw target to suggest
297 // a number of verts to reserve and whether to perform a flush.
298 fMaxVertices = kMinRequestedVerts;
299 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
300 SK_ARRAY_COUNT(gTextVertexAttribs));
301 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
302 if (flush) {
303 this->flushGlyphs();
304 fContext->flush();
305 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
306 SK_ARRAY_COUNT(gTextVertexAttribs));
307 }
308 fMaxVertices = kDefaultRequestedVerts;
309 // ignore return, no point in flushing again.
310 fDrawTarget->geometryHints(&fMaxVertices, NULL);
311
312 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
313 if (fMaxVertices < kMinRequestedVerts) {
314 fMaxVertices = kDefaultRequestedVerts;
315 } else if (fMaxVertices > maxQuadVertices) {
316 // don't exceed the limit of the index buffer
317 fMaxVertices = maxQuadVertices;
318 }
319 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
320 0,
321 GrTCast<void**>(&fVertices),
322 NULL);
323 GrAlwaysAssert(success);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000324 SkASSERT(2*sizeof(SkPoint) == fDrawTarget->getDrawState().getVertexSize());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000325 }
326
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000327 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
328 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
329 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
330 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000331
332 SkScalar scale = fTextRatio;
333 dx *= scale;
334 dy *= scale;
335 sx += dx;
336 sy += dy;
337 width *= scale;
338 height *= scale;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000339
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000340 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
341 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
342 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
343 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000344
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000345 static const size_t kVertexSize = 2 * sizeof(SkPoint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000346 fVertices[2*fCurrVertex].setRectFan(sx,
347 sy,
348 sx + width,
349 sy + height,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000350 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000351 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
352 SkFixedToFloat(texture->normalizeFixedY(ty)),
353 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
354 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000355 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000356 fCurrVertex += 4;
357}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000358
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000359inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
360 GrTextContext::init(paint, skPaint);
361
362 fStrike = NULL;
363
364 fCurrTexture = NULL;
365 fCurrVertex = 0;
366
367 fVertices = NULL;
368 fMaxVertices = 0;
369
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000370 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
371 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
372 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
373 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
374 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
375 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
376 } else {
377 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
378 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
379 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000380
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000381 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000382
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000383 fSkPaint.setLCDRenderText(false);
384 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700385 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000386 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700387
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000388}
389
390inline void GrDistanceFieldTextContext::finish() {
391 flushGlyphs();
392
393 GrTextContext::finish();
394}
395
jvanverth2d2a68c2014-06-10 06:42:56 -0700396static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
397 const SkDeviceProperties& deviceProperties,
398 GrTexture** gammaTexture) {
399 if (NULL == *gammaTexture) {
400 int width, height;
401 size_t size;
402
403#ifdef SK_GAMMA_CONTRAST
404 SkScalar contrast = SK_GAMMA_CONTRAST;
405#else
406 SkScalar contrast = 0.5f;
407#endif
408 SkScalar paintGamma = deviceProperties.fGamma;
409 SkScalar deviceGamma = deviceProperties.fGamma;
410
411 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
412 &width, &height);
413
414 SkAutoTArray<uint8_t> data((int)size);
415 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
416
417 // TODO: Update this to use the cache rather than directly creating a texture.
418 GrTextureDesc desc;
419 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
420 desc.fWidth = width;
421 desc.fHeight = height;
422 desc.fConfig = kAlpha_8_GrPixelConfig;
423
424 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
425 if (NULL == *gammaTexture) {
426 return;
427 }
428
429 context->writeTexturePixels(*gammaTexture,
430 0, 0, width, height,
431 (*gammaTexture)->config(), data.get(), 0,
432 GrContext::kDontFlush_PixelOpsFlag);
433 }
434}
435
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000436void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
437 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000438 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000439 SkASSERT(byteLength == 0 || text != NULL);
440
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000441 // nothing to draw or can't draw
442 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
443 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000444 return;
445 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000446
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000447 this->init(paint, skPaint);
448
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000449 SkScalar sizeRatio = fTextRatio;
450
451 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
452
jvanverth2d2a68c2014-06-10 06:42:56 -0700453 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
454 SkGlyphCache* cache = autoCache.getCache();
455 GrFontScaler* fontScaler = GetGrFontScaler(cache);
456
457 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000458
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000459 // need to measure first
460 // TODO - generate positions and pre-load cache as well?
461 const char* stop = text + byteLength;
462 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
463 SkFixed stopX = 0;
464 SkFixed stopY = 0;
465
466 const char* textPtr = text;
467 while (textPtr < stop) {
468 // don't need x, y here, since all subpixel variants will have the
469 // same advance
470 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
471
472 stopX += glyph.fAdvanceX;
473 stopY += glyph.fAdvanceY;
474 }
475 SkASSERT(textPtr == stop);
476
477 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
478 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
479
480 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
481 alignX = SkScalarHalf(alignX);
482 alignY = SkScalarHalf(alignY);
483 }
484
485 x -= alignX;
486 y -= alignY;
487 }
488
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000489 SkFixed fx = SkScalarToFixed(x);
490 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000491 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
492 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000493 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000494
495 if (glyph.fWidth) {
496 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
497 glyph.getSubXFixed(),
498 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000499 fx,
500 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000501 fontScaler);
502 }
503
504 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
505 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
506 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000507
508 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000509}
510
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000511void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
512 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000513 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000514 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000515
516 SkASSERT(byteLength == 0 || text != NULL);
517 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
518
519 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000520 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000521 return;
522 }
523
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000524 this->init(paint, skPaint);
525
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000526 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
527
jvanverth2d2a68c2014-06-10 06:42:56 -0700528 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
529 SkGlyphCache* cache = autoCache.getCache();
530 GrFontScaler* fontScaler = GetGrFontScaler(cache);
531
532 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000533
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000534 const char* stop = text + byteLength;
535
536 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
537 while (text < stop) {
538 // the last 2 parameters are ignored
539 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
540
541 if (glyph.fWidth) {
542 SkScalar x = pos[0];
543 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
544
545 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
546 glyph.getSubXFixed(),
547 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000548 SkScalarToFixed(x),
549 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000550 fontScaler);
551 }
552 pos += scalarsPerPosition;
553 }
554 } else {
555 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
556 while (text < stop) {
557 // the last 2 parameters are ignored
558 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
559
560 if (glyph.fWidth) {
561 SkScalar x = pos[0];
562 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000563
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000564 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
565 glyph.getSubXFixed(),
566 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000567 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
568 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000569 fontScaler);
570 }
571 pos += scalarsPerPosition;
572 }
573 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000574
575 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000576}