1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScalerContext.h"
11c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org#include "SkColorPriv.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkDescriptor.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkDraw.h"
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFontHost.h"
151ef6e7aa2ca040bc9a47708d832f21e22ae474acbungeman@google.com#include "SkGlyph.h"
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkMaskFilter.h"
178ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com#include "SkMaskGamma.h"
18d02e825bf79c38dad5fb7c02dfc301ad4dfabeaadjsollen@google.com#include "SkOrderedReadBuffer.h"
19b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com#include "SkOrderedWriteBuffer.h"
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPathEffect.h"
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkRasterizer.h"
2226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#include "SkRasterClip.h"
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkStroke.h"
24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkThread.h"
25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
26cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com#ifdef SK_BUILD_FOR_ANDROID
27cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com    #include "SkTypeface_android.h"
28cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com#endif
2918723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com
30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkGlyph::toMask(SkMask* mask) const {
33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(mask);
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask->fImage = (uint8_t*)fImage;
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask->fRowBytes = this->rowBytes();
3817f6e4bba20b6542cdf0a4fb0442a7f330003ee4reed@android.com    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comsize_t SkGlyph::computeImageSize() const {
42c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org    const size_t size = this->rowBytes() * fHeight;
43c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org
44c775c0b52526f14d8c82896c4dc654f4e5268f42agl@chromium.org    switch (fMaskFormat) {
4502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        case SkMask::k3D_Format:
4602a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            return 3 * size;
4702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        default:
4802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            return size;
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
52efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comvoid SkGlyph::zeroMetrics() {
53efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fAdvanceX = 0;
54efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fAdvanceY = 0;
55efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fWidth    = 0;
56efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fHeight   = 0;
57efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fTop      = 0;
58efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fLeft     = 0;
59efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fRsbDelta = 0;
60efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    fLsbDelta = 0;
61efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com}
62efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com
63efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com///////////////////////////////////////////////////////////////////////////////
64efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    #define DUMP_RECx
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag) {
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkFlattenable*  obj = NULL;
71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t        len;
72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const void*     data = desc->findEntry(tag, &len);
73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (data) {
75d02e825bf79c38dad5fb7c02dfc301ad4dfabeaadjsollen@google.com        SkOrderedReadBuffer   buffer(data, len);
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        obj = buffer.readFlattenable();
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(buffer.offset() == buffer.size());
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return obj;
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
828e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.comSkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc)
838ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
84ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
858ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fBaseGlyphCount(0)
868e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    , fTypeface(SkRef(typeface))
878ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag)))
888ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag)))
898ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag)))
90ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
91ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com      // Initialize based on our settings. Subclasses can also force this.
928ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
93ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
948ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com    , fNextContext(NULL)
95ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
96ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
97ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
98ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                                     : SkMaskGamma::PreBlend())
99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com{
100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef DUMP_REC
101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    desc->assertChecksum();
10202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    SkDebugf("SkScalarContext checksum %x count %d length %d\n",
10302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com             desc->getChecksum(), desc->getCount(), desc->getLength());
104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        rec->fMaskFormat, rec->fStrokeJoin);
11002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    SkDebugf("  pathEffect %x maskFilter %x\n",
11102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
1143a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org#ifdef SK_BUILD_FOR_ANDROID
1153a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org    uint32_t len;
1163a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org    const void* data = desc->findEntry(kAndroidOpts_SkDescriptorTag, &len);
1173a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org    if (data) {
1183a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org        SkOrderedReadBuffer buffer(data, len);
1193a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org        fPaintOptionsAndroid.unflatten(buffer);
1203a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org        SkASSERT(buffer.offset() == buffer.size());
1213a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org    }
1223a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org#endif
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSkScalerContext::~SkScalerContext() {
1267f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    SkDELETE(fNextContext);
1277f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com
128919114813d58933c9d9433b141e0222c34b700b1reed@google.com    SkSafeUnref(fPathEffect);
129919114813d58933c9d9433b141e0222c34b700b1reed@google.com    SkSafeUnref(fMaskFilter);
130919114813d58933c9d9433b141e0222c34b700b1reed@google.com    SkSafeUnref(fRasterizer);
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1338e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com// Return the context associated with the next logical typeface, or NULL if
1348e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com// there are no more entries in the fallback chain.
1357c91f91079e4350bf43a571255ab014f033c786areed@google.comSkScalerContext* SkScalerContext::allocNextContext() const {
1365d7697907f9ff73a88f47c70715564b23178524breed@google.com#ifdef SK_BUILD_FOR_ANDROID
137cc7164e248610379e481bcb5ab8f6bd52007cb49reed@google.com    SkTypeface* newFace = SkAndroidNextLogicalTypeface(fRec.fFontID,
1383a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org                                                       fRec.fOrigFontID,
1393a2896926de7270052847f19fa69135c08e1a36fcommit-bot@chromium.org                                                       fPaintOptionsAndroid);
1408e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    if (0 == newFace) {
1417f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        return NULL;
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
143cc8868bd44e24dd8a5f44dd02263e02b836d9b6fskia.committer@gmail.com
1448e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    SkAutoTUnref<SkTypeface> aur(newFace);
1458e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    uint32_t newFontID = newFace->uniqueID();
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
147b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com    SkOrderedWriteBuffer androidBuffer(128);
148b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com    fPaintOptionsAndroid.flatten(androidBuffer);
149b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com
150b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com    SkAutoDescriptor    ad(sizeof(fRec) + androidBuffer.size() + SkDescriptor::ComputeOverhead(2));
1517f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    SkDescriptor*       desc = ad.getDesc();
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
1537f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    desc->init();
1547f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    SkScalerContext::Rec* newRec =
1557f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    (SkScalerContext::Rec*)desc->addEntry(kRec_SkDescriptorTag,
1567c91f91079e4350bf43a571255ab014f033c786areed@google.com                                          sizeof(fRec), &fRec);
157b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com    androidBuffer.writeToMemory(desc->addEntry(kAndroidOpts_SkDescriptorTag,
158b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com                                               androidBuffer.size(), NULL));
159b0565b5b69b975e16cfd982ed9e2fab3dab8072cdjsollen@google.com
1607f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    newRec->fFontID = newFontID;
1617f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    desc->computeChecksum();
1627f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com
1638e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    return newFace->createScalerContext(desc);
1645d7697907f9ff73a88f47c70715564b23178524breed@google.com#else
1655d7697907f9ff73a88f47c70715564b23178524breed@google.com    return NULL;
1665d7697907f9ff73a88f47c70715564b23178524breed@google.com#endif
1677f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com}
1687f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com
1697f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com/*  Return the next context, creating it if its not already created, but return
1707f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    NULL if the fonthost says there are no more fonts to fallback to.
1717f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com */
1727f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comSkScalerContext* SkScalerContext::getNextContext() {
1737f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    SkScalerContext* next = fNextContext;
1747f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    // if next is null, then either it isn't cached yet, or we're at the
1757f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    // end of our possible chain
1767f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    if (NULL == next) {
1777c91f91079e4350bf43a571255ab014f033c786areed@google.com        next = this->allocNextContext();
1787f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        if (NULL == next) {
1797f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com            return NULL;
180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
1817f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        // next's base is our base + our local count
1827f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        next->setBaseGlyphCount(fBaseGlyphCount + this->getGlyphCount());
1837f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        // cache the answer
1847f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        fNextContext = next;
185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
1867f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    return next;
1877f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com}
1887f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com
1897f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comSkScalerContext* SkScalerContext::getGlyphContext(const SkGlyph& glyph) {
1907f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    unsigned glyphID = glyph.getGlyphID();
1917f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    SkScalerContext* ctx = this;
1927f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    for (;;) {
1937f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        unsigned count = ctx->getGlyphCount();
1947f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        if (glyphID < count) {
1957f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com            break;
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
1977f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        glyphID -= count;
1987f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        ctx = ctx->getNextContext();
1997f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        if (NULL == ctx) {
2005e1d374692c567a07696f9452c6e7024b5c69262scroggo@google.com//            SkDebugf("--- no context for glyph %x\n", glyph.getGlyphID());
2017f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com            // just return the original context (this)
2027f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com            return this;
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2057f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    return ctx;
206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
207bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
20833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.comSkScalerContext* SkScalerContext::getContextFromChar(SkUnichar uni,
20933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com                                                     uint16_t* glyphID) {
21033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    SkScalerContext* ctx = this;
21133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    for (;;) {
21233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        const uint16_t glyph = ctx->generateCharToGlyph(uni);
21333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        if (glyph) {
21433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com            if (NULL != glyphID) {
21533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com                *glyphID = glyph;
21633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com            }
21733845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com            break;  // found it
21833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        }
21933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        ctx = ctx->getNextContext();
22033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        if (NULL == ctx) {
22133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com            return NULL;
22233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        }
22333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    }
22433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    return ctx;
22533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com}
22633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com
227f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#ifdef SK_BUILD_FOR_ANDROID
22833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.comSkFontID SkScalerContext::findTypefaceIdForChar(SkUnichar uni) {
22933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
23033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    if (NULL != ctx) {
23133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        return ctx->fRec.fFontID;
23233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    } else {
23333845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        return 0;
23433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    }
23533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com}
23633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com
237f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com/*  This loops through all available fallback contexts (if needed) until it
238f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    finds some context that can handle the unichar and return it.
239f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com
240f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    As this is somewhat expensive operation, it should only be done on the first
241f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    char of a run.
242f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com */
243f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.comunsigned SkScalerContext::getBaseGlyphCount(SkUnichar uni) {
24433845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    SkScalerContext* ctx = this->getContextFromChar(uni, NULL);
24533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    if (NULL != ctx) {
24633845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        return ctx->fBaseGlyphCount;
24733845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    } else {
24833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        SkDEBUGF(("--- no context for char %x\n", uni));
24933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        return this->fBaseGlyphCount;
250f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com    }
251f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com}
252f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com#endif
253f2e6b589ab62dc52807e27d02fed14d0bd77e82fdjsollen@google.com
2547f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com/*  This loops through all available fallback contexts (if needed) until it
2557f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    finds some context that can handle the unichar. If all fail, returns 0
2567f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com */
2577f78761dbe9c208f0763a39d94c44dcf602a182breed@android.comuint16_t SkScalerContext::charToGlyphID(SkUnichar uni) {
25833845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com
25933845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    uint16_t tempID;
26033845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    SkScalerContext* ctx = this->getContextFromChar(uni, &tempID);
26133845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    if (NULL == ctx) {
26233845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com        return 0; // no more contexts, return missing glyph
263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
2647f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    // add the ctx's base, making glyphID unique for chain of contexts
26533845832e136c8d77dae6887fb58c2a15c32d789djsollen@google.com    unsigned glyphID = tempID + ctx->fBaseGlyphCount;
2667f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    // check for overflow of 16bits, since our glyphID cannot exceed that
2677f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    if (glyphID > 0xFFFF) {
2687f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com        glyphID = 0;
2697f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    }
2707f78761dbe9c208f0763a39d94c44dcf602a182breed@android.com    return SkToU16(glyphID);
271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
273739245e986d7a78b96129f559363b7ab6fb0a21creed@android.comSkUnichar SkScalerContext::glyphIDToChar(uint16_t glyphID) {
274739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    SkScalerContext* ctx = this;
275739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    unsigned rangeEnd = 0;
276739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    do {
277739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        unsigned rangeStart = rangeEnd;
278739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com
279739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        rangeEnd += ctx->getGlyphCount();
280739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        if (rangeStart <= glyphID && glyphID < rangeEnd) {
281739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com            return ctx->generateGlyphToChar(glyphID - rangeStart);
282739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        }
283739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com        ctx = ctx->getNextContext();
284739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    } while (NULL != ctx);
285739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    return 0;
286739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com}
287739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com
288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getAdvance(SkGlyph* glyph) {
289bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // mark us as just having a valid advance
290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // we mark the format before making the call, in case the impl
292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // internally ends up calling its generateMetrics, which is OK
293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // albeit slower than strictly necessary
294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->getGlyphContext(*glyph)->generateAdvance(glyph);
295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
297bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getMetrics(SkGlyph* glyph) {
298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->getGlyphContext(*glyph)->generateMetrics(glyph);
299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // for now we have separate cache entries for devkerning on and off
301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // in the future we might share caches, but make our measure/draw
302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // code make the distinction. Thus we zap the values if the caller
303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // has not asked for them.
304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // no devkern, so zap the fields
306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fLsbDelta = glyph->fRsbDelta = 0;
307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // if either dimension is empty, zap the image bounds of the glyph
310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fWidth   = 0;
312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fHeight  = 0;
313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fTop     = 0;
314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fLeft    = 0;
315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->fMaskFormat = 0;
316bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
317bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
318919114813d58933c9d9433b141e0222c34b700b1reed@google.com
319ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    if (fGenerateImageFromPath) {
320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPath      devPath, fillPath;
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMatrix    fillToDevMatrix;
322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fRasterizer) {
326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkMask  mask;
327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                       fMaskFilter, &mask,
330bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                       SkMask::kJustComputeBounds_CreateMode)) {
331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                glyph->fLeft    = mask.fBounds.fLeft;
332bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                glyph->fTop     = mask.fBounds.fTop;
333bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                glyph->fWidth   = SkToU16(mask.fBounds.width());
334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                glyph->fHeight  = SkToU16(mask.fBounds.height());
335bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
33641aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.org                goto SK_ERROR;
337bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
338bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
339bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // just use devPath
340bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkIRect ir;
341155c4e804736576f9352aa60d70669ac3e3f9d52reed@android.com            devPath.getBounds().roundOut(&ir);
342919114813d58933c9d9433b141e0222c34b700b1reed@google.com
34341308ff545b8133f3ace8341e7737b068abeded1reed@android.com            if (ir.isEmpty() || !ir.is16Bit()) {
34441aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.org                goto SK_ERROR;
345f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com            }
346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fLeft    = ir.fLeft;
347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fTop     = ir.fTop;
348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fWidth   = SkToU16(ir.width());
349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fHeight  = SkToU16(ir.height());
350a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
351a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            if (glyph->fWidth > 0) {
352a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            switch (fRec.fMaskFormat) {
353a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            case SkMask::kLCD16_Format:
354a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            case SkMask::kLCD32_Format:
355a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                glyph->fWidth += 2;
356a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                glyph->fLeft -= 1;
357a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                break;
358a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            default:
359a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                break;
360a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            }
361a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    }
362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
36518723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com    if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
36618723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com        glyph->fMaskFormat = fRec.fMaskFormat;
36718723ff03ab6a08cd02c5ae008ae6775d13b3281robertphillips@google.com    }
368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
3696d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // If we are going to create the mask, then we cannot keep the color
3706d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    if ((fGenerateImageFromPath || fMaskFilter) &&
3716d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            SkMask::kARGB32_Format == glyph->fMaskFormat) {
3726d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        glyph->fMaskFormat = SkMask::kA8_Format;
3736d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    }
3746d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fMaskFilter) {
376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMask      src, dst;
377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMatrix    matrix;
378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->toMask(&src);
380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fRec.getMatrixFrom2x2(&matrix);
381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        src.fImage = NULL;  // only want the bounds from the filter
383bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
38426a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com            if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
38526a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com                goto SK_ERROR;
38626a498d01d899ea9af78ee70df710ddbb4d9370creed@google.com            }
387bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkASSERT(dst.fImage == NULL);
388bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fLeft    = dst.fBounds.fLeft;
389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fTop     = dst.fBounds.fTop;
390bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fWidth   = SkToU16(dst.fBounds.width());
391bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fHeight  = SkToU16(dst.fBounds.height());
392bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            glyph->fMaskFormat = dst.fFormat;
393bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
395f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    return;
396919114813d58933c9d9433b141e0222c34b700b1reed@google.com
39741aa25d7d04bb3713c6afca42636613dc1a7dbf4senorblanco@chromium.orgSK_ERROR:
398f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    // draw nothing 'cause we failed
399f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    glyph->fLeft    = 0;
400f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    glyph->fTop     = 0;
401f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    glyph->fWidth   = 0;
402f2dbd4db2b41bf7ec551faa37627054c18c4a503reed@android.com    glyph->fHeight  = 0;
40341308ff545b8133f3ace8341e7737b068abeded1reed@android.com    // put a valid value here, in case it was earlier set to
40441308ff545b8133f3ace8341e7737b068abeded1reed@android.com    // MASK_FORMAT_JUST_ADVANCE
40541308ff545b8133f3ace8341e7737b068abeded1reed@android.com    glyph->fMaskFormat = fRec.fMaskFormat;
406bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
408a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define SK_SHOW_TEXT_BLIT_COVERAGE 0
409ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
410ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.comstatic void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
411ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
412ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    unsigned rowBytes = mask.fRowBytes;
413ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
414ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
415ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com        for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
416ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            dst[x] = lut[dst[x]];
417ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com        }
418ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com        dst += rowBytes;
419ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    }
420ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com}
421ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com
4228ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.comtemplate<bool APPLY_PREBLEND>
423a333d3eba46308e457f88aa62892eec86747b465bungeman@google.comstatic void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
424ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                           const SkMaskGamma::PreBlend& maskPreBlend) {
425a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define SAMPLES_PER_PIXEL 4
426a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#define LCD_PER_PIXEL 3
427ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    SkASSERT(SkBitmap::kA8_Config == src.config());
428e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
429935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
430a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    const int sample_width = src.width();
431a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    const int height = src.height();
432a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
433ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    uint16_t* dstP = (uint16_t*)dst.fImage;
434e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    size_t dstRB = dst.fRowBytes;
435a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // An N tap FIR is defined by
436a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
437a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // or
438a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
439a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
440a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
441a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // This means using every 4th FIR output value of each FIR and discarding the rest.
442a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
443a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
444fce1688c43b8c11084cb820721a02bce75d0d76bskia.committer@gmail.com
445a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // These are in some fixed point repesentation.
446a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // Adding up to more than one simulates ink spread.
447a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // For implementation reasons, these should never add up to more than two.
448a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
449a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
450a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // Calculated using tools/generate_fir_coeff.py
451a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
452a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // The lcd smoothed text is almost imperceptibly different from gray,
453a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // but is still sharper on small stems and small rounded corners than gray.
454a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // This also seems to be about as wide as one can get and only have a three pixel kernel.
455a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
456a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
457a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
458a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
459a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
460a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
461a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
462a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
463a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com    };
464935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
465e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    for (int y = 0; y < height; ++y) {
466e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        const uint8_t* srcP = src.getAddr8(0, y);
467a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
468a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        // TODO: this fir filter implementation is straight forward, but slow.
469a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        // It should be possible to make it much faster.
470a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
471a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            int fir[LCD_PER_PIXEL] = { 0 };
472a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
473a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                ; sample_index < SkMin32(sample_x + 8, sample_width)
474a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                ; ++sample_index, ++coeff_index)
475a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            {
476a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                int sample_value = srcP[sample_index];
477a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
478a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                    fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
479a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                }
480a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            }
481a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
482a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                fir[subpxl_index] /= 0x100;
483a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
484a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            }
485a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
486a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
487a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
488a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
489a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#if SK_SHOW_TEXT_BLIT_COVERAGE
490a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
491a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com#endif
492a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com            dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
493e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        }
494e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        dstP = (uint16_t*)((char*)dstP + dstRB);
495e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    }
496e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com}
497ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com
4988ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.comtemplate<bool APPLY_PREBLEND>
499a333d3eba46308e457f88aa62892eec86747b465bungeman@google.comstatic void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
500ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                           const SkMaskGamma::PreBlend& maskPreBlend) {
501e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkASSERT(SkBitmap::kA8_Config == src.config());
502e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
503935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
504e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    const int width = dst.fBounds.width();
505e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    const int height = dst.fBounds.height();
506ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    SkPMColor* dstP = (SkPMColor*)dst.fImage;
507e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    size_t dstRB = dst.fRowBytes;
508935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
509e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    for (int y = 0; y < height; ++y) {
510e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        const uint8_t* srcP = src.getAddr8(0, y);
511a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com
512a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com        // TODO: need to use fir filter here as well.
513e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        for (int x = 0; x < width; ++x) {
514ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
515ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
516ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
5178ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com            dstP[x] = SkPackARGB32(0xFF, r, g, b);
518ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com        }
519ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com        dstP = (SkPMColor*)((char*)dstP + dstRB);
520ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    }
521ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com}
522ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com
523ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.comstatic void generateMask(const SkMask& mask, const SkPath& path,
524ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                         const SkMaskGamma::PreBlend& maskPreBlend) {
525e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkBitmap::Config config;
526e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkPaint     paint;
527e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
528e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    int srcW = mask.fBounds.width();
529e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    int srcH = mask.fBounds.height();
530e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    int dstW = srcW;
531e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    int dstH = srcH;
532e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    int dstRB = mask.fRowBytes;
533e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
534e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkMatrix matrix;
535e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
536e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com                        -SkIntToScalar(mask.fBounds.fTop));
537e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
538e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    if (SkMask::kBW_Format == mask.fFormat) {
539e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        config = SkBitmap::kA1_Config;
540e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        paint.setAntiAlias(false);
541e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    } else {
542e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        config = SkBitmap::kA8_Config;
543e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        paint.setAntiAlias(true);
544e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        switch (mask.fFormat) {
545e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com            case SkMask::kA8_Format:
546e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com                break;
547e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com            case SkMask::kLCD16_Format:
548e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com            case SkMask::kLCD32_Format:
549e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com                // TODO: trigger off LCD orientation
550a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                dstW = 4*dstW - 8;
551a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
552a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                                    -SkIntToScalar(mask.fBounds.fTop));
553a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                matrix.postScale(SkIntToScalar(4), SK_Scalar1);
554e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com                dstRB = 0;  // signals we need a copy
555e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com                break;
556e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com            default:
5572d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com                SkDEBUGFAIL("unexpected mask format");
558e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        }
559e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    }
560e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
56126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    SkRasterClip clip;
56226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    clip.setRect(SkIRect::MakeWH(dstW, dstH));
563e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
564e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkBitmap bm;
565e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    bm.setConfig(config, dstW, dstH, dstRB);
566e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
567e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    if (0 == dstRB) {
5689ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com        if (!bm.allocPixels()) {
5699ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com            // can't allocate offscreen, so empty the mask and return
5709ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com            sk_bzero(mask.fImage, mask.computeImageSize());
5719ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com            return;
5729ad5278e84fc9b9dcbcee906c9a8355968b7ee3areed@google.com        }
573e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        bm.lockPixels();
574e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    } else {
575e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        bm.setPixels(mask.fImage);
576e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    }
577e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    sk_bzero(bm.getPixels(), bm.getSafeSize());
578935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
579e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    SkDraw  draw;
58026f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    draw.fRC    = &clip;
58126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    draw.fClip  = &clip.bwRgn();
582e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    draw.fMatrix = &matrix;
583e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    draw.fBitmap = &bm;
584e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    draw.drawPath(path, paint);
585935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
5862a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com    switch (mask.fFormat) {
5872a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com        case SkMask::kA8_Format:
5882a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            if (maskPreBlend.isApplicable()) {
5892a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com                applyLUTToA8Mask(mask, maskPreBlend.fG);
5902a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            }
5912a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            break;
5922a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com        case SkMask::kLCD16_Format:
5932a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            if (maskPreBlend.isApplicable()) {
594a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                pack4xHToLCD16<true>(bm, mask, maskPreBlend);
5952a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            } else {
596a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                pack4xHToLCD16<false>(bm, mask, maskPreBlend);
5972a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            }
5982a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            break;
5992a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com        case SkMask::kLCD32_Format:
6002a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            if (maskPreBlend.isApplicable()) {
601a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                pack4xHToLCD32<true>(bm, mask, maskPreBlend);
6022a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            } else {
603a333d3eba46308e457f88aa62892eec86747b465bungeman@google.com                pack4xHToLCD32<false>(bm, mask, maskPreBlend);
6042a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            }
6052a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            break;
6062a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com        default:
6072a6aad8454b4438f95df776bcc28f7860a650748bungeman@google.com            break;
608e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    }
609e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com}
610e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
6116d450fe32babea3eb42b8b76d594bdc0be37529areed@google.comstatic void extract_alpha(const SkMask& dst,
6126d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com                          const SkPMColor* srcRow, size_t srcRB) {
6136d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    int width = dst.fBounds.width();
6146d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    int height = dst.fBounds.height();
6156d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    int dstRB = dst.fRowBytes;
6166d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    uint8_t* dstRow = dst.fImage;
6176d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
6186d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    for (int y = 0; y < height; ++y) {
6196d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        for (int x = 0; x < width; ++x) {
6206d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            dstRow[x] = SkGetPackedA32(srcRow[x]);
6216d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        }
6226d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        // zero any padding on each row
6236d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        for (int x = width; x < dstRB; ++x) {
6246d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            dstRow[x] = 0;
6256d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        }
6266d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        dstRow += dstRB;
6276d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
6286d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    }
6296d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com}
6306d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
631bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid SkScalerContext::getImage(const SkGlyph& origGlyph) {
632bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkGlyph*  glyph = &origGlyph;
633bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkGlyph         tmpGlyph;
634935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
6356d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // in case we need to call generateImage on a mask-format that is different
6366d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // (i.e. larger) than what our caller allocated by looking at origGlyph.
6376d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    SkAutoMalloc tmpGlyphImageStorage;
6386d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
6396d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // If we are going to draw-from-path, then we cannot generate color, since
6406d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // the path only makes a mask. This case should have been caught up in
6416d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    // generateMetrics().
6426d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com    SkASSERT(!fGenerateImageFromPath ||
6436d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com             SkMask::kARGB32_Format != origGlyph.fMaskFormat);
6446d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
645bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fMaskFilter) {   // restore the prefilter bounds
646fdc8827831e99c91887497125df6a5143c126765reed@google.com        tmpGlyph.init(origGlyph.fID);
647bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
648bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // need the original bounds, sans our maskfilter
649bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMaskFilter* mf = fMaskFilter;
650bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fMaskFilter = NULL;             // temp disable
651bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->getMetrics(&tmpGlyph);
652bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fMaskFilter = mf;               // restore
653bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
654bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // we need the prefilter bounds to be <= filter bounds
655bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
656bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
6576d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
6586d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
6596d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            tmpGlyph.fImage = origGlyph.fImage;
6606d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        } else {
6616d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
6626d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            tmpGlyph.fImage = tmpGlyphImageStorage.get();
6636d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        }
664bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph = &tmpGlyph;
665bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
666bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
667ff10324db62df86ecc52bfc1baa14fc4d8ab849areed@google.com    if (fGenerateImageFromPath) {
668bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPath      devPath, fillPath;
669bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMatrix    fillToDevMatrix;
670e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        SkMask      mask;
671bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
672bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
673e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        glyph->toMask(&mask);
674bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
675bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fRasterizer) {
676bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            mask.fFormat = SkMask::kA8_Format;
6775eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com            sk_bzero(glyph->fImage, mask.computeImageSize());
678919114813d58933c9d9433b141e0222c34b700b1reed@google.com
679bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
680bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                        fMaskFilter, &mask,
681bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                        SkMask::kJustRenderImage_CreateMode)) {
682bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                return;
683bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
684ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            if (fPreBlend.isApplicable()) {
685ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                applyLUTToA8Mask(mask, fPreBlend.fG);
6868ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com            }
687bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
6886d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
689ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            generateMask(mask, devPath, fPreBlend);
690bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
691bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
692ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com        this->getGlyphContext(*glyph)->generateImage(*glyph);
693bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
694bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
695bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (fMaskFilter) {
696bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMask      srcM, dstM;
697bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMatrix    matrix;
698bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
699bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // the src glyph image shouldn't be 3D
700bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
7016d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com
7026d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        SkAutoSMalloc<32*32> a8storage;
703bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        glyph->toMask(&srcM);
7046d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        if (SkMask::kARGB32_Format == srcM.fFormat) {
7056d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            // now we need to extract the alpha-channel from the glyph's image
7066d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            // and copy it into a temp buffer, and then point srcM at that temp.
7076d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            srcM.fFormat = SkMask::kA8_Format;
7086d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
7096d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            size_t size = srcM.computeImageSize();
7106d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            a8storage.reset(size);
7116d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            srcM.fImage = (uint8_t*)a8storage.get();
7126d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com            extract_alpha(srcM,
7136d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com                          (const SkPMColor*)glyph->fImage, glyph->rowBytes());
7146d450fe32babea3eb42b8b76d594bdc0be37529areed@google.com        }
71574546d80ff050eecbf2d3a21194f10860504e68dskia.committer@gmail.com
716bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fRec.getMatrixFrom2x2(&matrix);
717bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
718bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
719bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
720bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
721bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int dstRB = origGlyph.rowBytes();
722bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            int srcRB = dstM.fRowBytes;
723919114813d58933c9d9433b141e0222c34b700b1reed@google.com
724bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            const uint8_t* src = (const uint8_t*)dstM.fImage;
725bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            uint8_t* dst = (uint8_t*)origGlyph.fImage;
726bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
727bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (SkMask::k3D_Format == dstM.fFormat) {
728bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                // we have to copy 3 times as much
729bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                height *= 3;
730bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
731bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
732bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            // clean out our glyph, since it may be larger than dstM
7335eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com            //sk_bzero(dst, height * dstRB);
734bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
735bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            while (--height >= 0) {
736bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                memcpy(dst, src, width);
737bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                src += srcRB;
738bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                dst += dstRB;
739bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
740bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkMask::FreeImage(dstM.fImage);
7418ebb786eca7079fed1c2d9521e2bf9604bb5825dbungeman@google.com
742ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            if (fPreBlendForFilter.isApplicable()) {
743ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
744ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com            }
745bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
746bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
747bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
748bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
74902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.comvoid SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
750bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->internalGetPath(glyph, NULL, path, NULL);
751bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
752bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
7532f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.comvoid SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
7542f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    // All of this complexity should go away when we change generateFontMetrics
7552f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    // to just take one parameter (since it knows if it is vertical or not)
7562f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    SkPaint::FontMetrics* mx = NULL;
7572f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    SkPaint::FontMetrics* my = NULL;
7582f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    if (fRec.fFlags & kVertical_Flag) {
7592f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com        mx = fm;
7602f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    } else {
7612f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com        my = fm;
7622f45f0074cf3f265711b74eb3a1d757ae4b2ce02reed@google.com    }
763bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->generateFontMetrics(mx, my);
764bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
765bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
766739245e986d7a78b96129f559363b7ab6fb0a21creed@android.comSkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
767739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com    return 0;
768739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com}
769739245e986d7a78b96129f559363b7ab6fb0a21creed@android.com
77002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com///////////////////////////////////////////////////////////////////////////////
771bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
77202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.comvoid SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
77302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
774bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkPath  path;
775bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
776bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->getGlyphContext(glyph)->generatePath(glyph, &path);
777919114813d58933c9d9433b141e0222c34b700b1reed@google.com
778e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
779e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        SkFixed dx = glyph.getSubXFixed();
780e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        SkFixed dy = glyph.getSubYFixed();
781e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        if (dx | dy) {
782e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
783e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com        }
784e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com    }
785e401d551b7ce2efd48d870f323e2b73302ca8166reed@google.com
78602a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
787bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // need the path in user-space, with only the point-size applied
788bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // so that our stroking and effects will operate the same way they
789bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // would if the user had extracted the path themself, and then
790bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // called drawPath
791bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkPath      localPath;
792bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkMatrix    matrix, inverse;
793bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
794bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fRec.getMatrixFrom2x2(&matrix);
79585b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com        if (!matrix.invert(&inverse)) {
79685b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com            // assume fillPath and devPath are already empty.
79785b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com            return;
79885b2aaca4e634952568fb7c226c99fc162c034febungeman@google.com        }
799bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        path.transform(inverse, &localPath);
800bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // now localPath is only affected by the paint settings, and not the canvas matrix
801bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
802d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
803935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
804d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com        if (fRec.fFrameWidth > 0) {
805d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            rec.setStrokeStyle(fRec.fFrameWidth,
806d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
807d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            // glyphs are always closed contours, so cap type is ignored,
808d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            // so we just pass something.
809d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            rec.setStrokeParams(SkPaint::kButt_Cap,
810d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com                                (SkPaint::Join)fRec.fStrokeJoin,
811d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com                                fRec.fMiterLimit);
812d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com        }
813935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
81402a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (fPathEffect) {
815bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            SkPath effectPath;
816bb77acf17c4eb4f58b6bfbe48d750d018485ecf2reed@google.com            if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
817bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                localPath.swap(effectPath);
81802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            }
819bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
820bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
821d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com        if (rec.needToApply()) {
822d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            SkPath strokePath;
823d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            if (rec.applyToPath(&strokePath, localPath)) {
824d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com                localPath.swap(strokePath);
825d49b87f7307690e47c5cb093ff9d7cce4f009e87reed@google.com            }
826bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
827919114813d58933c9d9433b141e0222c34b700b1reed@google.com
828bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // now return stuff to the caller
82902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (fillToDevMatrix) {
830bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            *fillToDevMatrix = matrix;
83102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        }
83202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (devPath) {
833bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            localPath.transform(matrix, devPath);
83402a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        }
83502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (fillPath) {
836bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fillPath->swap(localPath);
83702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        }
83802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    } else {   // nothing tricky to do
83902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (fillToDevMatrix) {
840bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fillToDevMatrix->reset();
84102a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        }
84202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (devPath) {
84302a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            if (fillPath == NULL) {
844bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                devPath->swap(path);
84502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            } else {
846bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                *devPath = path;
84702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com            }
848bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
849919114813d58933c9d9433b141e0222c34b700b1reed@google.com
85002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        if (fillPath) {
851bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fillPath->swap(path);
85202a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com        }
853bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
854919114813d58933c9d9433b141e0222c34b700b1reed@google.com
85502a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    if (devPath) {
856bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        devPath->updateBoundsCache();
85702a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    }
85802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    if (fillPath) {
859bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fillPath->updateBoundsCache();
86002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    }
861bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
862bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
863bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
864d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
865f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com    dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
866f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com                fPost2x2[1][0], fPost2x2[1][1], 0,
867f9657f297bb01db7d8ae4edcbc766354df1b0200bungeman@google.com                0,              0,              SkScalarToPersp(SK_Scalar1));
868bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
869bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
870d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
8714ea89a7639423dfa5aabed6830a71fc09d014196reed@google.com    SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
872bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
873bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
874d765b1f62822099898688837ea0f73d698db4f8areed@google.comvoid SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
875bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    this->getLocalMatrix(m);
876bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
877bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    //  now concat the device matrix
87802a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    SkMatrix    deviceMatrix;
87902a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    this->getMatrixFrom2x2(&deviceMatrix);
88002a9b1d3258a7a0d74344e5c84313b36fcd2a8c2reed@google.com    m->postConcat(deviceMatrix);
881bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
882bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
883454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.comSkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
884454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    SkASSERT(!matrix.hasPerspective());
885935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
886454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    if (0 == matrix[SkMatrix::kMSkewY]) {
887454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com        return kX_SkAxisAlignment;
888454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    }
889454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    if (0 == matrix[SkMatrix::kMScaleX]) {
890454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com        return kY_SkAxisAlignment;
891454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    }
892454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com    return kNone_SkAxisAlignment;
893454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com}
894454aadd1dba42a701e7bb9bc73f7c7e76a99700freed@google.com
895efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com///////////////////////////////////////////////////////////////////////////////
896efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com
897bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkFontHost.h"
898bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
899efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comclass SkScalerContext_Empty : public SkScalerContext {
900efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.compublic:
9018e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com    SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
9028e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com        : SkScalerContext(face, desc) {}
903efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com
904efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.comprotected:
905ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual unsigned generateGlyphCount() SK_OVERRIDE {
906efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        return 0;
907efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
908ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
909efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        return 0;
910efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
911ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
912efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        glyph->zeroMetrics();
913efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
914ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
915efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        glyph->zeroMetrics();
916efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
917ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
918ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
919efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    virtual void generateFontMetrics(SkPaint::FontMetrics* mx,
920ec0f292459a7b5fb0300c83e456714033ab802fbbungeman@google.com                                     SkPaint::FontMetrics* my) SK_OVERRIDE {
921efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        if (mx) {
9225eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com            sk_bzero(mx, sizeof(*mx));
923efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        }
924efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        if (my) {
9255eafe260fa3574ec71eccb5519f41b8095f56562reed@android.com            sk_bzero(my, sizeof(*my));
926efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com        }
927efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
928efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com};
929efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com
930e216b62841acd5db9d91b63960805568259a2e0ereed@android.comextern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
931e216b62841acd5db9d91b63960805568259a2e0ereed@android.com
932bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.comSkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
933bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com                                                 bool allowFailure) const {
934bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com    SkScalerContext* c = this->onCreateScalerContext(desc);
935bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com
936bcb996959ff24d7cc2c5cbaa1b4dd5b47bb9c8ccreed@google.com    if (!c && !allowFailure) {
9378e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com        c = SkNEW_ARGS(SkScalerContext_Empty,
9388e01453029702b114d4eb939e4fbe7fd33b57b50reed@google.com                       (const_cast<SkTypeface*>(this), desc));
939efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    }
940efc74b8af0ee522065266db255e9bc48c8ceaceereed@android.com    return c;
941bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
942