void SkRandomScalerContext::generateAdvance(SkGlyph* glyph) {
    fProxy->getAdvance(glyph);

    SkVector advance;
    fMatrix.mapXY(SkFixedToScalar(glyph->fAdvanceX),
                  SkFixedToScalar(glyph->fAdvanceY), &advance);
    glyph->fAdvanceX = SkScalarToFixed(advance.fX);
    glyph->fAdvanceY = SkScalarToFixed(advance.fY);
}
void SkRandomScalerContext::generateMetrics(SkGlyph* glyph) {
    fProxy->getAdvance(glyph);

    SkVector advance;
    fMatrix.mapXY(SkFixedToScalar(glyph->fAdvanceX),
                  SkFixedToScalar(glyph->fAdvanceY), &advance);
    glyph->fAdvanceX = SkScalarToFixed(advance.fX);
    glyph->fAdvanceY = SkScalarToFixed(advance.fY);

    SkPath path;
    fProxy->getPath(*glyph, &path);
    path.transform(fMatrix);

    SkRect storage;
    const SkPaint& paint = fFace->paint();
    const SkRect& newBounds = paint.doComputeFastBounds(path.getBounds(),
                                                        &storage,
                                                        SkPaint::kFill_Style);
    SkIRect ibounds;
    newBounds.roundOut(&ibounds);
    glyph->fLeft = ibounds.fLeft;
    glyph->fTop = ibounds.fTop;
    glyph->fWidth = ibounds.width();
    glyph->fHeight = ibounds.height();

    // Here we will change the mask format of the glyph
    // NOTE this is being overridden by the base class
    SkMask::Format format;
    switch (glyph->getGlyphID() % 6) {
        case 0:
            format = SkMask::kLCD16_Format;
            break;
        case 1:
            format = SkMask::kA8_Format;
            break;
        case 2:
            format = SkMask::kARGB32_Format;
            break;
        default:
            // we will fiddle with these in generate image
            format = (SkMask::Format)MASK_FORMAT_UNKNOWN;
    }

    glyph->fMaskFormat = format;
}
const char* SkParse::FindScalar(const char str[], SkScalar* value) {
    SkASSERT(str);
    str = skip_ws(str);
#ifdef SK_SCALAR_IS_FLOAT
    char* stop;
    float v = (float)strtod(str, &stop);
    if (str == stop) {
        return NULL;
    }
    if (value) {
        *value = v;
    }
    return stop;
#else
    int sign = 0;
    if (*str == '-')
    {
        sign = -1;
        str += 1;
    }

    if (!is_digit(*str) && *str != '.')
        return NULL;

    int n = 0;
    while (is_digit(*str))
    {
        n = 10*n + *str - '0';
        if (n > 0x7FFF)
            return NULL;
        str += 1;
    }
    n <<= 16;

    if (*str == '.')
    {
        static const int gFractions[] = { (1 << 24)  / 10, (1 << 24)  / 100, (1 << 24)  / 1000, 
            (1 << 24)  / 10000, (1 << 24)  / 100000 };
        str += 1;
        int d = 0;
        const int* fraction = gFractions;
        const int* end = &fraction[SK_ARRAY_COUNT(gFractions)];
        while (is_digit(*str) && fraction < end)
            d += (*str++ - '0') * *fraction++;
        d += 0x80; // round
        n += d >> 8;
    }
    while (is_digit(*str))
        str += 1;
    if (value)
    {
        n = (n ^ sign) - sign;  // apply the sign
        *value = SkFixedToScalar(n);
    }
#endif
    return str;
}
Beispiel #4
0
void SkGLDevice::drawDevice(const SkDraw& draw, SkDevice* dev,
                            int x, int y, const SkPaint& paint) {
    TRACE_DRAW("coreDrawDevice", this, draw);
    
    SkGLDevice::TexOrientation to = ((SkGLDevice*)dev)->bindDeviceAsTexture();
    if (SkGLDevice::kNo_TexOrientation != to) {
        SkGLClipIter* iter = this->updateMatrixClip();
        
        const SkBitmap& bm = dev->accessBitmap(false);
        int w = bm.width();
        int h = bm.height();
        SkPoint max;
        
        max.set(SkFixedToScalar(w << (16 - SkNextLog2(bm.rowBytesAsPixels()))),
                SkFixedToScalar(h << (16 - SkNextLog2(h))));
        
        if (SkGLDevice::kBottomToTop_TexOrientation == to) {
            h = -h;
        }
        gl_drawSprite(x, y, w, h, max, paint, iter);
    }
}
Beispiel #5
0
SkGradientShaderBase::GpuColorType SkGradientShaderBase::getGpuColorType(SkColor colors[3]) const {
    if (fColorCount <= 3) {
        memcpy(colors, fOrigColors, fColorCount * sizeof(SkColor));
    }

    if (SkShader::kClamp_TileMode == fTileMode) {
        if (2 == fColorCount) {
            return kTwo_GpuColorType;
        } else if (3 == fColorCount &&
                   (SkScalarAbs(
                    SkFixedToScalar(fRecs[1].fPos) - SK_ScalarHalf) < SK_Scalar1 / 1000)) {
            return kThree_GpuColorType;
        }
    }
    return kTexture_GpuColorType;
}
void SkProgressView::onDraw(SkCanvas* canvas)
{
    if (fMax == 0)
        return;

    SkFixed    percent;

    if (fInterp)
    {
        SkScalar x;
        if (fInterp->timeToValues(SkTime::GetMSecs(), &x) == SkInterpolator::kFreezeEnd_Result)
        {
            delete fInterp;
            fInterp = NULL;
        }
        percent = (SkFixed)x;    // now its 16.8
        percent = SkMax32(0, SkMin32(percent, fMax << 8));    // now its pinned
        percent = SkFixedDiv(percent, fMax << 8);    // now its 0.16
        this->inval(NULL);
    }
    else
    {
        U16CPU value = SkMax32(0, SkMin32(fValue, fMax));
        percent = SkFixedDiv(value, fMax);
    }


    SkRect    r;
    SkPaint    p;

    r.set(0, 0, this->width(), this->height());
    p.setAntiAlias(true);

    r.fRight = r.fLeft + SkScalarMul(r.width(), SkFixedToScalar(percent));
    p.setStyle(SkPaint::kFill_Style);

    p.setColor(SK_ColorDKGRAY);
    p.setShader(fOnShader);
    canvas->drawRect(r, p);

    p.setColor(SK_ColorWHITE);
    p.setShader(fOffShader);
    r.fLeft = r.fRight;
    r.fRight = this->width() - SK_Scalar1;
    if (r.width() > 0)
        canvas->drawRect(r, p);
}
Beispiel #7
0
SkGradientShaderBase::SkGradientShaderBase(SkReadBuffer& buffer) : INHERITED(buffer) {
    if (buffer.isVersionLT(SkReadBuffer::kNoUnitMappers_Version)) {
        // skip the old SkUnitMapper slot
        buffer.skipFlattenable();
    }

    int colorCount = fColorCount = buffer.getArrayCount();
    if (colorCount > kColorStorageCount) {
        size_t allocSize = (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec)) * colorCount;
        if (buffer.validateAvailable(allocSize)) {
            fOrigColors = reinterpret_cast<SkColor*>(sk_malloc_throw(allocSize));
        } else {
            fOrigColors =  NULL;
            colorCount = fColorCount = 0;
        }
    } else {
        fOrigColors = fStorage;
    }
    buffer.readColorArray(fOrigColors, colorCount);

    fOrigPos = (SkScalar*)(fOrigColors + colorCount);

    {
        uint32_t packed = buffer.readUInt();
        fGradFlags = SkToU8(unpack_flags(packed));
        fTileMode = unpack_mode(packed);
    }
    fTileProc = gTileProcs[fTileMode];
    fRecs = (Rec*)(fOrigPos + colorCount);
    if (colorCount > 2) {
        Rec* recs = fRecs;
        recs[0].fPos = 0;
        fOrigPos[0] = 0;
        for (int i = 1; i < colorCount; i++) {
            recs[i].fPos = buffer.readInt();
            recs[i].fScale = buffer.readUInt();
            fOrigPos[i] = SkFixedToScalar(recs[i].fPos);
        }
    } else {
        fOrigPos = NULL;
    }
    buffer.readMatrix(&fPtsToUnit);
    this->initCommon();
}
Beispiel #8
0
SkScalar SkUnitCubicInterp(SkScalar value, SkScalar bx, SkScalar by,
                           SkScalar cx, SkScalar cy) {
    // pin to the unit-square, and convert to 2.14
    Dot14 x = pin_and_convert(value);
    
    if (x == 0) return 0;
    if (x == Dot14_ONE) return SK_Scalar1;
    
    Dot14 b = pin_and_convert(bx);
    Dot14 c = pin_and_convert(cx);
    
    // Now compute our coefficients from the control points
    //  t   -> 3b
    //  t^2 -> 3c - 6b
    //  t^3 -> 3b - 3c + 1
    Dot14 A = 3*b;
    Dot14 B = 3*(c - 2*b);
    Dot14 C = 3*(b - c) + Dot14_ONE;

    // Now search for a t value given x
    Dot14   t = Dot14_HALF;
    Dot14   dt = Dot14_HALF;
    for (int i = 0; i < 13; i++) {
        dt >>= 1;
        Dot14 guess = eval_cubic(t, A, B, C);
        if (x < guess) {
            t -= dt;
        } else {
            t += dt;
        }
    }
    
    // Now we have t, so compute the coeff for Y and evaluate
    b = pin_and_convert(by);
    c = pin_and_convert(cy);
    A = 3*b;
    B = 3*(c - 2*b);
    C = 3*(b - c) + Dot14_ONE;
    return SkFixedToScalar(eval_cubic(t, A, B, C) << 2);
}
Beispiel #9
0
void SkSliderView::onDraw(SkCanvas* canvas)
{
	this->INHERITED::onDraw(canvas);

	U16CPU value = SkMax32(0, SkMin32(fValue, fMax));

	SkRect	r;
	SkPaint	p;

	r.set(0, 0, this->width(), this->height());

	p.setAntiAliasOn(true);
	p.setStyle(SkPaint::kStroke_Style);
	p.setStrokeWidth(SK_Scalar1);
	r.inset(SK_Scalar1/2, SK_Scalar1/2);
	canvas->drawRect(r, p);

	if (fMax)
	{
		SkFixed percent = SkFixedDiv(value, fMax);
		
		r.inset(SK_Scalar1/2, SK_Scalar1/2);
		r.fRight = r.fLeft + SkScalarMul(r.width(), SkFixedToScalar(percent));
		p.setStyle(SkPaint::kFill_Style);
		setgrad(&p, r);
		canvas->drawRect(r, p);
	}

#if 0
	r.set(0, 0, this->width(), this->height());
	r.inset(SK_Scalar1, SK_Scalar1);
	r.inset(r.width()/2, 0);
	p.setColor(SK_ColorBLACK);
	canvas->drawLine(*(SkPoint*)&r.fLeft, *(SkPoint*)&r.fRight, p);
#endif
}
void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
    SkPath  path;
    generatePath(glyph, &path);

    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
        SkFixed dx = glyph.getSubXFixed();
        SkFixed dy = glyph.getSubYFixed();
        if (dx | dy) {
            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
        }
    }

    if (fRec.fFrameWidth > 0 || fPathEffect != nullptr) {
        // need the path in user-space, with only the point-size applied
        // so that our stroking and effects will operate the same way they
        // would if the user had extracted the path themself, and then
        // called drawPath
        SkPath      localPath;
        SkMatrix    matrix, inverse;

        fRec.getMatrixFrom2x2(&matrix);
        if (!matrix.invert(&inverse)) {
            // assume fillPath and devPath are already empty.
            return;
        }
        path.transform(inverse, &localPath);
        // now localPath is only affected by the paint settings, and not the canvas matrix

        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);

        if (fRec.fFrameWidth > 0) {
            rec.setStrokeStyle(fRec.fFrameWidth,
                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
            // glyphs are always closed contours, so cap type is ignored,
            // so we just pass something.
            rec.setStrokeParams((SkPaint::Cap)fRec.fStrokeCap,
                                (SkPaint::Join)fRec.fStrokeJoin,
                                fRec.fMiterLimit);
        }

        if (fPathEffect) {
            SkPath effectPath;
            if (fPathEffect->filterPath(&effectPath, localPath, &rec, nullptr)) {
                localPath.swap(effectPath);
            }
        }

        if (rec.needToApply()) {
            SkPath strokePath;
            if (rec.applyToPath(&strokePath, localPath)) {
                localPath.swap(strokePath);
            }
        }

        // now return stuff to the caller
        if (fillToDevMatrix) {
            *fillToDevMatrix = matrix;
        }
        if (devPath) {
            localPath.transform(matrix, devPath);
        }
        if (fillPath) {
            fillPath->swap(localPath);
        }
    } else {   // nothing tricky to do
        if (fillToDevMatrix) {
            fillToDevMatrix->reset();
        }
        if (devPath) {
            if (fillPath == nullptr) {
                devPath->swap(path);
            } else {
                *devPath = path;
            }
        }

        if (fillPath) {
            fillPath->swap(path);
        }
    }

    if (devPath) {
        devPath->updateBoundsCache();
    }
    if (fillPath) {
        fillPath->updateBoundsCache();
    }
}
void GrStencilAndCoverTextContext::onDrawText(GrDrawContext* drawContext, GrRenderTarget* rt,
                                              const GrClip& clip,
                                              const GrPaint& paint,
                                              const SkPaint& skPaint,
                                              const SkMatrix& viewMatrix,
                                              const char text[],
                                              size_t byteLength,
                                              SkScalar x, SkScalar y,
                                              const SkIRect& regionClipBounds) {
    SkASSERT(byteLength == 0 || text != NULL);

    if (text == NULL || byteLength == 0 /*|| fRC->isEmpty()*/) {
        return;
    }

    // This is the slow path, mainly used by Skia unit tests.  The other
    // backends (8888, gpu, ...) use device-space dependent glyph caches. In
    // order to match the glyph positions that the other code paths produce, we
    // must also use device-space dependent glyph cache. This has the
    // side-effect that the glyph shape outline will be in device-space,
    // too. This in turn has the side-effect that NVPR can not stroke the paths,
    // as the stroke in NVPR is defined in object-space.
    // NOTE: here we have following coincidence that works at the moment:
    // - When using the device-space glyphs, the transforms we pass to NVPR
    // instanced drawing are the global transforms, and the view transform is
    // identity. NVPR can not use non-affine transforms in the instanced
    // drawing. This is taken care of by SkDraw::ShouldDrawTextAsPaths since it
    // will turn off the use of device-space glyphs when perspective transforms
    // are in use.

    this->init(rt, clip, paint, skPaint, byteLength, kMaxAccuracy_RenderMode, viewMatrix,
               regionClipBounds);

    // Transform our starting point.
    if (fUsingDeviceSpaceGlyphs) {
        SkPoint loc;
        fContextInitialMatrix.mapXY(x, y, &loc);
        x = loc.fX;
        y = loc.fY;
    }

    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();

    const char* stop = text + byteLength;

    // Measure first if needed.
    if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
        SkFixed    stopX = 0;
        SkFixed    stopY = 0;

        const char* textPtr = text;
        while (textPtr < stop) {
            // We don't need x, y here, since all subpixel variants will have the
            // same advance.
            const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &textPtr, 0, 0);

            stopX += glyph.fAdvanceX;
            stopY += glyph.fAdvanceY;
        }
        SkASSERT(textPtr == stop);

        SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
        SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;

        if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
            alignX = SkScalarHalf(alignX);
            alignY = SkScalarHalf(alignY);
        }

        x -= alignX;
        y -= alignY;
    }

    SkAutoKern autokern;

    SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);

    SkFixed fx = SkScalarToFixed(x);
    SkFixed fy = SkScalarToFixed(y);
    while (text < stop) {
        const SkGlyph& glyph = glyphCacheProc(fGlyphCache, &text, 0, 0);
        fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
        if (glyph.fWidth) {
            this->appendGlyph(drawContext, glyph, 
                              SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)));
        }

        fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
        fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
    }

    this->finish(drawContext);
}
Beispiel #12
0
 /** Return the next pseudo random number expressed as a SkScalar
     in the range [-SK_Scalar1..SK_Scalar1).
 */
 SkScalar nextSScalar1() { return SkFixedToScalar(this->nextSFixed1()); }
 SkPowerMode(SkFlattenableReadBuffer& b) : SkXfermode(b) {
     // read the exponent
     this->init(SkFixedToScalar(b.readS32()));
 }
