1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkScalerContext.h"
11309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org#include "SkColorPriv.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDescriptor.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkDraw.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFontHost.h"
15bbe50131413098bffed9186660c41f047d881596bungeman@google.com#include "SkGlyph.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMaskFilter.h"
1797efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com#include "SkMaskGamma.h"
188b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkReadBuffer.h"
198b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org#include "SkWriteBuffer.h"
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPathEffect.h"
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRasterizer.h"
22045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#include "SkRasterClip.h"
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkStroke.h"
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkThread.h"
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define ComputeBWRowBytes(width)        (((unsigned)(width) + 7) >> 3)
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkGlyph::toMask(SkMask* mask) const {
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(mask);
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mask->fImage = (uint8_t*)fImage;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mask->fBounds.set(fLeft, fTop, fLeft + fWidth, fTop + fHeight);
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    mask->fRowBytes = this->rowBytes();
346c14b43a840c791699747ba4cc0ed5abf2bda218reed@android.com    mask->fFormat = static_cast<SkMask::Format>(fMaskFormat);
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comsize_t SkGlyph::computeImageSize() const {
38309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org    const size_t size = this->rowBytes() * fHeight;
39309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org
40309485b7b51f4cae4c0361ab4da00fe9cc89515cagl@chromium.org    switch (fMaskFormat) {
417db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        case SkMask::k3D_Format:
427db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            return 3 * size;
437db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        default:
447db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            return size;
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comvoid SkGlyph::zeroMetrics() {
4962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fAdvanceX = 0;
5062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fAdvanceY = 0;
5162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fWidth    = 0;
5262900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fHeight   = 0;
5362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fTop      = 0;
5462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fLeft     = 0;
5562900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fRsbDelta = 0;
5662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    fLsbDelta = 0;
5762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com}
5862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
5962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com///////////////////////////////////////////////////////////////////////////////
6062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    #define DUMP_RECx
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
65353482251e61971a8cf3a60bbb6910f482be634freed@google.comstatic SkFlattenable* load_flattenable(const SkDescriptor* desc, uint32_t tag,
66c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                                       SkFlattenable::Type ft) {
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFlattenable*  obj = NULL;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t        len;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const void*     data = desc->findEntry(tag, &len);
70583b18a20959c9ac360316a366f4ddd9598bdf52skia.committer@gmail.com
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (data) {
728b0e8ac5f582de80356019406e2975079bf0829dcommit-bot@chromium.org        SkReadBuffer buffer(data, len);
73c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org        obj = buffer.readFlattenable(ft);
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(buffer.offset() == buffer.size());
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    return obj;
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
790da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.comSkScalerContext::SkScalerContext(SkTypeface* typeface, const SkDescriptor* desc)
8097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com    : fRec(*static_cast<const Rec*>(desc->findEntry(kRec_SkDescriptorTag, NULL)))
81a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com
820da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com    , fTypeface(SkRef(typeface))
83c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org    , fPathEffect(static_cast<SkPathEffect*>(load_flattenable(desc, kPathEffect_SkDescriptorTag,
84c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                                             SkFlattenable::kSkPathEffect_Type)))
85c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org    , fMaskFilter(static_cast<SkMaskFilter*>(load_flattenable(desc, kMaskFilter_SkDescriptorTag,
86c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                                             SkFlattenable::kSkMaskFilter_Type)))
87c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org    , fRasterizer(static_cast<SkRasterizer*>(load_flattenable(desc, kRasterizer_SkDescriptorTag,
88c0b7e10c6a68f59e1653e6c18e6bc954b3c3f0cfcommit-bot@chromium.org                                             SkFlattenable::kSkRasterizer_Type)))
89a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com      // Initialize based on our settings. Subclasses can also force this.
9097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com    , fGenerateImageFromPath(fRec.fFrameWidth > 0 || fPathEffect != NULL || fRasterizer != NULL)
91a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com
92a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    , fPreBlend(fMaskFilter ? SkMaskGamma::PreBlend() : SkScalerContext::GetMaskPreBlend(fRec))
93a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    , fPreBlendForFilter(fMaskFilter ? SkScalerContext::GetMaskPreBlend(fRec)
94a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                                     : SkMaskGamma::PreBlend())
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com{
968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef DUMP_REC
978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    desc->assertChecksum();
9834abef14a637450743e1debccdcdb5bdc2e9ba01commit-bot@chromium.org    SkDebugf("SkScalerContext checksum %x count %d length %d\n",
997db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com             desc->getChecksum(), desc->getCount(), desc->getLength());
1008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDebugf(" textsize %g prescale %g preskew %g post [%g %g %g %g]\n",
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rec->fTextSize, rec->fPreScaleX, rec->fPreSkewX, rec->fPost2x2[0][0],
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rec->fPost2x2[0][1], rec->fPost2x2[1][0], rec->fPost2x2[1][1]);
1038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDebugf("  frame %g miter %g hints %d framefill %d format %d join %d\n",
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rec->fFrameWidth, rec->fMiterLimit, rec->fHints, rec->fFrameAndFill,
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        rec->fMaskFormat, rec->fStrokeJoin);
1067db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    SkDebugf("  pathEffect %x maskFilter %x\n",
1077db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com             desc->findEntry(kPathEffect_SkDescriptorTag, NULL),
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        desc->findEntry(kMaskFilter_SkDescriptorTag, NULL));
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSkScalerContext::~SkScalerContext() {
11382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    SkSafeUnref(fPathEffect);
11482065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    SkSafeUnref(fMaskFilter);
11582065d667f64e232bcde2ad849756a6096fcbe6freed@google.com    SkSafeUnref(fRasterizer);
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getAdvance(SkGlyph* glyph) {
1198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // mark us as just having a valid advance
1208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    glyph->fMaskFormat = MASK_FORMAT_JUST_ADVANCE;
1218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we mark the format before making the call, in case the impl
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // internally ends up calling its generateMetrics, which is OK
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // albeit slower than strictly necessary
1241b27704eba15be4e9d1997faac42038493a30be5djsollen    generateAdvance(glyph);
1258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getMetrics(SkGlyph* glyph) {
1281b27704eba15be4e9d1997faac42038493a30be5djsollen    generateMetrics(glyph);
1298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // for now we have separate cache entries for devkerning on and off
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // in the future we might share caches, but make our measure/draw
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // code make the distinction. Thus we zap the values if the caller
1338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // has not asked for them.
1348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if ((fRec.fFlags & SkScalerContext::kDevKernText_Flag) == 0) {
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // no devkern, so zap the fields
1368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fLsbDelta = glyph->fRsbDelta = 0;
1378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // if either dimension is empty, zap the image bounds of the glyph
1408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (0 == glyph->fWidth || 0 == glyph->fHeight) {
1418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fWidth   = 0;
1428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fHeight  = 0;
1438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fTop     = 0;
1448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fLeft    = 0;
1458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->fMaskFormat = 0;
1468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
1478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
14882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
149a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com    if (fGenerateImageFromPath) {
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath      devPath, fillPath;
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    fillToDevMatrix;
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fRasterizer) {
1568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkMask  mask;
1578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
1598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       fMaskFilter, &mask,
1608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                       SkMask::kJustComputeBounds_CreateMode)) {
1618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                glyph->fLeft    = mask.fBounds.fLeft;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                glyph->fTop     = mask.fBounds.fTop;
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                glyph->fWidth   = SkToU16(mask.fBounds.width());
1648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                glyph->fHeight  = SkToU16(mask.fBounds.height());
1658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            } else {
1667767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.org                goto SK_ERROR;
1678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
1688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
1698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // just use devPath
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkIRect ir;
171d252db03d9650013b545ef9781fe993c07f8f314reed@android.com            devPath.getBounds().roundOut(&ir);
17282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
173b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com            if (ir.isEmpty() || !ir.is16Bit()) {
1747767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.org                goto SK_ERROR;
175d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com            }
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fLeft    = ir.fLeft;
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fTop     = ir.fTop;
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fWidth   = SkToU16(ir.width());
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fHeight  = SkToU16(ir.height());
1800abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
1810abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            if (glyph->fWidth > 0) {
182d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                switch (fRec.fMaskFormat) {
183d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                case SkMask::kLCD16_Format:
184d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                case SkMask::kLCD32_Format:
185d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    glyph->fWidth += 2;
186d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    glyph->fLeft -= 1;
187d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    break;
188d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                default:
189d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                    break;
190d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                }
1910abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            }
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
195a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    if (SkMask::kARGB32_Format != glyph->fMaskFormat) {
196a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com        glyph->fMaskFormat = fRec.fMaskFormat;
197a22e2117e44efa4298dd0eb6df304a8166c8e9c3robertphillips@google.com    }
1988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1995bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // If we are going to create the mask, then we cannot keep the color
2005bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    if ((fGenerateImageFromPath || fMaskFilter) &&
2015bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            SkMask::kARGB32_Format == glyph->fMaskFormat) {
2025bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        glyph->fMaskFormat = SkMask::kA8_Format;
2035bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    }
2045bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMaskFilter) {
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMask      src, dst;
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    matrix;
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->toMask(&src);
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fRec.getMatrixFrom2x2(&matrix);
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        src.fImage = NULL;  // only want the bounds from the filter
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fMaskFilter->filterMask(&dst, src, matrix, NULL)) {
2148136d58161c3fa314af42f5c65682be855dfec1breed@google.com            if (dst.fBounds.isEmpty() || !dst.fBounds.is16Bit()) {
2158136d58161c3fa314af42f5c65682be855dfec1breed@google.com                goto SK_ERROR;
2168136d58161c3fa314af42f5c65682be855dfec1breed@google.com            }
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkASSERT(dst.fImage == NULL);
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fLeft    = dst.fBounds.fLeft;
2198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fTop     = dst.fBounds.fTop;
2208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fWidth   = SkToU16(dst.fBounds.width());
2218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fHeight  = SkToU16(dst.fBounds.height());
2228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            glyph->fMaskFormat = dst.fFormat;
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
225d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    return;
22682065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
2277767cd87fdadeed868457a2407e8b0a50006fc4asenorblanco@chromium.orgSK_ERROR:
228d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    // draw nothing 'cause we failed
229d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    glyph->fLeft    = 0;
230d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    glyph->fTop     = 0;
231d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    glyph->fWidth   = 0;
232d4577757874d1dda1a3bffa3f2347c251859c27ereed@android.com    glyph->fHeight  = 0;
233b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com    // put a valid value here, in case it was earlier set to
234b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com    // MASK_FORMAT_JUST_ADVANCE
235b757f8d20c582463999bd7aa5a48110e84945d19reed@android.com    glyph->fMaskFormat = fRec.fMaskFormat;
2368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2380abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define SK_SHOW_TEXT_BLIT_COVERAGE 0
239a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com
240a76de72a6036da0a6b051b14411b80941971f881bungeman@google.comstatic void applyLUTToA8Mask(const SkMask& mask, const uint8_t* lut) {
241a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    uint8_t* SK_RESTRICT dst = (uint8_t*)mask.fImage;
242a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    unsigned rowBytes = mask.fRowBytes;
243a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com
244a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    for (int y = mask.fBounds.height() - 1; y >= 0; --y) {
245a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        for (int x = mask.fBounds.width() - 1; x >= 0; --x) {
246a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            dst[x] = lut[dst[x]];
247a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        }
248a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com        dst += rowBytes;
249a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    }
250a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com}
251a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com
25297efada074e4806479f1350ab1508939c2fdcb53bungeman@google.comtemplate<bool APPLY_PREBLEND>
2530abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.comstatic void pack4xHToLCD16(const SkBitmap& src, const SkMask& dst,
254a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                           const SkMaskGamma::PreBlend& maskPreBlend) {
2550abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define SAMPLES_PER_PIXEL 4
2560abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#define LCD_PER_PIXEL 3
257900ecf2f1579d42c9d2959831787af0346320f86reed@google.com    SkASSERT(kAlpha_8_SkColorType == src.colorType());
258cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    SkASSERT(SkMask::kLCD16_Format == dst.fFormat);
259fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2600abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    const int sample_width = src.width();
2610abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    const int height = src.height();
2620abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
263a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com    uint16_t* dstP = (uint16_t*)dst.fImage;
264cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    size_t dstRB = dst.fRowBytes;
2650abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // An N tap FIR is defined by
2660abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // out[n] = coeff[0]*x[n] + coeff[1]*x[n-1] + ... + coeff[N]*x[n-N]
2670abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // or
2680abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // out[n] = sum(i, 0, N, coeff[i]*x[n-i])
2690abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
2700abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // The strategy is to use one FIR (different coefficients) for each of r, g, and b.
2710abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // This means using every 4th FIR output value of each FIR and discarding the rest.
2720abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // The FIRs are aligned, and the coefficients reach 5 samples to each side of their 'center'.
2730abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // (For r and b this is technically incorrect, but the coeffs outside round to zero anyway.)
27427e21fe577211c1c40cbf40d0385b02c69d04522skia.committer@gmail.com
2750abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // These are in some fixed point repesentation.
2760abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // Adding up to more than one simulates ink spread.
2770abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // For implementation reasons, these should never add up to more than two.
2780abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
2790abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // Coefficients determined by a gausian where 5 samples = 3 std deviations (0x110 'contrast').
2800abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // Calculated using tools/generate_fir_coeff.py
2810abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // With this one almost no fringing is ever seen, but it is imperceptibly blurry.
2820abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // The lcd smoothed text is almost imperceptibly different from gray,
2830abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // but is still sharper on small stems and small rounded corners than gray.
2840abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // This also seems to be about as wide as one can get and only have a three pixel kernel.
2850abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    // TODO: caculate these at runtime so parameters can be adjusted (esp contrast).
2860abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    static const unsigned int coefficients[LCD_PER_PIXEL][SAMPLES_PER_PIXEL*3] = {
2870abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        //The red subpixel is centered inside the first sample (at 1/6 pixel), and is shifted.
2880abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        { 0x03, 0x0b, 0x1c, 0x33,  0x40, 0x39, 0x24, 0x10,  0x05, 0x01, 0x00, 0x00, },
2890abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        //The green subpixel is centered between two samples (at 1/2 pixel), so is symetric
2900abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        { 0x00, 0x02, 0x08, 0x16,  0x2b, 0x3d, 0x3d, 0x2b,  0x16, 0x08, 0x02, 0x00, },
2910abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        //The blue subpixel is centered inside the last sample (at 5/6 pixel), and is shifted.
2920abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        { 0x00, 0x00, 0x01, 0x05,  0x10, 0x24, 0x39, 0x40,  0x33, 0x1c, 0x0b, 0x03, },
2930abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com    };
294fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
295cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    for (int y = 0; y < height; ++y) {
296cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        const uint8_t* srcP = src.getAddr8(0, y);
2970abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
2980abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        // TODO: this fir filter implementation is straight forward, but slow.
2990abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        // It should be possible to make it much faster.
3000abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        for (int sample_x = -4, pixel_x = 0; sample_x < sample_width + 4; sample_x += 4, ++pixel_x) {
3010abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            int fir[LCD_PER_PIXEL] = { 0 };
3020abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            for (int sample_index = SkMax32(0, sample_x - 4), coeff_index = sample_index - (sample_x - 4)
3030abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                ; sample_index < SkMin32(sample_x + 8, sample_width)
3040abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                ; ++sample_index, ++coeff_index)
3050abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            {
3060abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                int sample_value = srcP[sample_index];
3070abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
3080abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                    fir[subpxl_index] += coefficients[subpxl_index][coeff_index] * sample_value;
3090abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                }
3100abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            }
3110abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            for (int subpxl_index = 0; subpxl_index < LCD_PER_PIXEL; ++subpxl_index) {
3120abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                fir[subpxl_index] /= 0x100;
3130abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                fir[subpxl_index] = SkMin32(fir[subpxl_index], 255);
3140abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            }
3150abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
3160abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(fir[0], maskPreBlend.fR);
3170abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(fir[1], maskPreBlend.fG);
3180abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(fir[2], maskPreBlend.fB);
3190abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#if SK_SHOW_TEXT_BLIT_COVERAGE
3200abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            r = SkMax32(r, 10); g = SkMax32(g, 10); b = SkMax32(b, 10);
3210abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com#endif
3220abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com            dstP[pixel_x] = SkPack888ToRGB16(r, g, b);
323cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        }
324cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        dstP = (uint16_t*)((char*)dstP + dstRB);
325cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    }
326cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com}
327a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com
32897efada074e4806479f1350ab1508939c2fdcb53bungeman@google.comtemplate<bool APPLY_PREBLEND>
3290abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.comstatic void pack4xHToLCD32(const SkBitmap& src, const SkMask& dst,
330a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                           const SkMaskGamma::PreBlend& maskPreBlend) {
331900ecf2f1579d42c9d2959831787af0346320f86reed@google.com    SkASSERT(kAlpha_8_SkColorType == src.colorType());
332cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    SkASSERT(SkMask::kLCD32_Format == dst.fFormat);
333fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
334cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    const int width = dst.fBounds.width();
335cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    const int height = dst.fBounds.height();
336a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com    SkPMColor* dstP = (SkPMColor*)dst.fImage;
337cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    size_t dstRB = dst.fRowBytes;
338fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
339cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    for (int y = 0; y < height; ++y) {
340cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        const uint8_t* srcP = src.getAddr8(0, y);
3410abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com
3420abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com        // TODO: need to use fir filter here as well.
343cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        for (int x = 0; x < width; ++x) {
344a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            U8CPU r = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fR);
345a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            U8CPU g = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fG);
346a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            U8CPU b = sk_apply_lut_if<APPLY_PREBLEND>(*srcP++, maskPreBlend.fB);
34797efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com            dstP[x] = SkPackARGB32(0xFF, r, g, b);
348a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com        }
349a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com        dstP = (SkPMColor*)((char*)dstP + dstRB);
350a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com    }
351a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com}
352a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com
353d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic inline int convert_8_to_1(unsigned byte) {
354d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    SkASSERT(byte <= 0xFF);
355d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    return byte >> 7;
356d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com}
357d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
358d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic uint8_t pack_8_to_1(const uint8_t alpha[8]) {
359d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    unsigned bits = 0;
360d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    for (int i = 0; i < 8; ++i) {
361d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        bits <<= 1;
362d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        bits |= convert_8_to_1(alpha[i]);
363d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    }
364d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    return SkToU8(bits);
365d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com}
366d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
367d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.comstatic void packA8ToA1(const SkMask& mask, const uint8_t* src, size_t srcRB) {
368d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    const int height = mask.fBounds.height();
369d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    const int width = mask.fBounds.width();
370d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    const int octs = width >> 3;
371d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    const int leftOverBits = width & 7;
372d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
373d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    uint8_t* dst = mask.fImage;
374d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    const int dstPad = mask.fRowBytes - SkAlign8(width)/8;
375d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    SkASSERT(dstPad >= 0);
376d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
377f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org    SkASSERT(width >= 0);
378f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org    SkASSERT(srcRB >= (size_t)width);
379f117781362ecf673f43f93918781853690f0e145commit-bot@chromium.org    const size_t srcPad = srcRB - width;
380d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
381d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    for (int y = 0; y < height; ++y) {
382d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        for (int i = 0; i < octs; ++i) {
383d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            *dst++ = pack_8_to_1(src);
384d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            src += 8;
385d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        }
386d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        if (leftOverBits > 0) {
387d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            unsigned bits = 0;
388d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            int shift = 7;
389d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            for (int i = 0; i < leftOverBits; ++i, --shift) {
390c932c9fd77503aec47c256818dd94a8b57219a43robertphillips@google.com                bits |= convert_8_to_1(*src++) << shift;
391d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            }
392d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            *dst++ = bits;
393d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        }
394d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        src += srcPad;
395d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        dst += dstPad;
396d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    }
397d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com}
398d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com
399a76de72a6036da0a6b051b14411b80941971f881bungeman@google.comstatic void generateMask(const SkMask& mask, const SkPath& path,
400a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                         const SkMaskGamma::PreBlend& maskPreBlend) {
401d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    SkPaint paint;
402cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
403cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    int srcW = mask.fBounds.width();
404cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    int srcH = mask.fBounds.height();
405cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    int dstW = srcW;
406cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    int dstH = srcH;
407cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    int dstRB = mask.fRowBytes;
408cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
409cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    SkMatrix matrix;
410cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
411cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com                        -SkIntToScalar(mask.fBounds.fTop));
412cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
413d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    paint.setAntiAlias(SkMask::kBW_Format != mask.fFormat);
414d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com    switch (mask.fFormat) {
415d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        case SkMask::kBW_Format:
416d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            dstRB = 0;  // signals we need a copy
417d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            break;
418d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        case SkMask::kA8_Format:
419d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            break;
420d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        case SkMask::kLCD16_Format:
421d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        case SkMask::kLCD32_Format:
422d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            // TODO: trigger off LCD orientation
423d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            dstW = 4*dstW - 8;
424d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft + 1),
425d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com                                -SkIntToScalar(mask.fBounds.fTop));
426d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            matrix.postScale(SkIntToScalar(4), SK_Scalar1);
427d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            dstRB = 0;  // signals we need a copy
428d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            break;
429d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        default:
430d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            SkDEBUGFAIL("unexpected mask format");
431cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    }
432cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
433045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    SkRasterClip clip;
434045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    clip.setRect(SkIRect::MakeWH(dstW, dstH));
435cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
436a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org    const SkImageInfo info = SkImageInfo::MakeA8(dstW, dstH);
437cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    SkBitmap bm;
438cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
439cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    if (0 == dstRB) {
440848250415eddc54075f7eb8795e8db79e749c6abreed        if (!bm.tryAllocPixels(info)) {
4419be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com            // can't allocate offscreen, so empty the mask and return
4429be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com            sk_bzero(mask.fImage, mask.computeImageSize());
4439be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com            return;
4449be5727d96979f6a0f89b00a43c19bca97ace0fcreed@google.com        }
445cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    } else {
446a3264e53ee3f3c5d6a2c813df7e44b5b96d207f2commit-bot@chromium.org        bm.installPixels(info, mask.fImage, dstRB);
447cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    }
448cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    sk_bzero(bm.getPixels(), bm.getSafeSize());
449fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
450cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    SkDraw  draw;
451045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    draw.fRC    = &clip;
452045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    draw.fClip  = &clip.bwRgn();
453cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    draw.fMatrix = &matrix;
454cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    draw.fBitmap = &bm;
455cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    draw.drawPath(path, paint);
456fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4570c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com    switch (mask.fFormat) {
458d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com        case SkMask::kBW_Format:
459d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            packA8ToA1(mask, bm.getAddr8(0, 0), bm.rowBytes());
460d6bab0238655dbab24dfe92bd0b16b464310a8c7rmistry@google.com            break;
4610c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com        case SkMask::kA8_Format:
4620c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            if (maskPreBlend.isApplicable()) {
4630c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com                applyLUTToA8Mask(mask, maskPreBlend.fG);
4640c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            }
4650c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            break;
4660c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com        case SkMask::kLCD16_Format:
4670c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            if (maskPreBlend.isApplicable()) {
4680abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                pack4xHToLCD16<true>(bm, mask, maskPreBlend);
4690c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            } else {
4700abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                pack4xHToLCD16<false>(bm, mask, maskPreBlend);
4710c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            }
4720c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            break;
4730c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com        case SkMask::kLCD32_Format:
4740c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            if (maskPreBlend.isApplicable()) {
4750abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                pack4xHToLCD32<true>(bm, mask, maskPreBlend);
4760c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            } else {
4770abbff9987b9452fd30cce198bea34fdb210ac41bungeman@google.com                pack4xHToLCD32<false>(bm, mask, maskPreBlend);
4780c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            }
4790c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            break;
4800c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com        default:
4810c5f3762e863411798b1d6c55157d24c69d5bc25bungeman@google.com            break;
482cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    }
483cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com}
484cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
4855bdfb331ac650cf464baa96a49e2473ee10a515creed@google.comstatic void extract_alpha(const SkMask& dst,
4865bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com                          const SkPMColor* srcRow, size_t srcRB) {
4875bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    int width = dst.fBounds.width();
4885bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    int height = dst.fBounds.height();
4895bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    int dstRB = dst.fRowBytes;
4905bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    uint8_t* dstRow = dst.fImage;
4915bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
4925bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    for (int y = 0; y < height; ++y) {
4935bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        for (int x = 0; x < width; ++x) {
4945bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            dstRow[x] = SkGetPackedA32(srcRow[x]);
4955bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        }
4965bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        // zero any padding on each row
4975bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        for (int x = width; x < dstRB; ++x) {
4985bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            dstRow[x] = 0;
4995bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        }
5005bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        dstRow += dstRB;
5015bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        srcRow = (const SkPMColor*)((const char*)srcRow + srcRB);
5025bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    }
5035bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com}
5045bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
5058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comvoid SkScalerContext::getImage(const SkGlyph& origGlyph) {
5068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkGlyph*  glyph = &origGlyph;
5078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkGlyph         tmpGlyph;
508fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
5095bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // in case we need to call generateImage on a mask-format that is different
5105bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // (i.e. larger) than what our caller allocated by looking at origGlyph.
5115bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    SkAutoMalloc tmpGlyphImageStorage;
5125bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
5135bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // If we are going to draw-from-path, then we cannot generate color, since
5145bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // the path only makes a mask. This case should have been caught up in
5155bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    // generateMetrics().
5165bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com    SkASSERT(!fGenerateImageFromPath ||
5175bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com             SkMask::kARGB32_Format != origGlyph.fMaskFormat);
5185bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMaskFilter) {   // restore the prefilter bounds
520ce2b1afb582f0a2274f476c949cff8b0e1c72b36reed@google.com        tmpGlyph.init(origGlyph.fID);
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // need the original bounds, sans our maskfilter
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMaskFilter* mf = fMaskFilter;
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMaskFilter = NULL;             // temp disable
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->getMetrics(&tmpGlyph);
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fMaskFilter = mf;               // restore
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // we need the prefilter bounds to be <= filter bounds
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(tmpGlyph.fWidth <= origGlyph.fWidth);
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(tmpGlyph.fHeight <= origGlyph.fHeight);
5315bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
5325bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        if (tmpGlyph.fMaskFormat == origGlyph.fMaskFormat) {
5335bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            tmpGlyph.fImage = origGlyph.fImage;
5345bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        } else {
5355bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            tmpGlyphImageStorage.reset(tmpGlyph.computeImageSize());
5365bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            tmpGlyph.fImage = tmpGlyphImageStorage.get();
5375bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        }
5388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph = &tmpGlyph;
5398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
541a767fa06ca28be9df1ff6e08a299e0bec839a2dcreed@google.com    if (fGenerateImageFromPath) {
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath      devPath, fillPath;
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    fillToDevMatrix;
544cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        SkMask      mask;
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->internalGetPath(*glyph, &fillPath, &devPath, &fillToDevMatrix);
547cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        glyph->toMask(&mask);
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fRasterizer) {
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            mask.fFormat = SkMask::kA8_Format;
5514516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com            sk_bzero(glyph->fImage, mask.computeImageSize());
55282065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (!fRasterizer->rasterize(fillPath, fillToDevMatrix, NULL,
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        fMaskFilter, &mask,
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                        SkMask::kJustRenderImage_CreateMode)) {
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                return;
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
558a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            if (fPreBlend.isApplicable()) {
559a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                applyLUTToA8Mask(mask, fPreBlend.fG);
56097efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com            }
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        } else {
5625bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            SkASSERT(SkMask::kARGB32_Format != mask.fFormat);
563a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            generateMask(mask, devPath, fPreBlend);
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    } else {
5661b27704eba15be4e9d1997faac42038493a30be5djsollen        generateImage(*glyph);
5678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (fMaskFilter) {
5708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMask      srcM, dstM;
5718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    matrix;
5728a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // the src glyph image shouldn't be 3D
5748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(SkMask::k3D_Format != glyph->fMaskFormat);
5755bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com
5765bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        SkAutoSMalloc<32*32> a8storage;
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        glyph->toMask(&srcM);
5785bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        if (SkMask::kARGB32_Format == srcM.fFormat) {
5795bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            // now we need to extract the alpha-channel from the glyph's image
5805bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            // and copy it into a temp buffer, and then point srcM at that temp.
5815bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            srcM.fFormat = SkMask::kA8_Format;
5825bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            srcM.fRowBytes = SkAlign4(srcM.fBounds.width());
5835bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            size_t size = srcM.computeImageSize();
5845bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            a8storage.reset(size);
5855bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            srcM.fImage = (uint8_t*)a8storage.get();
5865bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com            extract_alpha(srcM,
5875bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com                          (const SkPMColor*)glyph->fImage, glyph->rowBytes());
5885bdfb331ac650cf464baa96a49e2473ee10a515creed@google.com        }
5892fd42c471c77f54ace35c13975651e17d5b2e8c6skia.committer@gmail.com
5908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fRec.getMatrixFrom2x2(&matrix);
5918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (fMaskFilter->filterMask(&dstM, srcM, matrix, NULL)) {
5938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int width = SkFastMin32(origGlyph.fWidth, dstM.fBounds.width());
5948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int height = SkFastMin32(origGlyph.fHeight, dstM.fBounds.height());
5958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int dstRB = origGlyph.rowBytes();
5968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            int srcRB = dstM.fRowBytes;
59782065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
5988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            const uint8_t* src = (const uint8_t*)dstM.fImage;
5998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            uint8_t* dst = (uint8_t*)origGlyph.fImage;
6008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            if (SkMask::k3D_Format == dstM.fFormat) {
6028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                // we have to copy 3 times as much
6038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                height *= 3;
6048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            // clean out our glyph, since it may be larger than dstM
6074516f4786f5dda1b86a8f825b9e8e910d9c2363creed@android.com            //sk_bzero(dst, height * dstRB);
6088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            while (--height >= 0) {
6108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                memcpy(dst, src, width);
6118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                src += srcRB;
6128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                dst += dstRB;
6138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            }
6148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkMask::FreeImage(dstM.fImage);
61597efada074e4806479f1350ab1508939c2fdcb53bungeman@google.com
616a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            if (fPreBlendForFilter.isApplicable()) {
617a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com                applyLUTToA8Mask(srcM, fPreBlendForFilter.fG);
618a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com            }
6198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6237db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.comvoid SkScalerContext::getPath(const SkGlyph& glyph, SkPath* path) {
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->internalGetPath(glyph, NULL, path, NULL);
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6270a01f5a2c44f3d6a7fa2d3c837f46894d9b29e5dreed@google.comvoid SkScalerContext::getFontMetrics(SkPaint::FontMetrics* fm) {
628410780677af260e32948b02c0725ef6ad761260cbungeman    this->generateFontMetrics(fm);
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6319d3a985aa3c82605346ed1518375a8c384b925e5reed@android.comSkUnichar SkScalerContext::generateGlyphToChar(uint16_t glyph) {
6329d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com    return 0;
6339d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com}
6349d3a985aa3c82605346ed1518375a8c384b925e5reed@android.com
6357db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com///////////////////////////////////////////////////////////////////////////////
6368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6377db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.comvoid SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
6387db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com                                  SkPath* devPath, SkMatrix* fillToDevMatrix) {
6398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkPath  path;
6401b27704eba15be4e9d1997faac42038493a30be5djsollen    generatePath(glyph, &path);
64182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
642cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    if (fRec.fFlags & SkScalerContext::kSubpixelPositioning_Flag) {
643cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        SkFixed dx = glyph.getSubXFixed();
644cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        SkFixed dy = glyph.getSubYFixed();
645cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        if (dx | dy) {
646cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com            path.offset(SkFixedToScalar(dx), SkFixedToScalar(dy));
647cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com        }
648cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com    }
649cf598b176da861a8fd1a4e2386a7ddf874684bb3reed@google.com
6507db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    if (fRec.fFrameWidth > 0 || fPathEffect != NULL) {
6518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // need the path in user-space, with only the point-size applied
6528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // so that our stroking and effects will operate the same way they
6538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // would if the user had extracted the path themself, and then
6548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // called drawPath
6558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkPath      localPath;
6568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkMatrix    matrix, inverse;
6578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fRec.getMatrixFrom2x2(&matrix);
6599575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com        if (!matrix.invert(&inverse)) {
6609575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com            // assume fillPath and devPath are already empty.
6619575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com            return;
6629575fb8b1d505572dd9808af1697921fe48c021ebungeman@google.com        }
6638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        path.transform(inverse, &localPath);
6648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now localPath is only affected by the paint settings, and not the canvas matrix
6658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
666fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
667fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
668fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com        if (fRec.fFrameWidth > 0) {
669fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            rec.setStrokeStyle(fRec.fFrameWidth,
670fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
671fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            // glyphs are always closed contours, so cap type is ignored,
672fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            // so we just pass something.
673fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            rec.setStrokeParams(SkPaint::kButt_Cap,
674fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com                                (SkPaint::Join)fRec.fStrokeJoin,
675fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com                                fRec.fMiterLimit);
676fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com        }
677fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
6787db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (fPathEffect) {
6798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            SkPath effectPath;
6804bbdeac58cc928dc66296bde3bd06e78070d96b7reed@google.com            if (fPathEffect->filterPath(&effectPath, localPath, &rec, NULL)) {
6818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                localPath.swap(effectPath);
6827db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            }
6838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
685fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com        if (rec.needToApply()) {
686fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            SkPath strokePath;
687fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            if (rec.applyToPath(&strokePath, localPath)) {
688fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com                localPath.swap(strokePath);
689fd4be26c4202ae91f0f7cf2c03e44b5169d885ebreed@google.com            }
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
69182065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        // now return stuff to the caller
6937db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (fillToDevMatrix) {
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            *fillToDevMatrix = matrix;
6957db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        }
6967db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (devPath) {
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            localPath.transform(matrix, devPath);
6987db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        }
6997db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (fillPath) {
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fillPath->swap(localPath);
7017db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        }
7027db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    } else {   // nothing tricky to do
7037db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (fillToDevMatrix) {
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fillToDevMatrix->reset();
7057db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        }
7067db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (devPath) {
7077db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            if (fillPath == NULL) {
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                devPath->swap(path);
7097db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            } else {
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                *devPath = path;
7117db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com            }
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
71382065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
7147db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        if (fillPath) {
7158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fillPath->swap(path);
7167db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com        }
7178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
71882065d667f64e232bcde2ad849756a6096fcbe6freed@google.com
7197db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    if (devPath) {
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        devPath->updateBoundsCache();
7217db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    }
7227db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    if (fillPath) {
7238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fillPath->updateBoundsCache();
7247db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    }
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
728a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getMatrixFrom2x2(SkMatrix* dst) const {
72950dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com    dst->setAll(fPost2x2[0][0], fPost2x2[0][1], 0,
73050dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com                fPost2x2[1][0], fPost2x2[1][1], 0,
73150dd41017ad121b5f40f063d813ba517668fcfbcbungeman@google.com                0,              0,              SkScalarToPersp(SK_Scalar1));
7328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
734a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getLocalMatrix(SkMatrix* m) const {
735ed43dffbf140cebc0575bed7b4dff1b32430ad21reed@google.com    SkPaint::SetTextMatrix(m, fTextSize, fPreScaleX, fPreSkewX);
7368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
738a9d4e84c435f61be3c02d7f54acab973e8b7761creed@google.comvoid SkScalerContextRec::getSingleMatrix(SkMatrix* m) const {
7398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    this->getLocalMatrix(m);
7408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    //  now concat the device matrix
7427db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    SkMatrix    deviceMatrix;
7437db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    this->getMatrixFrom2x2(&deviceMatrix);
7447db9fe65b2bb099e9dc41f79cc15b6a7a142bed6reed@google.com    m->postConcat(deviceMatrix);
7458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7472e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.comSkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix) {
7482e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    SkASSERT(!matrix.hasPerspective());
749fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7502e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    if (0 == matrix[SkMatrix::kMSkewY]) {
7512e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com        return kX_SkAxisAlignment;
7522e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    }
7532e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    if (0 == matrix[SkMatrix::kMScaleX]) {
7542e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com        return kY_SkAxisAlignment;
7552e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    }
7562e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com    return kNone_SkAxisAlignment;
7572e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com}
7582e68478d8654c8a4048b45ad16ac039dadb25c33reed@google.com
75962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com///////////////////////////////////////////////////////////////////////////////
76062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
7618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkFontHost.h"
7628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
76362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comclass SkScalerContext_Empty : public SkScalerContext {
76462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.compublic:
7650da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com    SkScalerContext_Empty(SkTypeface* face, const SkDescriptor* desc)
7660da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com        : SkScalerContext(face, desc) {}
76762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
76862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.comprotected:
769a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual unsigned generateGlyphCount() SK_OVERRIDE {
77062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        return 0;
77162900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
772a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual uint16_t generateCharToGlyph(SkUnichar uni) SK_OVERRIDE {
77362900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        return 0;
77462900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
775a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual void generateAdvance(SkGlyph* glyph) SK_OVERRIDE {
77662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        glyph->zeroMetrics();
77762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
778a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual void generateMetrics(SkGlyph* glyph) SK_OVERRIDE {
77962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        glyph->zeroMetrics();
78062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
781a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual void generateImage(const SkGlyph& glyph) SK_OVERRIDE {}
782a76de72a6036da0a6b051b14411b80941971f881bungeman@google.com    virtual void generatePath(const SkGlyph& glyph, SkPath* path) SK_OVERRIDE {}
783410780677af260e32948b02c0725ef6ad761260cbungeman    virtual void generateFontMetrics(SkPaint::FontMetrics* metrics) SK_OVERRIDE {
784410780677af260e32948b02c0725ef6ad761260cbungeman        if (metrics) {
785410780677af260e32948b02c0725ef6ad761260cbungeman            sk_bzero(metrics, sizeof(*metrics));
78662900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com        }
78762900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
78862900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com};
78962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com
790f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.comextern SkScalerContext* SkCreateColorScalerContext(const SkDescriptor* desc);
791f2b98d67dcb6fcb3120feede9c72016fc7b3ead8reed@android.com
79284e22d847fc84727bc220947162363ee1fe068fcreed@google.comSkScalerContext* SkTypeface::createScalerContext(const SkDescriptor* desc,
79384e22d847fc84727bc220947162363ee1fe068fcreed@google.com                                                 bool allowFailure) const {
79484e22d847fc84727bc220947162363ee1fe068fcreed@google.com    SkScalerContext* c = this->onCreateScalerContext(desc);
79584e22d847fc84727bc220947162363ee1fe068fcreed@google.com
79684e22d847fc84727bc220947162363ee1fe068fcreed@google.com    if (!c && !allowFailure) {
7970da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com        c = SkNEW_ARGS(SkScalerContext_Empty,
7980da48618a758ef46c2174bdc1eaeb6dd8a693a2ereed@google.com                       (const_cast<SkTypeface*>(this), desc));
79962900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    }
80062900b4c64401bc80ae85f6f5c87309a273cae10reed@android.com    return c;
8018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
802