| Index: src/gpu/GrBitmapTextContext.cpp
|
| diff --git a/src/gpu/GrBitmapTextContext.cpp b/src/gpu/GrBitmapTextContext.cpp
|
| index 6e33d90d07fb53f0af25139664a20fb7dbffbf87..da887a54562ab547030afe7d3b6532911b56ef5d 100755
|
| --- a/src/gpu/GrBitmapTextContext.cpp
|
| +++ b/src/gpu/GrBitmapTextContext.cpp
|
| @@ -18,16 +18,21 @@
|
| #include "SkStrokeRec.h"
|
| #include "effects/GrCustomCoordsTextureEffect.h"
|
|
|
| +#include "SkAutoKern.h"
|
| +#include "SkGlyphCache.h"
|
| +#include "SkGpuDevice.h"
|
| +#include "SkGr.h"
|
| +
|
| static const int kGlyphCoordsAttributeIndex = 1;
|
|
|
| SK_CONF_DECLARE(bool, c_DumpFontCache, "gpu.dumpFontCache", false,
|
| "Dump the contents of the font cache before every purge.");
|
|
|
| -GrBitmapTextContext::GrBitmapTextContext(GrContext* context, const GrPaint& paint,
|
| - const SkPaint& skPaint) :
|
| - GrTextContext(context, paint, skPaint) {
|
| - fAutoMatrix.setIdentity(fContext, &fPaint);
|
| -
|
| +GrBitmapTextContext::GrBitmapTextContext(GrContext* context,
|
| + const GrPaint& grPaint,
|
| + const SkPaint& skPaint,
|
| + const SkDeviceProperties& properties)
|
| + : GrTextContext(context, grPaint, skPaint, properties) {
|
| fStrike = NULL;
|
|
|
| fCurrTexture = NULL;
|
| @@ -107,6 +112,330 @@ void GrBitmapTextContext::flushGlyphs() {
|
| }
|
| }
|
|
|
| +void GrBitmapTextContext::drawText(const char text[], size_t byteLength,
|
| + SkScalar x, SkScalar y) {
|
| + SkASSERT(byteLength == 0 || text != NULL);
|
| +
|
| + // nothing to draw
|
| + if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
|
| + return;
|
| + }
|
| +
|
| + SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
| +
|
| + SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
|
| + SkGlyphCache* cache = autoCache.getCache();
|
| + GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
| +
|
| + // transform our starting point
|
| + {
|
| + SkPoint loc;
|
| + fContext->getMatrix().mapXY(x, y, &loc);
|
| + x = loc.fX;
|
| + y = loc.fY;
|
| + }
|
| +
|
| + // need to measure first
|
| + if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
|
| + SkVector stop;
|
| +
|
| + MeasureText(cache, glyphCacheProc, text, byteLength, &stop);
|
| +
|
| + SkScalar stopX = stop.fX;
|
| + SkScalar stopY = stop.fY;
|
| +
|
| + if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
|
| + stopX = SkScalarHalf(stopX);
|
| + stopY = SkScalarHalf(stopY);
|
| + }
|
| + x -= stopX;
|
| + y -= stopY;
|
| + }
|
| +
|
| + const char* stop = text + byteLength;
|
| +
|
| + SkAutoKern autokern;
|
| +
|
| + SkFixed fxMask = ~0;
|
| + SkFixed fyMask = ~0;
|
| + SkFixed halfSampleX, halfSampleY;
|
| + if (cache->isSubpixel()) {
|
| + halfSampleX = halfSampleY = (SK_FixedHalf >> SkGlyph::kSubBits);
|
| + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(fContext->getMatrix());
|
| + if (kX_SkAxisAlignment == baseline) {
|
| + fyMask = 0;
|
| + halfSampleY = SK_FixedHalf;
|
| + } else if (kY_SkAxisAlignment == baseline) {
|
| + fxMask = 0;
|
| + halfSampleX = SK_FixedHalf;
|
| + }
|
| + } else {
|
| + halfSampleX = halfSampleY = SK_FixedHalf;
|
| + }
|
| +
|
| + SkFixed fx = SkScalarToFixed(x) + halfSampleX;
|
| + SkFixed fy = SkScalarToFixed(y) + halfSampleY;
|
| +
|
| + GrContext::AutoMatrix autoMatrix;
|
| + autoMatrix.setIdentity(fContext, &fPaint);
|
| +
|
| + while (text < stop) {
|
| + const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);
|
| +
|
| + fx += autokern.adjust(glyph);
|
| +
|
| + if (glyph.fWidth) {
|
| + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
| + glyph.getSubXFixed(),
|
| + glyph.getSubYFixed()),
|
| + SkFixedFloorToFixed(fx),
|
| + SkFixedFloorToFixed(fy),
|
| + fontScaler);
|
| + }
|
| +
|
| + fx += glyph.fAdvanceX;
|
| + fy += glyph.fAdvanceY;
|
| + }
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +// Copied from SkDraw
|
| +
|
| +// last parameter is interpreted as SkFixed [x, y]
|
| +// return the fixed position, which may be rounded or not by the caller
|
| +// e.g. subpixel doesn't round
|
| +typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
|
| +
|
| +static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
|
| + dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
|
| +}
|
| +
|
| +static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
|
| + dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
|
| + SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
|
| +}
|
| +
|
| +static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph, SkIPoint* dst) {
|
| + dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
|
| + SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
|
| +}
|
| +
|
| +static AlignProc pick_align_proc(SkPaint::Align align) {
|
| + static const AlignProc gProcs[] = {
|
| + leftAlignProc, centerAlignProc, rightAlignProc
|
| + };
|
| +
|
| + SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
|
| +
|
| + return gProcs[align];
|
| +}
|
| +
|
| +class BitmapTextMapState {
|
| +public:
|
| + mutable SkPoint fLoc;
|
| +
|
| + BitmapTextMapState(const SkMatrix& matrix, SkScalar y)
|
| + : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
|
| +
|
| + typedef void (*Proc)(const BitmapTextMapState&, const SkScalar pos[]);
|
| +
|
| + Proc pickProc(int scalarsPerPosition);
|
| +
|
| +private:
|
| + const SkMatrix& fMatrix;
|
| + SkMatrix::MapXYProc fProc;
|
| + SkScalar fY; // ignored by MapXYProc
|
| + // these are only used by Only... procs
|
| + SkScalar fScaleX, fTransX, fTransformedY;
|
| +
|
| + static void MapXProc(const BitmapTextMapState& state, const SkScalar pos[]) {
|
| + state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
|
| + }
|
| +
|
| + static void MapXYProc(const BitmapTextMapState& state, const SkScalar pos[]) {
|
| + state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
|
| + }
|
| +
|
| + static void MapOnlyScaleXProc(const BitmapTextMapState& state,
|
| + const SkScalar pos[]) {
|
| + state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
|
| + state.fTransformedY);
|
| + }
|
| +
|
| + static void MapOnlyTransXProc(const BitmapTextMapState& state,
|
| + const SkScalar pos[]) {
|
| + state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
|
| + }
|
| +};
|
| +
|
| +BitmapTextMapState::Proc BitmapTextMapState::pickProc(int scalarsPerPosition) {
|
| + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
|
| +
|
| + if (1 == scalarsPerPosition) {
|
| + unsigned mtype = fMatrix.getType();
|
| + if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
|
| + return MapXProc;
|
| + } else {
|
| + fScaleX = fMatrix.getScaleX();
|
| + fTransX = fMatrix.getTranslateX();
|
| + fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
|
| + fMatrix.getTranslateY();
|
| + return (mtype & SkMatrix::kScale_Mask) ?
|
| + MapOnlyScaleXProc : MapOnlyTransXProc;
|
| + }
|
| + } else {
|
| + return MapXYProc;
|
| + }
|
| +}
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| +
|
| +void GrBitmapTextContext::drawPosText(const char text[], size_t byteLength,
|
| + const SkScalar pos[], SkScalar constY,
|
| + int scalarsPerPosition) {
|
| + SkASSERT(byteLength == 0 || text != NULL);
|
| + SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
|
| +
|
| + // nothing to draw
|
| + if (text == NULL || byteLength == 0/* || fRC->isEmpty()*/) {
|
| + return;
|
| + }
|
| +
|
| + SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();
|
| +
|
| + SkAutoGlyphCache autoCache(fSkPaint, &fDeviceProperties, &fContext->getMatrix());
|
| + SkGlyphCache* cache = autoCache.getCache();
|
| + GrFontScaler* fontScaler = GetGrFontScaler(cache);
|
| +
|
| + // store original matrix before we reset, so we can use it to transform positions
|
| + SkMatrix ctm = fContext->getMatrix();
|
| + GrContext::AutoMatrix autoMatrix;
|
| + autoMatrix.setIdentity(fContext, &fPaint);
|
| +
|
| + const char* stop = text + byteLength;
|
| + AlignProc alignProc = pick_align_proc(fSkPaint.getTextAlign());
|
| + BitmapTextMapState tms(ctm, constY);
|
| + BitmapTextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
|
| + SkFixed halfSampleX = 0, halfSampleY = 0;
|
| +
|
| + if (cache->isSubpixel()) {
|
| + // maybe we should skip the rounding if linearText is set
|
| + SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(ctm);
|
| +
|
| + SkFixed fxMask = ~0;
|
| + SkFixed fyMask = ~0;
|
| + if (kX_SkAxisAlignment == baseline) {
|
| + fyMask = 0;
|
| +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
|
| + halfSampleY = SK_FixedHalf;
|
| +#endif
|
| + } else if (kY_SkAxisAlignment == baseline) {
|
| + fxMask = 0;
|
| +#ifndef SK_IGNORE_SUBPIXEL_AXIS_ALIGN_FIX
|
| + halfSampleX = SK_FixedHalf;
|
| +#endif
|
| + }
|
| +
|
| + if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
|
| + while (text < stop) {
|
| + tmsProc(tms, pos);
|
| + SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + halfSampleX;
|
| + SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + halfSampleY;
|
| +
|
| + const SkGlyph& glyph = glyphCacheProc(cache, &text,
|
| + fx & fxMask, fy & fyMask);
|
| +
|
| + if (glyph.fWidth) {
|
| + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
| + glyph.getSubXFixed(),
|
| + glyph.getSubYFixed()),
|
| + SkFixedFloorToFixed(fx),
|
| + SkFixedFloorToFixed(fy),
|
| + fontScaler);
|
| + }
|
| + pos += scalarsPerPosition;
|
| + }
|
| + } else {
|
| + while (text < stop) {
|
| + const char* currentText = text;
|
| + const SkGlyph& metricGlyph = glyphCacheProc(cache, &text, 0, 0);
|
| +
|
| + if (metricGlyph.fWidth) {
|
| + SkDEBUGCODE(SkFixed prevAdvX = metricGlyph.fAdvanceX;)
|
| + SkDEBUGCODE(SkFixed prevAdvY = metricGlyph.fAdvanceY;)
|
| +
|
| + tmsProc(tms, pos);
|
| + SkIPoint fixedLoc;
|
| + alignProc(tms.fLoc, metricGlyph, &fixedLoc);
|
| +
|
| + SkFixed fx = fixedLoc.fX + halfSampleX;
|
| + SkFixed fy = fixedLoc.fY + halfSampleY;
|
| +
|
| + // have to call again, now that we've been "aligned"
|
| + const SkGlyph& glyph = glyphCacheProc(cache, ¤tText,
|
| + fx & fxMask, fy & fyMask);
|
| + // the assumption is that the metrics haven't changed
|
| + SkASSERT(prevAdvX == glyph.fAdvanceX);
|
| + SkASSERT(prevAdvY == glyph.fAdvanceY);
|
| + SkASSERT(glyph.fWidth);
|
| +
|
| + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
| + glyph.getSubXFixed(),
|
| + glyph.getSubYFixed()),
|
| + SkFixedFloorToFixed(fx),
|
| + SkFixedFloorToFixed(fy),
|
| + fontScaler);
|
| + }
|
| + pos += scalarsPerPosition;
|
| + }
|
| + }
|
| + } else { // not subpixel
|
| +
|
| + if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
|
| + while (text < stop) {
|
| + // the last 2 parameters are ignored
|
| + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
| +
|
| + if (glyph.fWidth) {
|
| + tmsProc(tms, pos);
|
| +
|
| + SkFixed fx = SkScalarToFixed(tms.fLoc.fX) + SK_FixedHalf; //halfSampleX;
|
| + SkFixed fy = SkScalarToFixed(tms.fLoc.fY) + SK_FixedHalf; //halfSampleY;
|
| + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
| + glyph.getSubXFixed(),
|
| + glyph.getSubYFixed()),
|
| + SkFixedFloorToFixed(fx),
|
| + SkFixedFloorToFixed(fy),
|
| + fontScaler);
|
| + }
|
| + pos += scalarsPerPosition;
|
| + }
|
| + } else {
|
| + while (text < stop) {
|
| + // the last 2 parameters are ignored
|
| + const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
|
| +
|
| + if (glyph.fWidth) {
|
| + tmsProc(tms, pos);
|
| +
|
| + SkIPoint fixedLoc;
|
| + alignProc(tms.fLoc, glyph, &fixedLoc);
|
| +
|
| + SkFixed fx = fixedLoc.fX + SK_FixedHalf; //halfSampleX;
|
| + SkFixed fy = fixedLoc.fY + SK_FixedHalf; //halfSampleY;
|
| + this->drawPackedGlyph(GrGlyph::Pack(glyph.getGlyphID(),
|
| + glyph.getSubXFixed(),
|
| + glyph.getSubYFixed()),
|
| + SkFixedFloorToFixed(fx),
|
| + SkFixedFloorToFixed(fy),
|
| + fontScaler);
|
| + }
|
| + pos += scalarsPerPosition;
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| namespace {
|
|
|
| // position + texture coord
|
| @@ -123,6 +452,7 @@ void GrBitmapTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
|
| if (NULL == fDrawTarget) {
|
| return;
|
| }
|
| +
|
| if (NULL == fStrike) {
|
| #if SK_DISTANCEFIELD_FONTS
|
| fStrike = fContext->getFontCache()->getStrike(scaler, false);
|
|
|