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 "SkScanPriv.h"
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkPath.h"
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkMatrix.h"
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkBlitter.h"
148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRegion.h"
158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkAntiRun.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SHIFT   2
188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SCALE   (1 << SHIFT)
198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define MASK    (SCALE - 1)
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/** @file
222f3567c0003b948ad90528e597ea1e8326f644aereed@google.com    We have two techniques for capturing the output of the supersampler:
232f3567c0003b948ad90528e597ea1e8326f644aereed@google.com    - SUPERMASK, which records a large mask-bitmap
242f3567c0003b948ad90528e597ea1e8326f644aereed@google.com        this is often faster for small, complex objects
252f3567c0003b948ad90528e597ea1e8326f644aereed@google.com    - RLE, which records a rle-encoded scanline
262f3567c0003b948ad90528e597ea1e8326f644aereed@google.com        this is often faster for large objects with big spans
272f3567c0003b948ad90528e597ea1e8326f644aereed@google.com
2805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    These blitters use two coordinate systems:
2905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    - destination coordinates, scale equal to the output - often
3005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com        abbreviated with 'i' or 'I' in variable names
3105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    - supersampled coordinates, scale equal to the output * SCALE
3205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com
335b7d603e179a38735056db5f9092d18c187e76a0reed@google.com    Enabling SK_USE_LEGACY_AA_COVERAGE keeps the aa coverage calculations as
345b7d603e179a38735056db5f9092d18c187e76a0reed@google.com    they were before the fix that unified the output of the RLE and MASK
355b7d603e179a38735056db5f9092d18c187e76a0reed@google.com    supersamplers.
362f3567c0003b948ad90528e597ea1e8326f644aereed@google.com */
375b7d603e179a38735056db5f9092d18c187e76a0reed@google.com
389f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_SUPERMASK
399f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_RLE
40cd4e9fb538393be733ff4ea445ea428f041b21eareed@google.com//#define SK_USE_LEGACY_AA_COVERAGE
419f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
429f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com///////////////////////////////////////////////////////////////////////////////
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Base class for a single-pass supersampled blitter.
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass BaseSuperBlitter : public SkBlitter {
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     const SkRegion& clip);
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Must be explicitly defined on subclasses.
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
52967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com                           const int16_t runs[]) SK_OVERRIDE {
530c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// May not be called on BaseSuperBlitter because it blits out of order.
56967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
570c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlitter*  fRealBlitter;
6205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Current y coordinate, in destination coordinates.
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         fCurrIY;
6405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Widest row of region to be blitted, in destination coordinates.
6505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fWidth;
6605fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Leftmost x coordinate in any row, in destination coordinates.
6705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fLeft;
6805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Leftmost x coordinate in any row, in supersampled coordinates.
6905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fSuperLeft;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(int fCurrX;)
7205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Current y coordinate in supersampled coordinates.
73fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    int fCurrY;
7405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Initial y coordinate (top of bounds).
75045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    int fTop;
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comBaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                   const SkRegion& clip) {
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRealBlitter = realBlitter;
8155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
82dceecc70a881508998323fd07dba270b07c53d7freed@google.com    /*
83dceecc70a881508998323fd07dba270b07c53d7freed@google.com     *  We use the clip bounds instead of the ir, since we may be asked to
84dceecc70a881508998323fd07dba270b07c53d7freed@google.com     *  draw outside of the rect if we're a inverse filltype
85dceecc70a881508998323fd07dba270b07c53d7freed@google.com     */
86dceecc70a881508998323fd07dba270b07c53d7freed@google.com    const int left = clip.getBounds().fLeft;
87dceecc70a881508998323fd07dba270b07c53d7freed@google.com    const int right = clip.getBounds().fRight;
88fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLeft = left;
908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fSuperLeft = left << SHIFT;
918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fWidth = right - left;
92045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#if 0
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrIY = -1;
9434e52a0392f146b62f46cfe6714d9bddbb8d9e77reed@google.com    fCurrY = -1;
95045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#else
96045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    fTop = ir.fTop;
97045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    fCurrIY = ir.fTop - 1;
98045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    fCurrY = (ir.fTop << SHIFT) - 1;
99045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com#endif
10034e52a0392f146b62f46cfe6714d9bddbb8d9e77reed@google.com    SkDEBUGCODE(fCurrX = -1;)
1018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
10305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Run-length-encoded supersampling antialiased blitter.
1048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass SuperBlitter : public BaseSuperBlitter {
1058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
1068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                 const SkRegion& clip);
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~SuperBlitter() {
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->flush();
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Once fRuns contains a complete supersampled row, flush() blits
11405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// it out through the wrapped blitter.
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void flush();
1168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Blits a row of pixels, with location and width specified
11805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// in supersampled coordinates.
119967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
12005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Blits a rectangle of pixels, with location and size specified
12105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// in supersampled coordinates.
122967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1252ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // The next three variables are used to track a circular buffer that
1262ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // contains the values used in SkAlphaRuns. These variables should only
1272ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // ever be updated in advanceRuns(), and fRuns should always point to
1282ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // a valid SkAlphaRuns...
1292ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int         fRunsToBuffer;
1302ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    void*       fRunsBuffer;
1312ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int         fCurrentRun;
1328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkAlphaRuns fRuns;
1332ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
1342ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // extra one to store the zero at the end
1352ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
1362ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
1372ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // This function updates the fRuns variable to point to the next buffer space
1382ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
1392ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // and resets fRuns to point to an empty scanline.
1402ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    void advanceRuns() {
1412ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        const size_t kRunsSz = this->getRunsSz();
1422ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
1432ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.fRuns = reinterpret_cast<int16_t*>(
1442ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski            reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
1452ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
1462ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.reset(fWidth);
1472ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    }
1482ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
149fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    int         fOffsetX;
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comSuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
1538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                           const SkRegion& clip)
1548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        : BaseSuperBlitter(realBlitter, ir, clip) {
1552ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    fRunsToBuffer = realBlitter->requestRowsPreserved();
15675f88512a1b74ebb1bbb4f0046e43f1a5a234320krajcevski    fRunsBuffer = realBlitter->allocBlitMemory(fRunsToBuffer * this->getRunsSz());
1572ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    fCurrentRun = -1;
1588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1592ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    this->advanceRuns();
160fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com
161fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    fOffsetX = 0;
1628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1649f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid SuperBlitter::flush() {
165045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    if (fCurrIY >= fTop) {
1662ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
1672ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        SkASSERT(fCurrentRun < fRunsToBuffer);
1689f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        if (!fRuns.empty()) {
1692ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski            // SkDEBUGCODE(fRuns.dump();)
1708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com            fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
1712ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski            this->advanceRuns();
172fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com            fOffsetX = 0;
1738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
1742ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
175045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com        fCurrIY = fTop - 1;
1768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDEBUGCODE(fCurrX = -1;)
1778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
180ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com/** coverage_to_partial_alpha() is being used by SkAlphaRuns, which
181ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    *accumulates* SCALE pixels worth of "alpha" in [0,(256/SCALE)]
182ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    to produce a final value in [0, 255] and handles clamping 256->255
183ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    itself, with the same (alpha - (alpha >> 8)) correction as
184ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    coverage_to_exact_alpha().
185ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com*/
186ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.comstatic inline int coverage_to_partial_alpha(int aa) {
1878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    aa <<= 8 - 2*SHIFT;
1885b7d603e179a38735056db5f9092d18c187e76a0reed@google.com#ifdef SK_USE_LEGACY_AA_COVERAGE
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    aa -= aa >> (8 - SHIFT - 1);
190ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com#endif
1915b7d603e179a38735056db5f9092d18c187e76a0reed@google.com    return aa;
1928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
194ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com/** coverage_to_exact_alpha() is being used by our blitter, which wants
195ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    a final value in [0, 255].
196ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com*/
19749eac192faa35159752525b23345563252721c64tomhudson@google.comstatic inline int coverage_to_exact_alpha(int aa) {
19831bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    int alpha = (256 >> SHIFT) * aa;
19931bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    // clamp 256->255
20031bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    return alpha - (alpha >> 8);
20149eac192faa35159752525b23345563252721c64tomhudson@google.com}
20249eac192faa35159752525b23345563252721c64tomhudson@google.com
2039f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid SuperBlitter::blitH(int x, int y, int width) {
204967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(width > 0);
205967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int iy = y >> SHIFT;
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(iy >= fCurrIY);
2088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x -= fSuperLeft;
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
2119f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (x < 0) {
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        width += x;
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x = 0;
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(y != fCurrY || x >= fCurrX);
2188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
219fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    SkASSERT(y >= fCurrY);
220fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    if (fCurrY != y) {
221fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com        fOffsetX = 0;
222fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com        fCurrY = y;
223fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    }
224fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2259f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (iy != fCurrIY) {  // new scanline
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->flush();
2278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrIY = iy;
2288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2305a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int start = x;
2315a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int stop = x + width;
2325a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com
2335a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    SkASSERT(start >= 0 && stop > start);
23405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // integer-pixel-aligned ends of blit, rounded out
23505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fb = start & MASK;
23605fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fe = stop & MASK;
2375a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
2385a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com
2395a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    if (n < 0) {
2405a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        fb = fe - fb;
2415a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        n = 0;
2425a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        fe = 0;
2435a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    } else {
2445a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        if (fb == 0) {
2455a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com            n += 1;
2469f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        } else {
24749eac192faa35159752525b23345563252721c64tomhudson@google.com            fb = SCALE - fb;
2488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
250fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com
251ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb),
252ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com                         n, coverage_to_partial_alpha(fe),
253fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com                         (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
254fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com                         fOffsetX);
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrX = x + width;
2598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
262803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#if 0 // UNUSED
263a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.comstatic void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
264a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com                               int n, U8CPU riteA) {
265a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(leftA <= 0xFF);
266a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(riteA <= 0xFF);
267a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
268a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    int16_t* run = runs.fRuns;
269a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    uint8_t* aa = runs.fAlpha;
270a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
271a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (ileft > 0) {
272a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run[0] = ileft;
273a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa[0] = 0;
274a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run += ileft;
275a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa += ileft;
276a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
277a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
278a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(leftA < 0xFF);
279a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (leftA > 0) {
280a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *run++ = 1;
281a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *aa++ = leftA;
282a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
283a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
284a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (n > 0) {
285a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run[0] = n;
286a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa[0] = 0xFF;
287a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run += n;
288a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa += n;
289a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
290a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
291a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(riteA < 0xFF);
292a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (riteA > 0) {
293a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *run++ = 1;
294a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *aa++ = riteA;
295a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
296a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    run[0] = 0;
297a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com}
298803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#endif
299a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
300967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.comvoid SuperBlitter::blitRect(int x, int y, int width, int height) {
301967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(width > 0);
302967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(height > 0);
303967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
30405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // blit leading rows
30505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    while ((y & MASK)) {
306967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        this->blitH(x, y++, width);
307967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (--height <= 0) {
308967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            return;
309967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        }
310967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
311967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(height > 0);
312967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
31305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // Since this is a rect, instead of blitting supersampled rows one at a
31405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // time and then resolving to the destination canvas, we can blit
31505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // directly to the destintion canvas one row per SCALE supersampled rows.
316967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int start_y = y >> SHIFT;
317967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int stop_y = (y + height) >> SHIFT;
318967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int count = stop_y - start_y;
319967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    if (count > 0) {
320967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        y += count << SHIFT;
321967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        height -= count << SHIFT;
322967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
323967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // save original X for our tail blitH() loop at the bottom
324967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int origX = x;
325967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
326967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        x -= fSuperLeft;
327967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // hack, until I figure out why my cubics (I think) go beyond the bounds
328967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (x < 0) {
329967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            width += x;
330967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            x = 0;
331967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        }
332967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
33349eac192faa35159752525b23345563252721c64tomhudson@google.com        // There is always a left column, a middle, and a right column.
33449eac192faa35159752525b23345563252721c64tomhudson@google.com        // ileft is the destination x of the first pixel of the entire rect.
33549eac192faa35159752525b23345563252721c64tomhudson@google.com        // xleft is (SCALE - # of covered supersampled pixels) in that
33649eac192faa35159752525b23345563252721c64tomhudson@google.com        // destination pixel.
337967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int ileft = x >> SHIFT;
33805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com        int xleft = x & MASK;
33949eac192faa35159752525b23345563252721c64tomhudson@google.com        // irite is the destination x of the last pixel of the OPAQUE section.
34049eac192faa35159752525b23345563252721c64tomhudson@google.com        // xrite is the number of supersampled pixels extending beyond irite;
34149eac192faa35159752525b23345563252721c64tomhudson@google.com        // xrite/SCALE should give us alpha.
342967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int irite = (x + width) >> SHIFT;
34305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com        int xrite = (x + width) & MASK;
34449eac192faa35159752525b23345563252721c64tomhudson@google.com        if (!xrite) {
34549eac192faa35159752525b23345563252721c64tomhudson@google.com            xrite = SCALE;
34649eac192faa35159752525b23345563252721c64tomhudson@google.com            irite--;
34749eac192faa35159752525b23345563252721c64tomhudson@google.com        }
34849eac192faa35159752525b23345563252721c64tomhudson@google.com
3494714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        // Need to call flush() to clean up pending draws before we
3504714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        // even consider blitV(), since otherwise it can look nonmonotonic.
3514714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        SkASSERT(start_y > fCurrIY);
3524714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        this->flush();
3534714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com
354967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int n = irite - ileft - 1;
355967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (n < 0) {
3564714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // If n < 0, we'll only have a single partially-transparent column
3574714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // of pixels to render.
358967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            xleft = xrite - xleft;
35949eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(xleft <= SCALE);
36049eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(xleft > 0);
361967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            xrite = 0;
36249eac192faa35159752525b23345563252721c64tomhudson@google.com            fRealBlitter->blitV(ileft + fLeft, start_y, count,
36349eac192faa35159752525b23345563252721c64tomhudson@google.com                coverage_to_exact_alpha(xleft));
364967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        } else {
3654714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // With n = 0, we have two possibly-transparent columns of pixels
3664714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // to render; with n > 0, we have opaque columns between them.
3674714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com
36849eac192faa35159752525b23345563252721c64tomhudson@google.com            xleft = SCALE - xleft;
369967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3704714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // Using coverage_to_exact_alpha is not consistent with blitH()
3714714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            const int coverageL = coverage_to_exact_alpha(xleft);
3724714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            const int coverageR = coverage_to_exact_alpha(xrite);
37349eac192faa35159752525b23345563252721c64tomhudson@google.com
3744714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
3754714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
376967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3774714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
3784714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com                                       coverageL, coverageR);
3794714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        }
380967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
381967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // preamble for our next call to blitH()
382967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fCurrIY = stop_y - 1;
383967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fOffsetX = 0;
384967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fCurrY = y - 1;
385967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fRuns.reset(fWidth);
386967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        x = origX;
387967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
388967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
38949eac192faa35159752525b23345563252721c64tomhudson@google.com    // catch any remaining few rows
39005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    SkASSERT(height <= MASK);
391967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    while (--height >= 0) {
392967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        this->blitH(x, y++, width);
393967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
394967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com}
395967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
39805fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Masked supersampling antialiased blitter.
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass MaskSuperBlitter : public BaseSuperBlitter {
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                     const SkRegion& clip);
4038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~MaskSuperBlitter() {
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fRealBlitter->blitMask(fMask, fClipRect);
4058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
407967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
4088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4099f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    static bool CanHandleRect(const SkIRect& bounds) {
4109f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_RLE
4119f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        return false;
4129f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif
4138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int width = bounds.width();
414f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        int64_t rb = SkAlign4(width);
415f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        // use 64bits to detect overflow
416f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        int64_t storage = rb * bounds.height();
41755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
419f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com               (storage <= MaskSuperBlitter::kMAX_STORAGE);
4208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
42155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
4238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
4249f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_SUPERMASK
4259f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        kMAX_WIDTH = 2048,
4269f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        kMAX_STORAGE = 1024 * 1024 * 2
4279f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#else
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMAX_WIDTH = 32,    // so we don't try to do very wide things, where the RLE blitter would be faster
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMAX_STORAGE = 1024
4309f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMask      fMask;
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect     fClipRect;
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
4368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // perform a test to see if stopAlpha != 0
4378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    fStorage[(kMAX_STORAGE >> 2) + 1];
4388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
4398a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comMaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
4418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                                   const SkRegion& clip)
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        : BaseSuperBlitter(realBlitter, ir, clip) {
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(CanHandleRect(ir));
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fImage    = (uint8_t*)fStorage;
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fBounds   = ir;
4478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fRowBytes = ir.width();
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fFormat   = SkMask::kA8_Format;
449fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fClipRect = ir;
4518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fClipRect.intersect(clip.getBounds());
45255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // For valgrind, write 1 extra byte at the end so we don't read
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // uninitialized memory. See comment in add_aa_span and fStorage[].
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4589f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
4598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  I should be able to just add alpha[x] + startAlpha.
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        However, if the trailing edge of the previous span and the leading
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge of the current span round to the same super-sampled x value,
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        I might overflow to 256 with this add, hence the funny subtract.
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned tmp = *alpha + startAlpha;
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(tmp <= 256);
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *alpha = SkToU8(tmp - (tmp >> 8));
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4699f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic inline uint32_t quadplicate_byte(U8CPU value) {
4709f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    uint32_t pair = (value << 8) | value;
4719f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    return (pair << 16) | pair;
4729f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com}
4739f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
4746997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// Perform this tricky subtract, to avoid overflowing to 256. Our caller should
4756997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// only ever call us with at most enough to hit 256 (never larger), so it is
4766997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// enough to just subtract the high-bit. Actually clamping with a branch would
4776997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// be slower (e.g. if (tmp > 255) tmp = 255;)
4786997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com//
4796997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.comstatic inline void saturated_add(uint8_t* ptr, U8CPU add) {
4806997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    unsigned tmp = *ptr + add;
4816997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    SkASSERT(tmp <= 256);
4826997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    *ptr = SkToU8(tmp - (tmp >> 8));
4836997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com}
4846997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com
4859f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com// minimum count before we want to setup an inner loop, adding 4-at-a-time
4869f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#define MIN_COUNT_FOR_QUAD_LOOP  16
4879f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
4889f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
4899f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com                        U8CPU stopAlpha, U8CPU maxValue) {
4908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(middleCount >= 0);
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4926997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    saturated_add(alpha, startAlpha);
4936997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    alpha += 1;
4948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4959f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
4969f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        // loop until we're quad-byte aligned
4979f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        while (SkTCast<intptr_t>(alpha) & 0x3) {
4989f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            alpha[0] = SkToU8(alpha[0] + maxValue);
4999f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            alpha += 1;
5009f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            middleCount -= 1;
5019f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        }
5029f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5039f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        int bigCount = middleCount >> 2;
5049f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
5059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        uint32_t qval = quadplicate_byte(maxValue);
5069f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        do {
5079f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            *qptr++ += qval;
5089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        } while (--bigCount > 0);
5099f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5109f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        middleCount &= 3;
5119f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        alpha = reinterpret_cast<uint8_t*> (qptr);
5129f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        // fall through to the following while-loop
5139f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    }
5149f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5159f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    while (--middleCount >= 0) {
5168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        alpha[0] = SkToU8(alpha[0] + maxValue);
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        alpha += 1;
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // potentially this can be off the end of our "legal" alpha values, but that
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // every time (slow), we just do it, and ensure that we've allocated extra space
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // (see the + 1 comment in fStorage[]
5246997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    saturated_add(alpha, stopAlpha);
5258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5279f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid MaskSuperBlitter::blitH(int x, int y, int width) {
5288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int iy = (y >> SHIFT);
52955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
5308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    iy -= fMask.fBounds.fTop;   // make it relative to 0
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
533c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // This should never happen, but it does.  Until the true cause is
534c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // discovered, let's skip this span instead of crashing.
535c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // See http://crbug.com/17569.
536c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    if (iy < 0) {
537c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org        return;
538c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    }
539c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org
5408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ix = x >> SHIFT;
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
54655b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
5478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x -= (fMask.fBounds.fLeft << SHIFT);
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
5509f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (x < 0) {
5518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        width += x;
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x = 0;
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int start = x;
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int stop = x + width;
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(start >= 0 && stop > start);
56105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fb = start & MASK;
56205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fe = stop & MASK;
5638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5669f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (n < 0) {
567feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
568feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
569ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com        add_aa_span(row, coverage_to_partial_alpha(fe - fb));
5709f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    } else {
57149eac192faa35159752525b23345563252721c64tomhudson@google.com        fb = SCALE - fb;
572feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
573feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
574ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com        add_aa_span(row,  coverage_to_partial_alpha(fb),
575ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com                    n, coverage_to_partial_alpha(fe),
5768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrX = x + width;
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
58607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool fitsInsideLimit(const SkRect& r, SkScalar max) {
58707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    const SkScalar min = -max;
58807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    return  r.fLeft > min && r.fTop > min &&
58907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com            r.fRight < max && r.fBottom < max;
59007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com}
59107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com
59217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int overflows_short_shift(int value, int shift) {
59317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    const int s = 16 + shift;
59417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    return (value << s >> s) - value;
59517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com}
59617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
59717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com/**
59817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com  Would any of the coordinates of this rectangle not fit in a short,
59917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com  when left-shifted by shift?
60017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com*/
60117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int rect_overflows_short_shift(SkIRect rect, int shift) {
60217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(!overflows_short_shift(8191, SHIFT));
60317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(overflows_short_shift(8192, SHIFT));
60417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(!overflows_short_shift(32767, 0));
60517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(overflows_short_shift(32768, 0));
60617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
60717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // Since we expect these to succeed, we bit-or together
60817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // for a tiny extra bit of speed.
60917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    return overflows_short_shift(rect.fLeft, SHIFT) |
61017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fRight, SHIFT) |
61117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fTop, SHIFT) |
61217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fBottom, SHIFT);
61317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com}
61417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
61507db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) {
61607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    const SkScalar maxScalar = SkIntToScalar(maxInt);
6178f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com
61807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    if (fitsInsideLimit(src, maxScalar)) {
61907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        src.roundOut(dst);
62007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        return true;
62107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    }
62207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    return false;
6238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6255546ef2dd9edad601383b85907f677118f857332reed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip,
6262c508f2dc22027d61437b79326297ba055041561reed@google.com                          SkBlitter* blitter, bool forceRLE) {
6275546ef2dd9edad601383b85907f677118f857332reed@google.com    if (origClip.isEmpty()) {
6288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
631d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    SkIRect ir;
63207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com
63307db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) {
63407db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#if 0
63507db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        const SkRect& r = path.getBounds();
63607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        SkDebugf("--- bounds can't fit in SkIRect\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
63707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#endif
63807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        return;
63907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    }
6408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (ir.isEmpty()) {
641ee068aae552e8cfb3e23f9c972a377e75a07e822reed@google.com        if (path.isInverseFillType()) {
6425546ef2dd9edad601383b85907f677118f857332reed@google.com            blitter->blitRegion(origClip);
643ee068aae552e8cfb3e23f9c972a377e75a07e822reed@google.com        }
6448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
64717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // If the intersection of the path bounds and the clip bounds
64817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // will overflow 32767 when << by SHIFT, we can't supersample,
64917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // so draw without antialiasing.
65017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkIRect clippedIR;
65117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    if (path.isInverseFillType()) {
65217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       // If the path is an inverse fill, it's going to fill the entire
65317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       // clip, and we care whether the entire clip exceeds our limits.
65417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       clippedIR = origClip.getBounds();
65517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    } else {
65617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       if (!clippedIR.intersect(ir, origClip.getBounds())) {
65717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           return;
65817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       }
65917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    }
66017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    if (rect_overflows_short_shift(clippedIR, SHIFT)) {
66117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com        SkScan::FillPath(path, origClip, blitter);
66217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com        return;
66317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    }
66417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
6655546ef2dd9edad601383b85907f677118f857332reed@google.com    // Our antialiasing can't handle a clip larger than 32767, so we restrict
6665546ef2dd9edad601383b85907f677118f857332reed@google.com    // the clip to that limit here. (the runs[] uses int16_t for its index).
6675546ef2dd9edad601383b85907f677118f857332reed@google.com    //
66817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // A more general solution (one that could also eliminate the need to
66917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // disable aa based on ir bounds (see overflows_short_shift) would be
67017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // to tile the clip/target...
6715546ef2dd9edad601383b85907f677118f857332reed@google.com    SkRegion tmpClipStorage;
6725546ef2dd9edad601383b85907f677118f857332reed@google.com    const SkRegion* clipRgn = &origClip;
6735546ef2dd9edad601383b85907f677118f857332reed@google.com    {
6745546ef2dd9edad601383b85907f677118f857332reed@google.com        static const int32_t kMaxClipCoord = 32767;
6755546ef2dd9edad601383b85907f677118f857332reed@google.com        const SkIRect& bounds = origClip.getBounds();
6765546ef2dd9edad601383b85907f677118f857332reed@google.com        if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
6775546ef2dd9edad601383b85907f677118f857332reed@google.com            SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
6785546ef2dd9edad601383b85907f677118f857332reed@google.com            tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
6795546ef2dd9edad601383b85907f677118f857332reed@google.com            clipRgn = &tmpClipStorage;
6805546ef2dd9edad601383b85907f677118f857332reed@google.com        }
6815546ef2dd9edad601383b85907f677118f857332reed@google.com    }
6825546ef2dd9edad601383b85907f677118f857332reed@google.com    // for here down, use clipRgn, not origClip
6835546ef2dd9edad601383b85907f677118f857332reed@google.com
6845546ef2dd9edad601383b85907f677118f857332reed@google.com    SkScanClipper   clipper(blitter, clipRgn, ir);
6858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect*  clipRect = clipper.getClipRect();
6868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clipper.getBlitter() == NULL) { // clipped out
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        if (path.isInverseFillType()) {
6895546ef2dd9edad601383b85907f677118f857332reed@google.com            blitter->blitRegion(*clipRgn);
6908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
69355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now use the (possibly wrapped) blitter
6958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    blitter = clipper.getBlitter();
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (path.isInverseFillType()) {
6985546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_blit_above(blitter, ir, *clipRgn);
6998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect superRect, *superClipRect = NULL;
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7039f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (clipRect) {
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        superRect.set(  clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
7058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        superClipRect = &superRect;
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
709c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
710c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org
7118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
7128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // if we're an inverse filltype
7132c508f2dc22027d61437b79326297ba055041561reed@google.com    if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
7145546ef2dd9edad601383b85907f677118f857332reed@google.com        MaskSuperBlitter    superBlit(blitter, ir, *clipRgn);
715c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org        SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
7165546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
7179f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    } else {
7185546ef2dd9edad601383b85907f677118f857332reed@google.com        SuperBlitter    superBlit(blitter, ir, *clipRgn);
7195546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
7208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
72155b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
72255b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    if (path.isInverseFillType()) {
7235546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_blit_below(blitter, ir, *clipRgn);
72455b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    }
7258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7261ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7271ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com///////////////////////////////////////////////////////////////////////////////
7281ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7291ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com#include "SkRasterClip.h"
7301ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7311ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
7321ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com                          SkBlitter* blitter) {
7331ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isEmpty()) {
7341ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        return;
7351ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
736fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7371ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isBW()) {
7381ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        FillPath(path, clip.bwRgn(), blitter);
7391ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    } else {
7401ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkRegion        tmp;
7411ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkAAClipBlitter aaBlitter;
742fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7431ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        tmp.setRect(clip.getBounds());
7441ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
7451ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkScan::FillPath(path, tmp, &aaBlitter);
7461ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7471ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com}
7481ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7491ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
7501ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com                          SkBlitter* blitter) {
7511ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isEmpty()) {
7521ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        return;
7531ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7541ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7551ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isBW()) {
7561ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        AntiFillPath(path, clip.bwRgn(), blitter);
7571ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    } else {
7581ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkRegion        tmp;
7591ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkAAClipBlitter aaBlitter;
7601ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7611ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        tmp.setRect(clip.getBounds());
7621ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
7631ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
7641ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7651ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com}
766