Beispiel #14
0
void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
    SkPath  path;

    this->getGlyphContext(glyph)->generatePath(glyph, &path);

    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
        SkFixed dx = glyph.getSubXFixed();
        SkFixed dy = glyph.getSubYFixed();
        if (dx | dy) {
            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
        }
    }

    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
        // need the path in user-space, with only the point-size applied
        // so that our stroking and effects will operate the same way they
        // would if the user had extracted the path themself, and then
        // called drawPath
        SkPath      localPath;
        SkMatrix    matrix, inverse;

        fRec.getMatrixFrom2x2(&matrix);
        matrix.invert(&inverse);
        path.transform(inverse, &localPath);
        // now localPath is only affected by the paint settings, and not the canvas matrix

        SkScalar width = fRec.fFrameWidth;

        if (fPathEffect) {
            SkPath effectPath;

            if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
                localPath.swap(effectPath);
            }
        }

        if (width > 0) {
            SkStroke    stroker;
            SkPath      outline;

            stroker.setWidth(width);
            stroker.setMiterLimit(fRec.fMiterLimit);
            stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
            stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
            stroker.strokePath(localPath, &outline);
            localPath.swap(outline);
        }

        // now return stuff to the caller
        if (fillToDevMatrix) {
            *fillToDevMatrix = matrix;
        }
        if (devPath) {
            localPath.transform(matrix, devPath);
        }
        if (fillPath) {
            fillPath->swap(localPath);
        }
    } else {   // nothing tricky to do
        if (fillToDevMatrix) {
            fillToDevMatrix->reset();
        }
        if (devPath) {
            if (fillPath == NULL) {
                devPath->swap(path);
            } else {
                *devPath = path;
            }
        }

        if (fillPath) {
            fillPath->swap(path);
        }
    }

    if (devPath) {
        devPath->updateBoundsCache();
    }
    if (fillPath) {
        fillPath->updateBoundsCache();
    }
}
void GrDistanceFieldTextContext::drawPackedGlyph(GrGlyph::PackedID packed,
                                                 GrFixed vx, GrFixed vy,
                                                 GrFontScaler* scaler) {
    if (NULL == fDrawTarget) {
        return;
    }
    if (NULL == fStrike) {
        fStrike = fContext->getFontCache()->getStrike(scaler, true);
    }

    GrGlyph* glyph = fStrike->getGlyph(packed, scaler);
    if (NULL == glyph || glyph->fBounds.isEmpty()) {
        return;
    }

    SkScalar sx = SkFixedToScalar(vx);
    SkScalar sy = SkFixedToScalar(vy);
/*
    // not valid, need to find a different solution for this
    vx += SkIntToFixed(glyph->fBounds.fLeft);
    vy += SkIntToFixed(glyph->fBounds.fTop);

    // keep them as ints until we've done the clip-test
    GrFixed width = glyph->fBounds.width();
    GrFixed height = glyph->fBounds.height();

    // check if we clipped out
    if (true || NULL == glyph->fPlot) {
        int x = vx >> 16;
        int y = vy >> 16;
        if (fClipRect.quickReject(x, y, x + width, y + height)) {
//            SkCLZ(3);    // so we can set a break-point in the debugger
            return;
        }
    }
*/
    if (NULL == glyph->fPlot) {
        if (fStrike->getGlyphAtlas(glyph, scaler)) {
            goto HAS_ATLAS;
        }

        // try to clear out an unused plot before we flush
        fContext->getFontCache()->freePlotExceptFor(fStrike);
        if (fStrike->getGlyphAtlas(glyph, scaler)) {
            goto HAS_ATLAS;
        }

        if (c_DumpFontCache) {
#ifdef SK_DEVELOPER
            fContext->getFontCache()->dump();
#endif
        }

        // before we purge the cache, we must flush any accumulated draws
        this->flushGlyphs();
        fContext->flush();

        // try to purge
        fContext->getFontCache()->purgeExceptFor(fStrike);
        // need to use new flush count here
        if (fStrike->getGlyphAtlas(glyph, scaler)) {
            goto HAS_ATLAS;
        }

        if (NULL == glyph->fPath) {
            SkPath* path = SkNEW(SkPath);
            if (!scaler->getGlyphPath(glyph->glyphID(), path)) {
                // flag the glyph as being dead?
                delete path;
                return;
            }
            glyph->fPath = path;
        }

        GrContext::AutoMatrix am;
        SkMatrix translate;
        translate.setTranslate(sx, sy);
        GrPaint tmpPaint(fPaint);
        am.setPreConcat(fContext, translate, &tmpPaint);
        SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
        fContext->drawPath(tmpPaint, *glyph->fPath, stroke);
        return;
    }

HAS_ATLAS:
    SkASSERT(glyph->fPlot);
    GrDrawTarget::DrawToken drawToken = fDrawTarget->getCurrentDrawToken();
    glyph->fPlot->setDrawToken(drawToken);

    GrTexture* texture = glyph->fPlot->texture();
    SkASSERT(texture);

    if (fCurrTexture != texture || fCurrVertex + 4 > fMaxVertices) {
        this->flushGlyphs();
        fCurrTexture = texture;
        fCurrTexture->ref();
    }

    if (NULL == fVertices) {
       // If we need to reserve vertices allow the draw target to suggest
        // a number of verts to reserve and whether to perform a flush.
        fMaxVertices = kMinRequestedVerts;
        fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
            SK_ARRAY_COUNT(gTextVertexAttribs));
        bool flush = fDrawTarget->geometryHints(&fMaxVertices, NULL);
        if (flush) {
            this->flushGlyphs();
            fContext->flush();
            fDrawTarget->drawState()->setVertexAttribs<gTextVertexAttribs>(
                SK_ARRAY_COUNT(gTextVertexAttribs));
        }
        fMaxVertices = kDefaultRequestedVerts;
        // ignore return, no point in flushing again.
        fDrawTarget->geometryHints(&fMaxVertices, NULL);

        int maxQuadVertices = 4 * fContext->getQuadIndexBuffer()->maxQuads();
        if (fMaxVertices < kMinRequestedVerts) {
            fMaxVertices = kDefaultRequestedVerts;
        } else if (fMaxVertices > maxQuadVertices) {
            // don't exceed the limit of the index buffer
            fMaxVertices = maxQuadVertices;
        }
        bool success = fDrawTarget->reserveVertexAndIndexSpace(fMaxVertices,
                                                               0,
                                                               GrTCast<void**>(&fVertices),
                                                               NULL);
        GrAlwaysAssert(success);
        SkASSERT(2*sizeof(GrPoint) == fDrawTarget->getDrawState().getVertexSize());
    }

    SkScalar dx = SkIntToScalar(glyph->fBounds.fLeft);
    SkScalar dy = SkIntToScalar(glyph->fBounds.fTop);
    SkScalar width = SkIntToScalar(glyph->fBounds.width());
    SkScalar height = SkIntToScalar(glyph->fBounds.height());

    SkScalar scale = fTextRatio;
    dx *= scale;
    dy *= scale;
    sx += dx;
    sy += dy;
    width *= scale;
    height *= scale;

    GrFixed tx = SkIntToFixed(glyph->fAtlasLocation.fX);
    GrFixed ty = SkIntToFixed(glyph->fAtlasLocation.fY);
    GrFixed tw = SkIntToFixed(glyph->fBounds.width());
    GrFixed th = SkIntToFixed(glyph->fBounds.height());

    fVertices[2*fCurrVertex].setRectFan(sx,
                                        sy,
                                        sx + width,
                                        sy + height,
                                        2 * sizeof(SkPoint));
    fVertices[2*fCurrVertex+1].setRectFan(SkFixedToFloat(texture->normalizeFixedX(tx)),
                                          SkFixedToFloat(texture->normalizeFixedY(ty)),
                                          SkFixedToFloat(texture->normalizeFixedX(tx + tw)),
                                          SkFixedToFloat(texture->normalizeFixedY(ty + th)),
                                          2 * sizeof(SkPoint));
    fCurrVertex += 4;
}
Beispiel #16
0
static SkScalar FIXEDToSkScalar(FIXED fixed)
{
    SkFixed skFixed;
    memcpy(&skFixed, &fixed, sizeof(SkFixed));
    return SkFixedToScalar(skFixed);
}
Beispiel #17
0
GLuint SkGL::BindNewTexture(const SkBitmap& origBitmap, SkPoint* max) {
    SkBitmap tmpBitmap;
    const SkBitmap* bitmap = &origBitmap;

    if (needToPromoteTo32bit(origBitmap)) {
        origBitmap.copyTo(&tmpBitmap, SkBitmap::kARGB_8888_Config);
        // now bitmap points to our temp, which has been promoted to 32bits
        bitmap = &tmpBitmap;
    }

    GLenum format, type;
    if (!canBeTexture(*bitmap, &format, &type)) {
        return 0;
    }

    SkAutoLockPixels alp(*bitmap);
    if (!bitmap->readyToDraw()) {
        return 0;
    }

    GLuint  textureName;
    glGenTextures(1, &textureName);

    glBindTexture(GL_TEXTURE_2D, textureName);

    // express rowbytes as a number of pixels for ow
    int ow = bitmap->rowBytesAsPixels();
    int oh = bitmap->height();
    int nw = SkNextPow2(ow);
    int nh = SkNextPow2(oh);

    glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());

    // check if we need to scale to create power-of-2 dimensions
