blob: afc2a47ff15603f8f14ecf8b8dd43fc99302eedb [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"
10#include "GrDrawTarget.h"
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000011#include "GrDrawTargetCaps.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000012#include "GrFontScaler.h"
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000013#include "SkGlyphCache.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000014#include "GrIndexBuffer.h"
15#include "GrTextStrike.h"
16#include "GrTextStrike_impl.h"
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +000017#include "SkDistanceFieldGen.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000018#include "SkDraw.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000019#include "SkGpuDevice.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000020#include "SkPath.h"
21#include "SkRTConf.h"
22#include "SkStrokeRec.h"
23#include "effects/GrDistanceFieldTextureEffect.h"
24
25static const int kGlyphCoordsAttributeIndex = 1;
26
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +000027static const int kSmallDFFontSize = 32;
28static const int kSmallDFFontLimit = 32;
29static const int kMediumDFFontSize = 64;
30static const int kMediumDFFontLimit = 64;
31static const int kLargeDFFontSize = 128;
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000032
jvanverth@google.comd830d132013-11-11 20:54:09 +000033SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
34 "Dump the contents of the font cache before every purge.");
35
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000036GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000037 const SkDeviceProperties& properties,
38 bool enable)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000039 : GrTextContext(context, properties) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000040#if SK_FORCE_DISTANCEFIELD_FONTS
41 fEnableDFRendering = true;
42#else
43 fEnableDFRendering = enable;
44#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +000045 fStrike = NULL;
46
47 fCurrTexture = NULL;
48 fCurrVertex = 0;
49
50 fVertices = NULL;
51 fMaxVertices = 0;
52}
53
54GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
55 this->flushGlyphs();
56}
57
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000058bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000059 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000060 return false;
61 }
62
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000063 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000064 // translate well to distance
65 if (paint.getRasterizer() || paint.getMaskFilter() ||
66 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
67 return false;
68 }
69
70 // TODO: add some stroking support
71 if (paint.getStyle() != SkPaint::kFill_Style) {
72 return false;
73 }
74
75 // TODO: choose an appropriate maximum scale for distance fields and
76 // enable perspective
77 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
78 return false;
79 }
80
81 // distance fields cannot represent color fonts
82 SkScalerContext::Rec rec;
83 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
84 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000085}
86
jvanverth@google.comd830d132013-11-11 20:54:09 +000087static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
88 unsigned r = SkColorGetR(c);
89 unsigned g = SkColorGetG(c);
90 unsigned b = SkColorGetB(c);
91 return GrColorPackRGBA(r, g, b, 0xff);
92}
93
94void GrDistanceFieldTextContext::flushGlyphs() {
95 if (NULL == fDrawTarget) {
96 return;
97 }
98
99 GrDrawState* drawState = fDrawTarget->drawState();
100 GrDrawState::AutoRestoreEffects are(drawState);
101 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
102
103 if (fCurrVertex > 0) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +0000104 fContext->getFontCache()->updateTextures();
105
jvanverth@google.comd830d132013-11-11 20:54:09 +0000106 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000107 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000108 SkASSERT(fCurrTexture);
109 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
110
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000111 // Effects could be stored with one of the cache objects (atlas?)
112 if (fUseLCDText) {
113 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
114 fDeviceProperties.fGeometry.getLayout();
115 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
116 fCurrTexture,
117 params,
118 fContext->getMatrix().rectStaysRect() &&
119 fContext->getMatrix().isSimilarity(),
120 useBGR),
121 kGlyphCoordsAttributeIndex)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000122
jvanverth@google.comd830d132013-11-11 20:54:09 +0000123 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
124 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
125 fPaint.numColorStages()) {
126 GrPrintf("LCD Text will not draw correctly.\n");
127 }
128 // We don't use the GrPaint's color in this case because it's been premultiplied by
129 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
130 // the mask texture color. The end result is that we get
131 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000132 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000133 // paintAlpha
134 drawState->setColor(SkColorSetARGB(a, a, a, a));
135 // paintColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000136 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000137 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
138 } else {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000139 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(fCurrTexture, params,
140 fContext->getMatrix().isSimilarity()),
141 kGlyphCoordsAttributeIndex)->unref();
142
jvanverth@google.comd830d132013-11-11 20:54:09 +0000143 // set back to normal in case we took LCD path previously.
144 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
145 drawState->setColor(fPaint.getColor());
146 }
147
148 int nGlyphs = fCurrVertex / 4;
149 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
150 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
151 nGlyphs,
152 4, 6);
153 fDrawTarget->resetVertexSource();
154 fVertices = NULL;
155 fMaxVertices = 0;
156 fCurrVertex = 0;
157 SkSafeSetNull(fCurrTexture);
158 }
159}
160
161namespace {
162
163// position + texture coord
164extern const GrVertexAttrib gTextVertexAttribs[] = {
165 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000166 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kEffect_GrVertexAttribBinding}
jvanverth@google.comd830d132013-11-11 20:54:09 +0000167};
168
169};
170
171void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000172 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000173 GrFontScaler* scaler) {
174 if (NULL == fDrawTarget) {
175 return;
176 }
177 if (NULL == fStrike) {
178 fStrike = fContext->getFontCache()->getStrike(scaler, true);
179 }
180
181 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
182 if (NULL == glyph || glyph->fBounds.isEmpty()) {
183 return;
184 }
185
186 SkScalar sx = SkFixedToScalar(vx);
187 SkScalar sy = SkFixedToScalar(vy);
188/*
189 // not valid, need to find a different solution for this
190 vx += SkIntToFixed(glyph->fBounds.fLeft);
191 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000192
jvanverth@google.comd830d132013-11-11 20:54:09 +0000193 // keep them as ints until we've done the clip-test
194 GrFixed width = glyph->fBounds.width();
195 GrFixed height = glyph->fBounds.height();
196
197 // check if we clipped out
198 if (true || NULL == glyph->fPlot) {
199 int x = vx >> 16;
200 int y = vy >> 16;
201 if (fClipRect.quickReject(x, y, x + width, y + height)) {
202// SkCLZ(3); // so we can set a break-point in the debugger
203 return;
204 }
205 }
206*/
207 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000208 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000209 goto HAS_ATLAS;
210 }
211
212 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000213 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
214 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000215 goto HAS_ATLAS;
216 }
217
218 if (c_DumpFontCache) {
219#ifdef SK_DEVELOPER
220 fContext->getFontCache()->dump();
221#endif
222 }
223
224 // before we purge the cache, we must flush any accumulated draws
225 this->flushGlyphs();
226 fContext->flush();
227
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000228 // we should have an unused plot now
229 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 (NULL == glyph->fPath) {
235 SkPath* path = SkNEW(SkPath);
236 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
237 // flag the glyph as being dead?
238 delete path;
239 return;
240 }
241 glyph->fPath = path;
242 }
243
244 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000245 SkMatrix ctm;
246 ctm.setScale(fTextRatio, fTextRatio);
247 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000248 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000249 am.setPreConcat(fContext, ctm, &tmpPaint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000250 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
251 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
252 return;
253 }
254
255HAS_ATLAS:
256 SkASSERT(glyph->fPlot);
257 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
258 glyph->fPlot->setDrawToken(drawToken);
259
260 GrTexture* texture = glyph->fPlot->texture();
261 SkASSERT(texture);
262
263 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
264 this->flushGlyphs();
265 fCurrTexture = texture;
266 fCurrTexture->ref();
267 }
268
269 if (NULL == fVertices) {
270 // If we need to reserve vertices allow the draw target to suggest
271 // a number of verts to reserve and whether to perform a flush.
272 fMaxVertices = kMinRequestedVerts;
273 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
274 SK_ARRAY_COUNT(gTextVertexAttribs));
275 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
276 if (flush) {
277 this->flushGlyphs();
278 fContext->flush();
279 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
280 SK_ARRAY_COUNT(gTextVertexAttribs));
281 }
282 fMaxVertices = kDefaultRequestedVerts;
283 // ignore return, no point in flushing again.
284 fDrawTarget->geometryHints(&fMaxVertices, NULL);
285
286 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
287 if (fMaxVertices < kMinRequestedVerts) {
288 fMaxVertices = kDefaultRequestedVerts;
289 } else if (fMaxVertices > maxQuadVertices) {
290 // don't exceed the limit of the index buffer
291 fMaxVertices = maxQuadVertices;
292 }
293 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
294 0,
295 GrTCast<void**>(&fVertices),
296 NULL);
297 GrAlwaysAssert(success);
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000298 SkASSERT(2*sizeof(SkPoint) == fDrawTarget->getDrawState().getVertexSize());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000299 }
300
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000301 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
302 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
303 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
304 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000305
306 SkScalar scale = fTextRatio;
307 dx *= scale;
308 dy *= scale;
309 sx += dx;
310 sy += dy;
311 width *= scale;
312 height *= scale;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000313
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000314 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
315 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
316 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
317 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000318
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000319 static const size_t kVertexSize = 2 * sizeof(SkPoint);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000320 fVertices[2*fCurrVertex].setRectFan(sx,
321 sy,
322 sx + width,
323 sy + height,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000324 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000325 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
326 SkFixedToFloat(texture->normalizeFixedY(ty)),
327 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
328 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000329 kVertexSize);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000330 fCurrVertex += 4;
331}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000332
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000333inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
334 GrTextContext::init(paint, skPaint);
335
336 fStrike = NULL;
337
338 fCurrTexture = NULL;
339 fCurrVertex = 0;
340
341 fVertices = NULL;
342 fMaxVertices = 0;
343
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000344 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
345 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
346 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
347 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
348 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
349 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
350 } else {
351 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
352 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
353 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000354
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000355 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000356
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000357 fSkPaint.setLCDRenderText(false);
358 fSkPaint.setAutohinted(false);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000359 fSkPaint.setSubpixelText(true);
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000360}
361
362inline void GrDistanceFieldTextContext::finish() {
363 flushGlyphs();
364
365 GrTextContext::finish();
366}
367
368void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
369 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000370 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000371 SkASSERT(byteLength == 0 || text != NULL);
372
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000373 // nothing to draw or can't draw
374 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
375 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000376 return;
377 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000378
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000379 this->init(paint, skPaint);
380
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000381 SkScalar sizeRatio = fTextRatio;
382
383 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
384
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000385 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
386 SkGlyphCache* cache = autoCache.getCache();
387 GrFontScaler* fontScaler = GetGrFontScaler(cache);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000388
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000389 // need to measure first
390 // TODO - generate positions and pre-load cache as well?
391 const char* stop = text + byteLength;
392 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
393 SkFixed stopX = 0;
394 SkFixed stopY = 0;
395
396 const char* textPtr = text;
397 while (textPtr < stop) {
398 // don't need x, y here, since all subpixel variants will have the
399 // same advance
400 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
401
402 stopX += glyph.fAdvanceX;
403 stopY += glyph.fAdvanceY;
404 }
405 SkASSERT(textPtr == stop);
406
407 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
408 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
409
410 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
411 alignX = SkScalarHalf(alignX);
412 alignY = SkScalarHalf(alignY);
413 }
414
415 x -= alignX;
416 y -= alignY;
417 }
418
419 SkFixed fx = SkScalarToFixed(x) + SK_FixedHalf;
420 SkFixed fy = SkScalarToFixed(y) + SK_FixedHalf;
421 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
422 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000423 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000424
425 if (glyph.fWidth) {
426 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
427 glyph.getSubXFixed(),
428 glyph.getSubYFixed()),
429 SkFixedFloorToFixed(fx),
430 SkFixedFloorToFixed(fy),
431 fontScaler);
432 }
433
434 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
435 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
436 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000437
438 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000439}
440
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000441void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
442 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000443 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000444 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000445
446 SkASSERT(byteLength == 0 || text != NULL);
447 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
448
449 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000450 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000451 return;
452 }
453
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000454 this->init(paint, skPaint);
455
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000456 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
457
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000458 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
459 SkGlyphCache* cache = autoCache.getCache();
460 GrFontScaler* fontScaler = GetGrFontScaler(cache);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000461
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000462 const char* stop = text + byteLength;
463
464 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
465 while (text < stop) {
466 // the last 2 parameters are ignored
467 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
468
469 if (glyph.fWidth) {
470 SkScalar x = pos[0];
471 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
472
473 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
474 glyph.getSubXFixed(),
475 glyph.getSubYFixed()),
476 SkScalarToFixed(x) + SK_FixedHalf, //d1g.fHalfSampleX,
477 SkScalarToFixed(y) + SK_FixedHalf, //d1g.fHalfSampleY,
478 fontScaler);
479 }
480 pos += scalarsPerPosition;
481 }
482 } else {
483 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
484 while (text < stop) {
485 // the last 2 parameters are ignored
486 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
487
488 if (glyph.fWidth) {
489 SkScalar x = pos[0];
490 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000491
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000492 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
493 glyph.getSubXFixed(),
494 glyph.getSubYFixed()),
495 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift)
496 + SK_FixedHalf, //d1g.fHalfSampleX,
497 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift)
498 + SK_FixedHalf, //d1g.fHalfSampleY,
499 fontScaler);
500 }
501 pos += scalarsPerPosition;
502 }
503 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000504
505 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000506}