gfx/skia/trunk/src/gpu/GrBitmapTextContext.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rwxr-xr-x

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.

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

mercurial