blob: 0ef596a27ba0ef8ebea604127018d056c3bc7313 [file] [log] [blame]
jvanverth@google.comd830d132013-11-11 20:54:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrDistanceFieldTextContext.h"
9#include "GrAtlas.h"
jvanverth2d2a68c2014-06-10 06:42:56 -070010#include "SkColorFilter.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000011#include "GrDrawTarget.h"
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000012#include "GrDrawTargetCaps.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000013#include "GrFontScaler.h"
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000014#include "SkGlyphCache.h"
jvanverth2d2a68c2014-06-10 06:42:56 -070015#include "GrGpu.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000016#include "GrIndexBuffer.h"
egdanield58a0ba2014-06-11 10:30:05 -070017#include "GrStrokeInfo.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000018#include "GrTextStrike.h"
19#include "GrTextStrike_impl.h"
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +000020#include "SkDistanceFieldGen.h"
commit-bot@chromium.org9f94b912014-01-30 15:22:54 +000021#include "SkDraw.h"
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +000022#include "SkGpuDevice.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000023#include "SkPath.h"
24#include "SkRTConf.h"
25#include "SkStrokeRec.h"
26#include "effects/GrDistanceFieldTextureEffect.h"
27
jvanverthfeceba52014-07-25 19:03:34 -070028SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29 "Dump the contents of the font cache before every purge.");
30
31static const int kGlyphCoordsNoColorAttributeIndex = 1;
32static const int kGlyphCoordsWithColorAttributeIndex = 2;
jvanverth@google.comd830d132013-11-11 20:54:09 +000033
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +000034static const int kSmallDFFontSize = 32;
35static const int kSmallDFFontLimit = 32;
36static const int kMediumDFFontSize = 64;
37static const int kMediumDFFontLimit = 64;
38static const int kLargeDFFontSize = 128;
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +000039
jvanverthfeceba52014-07-25 19:03:34 -070040namespace {
41// position + texture coord
42extern const GrVertexAttrib gTextVertexAttribs[] = {
43 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
44 {kVec2f_GrVertexAttribType, sizeof(SkPoint) , kEffect_GrVertexAttribBinding}
45};
46
47// position + color + texture coord
48extern const GrVertexAttrib gTextVertexWithColorAttribs[] = {
49 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
50 {kVec4ub_GrVertexAttribType, sizeof(SkPoint), kColor_GrVertexAttribBinding},
51 {kVec2f_GrVertexAttribType, sizeof(SkPoint) + sizeof(GrColor), kEffect_GrVertexAttribBinding}
52};
53
54};
jvanverth@google.comd830d132013-11-11 20:54:09 +000055
skia.committer@gmail.come5d70152014-01-29 07:01:48 +000056GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000057 const SkDeviceProperties& properties,
58 bool enable)
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000059 : GrTextContext(context, properties) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000060#if SK_FORCE_DISTANCEFIELD_FONTS
61 fEnableDFRendering = true;
62#else
63 fEnableDFRendering = enable;
64#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +000065 fStrike = NULL;
jvanverth2d2a68c2014-06-10 06:42:56 -070066 fGammaTexture = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000067
jvanverth@google.comd830d132013-11-11 20:54:09 +000068 fCurrVertex = 0;
69
70 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +000071}
72
73GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
74 this->flushGlyphs();
jvanverth2d2a68c2014-06-10 06:42:56 -070075 SkSafeSetNull(fGammaTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +000076}
77
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +000078bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
commit-bot@chromium.org6fcd1ef2014-05-02 12:39:41 +000079 if (!fEnableDFRendering && !paint.isDistanceFieldTextTEMP()) {
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000080 return false;
81 }
82
skia.committer@gmail.come1d94432014-04-09 03:04:11 +000083 // rasterizers and mask filters modify alpha, which doesn't
commit-bot@chromium.orgeefd8a02014-04-08 20:14:32 +000084 // translate well to distance
85 if (paint.getRasterizer() || paint.getMaskFilter() ||
86 !fContext->getTextTarget()->caps()->shaderDerivativeSupport()) {
87 return false;
88 }
89
90 // TODO: add some stroking support
91 if (paint.getStyle() != SkPaint::kFill_Style) {
92 return false;
93 }
94
95 // TODO: choose an appropriate maximum scale for distance fields and
96 // enable perspective
97 if (SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix())) {
98 return false;
99 }
100
101 // distance fields cannot represent color fonts
102 SkScalerContext::Rec rec;
103 SkScalerContext::MakeRec(paint, &fDeviceProperties, NULL, &rec);
104 return rec.getFormat() != SkMask::kARGB32_Format;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000105}
106
jvanverth@google.comd830d132013-11-11 20:54:09 +0000107static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
108 unsigned r = SkColorGetR(c);
109 unsigned g = SkColorGetG(c);
110 unsigned b = SkColorGetB(c);
111 return GrColorPackRGBA(r, g, b, 0xff);
112}
113
114void GrDistanceFieldTextContext::flushGlyphs() {
115 if (NULL == fDrawTarget) {
116 return;
117 }
118
119 GrDrawState* drawState = fDrawTarget->drawState();
120 GrDrawState::AutoRestoreEffects are(drawState);
121 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
122
123 if (fCurrVertex > 0) {
124 // setup our sampler state for our text texture/atlas
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000125 SkASSERT(SkIsAlign4(fCurrVertex));
jvanverthf17bc6c2014-07-25 16:46:53 -0700126 GrTexture* currTexture = fStrike->getTexture();
127 SkASSERT(currTexture);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000128 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700129 GrTextureParams gammaParams(SkShader::kClamp_TileMode, GrTextureParams::kNone_FilterMode);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000130
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000131 // Effects could be stored with one of the cache objects (atlas?)
jvanverthfeceba52014-07-25 19:03:34 -0700132 int coordsIdx = drawState->hasColorVertexAttribute() ? kGlyphCoordsWithColorAttributeIndex :
133 kGlyphCoordsNoColorAttributeIndex;
jvanverth2d2a68c2014-06-10 06:42:56 -0700134 SkColor filteredColor;
135 SkColorFilter* colorFilter = fSkPaint.getColorFilter();
136 if (NULL != colorFilter) {
137 filteredColor = colorFilter->filterColor(fSkPaint.getColor());
138 } else {
139 filteredColor = fSkPaint.getColor();
140 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000141 if (fUseLCDText) {
jvanverth2d2a68c2014-06-10 06:42:56 -0700142 GrColor colorNoPreMul = skcolor_to_grcolor_nopremultiply(filteredColor);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000143 bool useBGR = SkDeviceProperties::Geometry::kBGR_Layout ==
144 fDeviceProperties.fGeometry.getLayout();
145 drawState->addCoverageEffect(GrDistanceFieldLCDTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700146 currTexture,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000147 params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700148 fGammaTexture,
149 gammaParams,
150 colorNoPreMul,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000151 fContext->getMatrix().rectStaysRect() &&
152 fContext->getMatrix().isSimilarity(),
153 useBGR),
jvanverthfeceba52014-07-25 19:03:34 -0700154 coordsIdx)->unref();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000155
jvanverth@google.comd830d132013-11-11 20:54:09 +0000156 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
157 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
158 fPaint.numColorStages()) {
159 GrPrintf("LCD Text will not draw correctly.\n");
160 }
jvanverthfeceba52014-07-25 19:03:34 -0700161 SkASSERT(!drawState->hasColorVertexAttribute());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000162 // We don't use the GrPaint's color in this case because it's been premultiplied by
163 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
164 // the mask texture color. The end result is that we get
165 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000166 int a = SkColorGetA(fSkPaint.getColor());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000167 // paintAlpha
168 drawState->setColor(SkColorSetARGB(a, a, a, a));
169 // paintColor
jvanverth2d2a68c2014-06-10 06:42:56 -0700170 drawState->setBlendConstant(colorNoPreMul);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000171 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
172 } else {
jvanverth2d2a68c2014-06-10 06:42:56 -0700173#ifdef SK_GAMMA_APPLY_TO_A8
174 U8CPU lum = SkColorSpaceLuminance::computeLuminance(fDeviceProperties.fGamma,
175 filteredColor);
176 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700177 currTexture, params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700178 fGammaTexture, gammaParams,
179 lum/255.f,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000180 fContext->getMatrix().isSimilarity()),
jvanverthfeceba52014-07-25 19:03:34 -0700181 coordsIdx)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700182#else
183 drawState->addCoverageEffect(GrDistanceFieldTextureEffect::Create(
jvanverthf17bc6c2014-07-25 16:46:53 -0700184 currTexture, params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700185 fContext->getMatrix().isSimilarity()),
jvanverthfeceba52014-07-25 19:03:34 -0700186 coordsIdx)->unref();
jvanverth2d2a68c2014-06-10 06:42:56 -0700187#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000188 // set back to normal in case we took LCD path previously.
189 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
jvanverthfeceba52014-07-25 19:03:34 -0700190 //drawState->setColor(fPaint.getColor());
191 // We're using per-vertex color.
192 SkASSERT(drawState->hasColorVertexAttribute());
193 drawState->setColor(0xFFFFFFFF);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000194 }
jvanverth@google.comd830d132013-11-11 20:54:09 +0000195 int nGlyphs = fCurrVertex / 4;
196 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
197 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
198 nGlyphs,
199 4, 6);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000200 fCurrVertex = 0;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000201 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700202 fDrawTarget->resetVertexSource();
203 fVertices = NULL;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000204}
205
jvanverth@google.comd830d132013-11-11 20:54:09 +0000206void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
commit-bot@chromium.org972f9cd2014-03-28 17:58:28 +0000207 SkFixed vx, SkFixed vy,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000208 GrFontScaler* scaler) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000209 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
210 if (NULL == glyph || glyph->fBounds.isEmpty()) {
211 return;
212 }
213
214 SkScalar sx = SkFixedToScalar(vx);
215 SkScalar sy = SkFixedToScalar(vy);
216/*
217 // not valid, need to find a different solution for this
218 vx += SkIntToFixed(glyph->fBounds.fLeft);
219 vy += SkIntToFixed(glyph->fBounds.fTop);
skia.committer@gmail.com11a253b2013-11-12 07:02:05 +0000220
jvanverth@google.comd830d132013-11-11 20:54:09 +0000221 // keep them as ints until we've done the clip-test
222 GrFixed width = glyph->fBounds.width();
223 GrFixed height = glyph->fBounds.height();
224
225 // check if we clipped out
226 if (true || NULL == glyph->fPlot) {
227 int x = vx >> 16;
228 int y = vy >> 16;
229 if (fClipRect.quickReject(x, y, x + width, y + height)) {
230// SkCLZ(3); // so we can set a break-point in the debugger
231 return;
232 }
233 }
234*/
235 if (NULL == glyph->fPlot) {
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000236 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 goto HAS_ATLAS;
238 }
239
240 // try to clear out an unused plot before we flush
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000241 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
242 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000243 goto HAS_ATLAS;
244 }
245
246 if (c_DumpFontCache) {
247#ifdef SK_DEVELOPER
248 fContext->getFontCache()->dump();
249#endif
250 }
251
252 // before we purge the cache, we must flush any accumulated draws
253 this->flushGlyphs();
254 fContext->flush();
255
commit-bot@chromium.orgc9b2c882014-03-03 14:30:25 +0000256 // we should have an unused plot now
257 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
258 fStrike->addGlyphToAtlas(glyph, scaler)) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000259 goto HAS_ATLAS;
260 }
261
262 if (NULL == glyph->fPath) {
263 SkPath* path = SkNEW(SkPath);
264 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
265 // flag the glyph as being dead?
266 delete path;
267 return;
268 }
269 glyph->fPath = path;
270 }
271
272 GrContext::AutoMatrix am;
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000273 SkMatrix ctm;
274 ctm.setScale(fTextRatio, fTextRatio);
275 ctm.postTranslate(sx, sy);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000276 GrPaint tmpPaint(fPaint);
commit-bot@chromium.org762cd802014-04-14 22:05:07 +0000277 am.setPreConcat(fContext, ctm, &tmpPaint);
egdanield58a0ba2014-06-11 10:30:05 -0700278 GrStrokeInfo strokeInfo(SkStrokeRec::kFill_InitStyle);
279 fContext->drawPath(tmpPaint, *glyph->fPath, strokeInfo);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000280 return;
281 }
282
283HAS_ATLAS:
284 SkASSERT(glyph->fPlot);
285 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
286 glyph->fPlot->setDrawToken(drawToken);
287
288 GrTexture* texture = glyph->fPlot->texture();
289 SkASSERT(texture);
290
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000291 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft + SK_DistanceFieldInset);
292 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop + SK_DistanceFieldInset);
293 SkScalar width = SkIntToScalar(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
294 SkScalar height = SkIntToScalar(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000295
296 SkScalar scale = fTextRatio;
297 dx *= scale;
298 dy *= scale;
299 sx += dx;
300 sy += dy;
301 width *= scale;
302 height *= scale;
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +0000303
commit-bot@chromium.org64b08a12014-04-15 17:53:21 +0000304 SkFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX + SK_DistanceFieldInset);
305 SkFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY + SK_DistanceFieldInset);
306 SkFixed tw = SkIntToFixed(glyph->fBounds.width() - 2*SK_DistanceFieldInset);
307 SkFixed th = SkIntToFixed(glyph->fBounds.height() - 2*SK_DistanceFieldInset);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000308
jvanverthfeceba52014-07-25 19:03:34 -0700309 size_t vertSize = fUseLCDText ? (2 * sizeof(SkPoint))
310 : (2 * sizeof(SkPoint) + sizeof(GrColor));
311
312 SkASSERT(vertSize == fDrawTarget->getDrawState().getVertexSize());
313
jvanverthf17bc6c2014-07-25 16:46:53 -0700314 SkPoint* positions = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700315 reinterpret_cast<intptr_t>(fVertices) + vertSize * fCurrVertex);
316 positions->setRectFan(sx, sy, sx + width, sy + height, vertSize);
317
318 // The texture coords are last in both the with and without color vertex layouts.
jvanverthf17bc6c2014-07-25 16:46:53 -0700319 SkPoint* textureCoords = reinterpret_cast<SkPoint*>(
jvanverthfeceba52014-07-25 19:03:34 -0700320 reinterpret_cast<intptr_t>(positions) + vertSize - sizeof(SkPoint));
jvanverthf17bc6c2014-07-25 16:46:53 -0700321 textureCoords->setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
jvanverthfeceba52014-07-25 19:03:34 -0700322 SkFixedToFloat(texture->normalizeFixedY(ty)),
323 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
324 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
325 vertSize);
326 if (!fUseLCDText) {
327 // color comes after position.
328 GrColor* colors = reinterpret_cast<GrColor*>(positions + 1);
329 for (int i = 0; i < 4; ++i) {
330 *colors = fPaint.getColor();
331 colors = reinterpret_cast<GrColor*>(reinterpret_cast<intptr_t>(colors) + vertSize);
332 }
333 }
334
jvanverth@google.comd830d132013-11-11 20:54:09 +0000335 fCurrVertex += 4;
336}
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000337
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000338inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
339 GrTextContext::init(paint, skPaint);
340
341 fStrike = NULL;
342
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000343 fCurrVertex = 0;
344
345 fVertices = NULL;
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000346
commit-bot@chromium.orgdc5cd852014-04-02 19:24:32 +0000347 if (fSkPaint.getTextSize() <= kSmallDFFontLimit) {
348 fTextRatio = fSkPaint.getTextSize()/kSmallDFFontSize;
349 fSkPaint.setTextSize(SkIntToScalar(kSmallDFFontSize));
350 } else if (fSkPaint.getTextSize() <= kMediumDFFontLimit) {
351 fTextRatio = fSkPaint.getTextSize()/kMediumDFFontSize;
352 fSkPaint.setTextSize(SkIntToScalar(kMediumDFFontSize));
353 } else {
354 fTextRatio = fSkPaint.getTextSize()/kLargeDFFontSize;
355 fSkPaint.setTextSize(SkIntToScalar(kLargeDFFontSize));
356 }
skia.committer@gmail.com4c18e9f2014-01-31 03:01:59 +0000357
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000358 fUseLCDText = fSkPaint.isLCDRenderText();
skia.committer@gmail.com221b9112014-04-04 03:04:32 +0000359
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000360 fSkPaint.setLCDRenderText(false);
361 fSkPaint.setAutohinted(false);
jvanverth2d2a68c2014-06-10 06:42:56 -0700362 fSkPaint.setHinting(SkPaint::kNormal_Hinting);
commit-bot@chromium.org0bed43c2014-03-14 21:22:38 +0000363 fSkPaint.setSubpixelText(true);
jvanverth2d2a68c2014-06-10 06:42:56 -0700364
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000365}
366
367inline void GrDistanceFieldTextContext::finish() {
jvanverthfeceba52014-07-25 19:03:34 -0700368 this->flushGlyphs();
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000369
370 GrTextContext::finish();
371}
372
jvanverth2d2a68c2014-06-10 06:42:56 -0700373static void setup_gamma_texture(GrContext* context, const SkGlyphCache* cache,
374 const SkDeviceProperties& deviceProperties,
375 GrTexture** gammaTexture) {
376 if (NULL == *gammaTexture) {
377 int width, height;
378 size_t size;
379
380#ifdef SK_GAMMA_CONTRAST
381 SkScalar contrast = SK_GAMMA_CONTRAST;
382#else
383 SkScalar contrast = 0.5f;
384#endif
385 SkScalar paintGamma = deviceProperties.fGamma;
386 SkScalar deviceGamma = deviceProperties.fGamma;
387
388 size = SkScalerContext::GetGammaLUTSize(contrast, paintGamma, deviceGamma,
389 &width, &height);
390
391 SkAutoTArray<uint8_t> data((int)size);
392 SkScalerContext::GetGammaLUTData(contrast, paintGamma, deviceGamma, data.get());
393
394 // TODO: Update this to use the cache rather than directly creating a texture.
395 GrTextureDesc desc;
396 desc.fFlags = kDynamicUpdate_GrTextureFlagBit;
397 desc.fWidth = width;
398 desc.fHeight = height;
399 desc.fConfig = kAlpha_8_GrPixelConfig;
400
401 *gammaTexture = context->getGpu()->createTexture(desc, NULL, 0);
402 if (NULL == *gammaTexture) {
403 return;
404 }
405
406 context->writeTexturePixels(*gammaTexture,
407 0, 0, width, height,
408 (*gammaTexture)->config(), data.get(), 0,
409 GrContext::kDontFlush_PixelOpsFlag);
410 }
411}
412
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000413void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
414 const char text[], size_t byteLength,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000415 SkScalar x, SkScalar y) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000416 SkASSERT(byteLength == 0 || text != NULL);
417
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000418 // nothing to draw or can't draw
419 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
420 || fSkPaint.getRasterizer()) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000421 return;
422 }
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000423
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000424 this->init(paint, skPaint);
425
jvanverthf17bc6c2014-07-25 16:46:53 -0700426 if (NULL == fDrawTarget) {
427 return;
428 }
429
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000430 SkScalar sizeRatio = fTextRatio;
431
432 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
433
jvanverth2d2a68c2014-06-10 06:42:56 -0700434 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
435 SkGlyphCache* cache = autoCache.getCache();
436 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700437 if (NULL == fStrike) {
438 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
439 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700440
441 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000442
jvanverthf17bc6c2014-07-25 16:46:53 -0700443 // allocate vertices
444 SkASSERT(NULL == fVertices);
jvanverthfeceba52014-07-25 19:03:34 -0700445 if (!fUseLCDText) {
446 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
447 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
448 } else {
449 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
450 SK_ARRAY_COUNT(gTextVertexAttribs));
451 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700452 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
453 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
454 0,
455 &fVertices,
456 NULL);
457 GrAlwaysAssert(success);
458
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000459 // need to measure first
460 // TODO - generate positions and pre-load cache as well?
461 const char* stop = text + byteLength;
462 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
463 SkFixed stopX = 0;
464 SkFixed stopY = 0;
465
466 const char* textPtr = text;
467 while (textPtr < stop) {
468 // don't need x, y here, since all subpixel variants will have the
469 // same advance
470 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
471
472 stopX += glyph.fAdvanceX;
473 stopY += glyph.fAdvanceY;
474 }
475 SkASSERT(textPtr == stop);
476
477 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
478 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
479
480 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
481 alignX = SkScalarHalf(alignX);
482 alignY = SkScalarHalf(alignY);
483 }
484
485 x -= alignX;
486 y -= alignY;
487 }
488
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000489 SkFixed fx = SkScalarToFixed(x);
490 SkFixed fy = SkScalarToFixed(y);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000491 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
492 while (text < stop) {
commit-bot@chromium.orga9dae712014-03-24 18:34:04 +0000493 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000494
495 if (glyph.fWidth) {
496 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
497 glyph.getSubXFixed(),
498 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000499 fx,
500 fy,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000501 fontScaler);
502 }
503
504 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
505 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
506 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000507
508 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000509}
510
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000511void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
512 const char text[], size_t byteLength,
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000513 const SkScalar pos[], SkScalar constY,
commit-bot@chromium.orge8612d92014-01-28 22:02:07 +0000514 int scalarsPerPosition) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000515
516 SkASSERT(byteLength == 0 || text != NULL);
517 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
518
519 // nothing to draw
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000520 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000521 return;
522 }
523
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000524 this->init(paint, skPaint);
525
jvanverthf17bc6c2014-07-25 16:46:53 -0700526 if (NULL == fDrawTarget) {
527 return;
528 }
529
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000530 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
531
jvanverth2d2a68c2014-06-10 06:42:56 -0700532 SkAutoGlyphCacheNoGamma autoCache(fSkPaint, &fDeviceProperties, NULL);
533 SkGlyphCache* cache = autoCache.getCache();
534 GrFontScaler* fontScaler = GetGrFontScaler(cache);
jvanverthf17bc6c2014-07-25 16:46:53 -0700535 if (NULL == fStrike) {
536 fStrike = fContext->getFontCache()->getStrike(fontScaler, true);
537 }
538
539 // allocate vertices
540 SkASSERT(NULL == fVertices);
jvanverthfeceba52014-07-25 19:03:34 -0700541 if (!fUseLCDText) {
542 fDrawTarget->drawState()->setVertexAttribs<gTextVertexWithColorAttribs>(
543 SK_ARRAY_COUNT(gTextVertexWithColorAttribs));
544 } else {
545 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
546 SK_ARRAY_COUNT(gTextVertexAttribs));
547 }
jvanverthf17bc6c2014-07-25 16:46:53 -0700548 int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
549 bool success = fDrawTarget->reserveVertexAndIndexSpace(4*numGlyphs,
550 0,
551 &fVertices,
552 NULL);
553 GrAlwaysAssert(success);
jvanverth2d2a68c2014-06-10 06:42:56 -0700554
555 setup_gamma_texture(fContext, cache, fDeviceProperties, &fGammaTexture);
skia.committer@gmail.come5d70152014-01-29 07:01:48 +0000556
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000557 const char* stop = text + byteLength;
558
559 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
560 while (text < stop) {
561 // the last 2 parameters are ignored
562 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
563
564 if (glyph.fWidth) {
565 SkScalar x = pos[0];
566 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
567
568 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
569 glyph.getSubXFixed(),
570 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000571 SkScalarToFixed(x),
572 SkScalarToFixed(y),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000573 fontScaler);
574 }
575 pos += scalarsPerPosition;
576 }
577 } else {
578 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
579 while (text < stop) {
580 // the last 2 parameters are ignored
581 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
582
583 if (glyph.fWidth) {
584 SkScalar x = pos[0];
585 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
skia.committer@gmail.com22e96722013-12-20 07:01:36 +0000586
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000587 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
588 glyph.getSubXFixed(),
589 glyph.getSubYFixed()),
commit-bot@chromium.org5408f8f2014-05-21 19:44:24 +0000590 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift),
591 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift),
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000592 fontScaler);
593 }
594 pos += scalarsPerPosition;
595 }
596 }
commit-bot@chromium.orgcbbc4812014-01-30 22:05:47 +0000597
598 this->finish();
commit-bot@chromium.org8128d8c2013-12-19 16:12:25 +0000599}