blob: c992b9527f9202252e3fe31c7d94d0b96a00d0b2 [file] [log] [blame]
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +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 "GrBitmapTextContext.h"
9#include "GrAtlas.h"
10#include "GrDrawTarget.h"
11#include "GrFontScaler.h"
12#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070013#include "GrStrokeInfo.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000014#include "GrTextStrike.h"
15#include "GrTextStrike_impl.h"
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000016#include "SkColorPriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017#include "SkPath.h"
18#include "SkRTConf.h"
19#include "SkStrokeRec.h"
20#include "effects/GrCustomCoordsTextureEffect.h"
21
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000022#include "SkAutoKern.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000023#include "SkDraw.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070024#include "SkDrawProcs.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000025#include "SkGlyphCache.h"
26#include "SkGpuDevice.h"
27#include "SkGr.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070028#include "SkTextMapStateProc.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000029
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000030SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
31 "Dump the contents of the font cache before every purge.");
32
bsalomon594069f2014-06-06 06:16:34 -070033static const int kGlyphCoordsNoColorAttributeIndex = 1;
34static const int kGlyphCoordsWithColorAttributeIndex = 2;
35
36namespace {
37// position + texture coord
38extern const GrVertexAttrib gTextVertexAttribs[] = {
39 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
40 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
41};
42
43// position + color + texture coord
44extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
45 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
46 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
47 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
48};
49
50};
51
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000052GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000053 const SkDeviceProperties& properties)
jvanverth9c3d24b2014-08-27 11:53:17 -070054 : GrTextContext(context, properties)
55 , fStrike(NULL)
56 , fEffectTextureUniqueID(SK_InvalidUniqueID)
57 , fVertices(NULL)
58 , fVertexCount(0)
59 , fCurrVertex(0) {
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000060 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000061}
62
63GrBitmapTextContext::~GrBitmapTextContext() {
64 this->flushGlyphs();
65}
66
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000067bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
68 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
69}
70
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000071static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
72 unsigned r = SkColorGetR(c);
73 unsigned g = SkColorGetG(c);
74 unsigned b = SkColorGetB(c);
75 return GrColorPackRGBA(r, g, b, 0xff);
76}
77
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000078void GrBitmapTextContext::flushGlyphs() {
79 if (NULL == fDrawTarget) {
80 return;
81 }
82
83 GrDrawState* drawState = fDrawTarget->drawState();
84 GrDrawState::AutoRestoreEffects are(drawState);
85 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
86
87 if (fCurrVertex > 0) {
88 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000089 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000090 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
91
jvanverth9c3d24b2014-08-27 11:53:17 -070092 GrTexture* currTexture = fStrike->getTexture();
93 SkASSERT(currTexture);
94 uint32_t textureUniqueID = currTexture->getUniqueID();
bsalomon8b2fac42014-06-19 14:13:45 -070095
bsalomon1c63bf62014-07-22 13:09:46 -070096 if (textureUniqueID != fEffectTextureUniqueID) {
jvanverth9c3d24b2014-08-27 11:53:17 -070097 fCachedEffect.reset(GrCustomCoordsTextureEffect::Create(currTexture, params));
bsalomon1c63bf62014-07-22 13:09:46 -070098 fEffectTextureUniqueID = textureUniqueID;
bsalomon8b2fac42014-06-19 14:13:45 -070099 }
100
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000101 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -0700102 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
103 kGlyphCoordsNoColorAttributeIndex;
bsalomon8b2fac42014-06-19 14:13:45 -0700104 drawState->addCoverageEffect(fCachedEffect.get(), coordsIdx);
bsalomon594069f2014-06-06 06:16:34 -0700105 SkASSERT(NULL != fStrike);
106 switch (fStrike->getMaskFormat()) {
107 // Color bitmap text
108 case kARGB_GrMaskFormat:
109 SkASSERT(!drawState->hasColorVertexAttribute());
110 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
111 drawState->setColor(0xffffffff);
112 break;
113 // LCD text
114 case kA888_GrMaskFormat:
115 case kA565_GrMaskFormat: {
116 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
117 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
118 fPaint.numColorStages()) {
119 GrPrintf("LCD Text will not draw correctly.\n");
120 }
121 SkASSERT(!drawState->hasColorVertexAttribute());
122 // We don't use the GrPaint's color in this case because it's been premultiplied by
123 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
124 // the mask texture color. The end result is that we get
125 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
126 int a = SkColorGetA(fSkPaint.getColor());
127 // paintAlpha
128 drawState->setColor(SkColorSetARGB(a, a, a, a));
129 // paintColor
130 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
131 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
132 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000133 }
bsalomon594069f2014-06-06 06:16:34 -0700134 // Grayscale/BW text
135 case kA8_GrMaskFormat:
136 // set back to normal in case we took LCD path previously.
137 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
bsalomon594069f2014-06-06 06:16:34 -0700138 // We're using per-vertex color.
139 SkASSERT(drawState->hasColorVertexAttribute());
bsalomon594069f2014-06-06 06:16:34 -0700140 break;
141 default:
142 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000143 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000144 int nGlyphs = fCurrVertex / 4;
145 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
146 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
147 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000148 4, 6, &fVertexBounds);
jvanverth9c3d24b2014-08-27 11:53:17 -0700149 fVertexCount = 0;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000150 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000151 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000152 }
jvanverth9c3d24b2014-08-27 11:53:17 -0700153
154 fDrawTarget->resetVertexSource();
155 fVertices = NULL;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000156}
157
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000158inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
159 GrTextContext::init(paint, skPaint);
160
161 fStrike = NULL;
162
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000163 fVertices = NULL;
jvanverth9c3d24b2014-08-27 11:53:17 -0700164 fVertexCount = 0;
165 fCurrVertex = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000166}
167
168inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700169 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000170
171 GrTextContext::finish();
172}
173
jvanverth9c3d24b2014-08-27 11:53:17 -0700174void GrBitmapTextContext::allocateVertices(const char text[], size_t byteLength) {
175 SkASSERT(NULL == fVertices);
176 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
177 if (useColorVerts) {
178 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
djsollenea81ced2014-08-27 13:07:34 -0700179 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
jvanverth9c3d24b2014-08-27 11:53:17 -0700180 } else {
181 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
djsollenea81ced2014-08-27 13:07:34 -0700182 SK_ARRAY_COUNT(gTextVertexAttribs));
jvanverth9c3d24b2014-08-27 11:53:17 -0700183 }
184 fVertexCount = 4*fSkPaint.textToGlyphs(text, byteLength, NULL);
185 bool success = fDrawTarget->reserveVertexAndIndexSpace(fVertexCount,
186 0,
187 &fVertices,
188 NULL);
189 GrAlwaysAssert(success);
190}
191
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000192void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000193 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000194 SkScalar x, SkScalar y) {
195 SkASSERT(byteLength == 0 || text != NULL);
196
197 // nothing to draw
198 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
199 return;
200 }
201
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000202 this->init(paint, skPaint);
jvanverth9c3d24b2014-08-27 11:53:17 -0700203
204 if (NULL == fDrawTarget) {
205 return;
206 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000207
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000208 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
209
210 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
211 SkGlyphCache* cache = autoCache.getCache();
212 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverth9c3d24b2014-08-27 11:53:17 -0700213 if (NULL == fStrike) {
214 fStrike = fContext->getFontCache()->getStrike(fontScaler, false);
215 }
216
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000217 // transform our starting point
218 {
219 SkPoint loc;
220 fContext->getMatrix().mapXY(x, y, &loc);
221 x = loc.fX;
222 y = loc.fY;
223 }
224
225 // need to measure first
226 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
227 SkVector stop;
228
229 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
230
231 SkScalar stopX = stop.fX;
232 SkScalar stopY = stop.fY;
233
234 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
235 stopX = SkScalarHalf(stopX);
236 stopY = SkScalarHalf(stopY);
237 }
238 x -= stopX;
239 y -= stopY;
240 }
241
242 const char* stop = text + byteLength;
243
jvanverth9c3d24b2014-08-27 11:53:17 -0700244 this->allocateVertices(text, byteLength);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000245
246 SkFixed fxMask = ~0;
247 SkFixed fyMask = ~0;
248 SkFixed halfSampleX, halfSampleY;
249 if (cache->isSubpixel()) {
250 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
251 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
252 if (kX_SkAxisAlignment == baseline) {
253 fyMask = 0;
254 halfSampleY = SK_FixedHalf;
255 } else if (kY_SkAxisAlignment == baseline) {
256 fxMask = 0;
257 halfSampleX = SK_FixedHalf;
258 }
259 } else {
260 halfSampleX = halfSampleY = SK_FixedHalf;
261 }
262
263 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
264 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000265
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000266 GrContext::AutoMatrix autoMatrix;
267 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000268
jvanverth9c3d24b2014-08-27 11:53:17 -0700269 SkAutoKern autokern;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000270 while (text < stop) {
271 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
272
273 fx += autokern.adjust(glyph);
274
275 if (glyph.fWidth) {
276 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
277 glyph.getSubXFixed(),
278 glyph.getSubYFixed()),
279 SkFixedFloorToFixed(fx),
280 SkFixedFloorToFixed(fy),
281 fontScaler);
282 }
283
284 fx += glyph.fAdvanceX;
285 fy += glyph.fAdvanceY;
286 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000287
288 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000289}
290
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000291void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000292 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000293 const SkScalar pos[], SkScalar constY,
294 int scalarsPerPosition) {
295 SkASSERT(byteLength == 0 || text != NULL);
296 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
297
298 // nothing to draw
299 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
300 return;
301 }
302
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000303 this->init(paint, skPaint);
304
jvanverth9c3d24b2014-08-27 11:53:17 -0700305 if (NULL == fDrawTarget) {
306 return;
307 }
308
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000309 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
310
311 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
312 SkGlyphCache* cache = autoCache.getCache();
313 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverth9c3d24b2014-08-27 11:53:17 -0700314 if (NULL == fStrike) {
315 fStrike = fContext->getFontCache()->getStrike(fontScaler, false);
316 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000317
318 // store original matrix before we reset, so we can use it to transform positions
319 SkMatrix ctm = fContext->getMatrix();
320 GrContext::AutoMatrix autoMatrix;
321 autoMatrix.setIdentity(fContext, &fPaint);
322
jvanverth9c3d24b2014-08-27 11:53:17 -0700323 this->allocateVertices(text, byteLength);
324
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000325 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700326 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
327 SkTextMapStateProc tmsProc(ctm, constY, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000328 SkFixed halfSampleX = 0, halfSampleY = 0;
329
330 if (cache->isSubpixel()) {
331 // maybe we should skip the rounding if linearText is set
332 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
333
334 SkFixed fxMask = ~0;
335 SkFixed fyMask = ~0;
336 if (kX_SkAxisAlignment == baseline) {
337 fyMask = 0;
338#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
339 halfSampleY = SK_FixedHalf;
340#endif
341 } else if (kY_SkAxisAlignment == baseline) {
342 fxMask = 0;
343#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
344 halfSampleX = SK_FixedHalf;
345#endif
346 }
347
348 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
349 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700350 SkPoint tmsLoc;
351 tmsProc(pos, &tmsLoc);
352 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
353 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000354
355 const SkGlyph& glyph = glyphCacheProc(cache, &text,
356 fx & fxMask, fy & fyMask);
357
358 if (glyph.fWidth) {
359 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
360 glyph.getSubXFixed(),
361 glyph.getSubYFixed()),
362 SkFixedFloorToFixed(fx),
363 SkFixedFloorToFixed(fy),
364 fontScaler);
365 }
366 pos += scalarsPerPosition;
367 }
368 } else {
369 while (text < stop) {
370 const char* currentText = text;
371 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
372
373 if (metricGlyph.fWidth) {
374 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
375 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700376 SkPoint tmsLoc;
377 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000378 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700379 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000380
381 SkFixed fx = fixedLoc.fX + halfSampleX;
382 SkFixed fy = fixedLoc.fY + halfSampleY;
383
384 // have to call again, now that we've been "aligned"
385 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
386 fx & fxMask, fy & fyMask);
387 // the assumption is that the metrics haven't changed
388 SkASSERT(prevAdvX == glyph.fAdvanceX);
389 SkASSERT(prevAdvY == glyph.fAdvanceY);
390 SkASSERT(glyph.fWidth);
391
392 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
393 glyph.getSubXFixed(),
394 glyph.getSubYFixed()),
395 SkFixedFloorToFixed(fx),
396 SkFixedFloorToFixed(fy),
397 fontScaler);
398 }
399 pos += scalarsPerPosition;
400 }
401 }
402 } else { // not subpixel
403
404 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
405 while (text < stop) {
406 // the last 2 parameters are ignored
407 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
408
409 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700410 SkPoint tmsLoc;
411 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000412
kkinnunencb9a2c82014-06-12 23:06:28 -0700413 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
414 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000415 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
416 glyph.getSubXFixed(),
417 glyph.getSubYFixed()),
418 SkFixedFloorToFixed(fx),
419 SkFixedFloorToFixed(fy),
420 fontScaler);
421 }
422 pos += scalarsPerPosition;
423 }
424 } else {
425 while (text < stop) {
426 // the last 2 parameters are ignored
427 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
428
429 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700430 SkPoint tmsLoc;
431 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000432
433 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700434 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000435
436 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
437 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
438 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
439 glyph.getSubXFixed(),
440 glyph.getSubYFixed()),
441 SkFixedFloorToFixed(fx),
442 SkFixedFloorToFixed(fy),
443 fontScaler);
444 }
445 pos += scalarsPerPosition;
446 }
447 }
448 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000449
450 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000451}
452
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000453void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000454 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000455 GrFontScaler* scaler) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000456 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
457 if (NULL == glyph || glyph->fBounds.isEmpty()) {
458 return;
459 }
460
461 vx += SkIntToFixed(glyph->fBounds.fLeft);
462 vy += SkIntToFixed(glyph->fBounds.fTop);
463
464 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000465 SkFixed width = glyph->fBounds.width();
466 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000467
468 // check if we clipped out
469 if (true || NULL == glyph->fPlot) {
470 int x = vx >> 16;
471 int y = vy >> 16;
472 if (fClipRect.quickReject(x, y, x + width, y + height)) {
473// SkCLZ(3); // so we can set a break-point in the debugger
474 return;
475 }
476 }
477
478 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000479 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000480 goto HAS_ATLAS;
481 }
482
483 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000484 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
485 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000486 goto HAS_ATLAS;
487 }
488
489 if (c_DumpFontCache) {
490#ifdef SK_DEVELOPER
491 fContext->getFontCache()->dump();
492#endif
493 }
494
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000495 // flush any accumulated draws to allow us to free up a plot
jvanverth9c3d24b2014-08-27 11:53:17 -0700496 int remainingVertexCount = fVertexCount - fCurrVertex;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000497 this->flushGlyphs();
498 fContext->flush();
499
jvanverth9c3d24b2014-08-27 11:53:17 -0700500 // need to reallocate the vertex buffer for the remaining glyphs
501 fVertexCount = remainingVertexCount;
502 bool success = fDrawTarget->reserveVertexAndIndexSpace(fVertexCount,
503 0,
504 &fVertices,
505 NULL);
506 GrAlwaysAssert(success);
507
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000508 // we should have an unused plot now
509 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
510 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000511 goto HAS_ATLAS;
512 }
513
514 if (NULL == glyph->fPath) {
515 SkPath* path = SkNEW(SkPath);
516 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
517 // flag the glyph as being dead?
518 delete path;
519 return;
520 }
521 glyph->fPath = path;
522 }
523
524 GrContext::AutoMatrix am;
525 SkMatrix translate;
526 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
527 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
528 GrPaint tmpPaint(fPaint);
529 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700530 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
531 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000532 return;
533 }
534
535HAS_ATLAS:
536 SkASSERT(glyph->fPlot);
537 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
538 glyph->fPlot->setDrawToken(drawToken);
539
540 // now promote them to fixed (TODO: Rethink using fixed pt).
541 width = SkIntToFixed(width);
542 height = SkIntToFixed(height);
543
544 GrTexture* texture = glyph->fPlot->texture();
545 SkASSERT(texture);
546
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000547 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
548 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000549
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000550 SkRect r;
551 r.fLeft = SkFixedToFloat(vx);
552 r.fTop = SkFixedToFloat(vy);
553 r.fRight = SkFixedToFloat(vx + width);
554 r.fBottom = SkFixedToFloat(vy + height);
555
556 fVertexBounds.growToInclude(r);
557
jvanverth9c3d24b2014-08-27 11:53:17 -0700558 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
bsalomon594069f2014-06-06 06:16:34 -0700559 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
560 (2 * sizeof(SkPoint));
561
djsollenea81ced2014-08-27 13:07:34 -0700562 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
bsalomon594069f2014-06-06 06:16:34 -0700563
564 SkPoint* positions = reinterpret_cast<SkPoint*>(
565 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
566 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
567
568 // The texture coords are last in both the with and without color vertex layouts.
569 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
570 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
571 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
572 SkFixedToFloat(texture->normalizeFixedY(ty)),
573 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
574 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
575 vertSize);
576 if (useColorVerts) {
bsalomon62c447d2014-08-08 08:08:50 -0700577 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
578 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
579 }
bsalomon594069f2014-06-06 06:16:34 -0700580 // color comes after position.
581 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
582 for (int i = 0; i < 4; ++i) {
583 *colors = fPaint.getColor();
584 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
585 }
586 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000587 fCurrVertex += 4;
588}