#ifdef SK_GL_SUPPORT_COMPRESSEDTEXIMAGE2D
    if (SkBitmap::kIndex8_Config == bitmap->config()) {
        size_t imagesize = bitmap->getSize() + SK_GL_SIZE_OF_PALETTE;
        SkAutoMalloc storage(imagesize);

        build_compressed_data(storage.get(), *bitmap);
        // we only support POW2 here (GLES 1.0 restriction)
        SkASSERT(ow == nw);
        SkASSERT(oh == nh);
        glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
                               imagesize, storage.get());
    } else  // fall through to non-compressed logic
#endif
    {
        if (ow != nw || oh != nh) {
            glTexImage2D(GL_TEXTURE_2D, 0, format, nw, nh, 0,
                         format, type, NULL);
            glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, ow, oh,
                            format, type, bitmap->getPixels());
        } else {
            // easy case, the bitmap is already pow2
            glTexImage2D(GL_TEXTURE_2D, 0, format, ow, oh, 0,
                         format, type, bitmap->getPixels());
        }
    }

#ifdef TRACE_TEXTURE_CREATION
    SkDebugf("--- new texture [%d] size=(%d %d) bpp=%d\n", textureName, ow, oh,
             bitmap->bytesPerPixel());
#endif

    if (max) {
        max->fX = SkFixedToScalar(bitmap->width() << (16 - SkNextLog2(nw)));
        max->fY = SkFixedToScalar(oh << (16 - SkNextLog2(nh)));
    }
    return textureName;
}
void GrDistanceFieldTextContext::onDrawPosText(GrRenderTarget* rt, const GrClip& clip,
                                               const GrPaint& paint,
                                               const SkPaint& skPaint, const SkMatrix& viewMatrix,
                                               const char text[], size_t byteLength,
                                               const SkScalar pos[], int scalarsPerPosition,
                                               const SkPoint& offset,
                                               const SkIRect& regionClipBounds) {

    SkASSERT(byteLength == 0 || text != NULL);
    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);

    // nothing to draw
    if (text == NULL || byteLength == 0 /* no raster clip? || fRC->isEmpty()*/) {
        return;
    }

    fViewMatrix = viewMatrix;
    this->init(rt, clip, paint, skPaint, regionClipBounds);

    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();

    SkAutoGlyphCacheNoGamma    autoCache(fSkPaint, &fDeviceProperties, NULL);
    SkGlyphCache*              cache = autoCache.getCache();
    GrFontScaler*              fontScaler = GetGrFontScaler(cache);

    int numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
    fTotalVertexCount = kVerticesPerGlyph*numGlyphs;

    const char*        stop = text + byteLength;
    SkTArray<char>     fallbackTxt;
    SkTArray<SkScalar> fallbackPos;

    if (SkPaint::kLeft_Align == fSkPaint.getTextAlign()) {
        while (text < stop) {
            const char* lastText = text;
            // the last 2 parameters are ignored
            const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);

            if (glyph.fWidth) {
                SkScalar x = offset.x() + pos[0];
                SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);

                if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
                                                     glyph.getSubXFixed(),
                                                     glyph.getSubYFixed(),
                                                     GrGlyph::kDistance_MaskStyle),
                                       x, y, fontScaler)) {
                    // couldn't append, send to fallback
                    fallbackTxt.push_back_n(SkToInt(text-lastText), lastText);
                    fallbackPos.push_back(pos[0]);
                    if (2 == scalarsPerPosition) {
                        fallbackPos.push_back(pos[1]);
                    }
                }
            }
            pos += scalarsPerPosition;
        }
    } else {
        SkScalar alignMul = SkPaint::kCenter_Align == fSkPaint.getTextAlign() ? SK_ScalarHalf
                                                                              : SK_Scalar1;
        while (text < stop) {
            const char* lastText = text;
            // the last 2 parameters are ignored
            const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);

            if (glyph.fWidth) {
                SkScalar x = offset.x() + pos[0];
                SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);

                SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX)*alignMul*fTextRatio;
                SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY)*alignMul*fTextRatio;

                if (!this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
                                                     glyph.getSubXFixed(),
                                                     glyph.getSubYFixed(),
                                                     GrGlyph::kDistance_MaskStyle),
                                       x - advanceX, y - advanceY, fontScaler)) {
                    // couldn't append, send to fallback
                    fallbackTxt.push_back_n(SkToInt(text-lastText), lastText);
                    fallbackPos.push_back(pos[0]);
                    if (2 == scalarsPerPosition) {
                        fallbackPos.push_back(pos[1]);
                    }
                }
            }
            pos += scalarsPerPosition;
        }
    }

    this->finish();
    
    if (fallbackTxt.count() > 0) {
        fFallbackTextContext->drawPosText(rt, clip, paint, skPaint, viewMatrix,
                                          fallbackTxt.begin(), fallbackTxt.count(),
                                          fallbackPos.begin(), scalarsPerPosition, offset,
                                          regionClipBounds);
    }
}
void GrStencilAndCoverTextContext::TextRun::setText(const char text[], size_t byteLength,
        SkScalar x, SkScalar y) {
    SkASSERT(byteLength == 0 || text != nullptr);

    SkGlyphCache* glyphCache = this->getGlyphCache();
    SkDrawCacheProc glyphCacheProc = fFont.getDrawCacheProc();

    fTotalGlyphCount = fFont.countText(text, byteLength);
    fInstanceData.reset(InstanceData::Alloc(GrPathRendering::kTranslate_PathTransformType,
                                            fTotalGlyphCount));

    const char* stop = text + byteLength;

    // Measure first if needed.
    if (fFont.getTextAlign() != SkPaint::kLeft_Align) {
        SkFixed    stopX = 0;
        SkFixed    stopY = 0;

        const char* textPtr = text;
        while (textPtr < stop) {
            // We don't need x, y here, since all subpixel variants will have the
            // same advance.
            const SkGlyph& glyph = glyphCacheProc(glyphCache, &textPtr, 0, 0);

            stopX += glyph.fAdvanceX;
            stopY += glyph.fAdvanceY;
        }
        SkASSERT(textPtr == stop);

        SkScalar alignX = SkFixedToScalar(stopX) * fTextRatio;
        SkScalar alignY = SkFixedToScalar(stopY) * fTextRatio;

        if (fFont.getTextAlign() == SkPaint::kCenter_Align) {
            alignX = SkScalarHalf(alignX);
            alignY = SkScalarHalf(alignY);
        }

        x -= alignX;
        y -= alignY;
    }

    SkAutoKern autokern;

    SkFixed fixedSizeRatio = SkScalarToFixed(fTextRatio);

    SkFixed fx = SkScalarToFixed(x);
    SkFixed fy = SkScalarToFixed(y);
    FallbackBlobBuilder fallback;
    while (text < stop) {
        const SkGlyph& glyph = glyphCacheProc(glyphCache, &text, 0, 0);
        fx += SkFixedMul(autokern.adjust(glyph), fixedSizeRatio);
        if (glyph.fWidth) {
            this->appendGlyph(glyph, SkPoint::Make(SkFixedToScalar(fx), SkFixedToScalar(fy)),
                              &fallback);
        }

        fx += SkFixedMul(glyph.fAdvanceX, fixedSizeRatio);
        fy += SkFixedMul(glyph.fAdvanceY, fixedSizeRatio);
    }

    fFallbackTextBlob.reset(fallback.buildIfNeeded(&fFallbackGlyphCount));
}
Beispiel #20
0
void GrTextUtils::DrawDFPosText(GrAtlasTextBlob* blob, int runIndex,
                                GrBatchFontCache* fontCache, const SkSurfaceProps& props,
                                const SkPaint& origPaint,
                                GrColor color, const SkMatrix& viewMatrix,
                                const char text[], size_t byteLength,
                                const SkScalar pos[], int scalarsPerPosition,
                                const SkPoint& offset) {
    SkASSERT(byteLength == 0 || text != nullptr);
    SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);

    // nothing to draw
    if (text == nullptr || byteLength == 0) {
        return;
    }

    SkTDArray<char> fallbackTxt;
    SkTDArray<SkScalar> fallbackPos;

    // Setup distance field paint and text ratio
    SkScalar textRatio;
    SkPaint dfPaint(origPaint);
    GrTextUtils::InitDistanceFieldPaint(blob, &dfPaint, &textRatio, viewMatrix);
    blob->setHasDistanceField();
    blob->setSubRunHasDistanceFields(runIndex, origPaint.isLCDRenderText());

    GrBatchTextStrike* currStrike = nullptr;

    SkGlyphCache* cache = blob->setupCache(runIndex, props, SkPaint::FakeGamma::Off,
                                           dfPaint, nullptr);
    SkPaint::GlyphCacheProc glyphCacheProc = dfPaint.getGlyphCacheProc(true);
    GrFontScaler* fontScaler = GrTextUtils::GetGrFontScaler(cache);

    const char* stop = text + byteLength;

    if (SkPaint::kLeft_Align == dfPaint.getTextAlign()) {
        while (text < stop) {
            const char* lastText = text;
            // the last 2 parameters are ignored
            const SkGlyph& glyph = glyphCacheProc(cache, &text);

            if (glyph.fWidth) {
                SkScalar x = offset.x() + pos[0];
                SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);

                if (!DfAppendGlyph(blob,
                                   runIndex,
                                   fontCache,
                                   &currStrike,
                                   glyph,
                                   x, y, color, fontScaler,
                                   textRatio, viewMatrix)) {
                    // couldn't append, send to fallback
                    fallbackTxt.append(SkToInt(text-lastText), lastText);
                    *fallbackPos.append() = pos[0];
                    if (2 == scalarsPerPosition) {
                        *fallbackPos.append() = pos[1];
                    }
                }
            }
            pos += scalarsPerPosition;
        }
    } else {
        SkScalar alignMul = SkPaint::kCenter_Align == dfPaint.getTextAlign() ? SK_ScalarHalf
                                                                             : SK_Scalar1;
        while (text < stop) {
            const char* lastText = text;
            // the last 2 parameters are ignored
            const SkGlyph& glyph = glyphCacheProc(cache, &text);

            if (glyph.fWidth) {
                SkScalar x = offset.x() + pos[0];
                SkScalar y = offset.y() + (2 == scalarsPerPosition ? pos[1] : 0);

                SkScalar advanceX = SkFixedToScalar(glyph.fAdvanceX) * alignMul * textRatio;
                SkScalar advanceY = SkFixedToScalar(glyph.fAdvanceY) * alignMul * textRatio;

                if (!DfAppendGlyph(blob,
                                   runIndex,
                                   fontCache,
                                   &currStrike,
                                   glyph,
                                   x - advanceX, y - advanceY, color,
                                   fontScaler,
                                   textRatio,
                                   viewMatrix)) {
                    // couldn't append, send to fallback
                    fallbackTxt.append(SkToInt(text-lastText), lastText);
                    *fallbackPos.append() = pos[0];
                    if (2 == scalarsPerPosition) {
                        *fallbackPos.append() = pos[1];
                    }
                }
            }
            pos += scalarsPerPosition;
        }
    }

    SkGlyphCache::AttachCache(cache);
    if (fallbackTxt.count()) {
        blob->initOverride(runIndex);
        GrTextUtils::DrawBmpPosText(blob, runIndex, fontCache, props,
                                    origPaint, origPaint.getColor(), viewMatrix,
                                    fallbackTxt.begin(), fallbackTxt.count(),
                                    fallbackPos.begin(), scalarsPerPosition, offset);
    }
}
Beispiel #21
0
void GrTextUtils::DrawDFText(GrAtlasTextBlob* blob, int runIndex,
                             GrBatchFontCache* fontCache, const SkSurfaceProps& props,
                             const SkPaint& skPaint, GrColor color,
                             const SkMatrix& viewMatrix,
                             const char text[], size_t byteLength,
                             SkScalar x, SkScalar y) {
    SkASSERT(byteLength == 0 || text != nullptr);

    // nothing to draw
    if (text == nullptr || byteLength == 0) {
        return;
    }

    SkPaint::GlyphCacheProc glyphCacheProc = skPaint.getGlyphCacheProc(true);
    SkAutoDescriptor desc;
    skPaint.getScalerContextDescriptor(&desc, props, SkPaint::FakeGamma::Off, nullptr);
    SkGlyphCache* origPaintCache = SkGlyphCache::DetachCache(skPaint.getTypeface(),
                                                             desc.getDesc());

    SkTArray<SkScalar> positions;

    const char* textPtr = text;
    SkFixed stopX = 0;
    SkFixed stopY = 0;
    SkFixed origin = 0;
    switch (skPaint.getTextAlign()) {
        case SkPaint::kRight_Align: origin = SK_Fixed1; break;
        case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
        case SkPaint::kLeft_Align: origin = 0; break;
    }

    SkAutoKern autokern;
    const char* stop = text + byteLength;
    while (textPtr < stop) {
        // don't need x, y here, since all subpixel variants will have the
        // same advance
        const SkGlyph& glyph = glyphCacheProc(origPaintCache, &textPtr);

        SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
        positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));

        SkFixed height = glyph.fAdvanceY;
        positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)));

        stopX += width;
        stopY += height;
    }
    SkASSERT(textPtr == stop);

    SkGlyphCache::AttachCache(origPaintCache);

    // now adjust starting point depending on alignment
    SkScalar alignX = SkFixedToScalar(stopX);
    SkScalar alignY = SkFixedToScalar(stopY);
    if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
        alignX = SkScalarHalf(alignX);
        alignY = SkScalarHalf(alignY);
    } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
        alignX = 0;
        alignY = 0;
    }
    x -= alignX;
    y -= alignY;
    SkPoint offset = SkPoint::Make(x, y);

    DrawDFPosText(blob, runIndex, fontCache, props, skPaint, color, viewMatrix, text, byteLength,
                  positions.begin(), 2, offset);
}
static sk_sp<GrTextureProxy> create_profile_texture(GrProxyProvider* proxyProvider,
                                                    const SkRect& circle, float sigma,
                                                    float* solidRadius, float* textureRadius) {
    float circleR = circle.width() / 2.0f;
    if (circleR < SK_ScalarNearlyZero) {
        return nullptr;
    }
    // Profile textures are cached by the ratio of sigma to circle radius and by the size of the
    // profile texture (binned by powers of 2).
    SkScalar sigmaToCircleRRatio = sigma / circleR;
    // When sigma is really small this becomes a equivalent to convolving a Gaussian with a
    // half-plane. Similarly, in the extreme high ratio cases circle becomes a point WRT to the
    // Guassian and the profile texture is a just a Gaussian evaluation. However, we haven't yet
    // implemented this latter optimization.
    sigmaToCircleRRatio = SkTMin(sigmaToCircleRRatio, 8.f);
    SkFixed sigmaToCircleRRatioFixed;
    static const SkScalar kHalfPlaneThreshold = 0.1f;
    bool useHalfPlaneApprox = false;
    if (sigmaToCircleRRatio <= kHalfPlaneThreshold) {
        useHalfPlaneApprox = true;
        sigmaToCircleRRatioFixed = 0;
        *solidRadius = circleR - 3 * sigma;
        *textureRadius = 6 * sigma;
    } else {
        // Convert to fixed point for the key.
        sigmaToCircleRRatioFixed = SkScalarToFixed(sigmaToCircleRRatio);
        // We shave off some bits to reduce the number of unique entries. We could probably
        // shave off more than we do.
        sigmaToCircleRRatioFixed &= ~0xff;
        sigmaToCircleRRatio = SkFixedToScalar(sigmaToCircleRRatioFixed);
        sigma = circleR * sigmaToCircleRRatio;
        *solidRadius = 0;
        *textureRadius = circleR + 3 * sigma;
    }

    static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
    GrUniqueKey key;
    GrUniqueKey::Builder builder(&key, kDomain, 1);
    builder[0] = sigmaToCircleRRatioFixed;
    builder.finish();

    sk_sp<GrTextureProxy> blurProfile =
            proxyProvider->findOrCreateProxyByUniqueKey(key, kTopLeft_GrSurfaceOrigin);
    if (!blurProfile) {
        static constexpr int kProfileTextureWidth = 512;
        GrSurfaceDesc texDesc;
        texDesc.fOrigin = kTopLeft_GrSurfaceOrigin;
        texDesc.fWidth = kProfileTextureWidth;
        texDesc.fHeight = 1;
        texDesc.fConfig = kAlpha_8_GrPixelConfig;

        std::unique_ptr<uint8_t[]> profile(nullptr);
        if (useHalfPlaneApprox) {
            profile.reset(create_half_plane_profile(kProfileTextureWidth));
        } else {
            // Rescale params to the size of the texture we're creating.
            SkScalar scale = kProfileTextureWidth / *textureRadius;
            profile.reset(
                    create_circle_profile(sigma * scale, circleR * scale, kProfileTextureWidth));
        }

        blurProfile =
                proxyProvider->createTextureProxy(texDesc, SkBudgeted::kYes, profile.get(), 0);
        if (!blurProfile) {
            return nullptr;
        }

        SkASSERT(blurProfile->origin() == kTopLeft_GrSurfaceOrigin);
        proxyProvider->assignUniqueKeyToProxy(key, blurProfile.get());
    }

    return blurProfile;
}
Beispiel #23
0
void GrBitmapTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
                                     const GrPaint& paint, const SkPaint& skPaint,
                                     const SkMatrix& viewMatrix,
                                     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;
    }

    this->init(rt, clip, paint, skPaint);

    SkDrawCacheProc glyphCacheProc = fSkPaint.getDrawCacheProc();

    SkAutoGlyphCache    autoCache(fSkPaint, &fDeviceProperties, &viewMatrix);
    SkGlyphCache*       cache = autoCache.getCache();
    GrFontScaler*       fontScaler = GetGrFontScaler(cache);

    // transform our starting point
    {
        SkPoint loc;
        viewMatrix.mapXY(x, y, &loc);
        x = loc.fX;
        y = loc.fY;
    }

    // need to measure first
    int numGlyphs;
    if (fSkPaint.getTextAlign() != SkPaint::kLeft_Align) {
        SkVector    stopVector;
        numGlyphs = MeasureText(cache, glyphCacheProc, text, byteLength, &stopVector);

        SkScalar    stopX = stopVector.fX;
        SkScalar    stopY = stopVector.fY;

        if (fSkPaint.getTextAlign() == SkPaint::kCenter_Align) {
            stopX = SkScalarHalf(stopX);
            stopY = SkScalarHalf(stopY);
        }
        x -= stopX;
        y -= stopY;
    } else {
        numGlyphs = fSkPaint.textToGlyphs(text, byteLength, NULL);
    }
    fTotalVertexCount = kVerticesPerGlyph*numGlyphs;

    const char* stop = text + byteLength;

    SkAutoKern autokern;

    SkFixed fxMask = ~0;
    SkFixed fyMask = ~0;
    SkScalar halfSampleX, halfSampleY;
    if (cache->isSubpixel()) {
        halfSampleX = halfSampleY = SkFixedToScalar(SkGlyph::kSubpixelRound);
        SkAxisAlignment baseline = SkComputeAxisAlignmentForHText(viewMatrix);
        if (kX_SkAxisAlignment == baseline) {
            fyMask = 0;
            halfSampleY = SK_ScalarHalf;
        } else if (kY_SkAxisAlignment == baseline) {
            fxMask = 0;
            halfSampleX = SK_ScalarHalf;
        }
    } else {
        halfSampleX = halfSampleY = SK_ScalarHalf;
    }

    Sk48Dot16 fx = SkScalarTo48Dot16(x + halfSampleX);
    Sk48Dot16 fy = SkScalarTo48Dot16(y + halfSampleY);

    // if we have RGB, then we won't have any SkShaders so no need to use a localmatrix, but for
    // performance reasons we just invert here instead
    if (!viewMatrix.invert(&fLocalMatrix)) {
        SkDebugf("Cannot invert viewmatrix\n");
        return;
    }

    while (text < stop) {
        const SkGlyph& glyph = glyphCacheProc(cache, &text, fx & fxMask, fy & fyMask);

        fx += autokern.adjust(glyph);

        if (glyph.fWidth) {
            this->appendGlyph(GrGlyph::Pack(glyph.getGlyphID(),
                                            glyph.getSubXFixed(),
                                            glyph.getSubYFixed(),
                                            GrGlyph::kCoverage_MaskStyle),
                              Sk48Dot16FloorToInt(fx),
                              Sk48Dot16FloorToInt(fy),
                              fontScaler);
        }

        fx += glyph.fAdvanceX;
        fy += glyph.fAdvanceY;
    }

    this->finish();
}
void GrDistanceFieldTextContext::onDrawText(GrRenderTarget* rt, const GrClip& clip,
                                            const GrPaint& paint,
                                            const SkPaint& skPaint, const SkMatrix& viewMatrix,
                                            const char text[], size_t byteLength,
                                            SkScalar x, SkScalar y,
                                            const SkIRect& regionClipBounds) {
    SkASSERT(byteLength == 0 || text != NULL);

    // nothing to draw
    if (text == NULL || byteLength == 0) {
        return;
    }

    fViewMatrix = viewMatrix;
    SkDrawCacheProc          glyphCacheProc = skPaint.getDrawCacheProc();
    SkAutoGlyphCache         autoCache(skPaint, &fDeviceProperties, NULL);
    SkGlyphCache*            cache = autoCache.getCache();

    SkTArray<SkScalar> positions;

    const char* textPtr = text;
    SkFixed stopX = 0;
    SkFixed stopY = 0;
    SkFixed origin;
    switch (skPaint.getTextAlign()) {
        case SkPaint::kRight_Align: origin = SK_Fixed1; break;
        case SkPaint::kCenter_Align: origin = SK_FixedHalf; break;
        case SkPaint::kLeft_Align: origin = 0; break;
        default: SkFAIL("Invalid paint origin"); return;
    }

    SkAutoKern autokern;
    const char* stop = text + byteLength;
    while (textPtr < stop) {
        // don't need x, y here, since all subpixel variants will have the
        // same advance
        const SkGlyph& glyph = glyphCacheProc(cache, &textPtr, 0, 0);

        SkFixed width = glyph.fAdvanceX + autokern.adjust(glyph);
        positions.push_back(SkFixedToScalar(stopX + SkFixedMul(origin, width)));

        SkFixed height = glyph.fAdvanceY;
        positions.push_back(SkFixedToScalar(stopY + SkFixedMul(origin, height)));

        stopX += width;
        stopY += height;
    }
    SkASSERT(textPtr == stop);

    // now adjust starting point depending on alignment
    SkScalar alignX = SkFixedToScalar(stopX);
    SkScalar alignY = SkFixedToScalar(stopY);
    if (skPaint.getTextAlign() == SkPaint::kCenter_Align) {
        alignX = SkScalarHalf(alignX);
        alignY = SkScalarHalf(alignY);
    } else if (skPaint.getTextAlign() == SkPaint::kLeft_Align) {
        alignX = 0;
        alignY = 0;
    }
    x -= alignX;
    y -= alignY;
    SkPoint offset = SkPoint::Make(x, y);

    this->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, positions.begin(),
                        2, offset, regionClipBounds);
}