1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/gpu/GrBitmapTextContext.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,633 @@ 1.4 +/* 1.5 + * Copyright 2013 Google Inc. 1.6 + * 1.7 + * Use of this source code is governed by a BSD-style license that can be 1.8 + * found in the LICENSE file. 1.9 + */ 1.10 + 1.11 +#include "GrBitmapTextContext.h" 1.12 +#include "GrAtlas.h" 1.13 +#include "GrDrawTarget.h" 1.14 +#include "GrFontScaler.h" 1.15 +#include "GrIndexBuffer.h" 1.16 +#include "GrTextStrike.h" 1.17 +#include "GrTextStrike_impl.h" 1.18 +#include "SkColorPriv.h" 1.19 +#include "SkPath.h" 1.20 +#include "SkRTConf.h" 1.21 +#include "SkStrokeRec.h" 1.22 +#include "effects/GrCustomCoordsTextureEffect.h" 1.23 + 1.24 +#include "SkAutoKern.h" 1.25 +#include "SkDraw.h" 1.26 +#include "SkGlyphCache.h" 1.27 +#include "SkGpuDevice.h" 1.28 +#include "SkGr.h" 1.29 + 1.30 +static const int kGlyphCoordsAttributeIndex = 1; 1.31 + 1.32 +SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false, 1.33 + "Dump the contents of the font cache before every purge."); 1.34 + 1.35 +GrBitmapTextContext::GrBitmapTextContext(GrContext* context, 1.36 + const SkDeviceProperties& properties) 1.37 + : GrTextContext(context, properties) { 1.38 + fStrike = NULL; 1.39 + 1.40 + fCurrTexture = NULL; 1.41 + fCurrVertex = 0; 1.42 + 1.43 + fVertices = NULL; 1.44 + fMaxVertices = 0; 1.45 + 1.46 + fVertexBounds.setLargestInverted(); 1.47 +} 1.48 + 1.49 +GrBitmapTextContext::~GrBitmapTextContext() { 1.50 + this->flushGlyphs(); 1.51 +} 1.52 + 1.53 +bool GrBitmapTextContext::canDraw(const SkPaint& paint) { 1.54 + return !SkDraw::ShouldDrawTextAsPaths(paint, fContext->getMatrix()); 1.55 +} 1.56 + 1.57 +static inline GrColor skcolor_to_grcolor_nopremultiply(SkColor c) { 1.58 + unsigned r = SkColorGetR(c); 1.59 + unsigned g = SkColorGetG(c); 1.60 + unsigned b = SkColorGetB(c); 1.61 + return GrColorPackRGBA(r, g, b, 0xff); 1.62 +} 1.63 + 1.64 +void GrBitmapTextContext::flushGlyphs() { 1.65 + if (NULL == fDrawTarget) { 1.66 + return; 1.67 + } 1.68 + 1.69 + GrDrawState* drawState = fDrawTarget->drawState(); 1.70 + GrDrawState::AutoRestoreEffects are(drawState); 1.71 + drawState->setFromPaint(fPaint, SkMatrix::I(), fContext->getRenderTarget()); 1.72 + 1.73 + if (fCurrVertex > 0) { 1.74 + // setup our sampler state for our text texture/atlas 1.75 + SkASSERT(GrIsALIGN4(fCurrVertex)); 1.76 + SkASSERT(fCurrTexture); 1.77 + GrTextureParams params(SkShader::kRepeat_TileMode, GrTextureParams::kNone_FilterMode); 1.78 + 1.79 + // This effect could be stored with one of the cache objects (atlas?) 1.80 + drawState->addCoverageEffect( 1.81 + GrCustomCoordsTextureEffect::Create(fCurrTexture, params), 1.82 + kGlyphCoordsAttributeIndex)->unref(); 1.83 + 1.84 + if (NULL != fStrike && kARGB_GrMaskFormat == fStrike->getMaskFormat()) { 1.85 + drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); 1.86 + drawState->setColor(0xffffffff); 1.87 + } else if (!GrPixelConfigIsAlphaOnly(fCurrTexture->config())) { 1.88 + if (kOne_GrBlendCoeff != fPaint.getSrcBlendCoeff() || 1.89 + kISA_GrBlendCoeff != fPaint.getDstBlendCoeff() || 1.90 + fPaint.numColorStages()) { 1.91 + GrPrintf("LCD Text will not draw correctly.\n"); 1.92 + } 1.93 + // We don't use the GrPaint's color in this case because it's been premultiplied by 1.94 + // alpha. Instead we feed in a non-premultiplied color, and multiply its alpha by 1.95 + // the mask texture color. The end result is that we get 1.96 + // mask*paintAlpha*paintColor + (1-mask*paintAlpha)*dstColor 1.97 + int a = SkColorGetA(fSkPaint.getColor()); 1.98 + // paintAlpha 1.99 + drawState->setColor(SkColorSetARGB(a, a, a, a)); 1.100 + // paintColor 1.101 + drawState->setBlendConstant(skcolor_to_grcolor_nopremultiply(fSkPaint.getColor())); 1.102 + drawState->setBlendFunc(kConstC_GrBlendCoeff, kISC_GrBlendCoeff); 1.103 + } else { 1.104 + // set back to normal in case we took LCD path previously. 1.105 + drawState->setBlendFunc(fPaint.getSrcBlendCoeff(), fPaint.getDstBlendCoeff()); 1.106 + drawState->setColor(fPaint.getColor()); 1.107 + } 1.108 + 1.109 + int nGlyphs = fCurrVertex / 4; 1.110 + fDrawTarget->setIndexSourceToBuffer(fContext->getQuadIndexBuffer()); 1.111 + fDrawTarget->drawIndexedInstances(kTriangles_GrPrimitiveType, 1.112 + nGlyphs, 1.113 + 4, 6, &fVertexBounds); 1.114 + 1.115 + fDrawTarget->resetVertexSource(); 1.116 + fVertices = NULL; 1.117 + fMaxVertices = 0; 1.118 + fCurrVertex = 0; 1.119 + fVertexBounds.setLargestInverted(); 1.120 + SkSafeSetNull(fCurrTexture); 1.121 + } 1.122 +} 1.123 + 1.124 +inline void GrBitmapTextContext::init(const GrPaint& paint, const SkPaint& skPaint) { 1.125 + GrTextContext::init(paint, skPaint); 1.126 + 1.127 + fStrike = NULL; 1.128 + 1.129 + fCurrTexture = NULL; 1.130 + fCurrVertex = 0; 1.131 + 1.132 + fVertices = NULL; 1.133 + fMaxVertices = 0; 1.134 +} 1.135 + 1.136 +inline void GrBitmapTextContext::finish() { 1.137 + flushGlyphs(); 1.138 + 1.139 + GrTextContext::finish(); 1.140 +} 1.141 + 1.142 +void GrBitmapTextContext::drawText(const GrPaint& paint, const SkPaint& skPaint, 1.143 + const char text[], size_t byteLength, 1.144 + SkScalar x, SkScalar y) { 1.145 + SkASSERT(byteLength == 0 || text != NULL); 1.146 + 1.147 + // nothing to draw 1.148 + if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) { 1.149 + return; 1.150 + } 1.151 + 1.152 + this->init(paint, skPaint); 1.153 + 1.154 + SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); 1.155 + 1.156 + SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix()); 1.157 + SkGlyphCache* cache = autoCache.getCache(); 1.158 + GrFontScaler* fontScaler = GetGrFontScaler(cache); 1.159 + 1.160 + // transform our starting point 1.161 + { 1.162 + SkPoint loc; 1.163 + fContext->getMatrix().mapXY(x, y, &loc); 1.164 + x = loc.fX; 1.165 + y = loc.fY; 1.166 + } 1.167 + 1.168 + // need to measure first 1.169 + if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) { 1.170 + SkVector stop; 1.171 + 1.172 + MeasureText(cache, glyphCacheProc, text, byteLength, &stop); 1.173 + 1.174 + SkScalar stopX = stop.fX; 1.175 + SkScalar stopY = stop.fY; 1.176 + 1.177 + if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) { 1.178 + stopX = SkScalarHalf(stopX); 1.179 + stopY = SkScalarHalf(stopY); 1.180 + } 1.181 + x -= stopX; 1.182 + y -= stopY; 1.183 + } 1.184 + 1.185 + const char* stop = text + byteLength; 1.186 + 1.187 + SkAutoKern autokern; 1.188 + 1.189 + SkFixed fxMask = ~0; 1.190 + SkFixed fyMask = ~0; 1.191 + SkFixed halfSampleX, halfSampleY; 1.192 + if (cache->isSubpixel()) { 1.193 + halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits); 1.194 + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix()); 1.195 + if (kX_SkAxisAlignment == baseline) { 1.196 + fyMask = 0; 1.197 + halfSampleY = SK_FixedHalf; 1.198 + } else if (kY_SkAxisAlignment == baseline) { 1.199 + fxMask = 0; 1.200 + halfSampleX = SK_FixedHalf; 1.201 + } 1.202 + } else { 1.203 + halfSampleX = halfSampleY = SK_FixedHalf; 1.204 + } 1.205 + 1.206 + SkFixed fx = SkScalarToFixed(x) + halfSampleX; 1.207 + SkFixed fy = SkScalarToFixed(y) + halfSampleY; 1.208 + 1.209 + GrContext::AutoMatrix autoMatrix; 1.210 + autoMatrix.setIdentity(fContext, &fPaint); 1.211 + 1.212 + while (text < stop) { 1.213 + const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask); 1.214 + 1.215 + fx += autokern.adjust(glyph); 1.216 + 1.217 + if (glyph.fWidth) { 1.218 + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1.219 + glyph.getSubXFixed(), 1.220 + glyph.getSubYFixed()), 1.221 + SkFixedFloorToFixed(fx), 1.222 + SkFixedFloorToFixed(fy), 1.223 + fontScaler); 1.224 + } 1.225 + 1.226 + fx += glyph.fAdvanceX; 1.227 + fy += glyph.fAdvanceY; 1.228 + } 1.229 + 1.230 + this->finish(); 1.231 +} 1.232 + 1.233 +/////////////////////////////////////////////////////////////////////////////// 1.234 +// Copied from SkDraw 1.235 + 1.236 +// last parameter is interpreted as SkFixed [x, y] 1.237 +// return the fixed position, which may be rounded or not by the caller 1.238 +// e.g. subpixel doesn't round 1.239 +typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*); 1.240 + 1.241 +static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.242 + dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY)); 1.243 +} 1.244 + 1.245 +static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.246 + dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1), 1.247 + SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1)); 1.248 +} 1.249 + 1.250 +static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) { 1.251 + dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX, 1.252 + SkScalarToFixed(loc.fY) - glyph.fAdvanceY); 1.253 +} 1.254 + 1.255 +static AlignProc pick_align_proc(SkPaint::Align align) { 1.256 + static const AlignProc gProcs[] = { 1.257 + leftAlignProc, centerAlignProc, rightAlignProc 1.258 + }; 1.259 + 1.260 + SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs)); 1.261 + 1.262 + return gProcs[align]; 1.263 +} 1.264 + 1.265 +class BitmapTextMapState { 1.266 +public: 1.267 + mutable SkPoint fLoc; 1.268 + 1.269 + BitmapTextMapState(const SkMatrix& matrix, SkScalar y) 1.270 + : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {} 1.271 + 1.272 + typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]); 1.273 + 1.274 + Proc pickProc(int scalarsPerPosition); 1.275 + 1.276 +private: 1.277 + const SkMatrix& fMatrix; 1.278 + SkMatrix::MapXYProc fProc; 1.279 + SkScalar fY; // ignored by MapXYProc 1.280 + // these are only used by Only... procs 1.281 + SkScalar fScaleX, fTransX, fTransformedY; 1.282 + 1.283 + static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) { 1.284 + state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc); 1.285 + } 1.286 + 1.287 + static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) { 1.288 + state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc); 1.289 + } 1.290 + 1.291 + static void MapOnlyScaleXProc(const BitmapTextMapState& state, 1.292 + const SkScalar pos[]) { 1.293 + state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX, 1.294 + state.fTransformedY); 1.295 + } 1.296 + 1.297 + static void MapOnlyTransXProc(const BitmapTextMapState& state, 1.298 + const SkScalar pos[]) { 1.299 + state.fLoc.set(*pos + state.fTransX, state.fTransformedY); 1.300 + } 1.301 +}; 1.302 + 1.303 +BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) { 1.304 + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1.305 + 1.306 + if (1 == scalarsPerPosition) { 1.307 + unsigned mtype = fMatrix.getType(); 1.308 + if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) { 1.309 + return MapXProc; 1.310 + } else { 1.311 + fScaleX = fMatrix.getScaleX(); 1.312 + fTransX = fMatrix.getTranslateX(); 1.313 + fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) + 1.314 + fMatrix.getTranslateY(); 1.315 + return (mtype & SkMatrix::kScale_Mask) ? 1.316 + MapOnlyScaleXProc : MapOnlyTransXProc; 1.317 + } 1.318 + } else { 1.319 + return MapXYProc; 1.320 + } 1.321 +} 1.322 + 1.323 +/////////////////////////////////////////////////////////////////////////////// 1.324 + 1.325 +void GrBitmapTextContext::drawPosText(const GrPaint& paint, const SkPaint& skPaint, 1.326 + const char text[], size_t byteLength, 1.327 + const SkScalar pos[], SkScalar constY, 1.328 + int scalarsPerPosition) { 1.329 + SkASSERT(byteLength == 0 || text != NULL); 1.330 + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition); 1.331 + 1.332 + // nothing to draw 1.333 + if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) { 1.334 + return; 1.335 + } 1.336 + 1.337 + this->init(paint, skPaint); 1.338 + 1.339 + SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc(); 1.340 + 1.341 + SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix()); 1.342 + SkGlyphCache* cache = autoCache.getCache(); 1.343 + GrFontScaler* fontScaler = GetGrFontScaler(cache); 1.344 + 1.345 + // store original matrix before we reset, so we can use it to transform positions 1.346 + SkMatrix ctm = fContext->getMatrix(); 1.347 + GrContext::AutoMatrix autoMatrix; 1.348 + autoMatrix.setIdentity(fContext, &fPaint); 1.349 + 1.350 + const char* stop = text + byteLength; 1.351 + AlignProc alignProc = pick_align_proc(fSkPaint.getTextAlign()); 1.352 + BitmapTextMapState tms(ctm, constY); 1.353 + BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition); 1.354 + SkFixed halfSampleX = 0, halfSampleY = 0; 1.355 + 1.356 + if (cache->isSubpixel()) { 1.357 + // maybe we should skip the rounding if linearText is set 1.358 + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm); 1.359 + 1.360 + SkFixed fxMask = ~0; 1.361 + SkFixed fyMask = ~0; 1.362 + if (kX_SkAxisAlignment == baseline) { 1.363 + fyMask = 0; 1.364 +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1.365 + halfSampleY = SK_FixedHalf; 1.366 +#endif 1.367 + } else if (kY_SkAxisAlignment == baseline) { 1.368 + fxMask = 0; 1.369 +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX 1.370 + halfSampleX = SK_FixedHalf; 1.371 +#endif 1.372 + } 1.373 + 1.374 + if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { 1.375 + while (text < stop) { 1.376 + tmsProc(tms, pos); 1.377 + SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX; 1.378 + SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY; 1.379 + 1.380 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 1.381 + fx & fxMask, fy & fyMask); 1.382 + 1.383 + if (glyph.fWidth) { 1.384 + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1.385 + glyph.getSubXFixed(), 1.386 + glyph.getSubYFixed()), 1.387 + SkFixedFloorToFixed(fx), 1.388 + SkFixedFloorToFixed(fy), 1.389 + fontScaler); 1.390 + } 1.391 + pos += scalarsPerPosition; 1.392 + } 1.393 + } else { 1.394 + while (text < stop) { 1.395 + const char* currentText = text; 1.396 + const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0); 1.397 + 1.398 + if (metricGlyph.fWidth) { 1.399 + SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;) 1.400 + SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;) 1.401 + 1.402 + tmsProc(tms, pos); 1.403 + SkIPoint fixedLoc; 1.404 + alignProc(tms.fLoc, metricGlyph, &fixedLoc); 1.405 + 1.406 + SkFixed fx = fixedLoc.fX + halfSampleX; 1.407 + SkFixed fy = fixedLoc.fY + halfSampleY; 1.408 + 1.409 + // have to call again, now that we've been "aligned" 1.410 + const SkGlyph& glyph = glyphCacheProc(cache, ¤tText, 1.411 + fx & fxMask, fy & fyMask); 1.412 + // the assumption is that the metrics haven't changed 1.413 + SkASSERT(prevAdvX == glyph.fAdvanceX); 1.414 + SkASSERT(prevAdvY == glyph.fAdvanceY); 1.415 + SkASSERT(glyph.fWidth); 1.416 + 1.417 + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1.418 + glyph.getSubXFixed(), 1.419 + glyph.getSubYFixed()), 1.420 + SkFixedFloorToFixed(fx), 1.421 + SkFixedFloorToFixed(fy), 1.422 + fontScaler); 1.423 + } 1.424 + pos += scalarsPerPosition; 1.425 + } 1.426 + } 1.427 + } else { // not subpixel 1.428 + 1.429 + if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) { 1.430 + while (text < stop) { 1.431 + // the last 2 parameters are ignored 1.432 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.433 + 1.434 + if (glyph.fWidth) { 1.435 + tmsProc(tms, pos); 1.436 + 1.437 + SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX; 1.438 + SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf; //halfSampleY; 1.439 + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1.440 + glyph.getSubXFixed(), 1.441 + glyph.getSubYFixed()), 1.442 + SkFixedFloorToFixed(fx), 1.443 + SkFixedFloorToFixed(fy), 1.444 + fontScaler); 1.445 + } 1.446 + pos += scalarsPerPosition; 1.447 + } 1.448 + } else { 1.449 + while (text < stop) { 1.450 + // the last 2 parameters are ignored 1.451 + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0); 1.452 + 1.453 + if (glyph.fWidth) { 1.454 + tmsProc(tms, pos); 1.455 + 1.456 + SkIPoint fixedLoc; 1.457 + alignProc(tms.fLoc, glyph, &fixedLoc); 1.458 + 1.459 + SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX; 1.460 + SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY; 1.461 + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(), 1.462 + glyph.getSubXFixed(), 1.463 + glyph.getSubYFixed()), 1.464 + SkFixedFloorToFixed(fx), 1.465 + SkFixedFloorToFixed(fy), 1.466 + fontScaler); 1.467 + } 1.468 + pos += scalarsPerPosition; 1.469 + } 1.470 + } 1.471 + } 1.472 + 1.473 + this->finish(); 1.474 +} 1.475 + 1.476 +namespace { 1.477 + 1.478 +// position + texture coord 1.479 +extern const GrVertexAttrib gTextVertexAttribs[] = { 1.480 + {kVec2f_GrVertexAttribType, 0, kPosition_GrVertexAttribBinding}, 1.481 + {kVec2f_GrVertexAttribType, sizeof(GrPoint), kEffect_GrVertexAttribBinding} 1.482 +}; 1.483 + 1.484 +}; 1.485 + 1.486 +void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed, 1.487 + GrFixed vx, GrFixed vy, 1.488 + GrFontScaler* scaler) { 1.489 + if (NULL == fDrawTarget) { 1.490 + return; 1.491 + } 1.492 + 1.493 + if (NULL == fStrike) { 1.494 + fStrike = fContext->getFontCache()->getStrike(scaler, false); 1.495 + } 1.496 + 1.497 + GrGlyph* glyph = fStrike->getGlyph(packed, scaler); 1.498 + if (NULL == glyph || glyph->fBounds.isEmpty()) { 1.499 + return; 1.500 + } 1.501 + 1.502 + vx += SkIntToFixed(glyph->fBounds.fLeft); 1.503 + vy += SkIntToFixed(glyph->fBounds.fTop); 1.504 + 1.505 + // keep them as ints until we've done the clip-test 1.506 + GrFixed width = glyph->fBounds.width(); 1.507 + GrFixed height = glyph->fBounds.height(); 1.508 + 1.509 + // check if we clipped out 1.510 + if (true || NULL == glyph->fPlot) { 1.511 + int x = vx >> 16; 1.512 + int y = vy >> 16; 1.513 + if (fClipRect.quickReject(x, y, x + width, y + height)) { 1.514 +// SkCLZ(3); // so we can set a break-point in the debugger 1.515 + return; 1.516 + } 1.517 + } 1.518 + 1.519 + if (NULL == glyph->fPlot) { 1.520 + if (fStrike->addGlyphToAtlas(glyph, scaler)) { 1.521 + goto HAS_ATLAS; 1.522 + } 1.523 + 1.524 + // try to clear out an unused plot before we flush 1.525 + if (fContext->getFontCache()->freeUnusedPlot(fStrike) && 1.526 + fStrike->addGlyphToAtlas(glyph, scaler)) { 1.527 + goto HAS_ATLAS; 1.528 + } 1.529 + 1.530 + if (c_DumpFontCache) { 1.531 +#ifdef SK_DEVELOPER 1.532 + fContext->getFontCache()->dump(); 1.533 +#endif 1.534 + } 1.535 + 1.536 + // flush any accumulated draws to allow us to free up a plot 1.537 + this->flushGlyphs(); 1.538 + fContext->flush(); 1.539 + 1.540 + // we should have an unused plot now 1.541 + if (fContext->getFontCache()->freeUnusedPlot(fStrike) && 1.542 + fStrike->addGlyphToAtlas(glyph, scaler)) { 1.543 + goto HAS_ATLAS; 1.544 + } 1.545 + 1.546 + if (NULL == glyph->fPath) { 1.547 + SkPath* path = SkNEW(SkPath); 1.548 + if (!scaler->getGlyphPath(glyph->glyphID(), path)) { 1.549 + // flag the glyph as being dead? 1.550 + delete path; 1.551 + return; 1.552 + } 1.553 + glyph->fPath = path; 1.554 + } 1.555 + 1.556 + GrContext::AutoMatrix am; 1.557 + SkMatrix translate; 1.558 + translate.setTranslate(SkFixedToScalar(vx - SkIntToFixed(glyph->fBounds.fLeft)), 1.559 + SkFixedToScalar(vy - SkIntToFixed(glyph->fBounds.fTop))); 1.560 + GrPaint tmpPaint(fPaint); 1.561 + am.setPreConcat(fContext, translate, &tmpPaint); 1.562 + SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle); 1.563 + fContext->drawPath(tmpPaint, *glyph->fPath, stroke); 1.564 + return; 1.565 + } 1.566 + 1.567 +HAS_ATLAS: 1.568 + SkASSERT(glyph->fPlot); 1.569 + GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken(); 1.570 + glyph->fPlot->setDrawToken(drawToken); 1.571 + 1.572 + // now promote them to fixed (TODO: Rethink using fixed pt). 1.573 + width = SkIntToFixed(width); 1.574 + height = SkIntToFixed(height); 1.575 + 1.576 + GrTexture* texture = glyph->fPlot->texture(); 1.577 + SkASSERT(texture); 1.578 + 1.579 + if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) { 1.580 + this->flushGlyphs(); 1.581 + fCurrTexture = texture; 1.582 + fCurrTexture->ref(); 1.583 + } 1.584 + 1.585 + if (NULL == fVertices) { 1.586 + // If we need to reserve vertices allow the draw target to suggest 1.587 + // a number of verts to reserve and whether to perform a flush. 1.588 + fMaxVertices = kMinRequestedVerts; 1.589 + fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( 1.590 + SK_ARRAY_COUNT(gTextVertexAttribs)); 1.591 + bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL); 1.592 + if (flush) { 1.593 + this->flushGlyphs(); 1.594 + fContext->flush(); 1.595 + fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>( 1.596 + SK_ARRAY_COUNT(gTextVertexAttribs)); 1.597 + } 1.598 + fMaxVertices = kDefaultRequestedVerts; 1.599 + // ignore return, no point in flushing again. 1.600 + fDrawTarget->geometryHints(&fMaxVertices, NULL); 1.601 + 1.602 + int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads(); 1.603 + if (fMaxVertices < kMinRequestedVerts) { 1.604 + fMaxVertices = kDefaultRequestedVerts; 1.605 + } else if (fMaxVertices > maxQuadVertices) { 1.606 + // don't exceed the limit of the index buffer 1.607 + fMaxVertices = maxQuadVertices; 1.608 + } 1.609 + bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices, 1.610 + 0, 1.611 + GrTCast<void**>(&fVertices), 1.612 + NULL); 1.613 + GrAlwaysAssert(success); 1.614 + SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize()); 1.615 + } 1.616 + 1.617 + GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX); 1.618 + GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY); 1.619 + 1.620 + SkRect r; 1.621 + r.fLeft = SkFixedToFloat(vx); 1.622 + r.fTop = SkFixedToFloat(vy); 1.623 + r.fRight = SkFixedToFloat(vx + width); 1.624 + r.fBottom = SkFixedToFloat(vy + height); 1.625 + 1.626 + fVertexBounds.growToInclude(r); 1.627 + 1.628 + fVertices[2*fCurrVertex].setRectFan(r.fLeft, r.fTop, r.fRight, r.fBottom, 1.629 + 2 * sizeof(SkPoint)); 1.630 + fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)), 1.631 + SkFixedToFloat(texture->normalizeFixedY(ty)), 1.632 + SkFixedToFloat(texture->normalizeFixedX(tx + width)), 1.633 + SkFixedToFloat(texture->normalizeFixedY(ty + height)), 1.634 + 2 * sizeof(SkPoint)); 1.635 + fCurrVertex += 4; 1.636 +}