GrTextContext.cpp revision 6e8cd9671958c69babde9338c5c18a4c3d895575
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2010 Google Inc.
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
6ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com */
7ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com
8375ff85e96cf0f8438ea0b11be67e85474e42c29tomhudson@google.com#include "GrTextContext.h"
9e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org#include "GrContext.h"
10570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt#include "GrDrawTarget.h"
11570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt#include "GrFontScaler.h"
12e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org
13e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org#include "SkAutoKern.h"
146e8cd9671958c69babde9338c5c18a4c3d895575joshualitt#include "SkDrawProcs.h"
15e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org#include "SkGlyphCache.h"
166e8cd9671958c69babde9338c5c18a4c3d895575joshualitt#include "SkGpuDevice.h"
176e8cd9671958c69babde9338c5c18a4c3d895575joshualitt#include "SkTextMapStateProc.h"
186e8cd9671958c69babde9338c5c18a4c3d895575joshualitt#include "SkTextToPathIter.h"
196e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
206e8cd9671958c69babde9338c5c18a4c3d895575joshualittGrTextContext::GrTextContext(GrContext* context, SkGpuDevice* gpuDevice,
216e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                             const SkDeviceProperties& properties)
226e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    : fFallbackTextContext(NULL)
236e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    , fContext(context)
246e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    , fGpuDevice(gpuDevice)
256e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    , fDeviceProperties(properties)
266e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    , fDrawTarget(NULL) {
27cbbc481e918c0d32454455626235f67106f216a1commit-bot@chromium.org}
28375ff85e96cf0f8438ea0b11be67e85474e42c29tomhudson@google.com
298c27a188a0b216021d439eb627622d17b9f78343jvanverthGrTextContext::~GrTextContext() {
308c27a188a0b216021d439eb627622d17b9f78343jvanverth    SkDELETE(fFallbackTextContext);
318c27a188a0b216021d439eb627622d17b9f78343jvanverth}
328c27a188a0b216021d439eb627622d17b9f78343jvanverth
33570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualittvoid GrTextContext::init(GrRenderTarget* rt, const GrClip& clip, const GrPaint& grPaint,
346e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                         const SkPaint& skPaint, const SkIRect& regionClipBounds) {
35570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    fClip = clip;
36beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com
3725d9c154087d2132a51d1ca74a104726f60ef380joshualitt    fRenderTarget.reset(SkRef(rt));
3825d9c154087d2132a51d1ca74a104726f60ef380joshualitt
396e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    fRegionClipBounds = regionClipBounds;
40570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt    fClip.getConservativeBounds(fRenderTarget->width(), fRenderTarget->height(), &fClipRect);
41beb1af78d016d2700c350487a383c6bcfa7e2e20robertphillips@google.com
42cbbc481e918c0d32454455626235f67106f216a1commit-bot@chromium.org    fDrawTarget = fContext->getTextTarget();
43cbbc481e918c0d32454455626235f67106f216a1commit-bot@chromium.org
44cbbc481e918c0d32454455626235f67106f216a1commit-bot@chromium.org    fPaint = grPaint;
45cbbc481e918c0d32454455626235f67106f216a1commit-bot@chromium.org    fSkPaint = skPaint;
46ac10a2d039c5d52eed66e27cbbc503ab523c1cd5reed@google.com}
47e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org
486e8cd9671958c69babde9338c5c18a4c3d895575joshualittvoid GrTextContext::drawText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint,
49570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                             const SkPaint& skPaint, const SkMatrix& viewMatrix,
508c27a188a0b216021d439eb627622d17b9f78343jvanverth                             const char text[], size_t byteLength,
516e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                             SkScalar x, SkScalar y, const SkIRect& clipBounds) {
525f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt    if (!fContext->getTextTarget()) {
536e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        return;
545f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt    }
558c27a188a0b216021d439eb627622d17b9f78343jvanverth
56aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth    GrTextContext* textContext = this;
57aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth    do {
585531d51ce7426bdae7563547326fcf0bf926a083joshualitt        if (textContext->canDraw(skPaint, viewMatrix)) {
596e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            textContext->onDrawText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, x, y,
606e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                    clipBounds);
616e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            return;
62aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth        }
63aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth        textContext = textContext->fFallbackTextContext;
64aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth    } while (textContext);
65aab626c3670205d02ca42bb34a540f550cb75dc2jvanverth
666e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    // fall back to drawing as a path
676e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    this->drawTextAsPath(skPaint, viewMatrix, text, byteLength, x, y, clipBounds);
688c27a188a0b216021d439eb627622d17b9f78343jvanverth}
698c27a188a0b216021d439eb627622d17b9f78343jvanverth
706e8cd9671958c69babde9338c5c18a4c3d895575joshualittvoid GrTextContext::drawPosText(GrRenderTarget* rt, const GrClip& clip, const GrPaint& paint,
71570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt                                const SkPaint& skPaint, const SkMatrix& viewMatrix,
728c27a188a0b216021d439eb627622d17b9f78343jvanverth                                const char text[], size_t byteLength,
738c27a188a0b216021d439eb627622d17b9f78343jvanverth                                const SkScalar pos[], int scalarsPerPosition,
746e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                const SkPoint& offset, const SkIRect& clipBounds) {
755f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt    if (!fContext->getTextTarget()) {
766e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        return;
775f5a8d7599b8e248633ac122294b7a01401fedcbjoshualitt    }
788c27a188a0b216021d439eb627622d17b9f78343jvanverth
798c27a188a0b216021d439eb627622d17b9f78343jvanverth    GrTextContext* textContext = this;
808c27a188a0b216021d439eb627622d17b9f78343jvanverth    do {
815531d51ce7426bdae7563547326fcf0bf926a083joshualitt        if (textContext->canDraw(skPaint, viewMatrix)) {
82570d2f81a65fc868d6300a7edf34c0d5d048c5d6joshualitt            textContext->onDrawPosText(rt, clip, paint, skPaint, viewMatrix, text, byteLength, pos,
836e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                       scalarsPerPosition, offset, clipBounds);
846e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            return;
858c27a188a0b216021d439eb627622d17b9f78343jvanverth        }
868c27a188a0b216021d439eb627622d17b9f78343jvanverth        textContext = textContext->fFallbackTextContext;
878c27a188a0b216021d439eb627622d17b9f78343jvanverth    } while (textContext);
888c27a188a0b216021d439eb627622d17b9f78343jvanverth
896e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    // fall back to drawing as a path
906e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    this->drawPosTextAsPath(skPaint, viewMatrix, text, byteLength, pos, scalarsPerPosition, offset,
916e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                            clipBounds);
928c27a188a0b216021d439eb627622d17b9f78343jvanverth}
938c27a188a0b216021d439eb627622d17b9f78343jvanverth
946e8cd9671958c69babde9338c5c18a4c3d895575joshualittvoid GrTextContext::drawTextAsPath(const SkPaint& skPaint, const SkMatrix& viewMatrix,
956e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                   const char text[], size_t byteLength, SkScalar x, SkScalar y,
966e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                   const SkIRect& clipBounds) {
976e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkTextToPathIter iter(text, byteLength, skPaint, true);
986e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
996e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkMatrix    matrix;
1006e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    matrix.setScale(iter.getPathScale(), iter.getPathScale());
1016e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    matrix.postTranslate(x, y);
1026e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1036e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    const SkPath* iterPath;
1046e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkScalar xpos, prevXPos = 0;
1056e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1066e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    while (iter.next(&iterPath, &xpos)) {
1076e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        matrix.postTranslate(xpos - prevXPos, 0);
1086e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        if (iterPath) {
1096e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            const SkPaint& pnt = iter.getPaint();
1106e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            fGpuDevice->internalDrawPath(*iterPath, pnt, viewMatrix, &matrix, clipBounds, false);
1116e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        }
1126e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        prevXPos = xpos;
1136e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    }
1146e8cd9671958c69babde9338c5c18a4c3d895575joshualitt}
1156e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1166e8cd9671958c69babde9338c5c18a4c3d895575joshualittvoid GrTextContext::drawPosTextAsPath(const SkPaint& origPaint, const SkMatrix& viewMatrix,
1176e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                      const char text[], size_t byteLength,
1186e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                      const SkScalar pos[], int scalarsPerPosition,
1196e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                                      const SkPoint& offset, const SkIRect& clipBounds) {
1206e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    // setup our std paint, in hopes of getting hits in the cache
1216e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkPaint paint(origPaint);
1226e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkScalar matrixScale = paint.setupForAsPaths();
1236e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1246e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkMatrix matrix;
1256e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    matrix.setScale(matrixScale, matrixScale);
1266e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1276e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1286e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    paint.setStyle(SkPaint::kFill_Style);
1296e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    paint.setPathEffect(NULL);
1306e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1316e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkDrawCacheProc     glyphCacheProc = paint.getDrawCacheProc();
1326e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkAutoGlyphCache    autoCache(paint, NULL, NULL);
1336e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkGlyphCache*       cache = autoCache.getCache();
1346e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1356e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    const char*        stop = text + byteLength;
1366e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkTextAlignProc    alignProc(paint.getTextAlign());
1376e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1386e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1396e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    // Now restore the original settings, so we "draw" with whatever style/stroking.
1406e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    paint.setStyle(origPaint.getStyle());
1416e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    paint.setPathEffect(origPaint.getPathEffect());
1426e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1436e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    while (text < stop) {
1446e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1456e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        if (glyph.fWidth) {
1466e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            const SkPath* path = cache->findPath(glyph);
1476e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            if (path) {
1486e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                SkPoint tmsLoc;
1496e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                tmsProc(pos, &tmsLoc);
1506e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                SkPoint loc;
1516e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                alignProc(tmsLoc, glyph, &loc);
1526e8cd9671958c69babde9338c5c18a4c3d895575joshualitt
1536e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                matrix[SkMatrix::kMTransX] = loc.fX;
1546e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                matrix[SkMatrix::kMTransY] = loc.fY;
1556e8cd9671958c69babde9338c5c18a4c3d895575joshualitt                fGpuDevice->internalDrawPath(*path, paint, viewMatrix, &matrix, clipBounds, false);
1566e8cd9671958c69babde9338c5c18a4c3d895575joshualitt            }
1576e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        }
1586e8cd9671958c69babde9338c5c18a4c3d895575joshualitt        pos += scalarsPerPosition;
1596e8cd9671958c69babde9338c5c18a4c3d895575joshualitt    }
1606e8cd9671958c69babde9338c5c18a4c3d895575joshualitt}
1618c27a188a0b216021d439eb627622d17b9f78343jvanverth
162e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org//*** change to output positions?
16373f105345066b1f22f15ba6575cb3800dd9313b8jvanverthint GrTextContext::MeasureText(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
164e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org                                const char text[], size_t byteLength, SkVector* stopVector) {
165e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    SkFixed     x = 0, y = 0;
166e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    const char* stop = text + byteLength;
167e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
168e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    SkAutoKern  autokern;
169e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
17073f105345066b1f22f15ba6575cb3800dd9313b8jvanverth    int numGlyphs = 0;
171e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    while (text < stop) {
172e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        // don't need x, y here, since all subpixel variants will have the
173e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        // same advance
174e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
175e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
176e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        x += autokern.adjust(glyph) + glyph.fAdvanceX;
177e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        y += glyph.fAdvanceY;
17873f105345066b1f22f15ba6575cb3800dd9313b8jvanverth        ++numGlyphs;
179e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    }
180e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
181e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
182e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    SkASSERT(text == stop);
18373f105345066b1f22f15ba6575cb3800dd9313b8jvanverth
18473f105345066b1f22f15ba6575cb3800dd9313b8jvanverth    return numGlyphs;
185e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org}
186e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org
187e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.orgstatic void GlyphCacheAuxProc(void* data) {
188e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    GrFontScaler* scaler = (GrFontScaler*)data;
189e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    SkSafeUnref(scaler);
190e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org}
191e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org
192e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.orgGrFontScaler* GrTextContext::GetGrFontScaler(SkGlyphCache* cache) {
193e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    void* auxData;
194e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    GrFontScaler* scaler = NULL;
195e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
196e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    if (cache->getAuxProcData(GlyphCacheAuxProc, &auxData)) {
197e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        scaler = (GrFontScaler*)auxData;
198e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    }
199e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    if (NULL == scaler) {
200733f5f5dbca10fc6385ec3c77b3e9ff78227dac7jvanverth        scaler = SkNEW_ARGS(GrFontScaler, (cache));
201e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org        cache->setAuxProc(GlyphCacheAuxProc, scaler);
202e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    }
203e5d7015cde3b6f2a3929b8e378822e3d7be223d4skia.committer@gmail.com
204e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org    return scaler;
205e8612d9a8d616c2ed0195421a0675e10b0c2d230commit-bot@chromium.org}
206