blob: ff81b2d2c20e40744457d930b0f4c59a8b544e8c [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"
13#include "GrTextStrike.h"
14#include "GrTextStrike_impl.h"
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000015#include "SkColorPriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000016#include "SkPath.h"
17#include "SkRTConf.h"
18#include "SkStrokeRec.h"
19#include "effects/GrCustomCoordsTextureEffect.h"
20
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000021#include "SkAutoKern.h"
22#include "SkGlyphCache.h"
23#include "SkGpuDevice.h"
24#include "SkGr.h"
25
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000026static const int kGlyphCoordsAttributeIndex = 1;
27
28SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29 "Dump the contents of the font cache before every purge.");
30
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000031GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000032 const GrPaint& grPaint,
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000033 const SkPaint& skPaint,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000034 const SkDeviceProperties& properties)
35 : GrTextContext(context, grPaint, skPaint, properties) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000036 fStrike = NULL;
37
38 fCurrTexture = NULL;
39 fCurrVertex = 0;
40
41 fVertices = NULL;
42 fMaxVertices = 0;
43}
44
45GrBitmapTextContext::~GrBitmapTextContext() {
46 this->flushGlyphs();
47}
48
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000049static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
50 unsigned r = SkColorGetR(c);
51 unsigned g = SkColorGetG(c);
52 unsigned b = SkColorGetB(c);
53 return GrColorPackRGBA(r, g, b, 0xff);
54}
55
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000056void GrBitmapTextContext::flushGlyphs() {
57 if (NULL == fDrawTarget) {
58 return;
59 }
60
61 GrDrawState* drawState = fDrawTarget->drawState();
62 GrDrawState::AutoRestoreEffects are(drawState);
63 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
64
65 if (fCurrVertex > 0) {
66 // setup our sampler state for our text texture/atlas
67 SkASSERT(GrIsALIGN4(fCurrVertex));
68 SkASSERT(fCurrTexture);
69 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
70
71 // This effect could be stored with one of the cache objects (atlas?)
72 drawState->addCoverageEffect(
73 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
74 kGlyphCoordsAttributeIndex)->unref();
75
commit-bot@chromium.orgf8cb1842013-12-03 19:45:22 +000076 if (NULL != fStrike && kARGB_GrMaskFormat == fStrike->getMaskFormat()) {
77 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
78 drawState->setColor(0xffffffff);
79 } else if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000080 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
81 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
82 fPaint.numColorStages()) {
83 GrPrintf("LCD Text will not draw correctly.\n");
84 }
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000085 // We don't use the GrPaint's color in this case because it's been premultiplied by
86 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
skia.committer@gmail.com70402c32013-10-29 07:01:50 +000087 // the mask texture color. The end result is that we get
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000088 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.orgcc40f062014-01-24 14:38:27 +000089 int a = SkColorGetA(fSkPaint.getColor());
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000090 // paintAlpha
91 drawState->setColor(SkColorSetARGB(a, a, a, a));
92 // paintColor
commit-bot@chromium.orgcc40f062014-01-24 14:38:27 +000093 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000094 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000095 } else {
96 // set back to normal in case we took LCD path previously.
97 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
98 drawState->setColor(fPaint.getColor());
99 }
100
101 int nGlyphs = fCurrVertex / 4;
102 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
103 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
104 nGlyphs,
105 4, 6);
commit-bot@chromium.org42a89572013-10-28 15:13:50 +0000106
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000107 fDrawTarget->resetVertexSource();
108 fVertices = NULL;
109 fMaxVertices = 0;
110 fCurrVertex = 0;
111 SkSafeSetNull(fCurrTexture);
112 }
113}
114
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000115void GrBitmapTextContext::drawText(const char text[], size_t byteLength,
116 SkScalar x, SkScalar y) {
117 SkASSERT(byteLength == 0 || text != NULL);
118
119 // nothing to draw
120 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
121 return;
122 }
123
124 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
125
126 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
127 SkGlyphCache* cache = autoCache.getCache();
128 GrFontScaler* fontScaler = GetGrFontScaler(cache);
129
130 // transform our starting point
131 {
132 SkPoint loc;
133 fContext->getMatrix().mapXY(x, y, &loc);
134 x = loc.fX;
135 y = loc.fY;
136 }
137
138 // need to measure first
139 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
140 SkVector stop;
141
142 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
143
144 SkScalar stopX = stop.fX;
145 SkScalar stopY = stop.fY;
146
147 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
148 stopX = SkScalarHalf(stopX);
149 stopY = SkScalarHalf(stopY);
150 }
151 x -= stopX;
152 y -= stopY;
153 }
154
155 const char* stop = text + byteLength;
156
157 SkAutoKern autokern;
158
159 SkFixed fxMask = ~0;
160 SkFixed fyMask = ~0;
161 SkFixed halfSampleX, halfSampleY;
162 if (cache->isSubpixel()) {
163 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
164 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
165 if (kX_SkAxisAlignment == baseline) {
166 fyMask = 0;
167 halfSampleY = SK_FixedHalf;
168 } else if (kY_SkAxisAlignment == baseline) {
169 fxMask = 0;
170 halfSampleX = SK_FixedHalf;
171 }
172 } else {
173 halfSampleX = halfSampleY = SK_FixedHalf;
174 }
175
176 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
177 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000178
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000179 GrContext::AutoMatrix autoMatrix;
180 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000181
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000182 while (text < stop) {
183 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
184
185 fx += autokern.adjust(glyph);
186
187 if (glyph.fWidth) {
188 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
189 glyph.getSubXFixed(),
190 glyph.getSubYFixed()),
191 SkFixedFloorToFixed(fx),
192 SkFixedFloorToFixed(fy),
193 fontScaler);
194 }
195
196 fx += glyph.fAdvanceX;
197 fy += glyph.fAdvanceY;
198 }
199}
200
201///////////////////////////////////////////////////////////////////////////////
202// Copied from SkDraw
203
204// last parameter is interpreted as SkFixed [x, y]
205// return the fixed position, which may be rounded or not by the caller
206// e.g. subpixel doesn't round
207typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
208
209static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
210 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
211}
212
213static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
214 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
215 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
216}
217
218static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
219 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
220 SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
221}
222
223static AlignProc pick_align_proc(SkPaint::Align align) {
224 static const AlignProc gProcs[] = {
225 leftAlignProc, centerAlignProc, rightAlignProc
226 };
227
228 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
229
230 return gProcs[align];
231}
232
233class BitmapTextMapState {
234public:
235 mutable SkPoint fLoc;
236
237 BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
238 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
239
240 typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
241
242 Proc pickProc(int scalarsPerPosition);
243
244private:
245 const SkMatrix& fMatrix;
246 SkMatrix::MapXYProc fProc;
247 SkScalar fY; // ignored by MapXYProc
248 // these are only used by Only... procs
249 SkScalar fScaleX, fTransX, fTransformedY;
250
251 static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
252 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
253 }
254
255 static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
256 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
257 }
258
259 static void MapOnlyScaleXProc(const BitmapTextMapState& state,
260 const SkScalar pos[]) {
261 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
262 state.fTransformedY);
263 }
264
265 static void MapOnlyTransXProc(const BitmapTextMapState& state,
266 const SkScalar pos[]) {
267 state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
268 }
269};
270
271BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
272 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
273
274 if (1 == scalarsPerPosition) {
275 unsigned mtype = fMatrix.getType();
276 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
277 return MapXProc;
278 } else {
279 fScaleX = fMatrix.getScaleX();
280 fTransX = fMatrix.getTranslateX();
281 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
282 fMatrix.getTranslateY();
283 return (mtype & SkMatrix::kScale_Mask) ?
284 MapOnlyScaleXProc : MapOnlyTransXProc;
285 }
286 } else {
287 return MapXYProc;
288 }
289}
290
291///////////////////////////////////////////////////////////////////////////////
292
293void GrBitmapTextContext::drawPosText(const char text[], size_t byteLength,
294 const SkScalar pos[], SkScalar constY,
295 int scalarsPerPosition) {
296 SkASSERT(byteLength == 0 || text != NULL);
297 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
298
299 // nothing to draw
300 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
301 return;
302 }
303
304 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
305
306 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
307 SkGlyphCache* cache = autoCache.getCache();
308 GrFontScaler* fontScaler = GetGrFontScaler(cache);
309
310 // store original matrix before we reset, so we can use it to transform positions
311 SkMatrix ctm = fContext->getMatrix();
312 GrContext::AutoMatrix autoMatrix;
313 autoMatrix.setIdentity(fContext, &fPaint);
314
315 const char* stop = text + byteLength;
316 AlignProc alignProc = pick_align_proc(fSkPaint.getTextAlign());
317 BitmapTextMapState tms(ctm, constY);
318 BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
319 SkFixed halfSampleX = 0, halfSampleY = 0;
320
321 if (cache->isSubpixel()) {
322 // maybe we should skip the rounding if linearText is set
323 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
324
325 SkFixed fxMask = ~0;
326 SkFixed fyMask = ~0;
327 if (kX_SkAxisAlignment == baseline) {
328 fyMask = 0;
329#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
330 halfSampleY = SK_FixedHalf;
331#endif
332 } else if (kY_SkAxisAlignment == baseline) {
333 fxMask = 0;
334#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
335 halfSampleX = SK_FixedHalf;
336#endif
337 }
338
339 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
340 while (text < stop) {
341 tmsProc(tms, pos);
342 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX;
343 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY;
344
345 const SkGlyph& glyph = glyphCacheProc(cache, &text,
346 fx & fxMask, fy & fyMask);
347
348 if (glyph.fWidth) {
349 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
350 glyph.getSubXFixed(),
351 glyph.getSubYFixed()),
352 SkFixedFloorToFixed(fx),
353 SkFixedFloorToFixed(fy),
354 fontScaler);
355 }
356 pos += scalarsPerPosition;
357 }
358 } else {
359 while (text < stop) {
360 const char* currentText = text;
361 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
362
363 if (metricGlyph.fWidth) {
364 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
365 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
366
367 tmsProc(tms, pos);
368 SkIPoint fixedLoc;
369 alignProc(tms.fLoc, metricGlyph, &fixedLoc);
370
371 SkFixed fx = fixedLoc.fX + halfSampleX;
372 SkFixed fy = fixedLoc.fY + halfSampleY;
373
374 // have to call again, now that we've been "aligned"
375 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
376 fx & fxMask, fy & fyMask);
377 // the assumption is that the metrics haven't changed
378 SkASSERT(prevAdvX == glyph.fAdvanceX);
379 SkASSERT(prevAdvY == glyph.fAdvanceY);
380 SkASSERT(glyph.fWidth);
381
382 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
383 glyph.getSubXFixed(),
384 glyph.getSubYFixed()),
385 SkFixedFloorToFixed(fx),
386 SkFixedFloorToFixed(fy),
387 fontScaler);
388 }
389 pos += scalarsPerPosition;
390 }
391 }
392 } else { // not subpixel
393
394 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
395 while (text < stop) {
396 // the last 2 parameters are ignored
397 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
398
399 if (glyph.fWidth) {
400 tmsProc(tms, pos);
401
402 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX;
403 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf; //halfSampleY;
404 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
405 glyph.getSubXFixed(),
406 glyph.getSubYFixed()),
407 SkFixedFloorToFixed(fx),
408 SkFixedFloorToFixed(fy),
409 fontScaler);
410 }
411 pos += scalarsPerPosition;
412 }
413 } else {
414 while (text < stop) {
415 // the last 2 parameters are ignored
416 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
417
418 if (glyph.fWidth) {
419 tmsProc(tms, pos);
420
421 SkIPoint fixedLoc;
422 alignProc(tms.fLoc, glyph, &fixedLoc);
423
424 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
425 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
426 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
427 glyph.getSubXFixed(),
428 glyph.getSubYFixed()),
429 SkFixedFloorToFixed(fx),
430 SkFixedFloorToFixed(fy),
431 fontScaler);
432 }
433 pos += scalarsPerPosition;
434 }
435 }
436 }
437}
438
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000439namespace {
440
441// position + texture coord
442extern const GrVertexAttrib gTextVertexAttribs[] = {
443 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
444 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
445};
446
447};
448
449void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
450 GrFixed vx, GrFixed vy,
451 GrFontScaler* scaler) {
452 if (NULL == fDrawTarget) {
453 return;
454 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000455
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000456 if (NULL == fStrike) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000457#if SK_DISTANCEFIELD_FONTS
commit-bot@chromium.org75a22952013-11-21 15:09:33 +0000458 fStrike = fContext->getFontCache()->getStrike(scaler, false);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000459#else
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000460 fStrike = fContext->getFontCache()->getStrike(scaler);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000461#endif
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000462 }
463
464 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
465 if (NULL == glyph || glyph->fBounds.isEmpty()) {
466 return;
467 }
468
469 vx += SkIntToFixed(glyph->fBounds.fLeft);
470 vy += SkIntToFixed(glyph->fBounds.fTop);
471
472 // keep them as ints until we've done the clip-test
473 GrFixed width = glyph->fBounds.width();
474 GrFixed height = glyph->fBounds.height();
475
476 // check if we clipped out
477 if (true || NULL == glyph->fPlot) {
478 int x = vx >> 16;
479 int y = vy >> 16;
480 if (fClipRect.quickReject(x, y, x + width, y + height)) {
481// SkCLZ(3); // so we can set a break-point in the debugger
482 return;
483 }
484 }
485
486 if (NULL == glyph->fPlot) {
487 if (fStrike->getGlyphAtlas(glyph, scaler)) {
488 goto HAS_ATLAS;
489 }
490
491 // try to clear out an unused plot before we flush
492 fContext->getFontCache()->freePlotExceptFor(fStrike);
493 if (fStrike->getGlyphAtlas(glyph, scaler)) {
494 goto HAS_ATLAS;
495 }
496
497 if (c_DumpFontCache) {
498#ifdef SK_DEVELOPER
499 fContext->getFontCache()->dump();
500#endif
501 }
502
503 // before we purge the cache, we must flush any accumulated draws
504 this->flushGlyphs();
505 fContext->flush();
506
507 // try to purge
508 fContext->getFontCache()->purgeExceptFor(fStrike);
509 // need to use new flush count here
510 if (fStrike->getGlyphAtlas(glyph, scaler)) {
511 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);
530 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
531 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
532 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
547 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
548 this->flushGlyphs();
549 fCurrTexture = texture;
550 fCurrTexture->ref();
551 }
552
553 if (NULL == fVertices) {
554 // If we need to reserve vertices allow the draw target to suggest
555 // a number of verts to reserve and whether to perform a flush.
556 fMaxVertices = kMinRequestedVerts;
557 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
558 SK_ARRAY_COUNT(gTextVertexAttribs));
559 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
560 if (flush) {
561 this->flushGlyphs();
562 fContext->flush();
563 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
564 SK_ARRAY_COUNT(gTextVertexAttribs));
565 }
566 fMaxVertices = kDefaultRequestedVerts;
567 // ignore return, no point in flushing again.
568 fDrawTarget->geometryHints(&fMaxVertices, NULL);
569
570 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
571 if (fMaxVertices < kMinRequestedVerts) {
572 fMaxVertices = kDefaultRequestedVerts;
573 } else if (fMaxVertices > maxQuadVertices) {
574 // don't exceed the limit of the index buffer
575 fMaxVertices = maxQuadVertices;
576 }
577 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
578 0,
579 GrTCast<void**>(&fVertices),
580 NULL);
581 GrAlwaysAssert(success);
582 SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
583 }
584
585 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
586 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
587
588 fVertices[2*fCurrVertex].setRectFan(SkFixedToFloat(vx),
589 SkFixedToFloat(vy),
590 SkFixedToFloat(vx + width),
591 SkFixedToFloat(vy + height),
592 2 * sizeof(SkPoint));
593 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
594 SkFixedToFloat(texture->normalizeFixedY(ty)),
595 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
596 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
597 2 * sizeof(SkPoint));
598 fCurrVertex += 4;
599}