Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /*
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 */
8 #include "GrDistanceFieldTextContext.h"
9 #include "GrAtlas.h"
10 #include "GrDrawTarget.h"
11 #include "GrDrawTargetCaps.h"
12 #include "GrFontScaler.h"
13 #include "SkGlyphCache.h"
14 #include "GrIndexBuffer.h"
15 #include "GrTextStrike.h"
16 #include "GrTextStrike_impl.h"
17 #include "SkDraw.h"
18 #include "SkGpuDevice.h"
19 #include "SkPath.h"
20 #include "SkRTConf.h"
21 #include "SkStrokeRec.h"
22 #include "effects/GrDistanceFieldTextureEffect.h"
24 static const int kGlyphCoordsAttributeIndex = 1;
26 static const int kBaseDFFontSize = 32;
28 SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
29 "Dump the contents of the font cache before every purge.");
31 #if SK_FORCE_DISTANCEFIELD_FONTS
32 static const bool kForceDistanceFieldFonts = true;
33 #else
34 static const bool kForceDistanceFieldFonts = false;
35 #endif
37 GrDistanceFieldTextContext::GrDistanceFieldTextContext(GrContext* context,
38 const SkDeviceProperties& properties)
39 : GrTextContext(context, properties) {
40 fStrike = NULL;
42 fCurrTexture = NULL;
43 fCurrVertex = 0;
45 fVertices = NULL;
46 fMaxVertices = 0;
47 }
49 GrDistanceFieldTextContext::~GrDistanceFieldTextContext() {
50 this->flushGlyphs();
51 }
53 bool GrDistanceFieldTextContext::canDraw(const SkPaint& paint) {
54 return (kForceDistanceFieldFonts || paint.isDistanceFieldTextTEMP()) &&
55 !paint.getRasterizer() && !paint.getMaskFilter() &&
56 paint.getStyle() == SkPaint::kFill_Style &&
57 fContext->getTextTarget()->caps()->shaderDerivativeSupport() &&
58 !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix());
59 }
61 static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) {
62 unsigned r = SkColorGetR(c);
63 unsigned g = SkColorGetG(c);
64 unsigned b = SkColorGetB(c);
65 return GrColorPackRGBA(r, g, b, 0xff);
66 }
68 void GrDistanceFieldTextContext::flushGlyphs() {
69 if (NULL == fDrawTarget) {
70 return;
71 }
73 GrDrawState* drawState = fDrawTarget->drawState();
74 GrDrawState::AutoRestoreEffects are(drawState);
75 drawState->setFromPaint(fPaint, fContext->getMatrix(), fContext->getRenderTarget());
77 if (fCurrVertex > 0) {
78 // setup our sampler state for our text texture/atlas
79 SkASSERT(GrIsALIGN4(fCurrVertex));
80 SkASSERT(fCurrTexture);
81 GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kBilerp_FilterMode);
83 // This effect could be stored with one of the cache objects (atlas?)
84 SkISize size = fStrike->getAtlasSize();
85 drawState->addCoverageEffect(
86 GrDistanceFieldTextureEffect::Create(fCurrTexture, params, size),
87 kGlyphCoordsAttributeIndex)->unref();
89 if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) {
90 if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() ||
91 kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() ||
92 fPaint.numColorStages()) {
93 GrPrintf("LCD Text will not draw correctly.\n");
94 }
95 // We don't use the GrPaint's color in this case because it's been premultiplied by
96 // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by
97 // the mask texture color. The end result is that we get
98 // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor
99 int a = SkColorGetA(fSkPaint.getColor());
100 // paintAlpha
101 drawState->setColor(SkColorSetARGB(a, a, a, a));
102 // paintColor
103 drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor()));
104 drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff);
105 } else {
106 // set back to normal in case we took LCD path previously.
107 drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff());
108 drawState->setColor(fPaint.getColor());
109 }
111 int nGlyphs = fCurrVertex / 4;
112 fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer());
113 fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType,
114 nGlyphs,
115 4, 6);
116 fDrawTarget->resetVertexSource();
117 fVertices = NULL;
118 fMaxVertices = 0;
119 fCurrVertex = 0;
120 SkSafeSetNull(fCurrTexture);
121 }
122 }
124 namespace {
126 // position + texture coord
127 extern const GrVertexAttrib gTextVertexAttribs[] = {
128 {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding},
129 {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding}
130 };
132 };
134 void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
135 GrFixed vx, GrFixed vy,
136 GrFontScaler* scaler) {
137 if (NULL == fDrawTarget) {
138 return;
139 }
140 if (NULL == fStrike) {
141 fStrike = fContext->getFontCache()->getStrike(scaler, true);
142 }
144 GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
145 if (NULL == glyph || glyph->fBounds.isEmpty()) {
146 return;
147 }
149 SkScalar sx = SkFixedToScalar(vx);
150 SkScalar sy = SkFixedToScalar(vy);
151 /*
152 // not valid, need to find a different solution for this
153 vx += SkIntToFixed(glyph->fBounds.fLeft);
154 vy += SkIntToFixed(glyph->fBounds.fTop);
156 // keep them as ints until we've done the clip-test
157 GrFixed width = glyph->fBounds.width();
158 GrFixed height = glyph->fBounds.height();
160 // check if we clipped out
161 if (true || NULL == glyph->fPlot) {
162 int x = vx >> 16;
163 int y = vy >> 16;
164 if (fClipRect.quickReject(x, y, x + width, y + height)) {
165 // SkCLZ(3); // so we can set a break-point in the debugger
166 return;
167 }
168 }
169 */
170 if (NULL == glyph->fPlot) {
171 if (fStrike->addGlyphToAtlas(glyph, scaler)) {
172 goto HAS_ATLAS;
173 }
175 // try to clear out an unused plot before we flush
176 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
177 fStrike->addGlyphToAtlas(glyph, scaler)) {
178 goto HAS_ATLAS;
179 }
181 if (c_DumpFontCache) {
182 #ifdef SK_DEVELOPER
183 fContext->getFontCache()->dump();
184 #endif
185 }
187 // before we purge the cache, we must flush any accumulated draws
188 this->flushGlyphs();
189 fContext->flush();
191 // we should have an unused plot now
192 if (fContext->getFontCache()->freeUnusedPlot(fStrike) &&
193 fStrike->addGlyphToAtlas(glyph, scaler)) {
194 goto HAS_ATLAS;
195 }
197 if (NULL == glyph->fPath) {
198 SkPath* path = SkNEW(SkPath);
199 if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
200 // flag the glyph as being dead?
201 delete path;
202 return;
203 }
204 glyph->fPath = path;
205 }
207 GrContext::AutoMatrix am;
208 SkMatrix translate;
209 translate.setTranslate(sx, sy);
210 GrPaint tmpPaint(fPaint);
211 am.setPreConcat(fContext, translate, &tmpPaint);
212 SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
213 fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
214 return;
215 }
217 HAS_ATLAS:
218 SkASSERT(glyph->fPlot);
219 GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
220 glyph->fPlot->setDrawToken(drawToken);
222 GrTexture* texture = glyph->fPlot->texture();
223 SkASSERT(texture);
225 if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
226 this->flushGlyphs();
227 fCurrTexture = texture;
228 fCurrTexture->ref();
229 }
231 if (NULL == fVertices) {
232 // If we need to reserve vertices allow the draw target to suggest
233 // a number of verts to reserve and whether to perform a flush.
234 fMaxVertices = kMinRequestedVerts;
235 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
236 SK_ARRAY_COUNT(gTextVertexAttribs));
237 bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
238 if (flush) {
239 this->flushGlyphs();
240 fContext->flush();
241 fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
242 SK_ARRAY_COUNT(gTextVertexAttribs));
243 }
244 fMaxVertices = kDefaultRequestedVerts;
245 // ignore return, no point in flushing again.
246 fDrawTarget->geometryHints(&fMaxVertices, NULL);
248 int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
249 if (fMaxVertices < kMinRequestedVerts) {
250 fMaxVertices = kDefaultRequestedVerts;
251 } else if (fMaxVertices > maxQuadVertices) {
252 // don't exceed the limit of the index buffer
253 fMaxVertices = maxQuadVertices;
254 }
255 bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
256 0,
257 GrTCast<void**>(&fVertices),
258 NULL);
259 GrAlwaysAssert(success);
260 SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
261 }
263 SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft);
264 SkScalar dy = SkIntToScalar(glyph->fBounds.fTop);
265 SkScalar width = SkIntToScalar(glyph->fBounds.width());
266 SkScalar height = SkIntToScalar(glyph->fBounds.height());
268 SkScalar scale = fTextRatio;
269 dx *= scale;
270 dy *= scale;
271 sx += dx;
272 sy += dy;
273 width *= scale;
274 height *= scale;
276 GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
277 GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
278 GrFixed tw = SkIntToFixed(glyph->fBounds.width());
279 GrFixed th = SkIntToFixed(glyph->fBounds.height());
281 static const size_t kVertexSize = 2 * sizeof(SkPoint);
282 fVertices[2*fCurrVertex].setRectFan(sx,
283 sy,
284 sx + width,
285 sy + height,
286 kVertexSize);
287 fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
288 SkFixedToFloat(texture->normalizeFixedY(ty)),
289 SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
290 SkFixedToFloat(texture->normalizeFixedY(ty + th)),
291 kVertexSize);
292 fCurrVertex += 4;
293 }
295 inline void GrDistanceFieldTextContext::init(const GrPaint& paint, const SkPaint& skPaint) {
296 GrTextContext::init(paint, skPaint);
298 fStrike = NULL;
300 fCurrTexture = NULL;
301 fCurrVertex = 0;
303 fVertices = NULL;
304 fMaxVertices = 0;
306 fTextRatio = fSkPaint.getTextSize()/kBaseDFFontSize;
308 fSkPaint.setTextSize(SkIntToScalar(kBaseDFFontSize));
309 fSkPaint.setLCDRenderText(false);
310 fSkPaint.setAutohinted(false);
311 fSkPaint.setSubpixelText(true);
312 }
314 inline void GrDistanceFieldTextContext::finish() {
315 flushGlyphs();
317 GrTextContext::finish();
318 }
320 void GrDistanceFieldTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint,
321 const char text[], size_t byteLength,
322 SkScalar x, SkScalar y) {
323 SkASSERT(byteLength == 0 || text != NULL);
325 // nothing to draw or can't draw
326 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/
327 || fSkPaint.getRasterizer()) {
328 return;
329 }
331 this->init(paint, skPaint);
333 SkScalar sizeRatio = fTextRatio;
335 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
337 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
338 SkGlyphCache* cache = autoCache.getCache();
339 GrFontScaler* fontScaler = GetGrFontScaler(cache);
341 // need to measure first
342 // TODO - generate positions and pre-load cache as well?
343 const char* stop = text + byteLength;
344 if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
345 SkFixed stopX = 0;
346 SkFixed stopY = 0;
348 const char* textPtr = text;
349 while (textPtr < stop) {
350 // don't need x, y here, since all subpixel variants will have the
351 // same advance
352 const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);
354 stopX += glyph.fAdvanceX;
355 stopY += glyph.fAdvanceY;
356 }
357 SkASSERT(textPtr == stop);
359 SkScalar alignX = SkFixedToScalar(stopX)*sizeRatio;
360 SkScalar alignY = SkFixedToScalar(stopY)*sizeRatio;
362 if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
363 alignX = SkScalarHalf(alignX);
364 alignY = SkScalarHalf(alignY);
365 }
367 x -= alignX;
368 y -= alignY;
369 }
371 SkFixed fx = SkScalarToFixed(x) + SK_FixedHalf;
372 SkFixed fy = SkScalarToFixed(y) + SK_FixedHalf;
373 SkFixed fixedScale = SkScalarToFixed(sizeRatio);
374 while (text < stop) {
375 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
377 if (glyph.fWidth) {
378 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
379 glyph.getSubXFixed(),
380 glyph.getSubYFixed()),
381 SkFixedFloorToFixed(fx),
382 SkFixedFloorToFixed(fy),
383 fontScaler);
384 }
386 fx += SkFixedMul_portable(glyph.fAdvanceX, fixedScale);
387 fy += SkFixedMul_portable(glyph.fAdvanceY, fixedScale);
388 }
390 this->finish();
391 }
393 void GrDistanceFieldTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint,
394 const char text[], size_t byteLength,
395 const SkScalar pos[], SkScalar constY,
396 int scalarsPerPosition) {
398 SkASSERT(byteLength == 0 || text != NULL);
399 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
401 // nothing to draw
402 if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
403 return;
404 }
406 this->init(paint, skPaint);
408 SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
410 SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, NULL);
411 SkGlyphCache* cache = autoCache.getCache();
412 GrFontScaler* fontScaler = GetGrFontScaler(cache);
414 const char* stop = text + byteLength;
416 if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
417 while (text < stop) {
418 // the last 2 parameters are ignored
419 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
421 if (glyph.fWidth) {
422 SkScalar x = pos[0];
423 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
425 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
426 glyph.getSubXFixed(),
427 glyph.getSubYFixed()),
428 SkScalarToFixed(x) + SK_FixedHalf, //d1g.fHalfSampleX,
429 SkScalarToFixed(y) + SK_FixedHalf, //d1g.fHalfSampleY,
430 fontScaler);
431 }
432 pos += scalarsPerPosition;
433 }
434 } else {
435 int alignShift = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? 1 : 0;
436 while (text < stop) {
437 // the last 2 parameters are ignored
438 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
440 if (glyph.fWidth) {
441 SkScalar x = pos[0];
442 SkScalar y = scalarsPerPosition == 1 ? constY : pos[1];
444 this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
445 glyph.getSubXFixed(),
446 glyph.getSubYFixed()),
447 SkScalarToFixed(x) - (glyph.fAdvanceX >> alignShift)
448 + SK_FixedHalf, //d1g.fHalfSampleX,
449 SkScalarToFixed(y) - (glyph.fAdvanceY >> alignShift)
450 + SK_FixedHalf, //d1g.fHalfSampleY,
451 fontScaler);
452 }
453 pos += scalarsPerPosition;
454 }
455 }
457 this->finish();
458 }