blob: 41dc784e791493d1ac693f5558252736e04d0bb0 [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"
bsalomonafbf2d62014-09-30 12:18:44 -070014#include "GrTexturePriv.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000015#include "GrTextStrike.h"
16#include "GrTextStrike_impl.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000017#include "effects/GrCustomCoordsTextureEffect.h"
egdanieled3af662014-10-31 06:55:45 -070018#include "effects/GrSimpleTextureEffect.h"
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000019
jvanverthaab626c2014-10-16 08:04:39 -070020#include "SkAutoKern.h"
bsalomonafbf2d62014-09-30 12:18:44 -070021#include "SkColorPriv.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000022#include "SkDraw.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070023#include "SkDrawProcs.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000024#include "SkGlyphCache.h"
25#include "SkGpuDevice.h"
26#include "SkGr.h"
bsalomonafbf2d62014-09-30 12:18:44 -070027#include "SkPath.h"
28#include "SkRTConf.h"
29#include "SkStrokeRec.h"
kkinnunencb9a2c82014-06-12 23:06:28 -070030#include "SkTextMapStateProc.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000031
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000032SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
33 "Dump the contents of the font cache before every purge.");
34
bsalomon594069f2014-06-06 06:16:34 -070035namespace {
36// position + texture coord
egdanieled3af662014-10-31 06:55:45 -070037extern const GrVertexAttrib gLCDVertexAttribs[] = {
bsalomon594069f2014-06-06 06:16:34 -070038 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070039 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070040};
41
egdanieled3af662014-10-31 06:55:45 -070042static const size_t kLCDTextVASize = 2 * sizeof(SkPoint);
43
44// position + local coord
45extern const GrVertexAttrib gColorVertexAttribs[] = {
46 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
47 {kVec2f_GrVertexAttribType, sizeof(SkPoint), kLocalCoord_GrVertexAttribBinding}
48};
49
50static const size_t kColorTextVASize = 2 * sizeof(SkPoint);
egdaniel7b3d5ee2014-08-28 05:41:14 -070051
bsalomon594069f2014-06-06 06:16:34 -070052// position + color + texture coord
egdanieled3af662014-10-31 06:55:45 -070053extern const GrVertexAttrib gGrayVertexAttribs[] = {
bsalomon594069f2014-06-06 06:16:34 -070054 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
55 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
joshualittb0a8a372014-09-23 09:50:21 -070056 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kGeometryProcessor_GrVertexAttribBinding}
bsalomon594069f2014-06-06 06:16:34 -070057};
58
egdanieled3af662014-10-31 06:55:45 -070059static const size_t kGrayTextVASize = 2 * sizeof(SkPoint) + sizeof(GrColor);
egdaniel7b3d5ee2014-08-28 05:41:14 -070060
jvanverth73f10532014-10-23 11:57:12 -070061static const int kVerticesPerGlyph = 4;
62static const int kIndicesPerGlyph = 6;
bsalomon594069f2014-06-06 06:16:34 -070063};
64
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000065GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000066 const SkDeviceProperties& properties)
Mike Klein6a25bd02014-08-29 10:03:59 -040067 : GrTextContext(context, properties) {
68 fStrike = NULL;
69
70 fCurrTexture = NULL;
Mike Klein6a25bd02014-08-29 10:03:59 -040071 fEffectTextureUniqueID = SK_InvalidUniqueID;
72
73 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -070074 fCurrVertex = 0;
75 fAllocVertexCount = 0;
76 fTotalVertexCount = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -040077
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +000078 fVertexBounds.setLargestInverted();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000079}
80
jvanverth8c27a182014-10-14 08:45:50 -070081GrBitmapTextContext* GrBitmapTextContext::Create(GrContext* context,
82 const SkDeviceProperties& props) {
83 return SkNEW_ARGS(GrBitmapTextContext, (context, props));
84}
85
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000086GrBitmapTextContext::~GrBitmapTextContext() {
jvanverth73f10532014-10-23 11:57:12 -070087 this->finish();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +000088}
89
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000090bool GrBitmapTextContext::canDraw(const SkPaint& paint) {
91 return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
92}
93
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000094inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
95 GrTextContext::init(paint, skPaint);
96
97 fStrike = NULL;
98
Mike Klein6a25bd02014-08-29 10:03:59 -040099 fCurrTexture = NULL;
jvanverth63b9dc82014-08-28 10:39:40 -0700100 fCurrVertex = 0;
Mike Klein6a25bd02014-08-29 10:03:59 -0400101
102 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700103 fAllocVertexCount = 0;
104 fTotalVertexCount = 0;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000105}
106
jvanverthaab626c2014-10-16 08:04:39 -0700107void GrBitmapTextContext::onDrawText(const GrPaint& paint, const SkPaint& skPaint,
108 const char text[], size_t byteLength,
109 SkScalar x, SkScalar y) {
110 SkASSERT(byteLength == 0 || text != NULL);
111
112 // nothing to draw
113 if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
114 return;
115 }
116
117 this->init(paint, skPaint);
118
119 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
120
121 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
122 SkGlyphCache* cache = autoCache.getCache();
123 GrFontScaler* fontScaler = GetGrFontScaler(cache);
124
125 // transform our starting point
126 {
127 SkPoint loc;
128 fContext->getMatrix().mapXY(x, y, &loc);
129 x = loc.fX;
130 y = loc.fY;
131 }
132
133 // need to measure first
jvanverth73f10532014-10-23 11:57:12 -0700134 int numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700135 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
jvanverth73f10532014-10-23 11:57:12 -0700136 SkVector stopVector;
137 numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);
jvanverthaab626c2014-10-16 08:04:39 -0700138
jvanverth73f10532014-10-23 11:57:12 -0700139 SkScalar stopX = stopVector.fX;
140 SkScalar stopY = stopVector.fY;
jvanverthaab626c2014-10-16 08:04:39 -0700141
142 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
143 stopX = SkScalarHalf(stopX);
144 stopY = SkScalarHalf(stopY);
145 }
146 x -= stopX;
147 y -= stopY;
jvanverth73f10532014-10-23 11:57:12 -0700148 } else {
149 numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
jvanverthaab626c2014-10-16 08:04:39 -0700150 }
jvanverth73f10532014-10-23 11:57:12 -0700151 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
jvanverthaab626c2014-10-16 08:04:39 -0700152
153 const char* stop = text + byteLength;
154
155 SkAutoKern autokern;
156
157 SkFixed fxMask = ~0;
158 SkFixed fyMask = ~0;
159 SkFixed halfSampleX, halfSampleY;
160 if (cache->isSubpixel()) {
161 halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
162 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
163 if (kX_SkAxisAlignment == baseline) {
164 fyMask = 0;
165 halfSampleY = SK_FixedHalf;
166 } else if (kY_SkAxisAlignment == baseline) {
167 fxMask = 0;
168 halfSampleX = SK_FixedHalf;
169 }
170 } else {
171 halfSampleX = halfSampleY = SK_FixedHalf;
172 }
173
174 SkFixed fx = SkScalarToFixed(x) + halfSampleX;
175 SkFixed fy = SkScalarToFixed(y) + halfSampleY;
176
177 GrContext::AutoMatrix autoMatrix;
178 autoMatrix.setIdentity(fContext, &fPaint);
179
180 while (text < stop) {
181 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
182
183 fx += autokern.adjust(glyph);
184
185 if (glyph.fWidth) {
186 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
187 glyph.getSubXFixed(),
188 glyph.getSubYFixed()),
189 SkFixedFloorToFixed(fx),
190 SkFixedFloorToFixed(fy),
191 fontScaler);
192 }
193
194 fx += glyph.fAdvanceX;
195 fy += glyph.fAdvanceY;
196 }
197
198 this->finish();
199}
200
jvanverth8c27a182014-10-14 08:45:50 -0700201void GrBitmapTextContext::onDrawPosText(const GrPaint& paint, const SkPaint& skPaint,
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000202 const char text[], size_t byteLength,
fmalita05c4a432014-09-29 06:29:53 -0700203 const SkScalar pos[], int scalarsPerPosition,
204 const SkPoint& offset) {
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000205 SkASSERT(byteLength == 0 || text != NULL);
206 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
207
208 // nothing to draw
209 if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
210 return;
211 }
212
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000213 this->init(paint, skPaint);
214
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000215 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
216
217 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
218 SkGlyphCache* cache = autoCache.getCache();
219 GrFontScaler* fontScaler = GetGrFontScaler(cache);
220
221 // store original matrix before we reset, so we can use it to transform positions
222 SkMatrix ctm = fContext->getMatrix();
223 GrContext::AutoMatrix autoMatrix;
224 autoMatrix.setIdentity(fContext, &fPaint);
225
jvanverth73f10532014-10-23 11:57:12 -0700226 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
227 fTotalVertexCount = kVerticesPerGlyph*numGlyphs;
228
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000229 const char* stop = text + byteLength;
kkinnunencb9a2c82014-06-12 23:06:28 -0700230 SkTextAlignProc alignProc(fSkPaint.getTextAlign());
fmalita05c4a432014-09-29 06:29:53 -0700231 SkTextMapStateProc tmsProc(ctm, offset, scalarsPerPosition);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000232 SkFixed halfSampleX = 0, halfSampleY = 0;
233
234 if (cache->isSubpixel()) {
235 // maybe we should skip the rounding if linearText is set
236 SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
237
238 SkFixed fxMask = ~0;
239 SkFixed fyMask = ~0;
240 if (kX_SkAxisAlignment == baseline) {
241 fyMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000242 halfSampleY = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000243 } else if (kY_SkAxisAlignment == baseline) {
244 fxMask = 0;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000245 halfSampleX = SK_FixedHalf;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000246 }
247
248 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
249 while (text < stop) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700250 SkPoint tmsLoc;
251 tmsProc(pos, &tmsLoc);
252 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + halfSampleX;
253 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + halfSampleY;
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000254
255 const SkGlyph& glyph = glyphCacheProc(cache, &text,
256 fx & fxMask, fy & fyMask);
257
258 if (glyph.fWidth) {
jvanverth0fedb192014-10-08 09:07:27 -0700259 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
260 glyph.getSubXFixed(),
261 glyph.getSubYFixed()),
262 SkFixedFloorToFixed(fx),
263 SkFixedFloorToFixed(fy),
264 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000265 }
266 pos += scalarsPerPosition;
267 }
268 } else {
269 while (text < stop) {
270 const char* currentText = text;
271 const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
272
273 if (metricGlyph.fWidth) {
274 SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
275 SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
kkinnunencb9a2c82014-06-12 23:06:28 -0700276 SkPoint tmsLoc;
277 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000278 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700279 alignProc(tmsLoc, metricGlyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000280
281 SkFixed fx = fixedLoc.fX + halfSampleX;
282 SkFixed fy = fixedLoc.fY + halfSampleY;
283
284 // have to call again, now that we've been "aligned"
285 const SkGlyph& glyph = glyphCacheProc(cache, &currentText,
286 fx & fxMask, fy & fyMask);
287 // the assumption is that the metrics haven't changed
288 SkASSERT(prevAdvX == glyph.fAdvanceX);
289 SkASSERT(prevAdvY == glyph.fAdvanceY);
290 SkASSERT(glyph.fWidth);
291
jvanverth0fedb192014-10-08 09:07:27 -0700292 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
293 glyph.getSubXFixed(),
294 glyph.getSubYFixed()),
295 SkFixedFloorToFixed(fx),
296 SkFixedFloorToFixed(fy),
297 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000298 }
299 pos += scalarsPerPosition;
300 }
301 }
302 } else { // not subpixel
303
304 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
305 while (text < stop) {
306 // the last 2 parameters are ignored
307 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
308
309 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700310 SkPoint tmsLoc;
311 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000312
kkinnunencb9a2c82014-06-12 23:06:28 -0700313 SkFixed fx = SkScalarToFixed(tmsLoc.fX) + SK_FixedHalf; //halfSampleX;
314 SkFixed fy = SkScalarToFixed(tmsLoc.fY) + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700315 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
316 glyph.getSubXFixed(),
317 glyph.getSubYFixed()),
318 SkFixedFloorToFixed(fx),
319 SkFixedFloorToFixed(fy),
320 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000321 }
322 pos += scalarsPerPosition;
323 }
324 } else {
325 while (text < stop) {
326 // the last 2 parameters are ignored
327 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
328
329 if (glyph.fWidth) {
kkinnunencb9a2c82014-06-12 23:06:28 -0700330 SkPoint tmsLoc;
331 tmsProc(pos, &tmsLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000332
333 SkIPoint fixedLoc;
kkinnunencb9a2c82014-06-12 23:06:28 -0700334 alignProc(tmsLoc, glyph, &fixedLoc);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000335
336 SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
337 SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
jvanverth0fedb192014-10-08 09:07:27 -0700338 this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
339 glyph.getSubXFixed(),
340 glyph.getSubYFixed()),
341 SkFixedFloorToFixed(fx),
342 SkFixedFloorToFixed(fy),
343 fontScaler);
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000344 }
345 pos += scalarsPerPosition;
346 }
347 }
348 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000349
350 this->finish();
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000351}
352
egdanieled3af662014-10-31 06:55:45 -0700353static void* alloc_vertices(GrDrawTarget* drawTarget, int numVertices, GrMaskFormat maskFormat) {
jvanverth73f10532014-10-23 11:57:12 -0700354 if (numVertices <= 0) {
355 return NULL;
356 }
357
358 // set up attributes
egdanieled3af662014-10-31 06:55:45 -0700359 if (kA8_GrMaskFormat == maskFormat) {
360 drawTarget->drawState()->setVertexAttribs<gGrayVertexAttribs>(
361 SK_ARRAY_COUNT(gGrayVertexAttribs), kGrayTextVASize);
362 } else if (kARGB_GrMaskFormat == maskFormat) {
363 drawTarget->drawState()->setVertexAttribs<gColorVertexAttribs>(
364 SK_ARRAY_COUNT(gColorVertexAttribs), kColorTextVASize);
jvanverth73f10532014-10-23 11:57:12 -0700365 } else {
egdanieled3af662014-10-31 06:55:45 -0700366 drawTarget->drawState()->setVertexAttribs<gLCDVertexAttribs>(
367 SK_ARRAY_COUNT(gLCDVertexAttribs), kLCDTextVASize);
jvanverth73f10532014-10-23 11:57:12 -0700368 }
369 void* vertices = NULL;
370 bool success = drawTarget->reserveVertexAndIndexSpace(numVertices,
371 0,
372 &vertices,
373 NULL);
374 GrAlwaysAssert(success);
375 return vertices;
376}
377
jvanverth0fedb192014-10-08 09:07:27 -0700378void GrBitmapTextContext::appendGlyph(GrGlyph::PackedID packed,
379 SkFixed vx, SkFixed vy,
380 GrFontScaler* scaler) {
Mike Klein6a25bd02014-08-29 10:03:59 -0400381 if (NULL == fDrawTarget) {
382 return;
383 }
384
385 if (NULL == fStrike) {
386 fStrike = fContext->getFontCache()->getStrike(scaler, false);
387 }
388
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000389 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
390 if (NULL == glyph || glyph->fBounds.isEmpty()) {
391 return;
392 }
393
394 vx += SkIntToFixed(glyph->fBounds.fLeft);
395 vy += SkIntToFixed(glyph->fBounds.fTop);
396
397 // keep them as ints until we've done the clip-test
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000398 SkFixed width = glyph->fBounds.width();
399 SkFixed height = glyph->fBounds.height();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000400
401 // check if we clipped out
402 if (true || NULL == glyph->fPlot) {
403 int x = vx >> 16;
404 int y = vy >> 16;
405 if (fClipRect.quickReject(x, y, x + width, y + height)) {
406// SkCLZ(3); // so we can set a break-point in the debugger
407 return;
408 }
409 }
410
411 if (NULL == glyph->fPlot) {
jvanverth681e65b2014-09-19 13:07:38 -0700412 if (!fStrike->glyphTooLargeForAtlas(glyph)) {
413 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
414 goto HAS_ATLAS;
415 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000416
jvanverth681e65b2014-09-19 13:07:38 -0700417 // try to clear out an unused plot before we flush
jvanverth294c3262014-10-10 11:36:12 -0700418 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
jvanverth681e65b2014-09-19 13:07:38 -0700419 fStrike->addGlyphToAtlas(glyph, scaler)) {
420 goto HAS_ATLAS;
421 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000422
jvanverth681e65b2014-09-19 13:07:38 -0700423 if (c_DumpFontCache) {
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000424#ifdef SK_DEVELOPER
jvanverth681e65b2014-09-19 13:07:38 -0700425 fContext->getFontCache()->dump();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000426#endif
jvanverth681e65b2014-09-19 13:07:38 -0700427 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000428
jvanverth681e65b2014-09-19 13:07:38 -0700429 // flush any accumulated draws to allow us to free up a plot
jvanverth0fedb192014-10-08 09:07:27 -0700430 this->flush();
jvanverth681e65b2014-09-19 13:07:38 -0700431 fContext->flush();
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000432
jvanverth681e65b2014-09-19 13:07:38 -0700433 // we should have an unused plot now
jvanverth294c3262014-10-10 11:36:12 -0700434 if (fContext->getFontCache()->freeUnusedPlot(fStrike, glyph) &&
jvanverth681e65b2014-09-19 13:07:38 -0700435 fStrike->addGlyphToAtlas(glyph, scaler)) {
436 goto HAS_ATLAS;
437 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000438 }
439
440 if (NULL == glyph->fPath) {
441 SkPath* path = SkNEW(SkPath);
442 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
443 // flag the glyph as being dead?
444 delete path;
445 return;
446 }
447 glyph->fPath = path;
448 }
449
bsalomonec87dc62014-10-14 10:52:00 -0700450 // flush any accumulated draws before drawing this glyph as a path.
451 this->flush();
452
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000453 GrContext::AutoMatrix am;
454 SkMatrix translate;
455 translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)),
456 SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop)));
457 GrPaint tmpPaint(fPaint);
458 am.setPreConcat(fContext, translate, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700459 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
460 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth73f10532014-10-23 11:57:12 -0700461
462 // remove this glyph from the vertices we need to allocate
463 fTotalVertexCount -= kVerticesPerGlyph;
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000464 return;
465 }
466
467HAS_ATLAS:
468 SkASSERT(glyph->fPlot);
469 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
470 glyph->fPlot->setDrawToken(drawToken);
471
472 // now promote them to fixed (TODO: Rethink using fixed pt).
473 width = SkIntToFixed(width);
474 height = SkIntToFixed(height);
475
jvanverth294c3262014-10-10 11:36:12 -0700476 // the current texture/maskformat must match what the glyph needs
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000477 GrTexture* texture = glyph->fPlot->texture();
478 SkASSERT(texture);
479
jvanverth73f10532014-10-23 11:57:12 -0700480 if (fCurrTexture != texture || fCurrVertex + kVerticesPerGlyph > fAllocVertexCount) {
jvanverth0fedb192014-10-08 09:07:27 -0700481 this->flush();
Mike Klein6a25bd02014-08-29 10:03:59 -0400482 fCurrTexture = texture;
483 fCurrTexture->ref();
jvanverth294c3262014-10-10 11:36:12 -0700484 fCurrMaskFormat = glyph->fMaskFormat;
Mike Klein6a25bd02014-08-29 10:03:59 -0400485 }
486
Mike Klein6a25bd02014-08-29 10:03:59 -0400487 if (NULL == fVertices) {
jvanverth73f10532014-10-23 11:57:12 -0700488 int maxQuadVertices = kVerticesPerGlyph * fContext->getQuadIndexBuffer()->maxQuads();
489 fAllocVertexCount = SkMin32(fTotalVertexCount, maxQuadVertices);
egdanieled3af662014-10-31 06:55:45 -0700490 fVertices = alloc_vertices(fDrawTarget, fAllocVertexCount, fCurrMaskFormat);
Mike Klein6a25bd02014-08-29 10:03:59 -0400491 }
492
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000493 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
494 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000495
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000496 SkRect r;
497 r.fLeft = SkFixedToFloat(vx);
498 r.fTop = SkFixedToFloat(vy);
499 r.fRight = SkFixedToFloat(vx + width);
500 r.fBottom = SkFixedToFloat(vy + height);
501
reed10d03272014-10-01 09:24:12 -0700502 fVertexBounds.joinNonEmptyArg(r);
commit-bot@chromium.org3ae0e6c2014-02-11 18:24:25 +0000503
egdanieled3af662014-10-31 06:55:45 -0700504 size_t vertSize;
505 switch (fCurrMaskFormat) {
506 case kA8_GrMaskFormat:
507 vertSize = kGrayTextVASize;
508 break;
509 case kARGB_GrMaskFormat:
510 vertSize = kColorTextVASize;
511 default:
512 vertSize = kLCDTextVASize;
513 }
bsalomon594069f2014-06-06 06:16:34 -0700514
egdaniel7b3d5ee2014-08-28 05:41:14 -0700515 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexStride());
bsalomon594069f2014-06-06 06:16:34 -0700516
517 SkPoint* positions = reinterpret_cast<SkPoint*>(
518 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
519 positions->setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, vertSize);
520
521 // The texture coords are last in both the with and without color vertex layouts.
522 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
523 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
bsalomonafbf2d62014-09-30 12:18:44 -0700524 textureCoords->setRectFan(SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx)),
525 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty)),
526 SkFixedToFloat(texture->texturePriv().normalizeFixedX(tx + width)),
527 SkFixedToFloat(texture->texturePriv().normalizeFixedY(ty + height)),
bsalomon594069f2014-06-06 06:16:34 -0700528 vertSize);
egdanieled3af662014-10-31 06:55:45 -0700529 if (kA8_GrMaskFormat == fCurrMaskFormat) {
bsalomon62c447d2014-08-08 08:08:50 -0700530 if (0xFF == GrColorUnpackA(fPaint.getColor())) {
531 fDrawTarget->drawState()->setHint(GrDrawState::kVertexColorsAreOpaque_Hint, true);
532 }
bsalomon594069f2014-06-06 06:16:34 -0700533 // color comes after position.
534 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
535 for (int i = 0; i < 4; ++i) {
536 *colors = fPaint.getColor();
537 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
538 }
539 }
jvanverth@google.comc7a40fa2013-10-16 18:15:34 +0000540 fCurrVertex += 4;
541}
jvanverth0fedb192014-10-08 09:07:27 -0700542
543static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
544 unsigned r = SkColorGetR(c);
545 unsigned g = SkColorGetG(c);
546 unsigned b = SkColorGetB(c);
547 return GrColorPackRGBA(r, g, b, 0xff);
548}
549
550void GrBitmapTextContext::flush() {
551 if (NULL == fDrawTarget) {
552 return;
553 }
554
555 GrDrawState* drawState = fDrawTarget->drawState();
556 GrDrawState::AutoRestoreEffects are(drawState);
557 drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget());
558
559 if (fCurrVertex > 0) {
560 // setup our sampler state for our text texture/atlas
561 SkASSERT(SkIsAlign4(fCurrVertex));
562 SkASSERT(fCurrTexture);
563 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode);
564
egdanieled3af662014-10-31 06:55:45 -0700565 // This effect could be stored with one of the cache objects (atlas?)
566 if (kARGB_GrMaskFormat == fCurrMaskFormat) {
567 GrFragmentProcessor* fragProcessor = GrSimpleTextureEffect::Create(fCurrTexture,
568 SkMatrix::I(),
569 params);
570 drawState->addColorProcessor(fragProcessor)->unref();
571 } else {
572 uint32_t textureUniqueID = fCurrTexture->getUniqueID();
573 if (textureUniqueID != fEffectTextureUniqueID) {
574 fCachedGeometryProcessor.reset(GrCustomCoordsTextureEffect::Create(fCurrTexture,
575 params));
576 fEffectTextureUniqueID = textureUniqueID;
577 }
jvanverth0fedb192014-10-08 09:07:27 -0700578
egdanieled3af662014-10-31 06:55:45 -0700579 drawState->setGeometryProcessor(fCachedGeometryProcessor.get());
jvanverth0fedb192014-10-08 09:07:27 -0700580 }
581
jvanverth0fedb192014-10-08 09:07:27 -0700582 SkASSERT(fStrike);
jvanverth294c3262014-10-10 11:36:12 -0700583 switch (fCurrMaskFormat) {
jvanverth0fedb192014-10-08 09:07:27 -0700584 // Color bitmap text
585 case kARGB_GrMaskFormat:
586 SkASSERT(!drawState->hasColorVertexAttribute());
587 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
jvanverth294c3262014-10-10 11:36:12 -0700588 drawState->setAlpha(fSkPaint.getAlpha());
jvanverth0fedb192014-10-08 09:07:27 -0700589 break;
590 // LCD text
jvanverth0fedb192014-10-08 09:07:27 -0700591 case kA565_GrMaskFormat: {
592 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
593 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
594 fPaint.numColorStages()) {
tfarina38406c82014-10-31 07:11:12 -0700595 SkDebugf("LCD Text will not draw correctly.\n");
jvanverth0fedb192014-10-08 09:07:27 -0700596 }
597 SkASSERT(!drawState->hasColorVertexAttribute());
598 // We don't use the GrPaint's color in this case because it's been premultiplied by
599 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
600 // the mask texture color. The end result is that we get
601 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
602 int a = SkColorGetA(fSkPaint.getColor());
603 // paintAlpha
604 drawState->setColor(SkColorSetARGB(a, a, a, a));
605 // paintColor
606 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
607 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
608 break;
609 }
610 // Grayscale/BW text
611 case kA8_GrMaskFormat:
612 // set back to normal in case we took LCD path previously.
613 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
614 // We're using per-vertex color.
615 SkASSERT(drawState->hasColorVertexAttribute());
616 break;
617 default:
jvanverth294c3262014-10-10 11:36:12 -0700618 SkFAIL("Unexpected mask format.");
jvanverth0fedb192014-10-08 09:07:27 -0700619 }
jvanverth73f10532014-10-23 11:57:12 -0700620 int nGlyphs = fCurrVertex / kVerticesPerGlyph;
jvanverth0fedb192014-10-08 09:07:27 -0700621 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
622 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
623 nGlyphs,
jvanverth73f10532014-10-23 11:57:12 -0700624 kVerticesPerGlyph, kIndicesPerGlyph, &fVertexBounds);
jvanverth0fedb192014-10-08 09:07:27 -0700625
626 fDrawTarget->resetVertexSource();
627 fVertices = NULL;
jvanverth73f10532014-10-23 11:57:12 -0700628 fAllocVertexCount = 0;
629 // reset to be those that are left
630 fTotalVertexCount -= fCurrVertex;
jvanverth0fedb192014-10-08 09:07:27 -0700631 fCurrVertex = 0;
632 fVertexBounds.setLargestInverted();
633 SkSafeSetNull(fCurrTexture);
634 }
635}
636
637inline void GrBitmapTextContext::finish() {
638 this->flush();
jvanverth73f10532014-10-23 11:57:12 -0700639 fTotalVertexCount = 0;
jvanverth0fedb192014-10-08 09:07:27 -0700640
641 GrTextContext::finish();
642}
643