blob: 8827382b75dff8fc1612c5e8cbabd36c43be9b51 [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
jvanverth@google.comd830d132013-11-11 20:54:09 +000051 fCurrVertex = 0;
52
53 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000054}
55
56GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
57 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070058 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000059}
60
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000061bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000062 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000063 return false;
64 }
65
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000066 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000067 // translate well to distance
68 if (paint.getRasterizer() || paint.getMaskFilter() ||
69 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
70 return false;
71 }
72
73 // TODO: add some stroking support
74 if (paint.getStyle() != SkPaint::kFill_Style) {
75 return false;
76 }
77
78 // TODO: choose an appropriate maximum scale for distance fields and
79 // enable perspective
80 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
81 return false;
82 }
83
84 // distance fields cannot represent color fonts
85 SkScalerContext::Rec rec;
86 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
87 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000088}
89
jvanverth@google.comd830d132013-11-11 20:54:09 +000090static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
91 unsigned r = SkColorGetR(c);
92 unsigned g = SkColorGetG(c);
93 unsigned b = SkColorGetB(c);
94 return GrColorPackRGBA(r, g, b, 0xff);
95}
96
97void GrDistanceFieldTextContext::flushGlyphs() {
98 if (NULL == fDrawTarget) {
99 return;
100 }
101
102 GrDrawState* drawState = fDrawTarget->drawState();
103 GrDrawState::AutoRestoreEffects are(drawState);
104 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
105
106 if (fCurrVertex > 0) {
107 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000108 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverthf17bc6c2014-07-25 16:46:53 -0700109 GrTexture* currTexture = fStrike->getTexture();
110 SkASSERT(currTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000111 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700112 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000113
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000114 // Effects could be stored with one of the cache objects (atlas?)
jvanverth2d2a68c2014-06-10 06:42:56 -0700115 SkColor filteredColor;
116 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
117 if (NULL != colorFilter) {
118 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
119 } else {
120 filteredColor = fSkPaint.getColor();
121 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000122 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700123 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000124 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
125 fDeviceProperties.fGeometry.getLayout();
126 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700127 currTexture,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000128 params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700129 fGammaTexture,
130 gammaParams,
131 colorNoPreMul,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000132 fContext->getMatrix().rectStaysRect() &&
133 fContext->getMatrix().isSimilarity(),
134 useBGR),
135 kGlyphCoordsAttributeIndex)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000136
jvanverth@google.comd830d132013-11-11 20:54:09 +0000137 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
138 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
139 fPaint.numColorStages()) {
140 GrPrintf("LCD Text will not draw correctly.\n");
141 }
142 // We don't use the GrPaint's color in this case because it's been premultiplied by
143 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
144 // the mask texture color. The end result is that we get
145 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000146 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000147 // paintAlpha
148 drawState->setColor(SkColorSetARGB(a, a, a, a));
149 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700150 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000151 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
152 } else {
jvanverth2d2a68c2014-06-10 06:42:56 -0700153#ifdef SK_GAMMA_APPLY_TO_A8
154 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
155 filteredColor);
156 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700157 currTexture, params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700158 fGammaTexture, gammaParams,
159 lum/255.f,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000160 fContext->getMatrix().isSimilarity()),
161 kGlyphCoordsAttributeIndex)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700162#else
163 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700164 currTexture, params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700165 fContext->getMatrix().isSimilarity()),
166 kGlyphCoordsAttributeIndex)->unref();
167#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000168 // set back to normal in case we took LCD path previously.
169 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
170 drawState->setColor(fPaint.getColor());
171 }
172
173 int nGlyphs = fCurrVertex / 4;
174 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
175 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
176 nGlyphs,
177 4, 6);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000178 fCurrVertex = 0;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000179 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700180 fDrawTarget->resetVertexSource();
181 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000182}
183
184namespace {
185
186// position + texture coord
187extern const GrVertexAttrib gTextVertexAttribs[] = {
188 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000189 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
jvanverth@google.comd830d132013-11-11 20:54:09 +0000190};
191
192};
193
194void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000195 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000196 GrFontScaler* scaler) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000197 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
198 if (NULL == glyph || glyph->fBounds.isEmpty()) {
199 return;
200 }
201
202 SkScalar sx = SkFixedToScalar(vx);
203 SkScalar sy = SkFixedToScalar(vy);
204/*
205 // not valid, need to find a different solution for this
206 vx += SkIntToFixed(glyph->fBounds.fLeft);
207 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000208
jvanverth@google.comd830d132013-11-11 20:54:09 +0000209 // keep them as ints until we've done the clip-test
210 GrFixed width = glyph->fBounds.width();
211 GrFixed height = glyph->fBounds.height();
212
213 // check if we clipped out
214 if (true || NULL == glyph->fPlot) {
215 int x = vx >> 16;
216 int y = vy >> 16;
217 if (fClipRect.quickReject(x, y, x + width, y + height)) {
218// SkCLZ(3); // so we can set a break-point in the debugger
219 return;
220 }
221 }
222*/
223 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000224 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000225 goto HAS_ATLAS;
226 }
227
228 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000229 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
230 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000231 goto HAS_ATLAS;
232 }
233
234 if (c_DumpFontCache) {
235#ifdef SK_DEVELOPER
236 fContext->getFontCache()->dump();
237#endif
238 }
239
240 // before we purge the cache, we must flush any accumulated draws
241 this->flushGlyphs();
242 fContext->flush();
243
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000244 // we should have an unused plot now
245 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
246 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000247 goto HAS_ATLAS;
248 }
249
250 if (NULL == glyph->fPath) {
251 SkPath* path = SkNEW(SkPath);
252 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
253 // flag the glyph as being dead?
254 delete path;
255 return;
256 }
257 glyph->fPath = path;
258 }
259
260 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000261 SkMatrix ctm;
262 ctm.setScale(fTextRatio, fTextRatio);
263 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000264 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000265 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700266 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
267 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000268 return;
269 }
270
271HAS_ATLAS:
272 SkASSERT(glyph->fPlot);
273 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
274 glyph->fPlot->setDrawToken(drawToken);
275
276 GrTexture* texture = glyph->fPlot->texture();
277 SkASSERT(texture);
278
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000279 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
280 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
281 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
282 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000283
284 SkScalar scale = fTextRatio;
285 dx *= scale;
286 dy *= scale;
287 sx += dx;
288 sy += dy;
289 width *= scale;
290 height *= scale;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000291
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000292 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
293 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
294 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
295 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000296
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000297 static const size_t kVertexSize = 2 * sizeof(SkPoint);
jvanverthf17bc6c2014-07-25 16:46:53 -0700298 SkPoint* positions = reinterpret_cast<SkPoint*>(
299 reinterpret_cast<intptr_t>(fVertices) + kVertexSize * fCurrVertex);
300 positions->setRectFan(sx,
301 sy,
302 sx + width,
303 sy + height,
304 kVertexSize);
305 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
306 reinterpret_cast<intptr_t>(positions) + kVertexSize - sizeof(SkPoint));
307 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
jvanverth@google.comd830d132013-11-11 20:54:09 +0000308 SkFixedToFloat(texture->normalizeFixedY(ty)),
309 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
310 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000311 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000312 fCurrVertex += 4;
313}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000314
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000315inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
316 GrTextContext::init(paint, skPaint);
317
318 fStrike = NULL;
319
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000320 fCurrVertex = 0;
321
322 fVertices = NULL;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000323
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000324 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
325 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
326 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
327 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
328 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
329 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
330 } else {
331 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
332 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
333 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000334
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000335 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000336
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000337 fSkPaint.setLCDRenderText(false);
338 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700339 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000340 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700341
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000342}
343
344inline void GrDistanceFieldTextContext::finish() {
345 flushGlyphs();
346
347 GrTextContext::finish();
348}
349
jvanverth2d2a68c2014-06-10 06:42:56 -0700350static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
351 const SkDeviceProperties& deviceProperties,
352 GrTexture** gammaTexture) {
353 if (NULL == *gammaTexture) {
354 int width, height;
355 size_t size;
356
357#ifdef SK_GAMMA_CONTRAST
358 SkScalar contrast = SK_GAMMA_CONTRAST;
359#else
360 SkScalar contrast = 0.5f;
361#endif
362 SkScalar paintGamma = deviceProperties.fGamma;
363 SkScalar deviceGamma = deviceProperties.fGamma;
364
365 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
366 &width, &height);
367
368 SkAutoTArray<uint8_t> data((int)size);
369 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
370
371 // TODO: Update this to use the cache rather than directly creating a texture.
372 GrTextureDesc desc;
373 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
374 desc.fWidth = width;
375 desc.fHeight = height;
376 desc.fConfig = kAlpha_8_GrPixelConfig;
377
378 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
379 if (NULL == *gammaTexture) {
380 return;
381 }
382
383 context->writeTexturePixels(*gammaTexture,
384 0, 0, width, height,
385 (*gammaTexture)->config(), data.get(), 0,
386 GrContext::kDontFlush_PixelOpsFlag);
387 }
388}
389
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000390void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
391 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000392 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000393 SkASSERT(byteLength == 0 || text != NULL);
394
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000395 // nothing to draw or can't draw
396 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
397 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000398 return;
399 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000400
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000401 this->init(paint, skPaint);
402
jvanverthf17bc6c2014-07-25 16:46:53 -0700403 if (NULL == fDrawTarget) {
404 return;
405 }
406
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000407 SkScalar sizeRatio = fTextRatio;
408
409 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
410
jvanverth2d2a68c2014-06-10 06:42:56 -0700411 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
412 SkGlyphCache* cache = autoCache.getCache();
413 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700414 if (NULL == fStrike) {
415 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
416 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700417
418 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000419
jvanverthf17bc6c2014-07-25 16:46:53 -0700420 // allocate vertices
421 SkASSERT(NULL == fVertices);
422 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
423 SK_ARRAY_COUNT(gTextVertexAttribs));
424 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
425 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
426 0,
427 &fVertices,
428 NULL);
429 GrAlwaysAssert(success);
430
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000431 // need to measure first
432 // TODO - generate positions and pre-load cache as well?
433 const char* stop = text + byteLength;
434 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
435 SkFixed stopX = 0;
436 SkFixed stopY = 0;
437
438 const char* textPtr = text;
439 while (textPtr < stop) {
440 // don't need x, y here, since all subpixel variants will have the
441 // same advance
442 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
443
444 stopX += glyph.fAdvanceX;
445 stopY += glyph.fAdvanceY;
446 }
447 SkASSERT(textPtr == stop);
448
449 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
450 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
451
452 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
453 alignX = SkScalarHalf(alignX);
454 alignY = SkScalarHalf(alignY);
455 }
456
457 x -= alignX;
458 y -= alignY;
459 }
460
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000461 SkFixed fx = SkScalarToFixed(x);
462 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000463 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
464 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000465 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000466
467 if (glyph.fWidth) {
468 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
469 glyph.getSubXFixed(),
470 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000471 fx,
472 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000473 fontScaler);
474 }
475
476 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
477 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
478 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000479
480 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000481}
482
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000483void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
484 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000485 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000486 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000487
488 SkASSERT(byteLength == 0 || text != NULL);
489 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
490
491 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000492 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000493 return;
494 }
495
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000496 this->init(paint, skPaint);
497
jvanverthf17bc6c2014-07-25 16:46:53 -0700498 if (NULL == fDrawTarget) {
499 return;
500 }
501
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000502 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
503
jvanverth2d2a68c2014-06-10 06:42:56 -0700504 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
505 SkGlyphCache* cache = autoCache.getCache();
506 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700507 if (NULL == fStrike) {
508 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
509 }
510
511 // allocate vertices
512 SkASSERT(NULL == fVertices);
513 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
514 SK_ARRAY_COUNT(gTextVertexAttribs));
515 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
516 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
517 0,
518 &fVertices,
519 NULL);
520 GrAlwaysAssert(success);
jvanverth2d2a68c2014-06-10 06:42:56 -0700521
522 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000523
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000524 const char* stop = text + byteLength;
525
526 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
527 while (text < stop) {
528 // the last 2 parameters are ignored
529 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
530
531 if (glyph.fWidth) {
532 SkScalar x = pos[0];
533 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
534
535 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
536 glyph.getSubXFixed(),
537 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000538 SkScalarToFixed(x),
539 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000540 fontScaler);
541 }
542 pos += scalarsPerPosition;
543 }
544 } else {
545 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
546 while (text < stop) {
547 // the last 2 parameters are ignored
548 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
549
550 if (glyph.fWidth) {
551 SkScalar x = pos[0];
552 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000553
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000554 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
555 glyph.getSubXFixed(),
556 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000557 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
558 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000559 fontScaler);
560 }
561 pos += scalarsPerPosition;
562 }
563 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000564
565 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000566}