blob: c79276777d80bb55e9201e71479c4cc29d66d2e7 [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) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000109 fContext->getFontCache()->updateTextures();
110
jvanverth@google.comd830d132013-11-11 20:54:09 +0000111 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000112 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000113 SkASSERT(fCurrTexture);
114 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700115 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000116
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000117 // Effects could be stored with one of the cache objects (atlas?)
jvanverth2d2a68c2014-06-10 06:42:56 -0700118 SkColor filteredColor;
119 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
120 if (NULL != colorFilter) {
121 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
122 } else {
123 filteredColor = fSkPaint.getColor();
124 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000125 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700126 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000127 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
128 fDeviceProperties.fGeometry.getLayout();
129 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
130 fCurrTexture,
131 params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700132 fGammaTexture,
133 gammaParams,
134 colorNoPreMul,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000135 fContext->getMatrix().rectStaysRect() &&
136 fContext->getMatrix().isSimilarity(),
137 useBGR),
138 kGlyphCoordsAttributeIndex)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000139
jvanverth@google.comd830d132013-11-11 20:54:09 +0000140 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
141 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
142 fPaint.numColorStages()) {
143 GrPrintf("LCD Text will not draw correctly.\n");
144 }
145 // We don't use the GrPaint's color in this case because it's been premultiplied by
146 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
147 // the mask texture color. The end result is that we get
148 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000149 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000150 // paintAlpha
151 drawState->setColor(SkColorSetARGB(a, a, a, a));
152 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700153 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000154 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
155 } else {
jvanverth2d2a68c2014-06-10 06:42:56 -0700156#ifdef SK_GAMMA_APPLY_TO_A8
157 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
158 filteredColor);
159 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
160 fCurrTexture, params,
161 fGammaTexture, gammaParams,
162 lum/255.f,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000163 fContext->getMatrix().isSimilarity()),
164 kGlyphCoordsAttributeIndex)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700165#else
166 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
167 fCurrTexture, params,
168 fContext->getMatrix().isSimilarity()),
169 kGlyphCoordsAttributeIndex)->unref();
170#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000171 // set back to normal in case we took LCD path previously.
172 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
173 drawState->setColor(fPaint.getColor());
174 }
175
176 int nGlyphs = fCurrVertex / 4;
177 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
178 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
179 nGlyphs,
180 4, 6);
181 fDrawTarget->resetVertexSource();
182 fVertices = NULL;
183 fMaxVertices = 0;
184 fCurrVertex = 0;
185 SkSafeSetNull(fCurrTexture);
186 }
187}
188
189namespace {
190
191// position + texture coord
192extern const GrVertexAttrib gTextVertexAttribs[] = {
193 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000194 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
jvanverth@google.comd830d132013-11-11 20:54:09 +0000195};
196
197};
198
199void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000200 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000201 GrFontScaler* scaler) {
202 if (NULL == fDrawTarget) {
203 return;
204 }
205 if (NULL == fStrike) {
206 fStrike = fContext->getFontCache()->getStrike(scaler, true);
207 }
208
209 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
210 if (NULL == glyph || glyph->fBounds.isEmpty()) {
211 return;
212 }
213
214 SkScalar sx = SkFixedToScalar(vx);
215 SkScalar sy = SkFixedToScalar(vy);
216/*
217 // not valid, need to find a different solution for this
218 vx += SkIntToFixed(glyph->fBounds.fLeft);
219 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000220
jvanverth@google.comd830d132013-11-11 20:54:09 +0000221 // keep them as ints until we've done the clip-test
222 GrFixed width = glyph->fBounds.width();
223 GrFixed height = glyph->fBounds.height();
224
225 // check if we clipped out
226 if (true || NULL == glyph->fPlot) {
227 int x = vx >> 16;
228 int y = vy >> 16;
229 if (fClipRect.quickReject(x, y, x + width, y + height)) {
230// SkCLZ(3); // so we can set a break-point in the debugger
231 return;
232 }
233 }
234*/
235 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000236 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 goto HAS_ATLAS;
238 }
239
240 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000241 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
242 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000243 goto HAS_ATLAS;
244 }
245
246 if (c_DumpFontCache) {
247#ifdef SK_DEVELOPER
248 fContext->getFontCache()->dump();
249#endif
250 }
251
252 // before we purge the cache, we must flush any accumulated draws
253 this->flushGlyphs();
254 fContext->flush();
255
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000256 // we should have an unused plot now
257 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
258 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000259 goto HAS_ATLAS;
260 }
261
262 if (NULL == glyph->fPath) {
263 SkPath* path = SkNEW(SkPath);
264 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
265 // flag the glyph as being dead?
266 delete path;
267 return;
268 }
269 glyph->fPath = path;
270 }
271
272 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000273 SkMatrix ctm;
274 ctm.setScale(fTextRatio, fTextRatio);
275 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000276 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000277 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700278 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
279 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000280 return;
281 }
282
283HAS_ATLAS:
284 SkASSERT(glyph->fPlot);
285 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
286 glyph->fPlot->setDrawToken(drawToken);
287
288 GrTexture* texture = glyph->fPlot->texture();
289 SkASSERT(texture);
290
291 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
292 this->flushGlyphs();
293 fCurrTexture = texture;
294 fCurrTexture->ref();
295 }
296
297 if (NULL == fVertices) {
298 // If we need to reserve vertices allow the draw target to suggest
299 // a number of verts to reserve and whether to perform a flush.
300 fMaxVertices = kMinRequestedVerts;
301 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
302 SK_ARRAY_COUNT(gTextVertexAttribs));
303 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
304 if (flush) {
305 this->flushGlyphs();
306 fContext->flush();
307 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
308 SK_ARRAY_COUNT(gTextVertexAttribs));
309 }
310 fMaxVertices = kDefaultRequestedVerts;
311 // ignore return, no point in flushing again.
312 fDrawTarget->geometryHints(&fMaxVertices, NULL);
313
314 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
315 if (fMaxVertices < kMinRequestedVerts) {
316 fMaxVertices = kDefaultRequestedVerts;
317 } else if (fMaxVertices > maxQuadVertices) {
318 // don't exceed the limit of the index buffer
319 fMaxVertices = maxQuadVertices;
320 }
321 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
322 0,
323 GrTCast<void**>(&fVertices),
324 NULL);
325 GrAlwaysAssert(success);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000326 SkASSERT(2*sizeof(SkPoint) == fDrawTarget->getDrawState().getVertexSize());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000327 }
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;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000341
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
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000347 static const size_t kVertexSize = 2 * sizeof(SkPoint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000348 fVertices[2*fCurrVertex].setRectFan(sx,
349 sy,
350 sx + width,
351 sy + height,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000352 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000353 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
354 SkFixedToFloat(texture->normalizeFixedY(ty)),
355 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
356 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000357 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000358 fCurrVertex += 4;
359}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000360
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000361inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
362 GrTextContext::init(paint, skPaint);
363
364 fStrike = NULL;
365
366 fCurrTexture = NULL;
367 fCurrVertex = 0;
368
369 fVertices = NULL;
370 fMaxVertices = 0;
371
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000372 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
373 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
374 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
375 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
376 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
377 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
378 } else {
379 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
380 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
381 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000382
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000383 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000384
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000385 fSkPaint.setLCDRenderText(false);
386 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700387 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000388 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700389
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000390}
391
392inline void GrDistanceFieldTextContext::finish() {
393 flushGlyphs();
394
395 GrTextContext::finish();
396}
397
jvanverth2d2a68c2014-06-10 06:42:56 -0700398static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
399 const SkDeviceProperties& deviceProperties,
400 GrTexture** gammaTexture) {
401 if (NULL == *gammaTexture) {
402 int width, height;
403 size_t size;
404
405#ifdef SK_GAMMA_CONTRAST
406 SkScalar contrast = SK_GAMMA_CONTRAST;
407#else
408 SkScalar contrast = 0.5f;
409#endif
410 SkScalar paintGamma = deviceProperties.fGamma;
411 SkScalar deviceGamma = deviceProperties.fGamma;
412
413 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
414 &width, &height);
415
416 SkAutoTArray<uint8_t> data((int)size);
417 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
418
419 // TODO: Update this to use the cache rather than directly creating a texture.
420 GrTextureDesc desc;
421 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
422 desc.fWidth = width;
423 desc.fHeight = height;
424 desc.fConfig = kAlpha_8_GrPixelConfig;
425
426 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
427 if (NULL == *gammaTexture) {
428 return;
429 }
430
431 context->writeTexturePixels(*gammaTexture,
432 0, 0, width, height,
433 (*gammaTexture)->config(), data.get(), 0,
434 GrContext::kDontFlush_PixelOpsFlag);
435 }
436}
437
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000438void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
439 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000440 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000441 SkASSERT(byteLength == 0 || text != NULL);
442
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000443 // nothing to draw or can't draw
444 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
445 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000446 return;
447 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000448
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000449 this->init(paint, skPaint);
450
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000451 SkScalar sizeRatio = fTextRatio;
452
453 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
454
jvanverth2d2a68c2014-06-10 06:42:56 -0700455 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
456 SkGlyphCache* cache = autoCache.getCache();
457 GrFontScaler* fontScaler = GetGrFontScaler(cache);
458
459 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000460
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000461 // need to measure first
462 // TODO - generate positions and pre-load cache as well?
463 const char* stop = text + byteLength;
464 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
465 SkFixed stopX = 0;
466 SkFixed stopY = 0;
467
468 const char* textPtr = text;
469 while (textPtr < stop) {
470 // don't need x, y here, since all subpixel variants will have the
471 // same advance
472 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
473
474 stopX += glyph.fAdvanceX;
475 stopY += glyph.fAdvanceY;
476 }
477 SkASSERT(textPtr == stop);
478
479 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
480 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
481
482 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
483 alignX = SkScalarHalf(alignX);
484 alignY = SkScalarHalf(alignY);
485 }
486
487 x -= alignX;
488 y -= alignY;
489 }
490
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000491 SkFixed fx = SkScalarToFixed(x);
492 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000493 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
494 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000495 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000496
497 if (glyph.fWidth) {
498 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
499 glyph.getSubXFixed(),
500 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000501 fx,
502 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000503 fontScaler);
504 }
505
506 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
507 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
508 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000509
510 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000511}
512
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000513void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
514 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000515 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000516 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000517
518 SkASSERT(byteLength == 0 || text != NULL);
519 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
520
521 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000522 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000523 return;
524 }
525
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000526 this->init(paint, skPaint);
527
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000528 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
529
jvanverth2d2a68c2014-06-10 06:42:56 -0700530 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
531 SkGlyphCache* cache = autoCache.getCache();
532 GrFontScaler* fontScaler = GetGrFontScaler(cache);
533
534 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000535
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000536 const char* stop = text + byteLength;
537
538 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
539 while (text < stop) {
540 // the last 2 parameters are ignored
541 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
542
543 if (glyph.fWidth) {
544 SkScalar x = pos[0];
545 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
546
547 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
548 glyph.getSubXFixed(),
549 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000550 SkScalarToFixed(x),
551 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000552 fontScaler);
553 }
554 pos += scalarsPerPosition;
555 }
556 } else {
557 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
558 while (text < stop) {
559 // the last 2 parameters are ignored
560 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
561
562 if (glyph.fWidth) {
563 SkScalar x = pos[0];
564 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000565
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000566 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
567 glyph.getSubXFixed(),
568 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000569 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
570 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000571 fontScaler);
572 }
573 pos += scalarsPerPosition;
574 }
575 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000576
577 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000578}