blob: 9747d6a91f7ba4ebf50a8c4942e2abeb5653da7e [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"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000024#include "SkGlyphCache.h"
25#include "SkGpuDevice.h"
26#include "SkGr.h"
27
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000028SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29 "Dump the contents of the font cache before every purge.");
30
bsalomon594069f2014-06-06 06:16:34 -070031static const int kGlyphCoordsNoColorAttributeIndex = 1;
32static const int kGlyphCoordsWithColorAttributeIndex = 2;
33
34namespace {
35// position + texture coord
36extern const GrVertexAttrib gTextVertexAttribs[] = {
37 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
38 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
39};
40
41// position + color + texture coord
42extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
43 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
44 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
45 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
46};
47
48};
49
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000050GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000051 const SkDeviceProperties& properties)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000052 : GrTextContext(context, properties) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000053 fStrike = NULL;
54
55 fCurrTexture = NULL;
56 fCurrVertex = 0;
57
58 fVertices = NULL;
59 fMaxVertices = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000060
61 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000062}
63
64GrBitmapTextContext::~GrBitmapTextContext() {
65 this->flushGlyphs();
66}
67
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000068bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
69 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
70}
71
commit-bot@chromium.org42a89572013-10-28 15:13:50 +000072static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
73 unsigned r = SkColorGetR(c);
74 unsigned g = SkColorGetG(c);
75 unsigned b = SkColorGetB(c);
76 return GrColorPackRGBA(r, g, b, 0xff);
77}
78
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000079void GrBitmapTextContext::flushGlyphs() {
80 if (NULL == fDrawTarget) {
81 return;
82 }
83
84 GrDrawState* drawState = fDrawTarget->drawState();
85 GrDrawState::AutoRestoreEffects are(drawState);
86 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
87
88 if (fCurrVertex > 0) {
commit-bot@chromium.org7801faa2014-05-14 15:14:51 +000089 fContext->getFontCache()->updateTextures();
90
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000091 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +000092 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000093 SkASSERT(fCurrTexture);
94 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
95
96 // This effect could be stored with one of the cache objects (atlas?)
bsalomon594069f2014-06-06 06:16:34 -070097 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
98 kGlyphCoordsNoColorAttributeIndex;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000099 drawState->addCoverageEffect(
100 GrCustomCoordsTextureEffect::Create(fCurrTexture, params),
bsalomon594069f2014-06-06 06:16:34 -0700101 coordsIdx)->unref();
102 SkASSERT(NULL != fStrike);
103 switch (fStrike->getMaskFormat()) {
104 // Color bitmap text
105 case kARGB_GrMaskFormat:
106 SkASSERT(!drawState->hasColorVertexAttribute());
107 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
108 drawState->setColor(0xffffffff);
109 break;
110 // LCD text
111 case kA888_GrMaskFormat:
112 case kA565_GrMaskFormat: {
113 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
114 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
115 fPaint.numColorStages()) {
116 GrPrintf("LCD Text will not draw correctly.\n");
117 }
118 SkASSERT(!drawState->hasColorVertexAttribute());
119 // We don't use the GrPaint's color in this case because it's been premultiplied by
120 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
121 // the mask texture color. The end result is that we get
122 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
123 int a = SkColorGetA(fSkPaint.getColor());
124 // paintAlpha
125 drawState->setColor(SkColorSetARGB(a, a, a, a));
126 // paintColor
127 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
128 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
129 break;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000130 }
bsalomon594069f2014-06-06 06:16:34 -0700131 // Grayscale/BW text
132 case kA8_GrMaskFormat:
133 // set back to normal in case we took LCD path previously.
134 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
135 //drawState->setColor(fPaint.getColor());
136 // We're using per-vertex color.
137 SkASSERT(drawState->hasColorVertexAttribute());
138 drawState->setColor(0xFFFFFFFF);
139 break;
140 default:
141 SkFAIL("Unexepected mask format.");
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000142 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000143 int nGlyphs = fCurrVertex / 4;
144 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
145 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
146 nGlyphs,
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000147 4, 6, &fVertexBounds);
commit-bot@chromium.org42a89572013-10-28 15:13:50 +0000148
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000149 fDrawTarget->resetVertexSource();
150 fVertices = NULL;
151 fMaxVertices = 0;
152 fCurrVertex = 0;
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000153 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000154 SkSafeSetNull(fCurrTexture);
155 }
156}
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
163 fCurrTexture = NULL;
164 fCurrVertex = 0;
165
166 fVertices = NULL;
167 fMaxVertices = 0;
168}
169
170inline void GrBitmapTextContext::finish() {
bsalomon594069f2014-06-06 06:16:34 -0700171 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000172
173 GrTextContext::finish();
174}
175
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000176void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000177 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000178 SkScalar x, SkScalar y) {
179 SkASSERT(byteLength == 0 || text != NULL);
180
181 // nothing to draw
182 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
183 return;
184 }
185
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000186 this->init(paint, skPaint);
187
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000188 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
189
190 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
191 SkGlyphCache* cache = autoCache.getCache();
192 GrFontScaler* fontScaler = GetGrFontScaler(cache);
193
194 // transform our starting point
195 {
196 SkPoint loc;
197 fContext->getMatrix().mapXY(x, y, &loc);
198 x = loc.fX;
199 y = loc.fY;
200 }
201
202 // need to measure first
203 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
204 SkVector stop;
205
206 MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
207
208 SkScalar stopX = stop.fX;
209 SkScalar stopY = stop.fY;
210
211 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
212 stopX = SkScalarHalf(stopX);
213 stopY = SkScalarHalf(stopY);
214 }
215 x -= stopX;
216 y -= stopY;
217 }
218
219 const char* stop = text + byteLength;
220
221 SkAutoKern autokern;
222
223 SkFixed fxMask = ~0;
224 SkFixed fyMask = ~0;
225 SkFixed halfSampleX, halfSampleY;
226 if (cache->isSubpixel()) {
227 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
228 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
229 if (kX_SkAxisAlignment == baseline) {
230 fyMask = 0;
231 halfSampleY = SK_FixedHalf;
232 } else if (kY_SkAxisAlignment == baseline) {
233 fxMask = 0;
234 halfSampleX = SK_FixedHalf;
235 }
236 } else {
237 halfSampleX = halfSampleY = SK_FixedHalf;
238 }
239
240 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
241 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000242
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000243 GrContext::AutoMatrix autoMatrix;
244 autoMatrix.setIdentity(fContext, &fPaint);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000245
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000246 while (text < stop) {
247 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
248
249 fx += autokern.adjust(glyph);
250
251 if (glyph.fWidth) {
252 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
253 glyph.getSubXFixed(),
254 glyph.getSubYFixed()),
255 SkFixedFloorToFixed(fx),
256 SkFixedFloorToFixed(fy),
257 fontScaler);
258 }
259
260 fx += glyph.fAdvanceX;
261 fy += glyph.fAdvanceY;
262 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000263
264 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000265}
266
267///////////////////////////////////////////////////////////////////////////////
268// Copied from SkDraw
269
270// last parameter is interpreted as SkFixed [x, y]
271// return the fixed position, which may be rounded or not by the caller
272// e.g. subpixel doesn't round
273typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
274
275static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
276 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
277}
278
279static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
280 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
281 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
282}
283
284static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
285 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
286 SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
287}
288
289static AlignProc pick_align_proc(SkPaint::Align align) {
290 static const AlignProc gProcs[] = {
291 leftAlignProc, centerAlignProc, rightAlignProc
292 };
293
294 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
295
296 return gProcs[align];
297}
298
299class BitmapTextMapState {
300public:
301 mutable SkPoint fLoc;
302
303 BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
304 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
305
306 typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
307
308 Proc pickProc(int scalarsPerPosition);
309
310private:
311 const SkMatrix& fMatrix;
312 SkMatrix::MapXYProc fProc;
313 SkScalar fY; // ignored by MapXYProc
314 // these are only used by Only... procs
315 SkScalar fScaleX, fTransX, fTransformedY;
316
317 static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
318 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
319 }
320
321 static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
322 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
323 }
324
325 static void MapOnlyScaleXProc(const BitmapTextMapState& state,
326 const SkScalar pos[]) {
327 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
328 state.fTransformedY);
329 }
330
331 static void MapOnlyTransXProc(const BitmapTextMapState& state,
332 const SkScalar pos[]) {
333 state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
334 }
335};
336
337BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
338 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
339
340 if (1 == scalarsPerPosition) {
341 unsigned mtype = fMatrix.getType();
342 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
343 return MapXProc;
344 } else {
345 fScaleX = fMatrix.getScaleX();
346 fTransX = fMatrix.getTranslateX();
347 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
348 fMatrix.getTranslateY();
349 return (mtype & SkMatrix::kScale_Mask) ?
350 MapOnlyScaleXProc : MapOnlyTransXProc;
351 }
352 } else {
353 return MapXYProc;
354 }
355}
356
357///////////////////////////////////////////////////////////////////////////////
358
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000359void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000360 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000361 const SkScalar pos[], SkScalar constY,
362 int scalarsPerPosition) {
363 SkASSERT(byteLength == 0 || text != NULL);
364 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
365
366 // nothing to draw
367 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
368 return;
369 }
370
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000371 this->init(paint, skPaint);
372
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000373 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
374
375 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
376 SkGlyphCache* cache = autoCache.getCache();
377 GrFontScaler* fontScaler = GetGrFontScaler(cache);
378
379 // store original matrix before we reset, so we can use it to transform positions
380 SkMatrix ctm = fContext->getMatrix();
381 GrContext::AutoMatrix autoMatrix;
382 autoMatrix.setIdentity(fContext, &fPaint);
383
384 const char* stop = text + byteLength;
385 AlignProc alignProc = pick_align_proc(fSkPaint.getTextAlign());
386 BitmapTextMapState tms(ctm, constY);
387 BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
388 SkFixed halfSampleX = 0, halfSampleY = 0;
389
390 if (cache->isSubpixel()) {
391 // maybe we should skip the rounding if linearText is set
392 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
393
394 SkFixed fxMask = ~0;
395 SkFixed fyMask = ~0;
396 if (kX_SkAxisAlignment == baseline) {
397 fyMask = 0;
398#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
399 halfSampleY = SK_FixedHalf;
400#endif
401 } else if (kY_SkAxisAlignment == baseline) {
402 fxMask = 0;
403#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
404 halfSampleX = SK_FixedHalf;
405#endif
406 }
407
408 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
409 while (text < stop) {
410 tmsProc(tms, pos);
411 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX;
412 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY;
413
414 const SkGlyph& glyph = glyphCacheProc(cache, &text,
415 fx & fxMask, fy & fyMask);
416
417 if (glyph.fWidth) {
418 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
419 glyph.getSubXFixed(),
420 glyph.getSubYFixed()),
421 SkFixedFloorToFixed(fx),
422 SkFixedFloorToFixed(fy),
423 fontScaler);
424 }
425 pos += scalarsPerPosition;
426 }
427 } else {
428 while (text < stop) {
429 const char* currentText = text;
430 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
431
432 if (metricGlyph.fWidth) {
433 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
434 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
435
436 tmsProc(tms, pos);
437 SkIPoint fixedLoc;
438 alignProc(tms.fLoc, metricGlyph, &fixedLoc);
439
440 SkFixed fx = fixedLoc.fX + halfSampleX;
441 SkFixed fy = fixedLoc.fY + halfSampleY;
442
443 // have to call again, now that we've been "aligned"
444 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
445 fx & fxMask, fy & fyMask);
446 // the assumption is that the metrics haven't changed
447 SkASSERT(prevAdvX == glyph.fAdvanceX);
448 SkASSERT(prevAdvY == glyph.fAdvanceY);
449 SkASSERT(glyph.fWidth);
450
451 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
452 glyph.getSubXFixed(),
453 glyph.getSubYFixed()),
454 SkFixedFloorToFixed(fx),
455 SkFixedFloorToFixed(fy),
456 fontScaler);
457 }
458 pos += scalarsPerPosition;
459 }
460 }
461 } else { // not subpixel
462
463 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
464 while (text < stop) {
465 // the last 2 parameters are ignored
466 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
467
468 if (glyph.fWidth) {
469 tmsProc(tms, pos);
470
471 SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX;
472 SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf; //halfSampleY;
473 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
474 glyph.getSubXFixed(),
475 glyph.getSubYFixed()),
476 SkFixedFloorToFixed(fx),
477 SkFixedFloorToFixed(fy),
478 fontScaler);
479 }
480 pos += scalarsPerPosition;
481 }
482 } else {
483 while (text < stop) {
484 // the last 2 parameters are ignored
485 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
486
487 if (glyph.fWidth) {
488 tmsProc(tms, pos);
489
490 SkIPoint fixedLoc;
491 alignProc(tms.fLoc, glyph, &fixedLoc);
492
493 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
494 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
495 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
496 glyph.getSubXFixed(),
497 glyph.getSubYFixed()),
498 SkFixedFloorToFixed(fx),
499 SkFixedFloorToFixed(fy),
500 fontScaler);
501 }
502 pos += scalarsPerPosition;
503 }
504 }
505 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000506
507 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000508}
509
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000510void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000511 SkFixed vx, SkFixed vy,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000512 GrFontScaler* scaler) {
513 if (NULL == fDrawTarget) {
514 return;
515 }
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000516
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000517 if (NULL == fStrike) {
commit-bot@chromium.org75a22952013-11-21 15:09:33 +0000518 fStrike = fContext->getFontCache()->getStrike(scaler, false);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000519 }
520
521 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
522 if (NULL == glyph || glyph->fBounds.isEmpty()) {
523 return;
524 }
525
526 vx += SkIntToFixed(glyph->fBounds.fLeft);
527 vy += SkIntToFixed(glyph->fBounds.fTop);
528
529 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000530 SkFixed width = glyph->fBounds.width();
531 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000532
533 // check if we clipped out
534 if (true || NULL == glyph->fPlot) {
535 int x = vx >> 16;
536 int y = vy >> 16;
537 if (fClipRect.quickReject(x, y, x + width, y + height)) {
538// SkCLZ(3); // so we can set a break-point in the debugger
539 return;
540 }
541 }
542
543 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000544 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000545 goto HAS_ATLAS;
546 }
547
548 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000549 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
550 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000551 goto HAS_ATLAS;
552 }
553
554 if (c_DumpFontCache) {
555#ifdef SK_DEVELOPER
556 fContext->getFontCache()->dump();
557#endif
558 }
559
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000560 // flush any accumulated draws to allow us to free up a plot
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000561 this->flushGlyphs();
562 fContext->flush();
563
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000564 // we should have an unused plot now
565 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
566 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000567 goto HAS_ATLAS;
568 }
569
570 if (NULL == glyph->fPath) {
571 SkPath* path = SkNEW(SkPath);
572 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
573 // flag the glyph as being dead?
574 delete path;
575 return;
576 }
577 glyph->fPath = path;
578 }
579
580 GrContext::AutoMatrix am;
581 SkMatrix translate;
582 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
583 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
584 GrPaint tmpPaint(fPaint);
585 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700586 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
587 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000588 return;
589 }
590
591HAS_ATLAS:
592 SkASSERT(glyph->fPlot);
593 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
594 glyph->fPlot->setDrawToken(drawToken);
595
596 // now promote them to fixed (TODO: Rethink using fixed pt).
597 width = SkIntToFixed(width);
598 height = SkIntToFixed(height);
599
600 GrTexture* texture = glyph->fPlot->texture();
601 SkASSERT(texture);
602
603 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
604 this->flushGlyphs();
605 fCurrTexture = texture;
606 fCurrTexture->ref();
607 }
608
bsalomon594069f2014-06-06 06:16:34 -0700609 bool useColorVerts = kA8_GrMaskFormat == fStrike->getMaskFormat();
610
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000611 if (NULL == fVertices) {
612 // If we need to reserve vertices allow the draw target to suggest
613 // a number of verts to reserve and whether to perform a flush.
614 fMaxVertices = kMinRequestedVerts;
bsalomon594069f2014-06-06 06:16:34 -0700615 if (useColorVerts) {
616 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
617 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
618 } else {
619 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
620 SK_ARRAY_COUNT(gTextVertexAttribs));
621 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000622 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
623 if (flush) {
624 this->flushGlyphs();
625 fContext->flush();
bsalomon594069f2014-06-06 06:16:34 -0700626 if (useColorVerts) {
627 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
628 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
629 } else {
630 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
631 SK_ARRAY_COUNT(gTextVertexAttribs));
632 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000633 }
634 fMaxVertices = kDefaultRequestedVerts;
635 // ignore return, no point in flushing again.
636 fDrawTarget->geometryHints(&fMaxVertices, NULL);
637
638 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
639 if (fMaxVertices < kMinRequestedVerts) {
640 fMaxVertices = kDefaultRequestedVerts;
641 } else if (fMaxVertices > maxQuadVertices) {
642 // don't exceed the limit of the index buffer
643 fMaxVertices = maxQuadVertices;
644 }
645 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
646 0,
bsalomon594069f2014-06-06 06:16:34 -0700647 &fVertices,
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000648 NULL);
649 GrAlwaysAssert(success);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000650 }
651
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000652 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
653 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000654
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000655 SkRect r;
656 r.fLeft = SkFixedToFloat(vx);
657 r.fTop = SkFixedToFloat(vy);
658 r.fRight = SkFixedToFloat(vx + width);
659 r.fBottom = SkFixedToFloat(vy + height);
660
661 fVertexBounds.growToInclude(r);
662
bsalomon594069f2014-06-06 06:16:34 -0700663 size_t vertSize = useColorVerts ? (2 * sizeof(SkPoint) + sizeof(GrColor)) :
664 (2 * sizeof(SkPoint));
665
666 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
667
668 SkPoint* positions = reinterpret_cast<SkPoint*>(
669 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
670 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
671
672 // The texture coords are last in both the with and without color vertex layouts.
673 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
674 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
675 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
676 SkFixedToFloat(texture->normalizeFixedY(ty)),
677 SkFixedToFloat(texture->normalizeFixedX(tx + width)),
678 SkFixedToFloat(texture->normalizeFixedY(ty + height)),
679 vertSize);
680 if (useColorVerts) {
681 // color comes after position.
682 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
683 for (int i = 0; i < 4; ++i) {
684 *colors = fPaint.getColor();
685 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
686 }
687 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000688 fCurrVertex += 4;
689}