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
322f3567c0003b948ad90528e597ea1e8326f644aereed@google.com */
335b7d603e179a38735056db5f9092d18c187e76a0reed@google.com
349f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_SUPERMASK
359f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com//#define FORCE_RLE
369f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
379f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com///////////////////////////////////////////////////////////////////////////////
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
3905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Base class for a single-pass supersampled blitter.
408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass BaseSuperBlitter : public SkBlitter {
418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
43bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed                     const SkRegion& clip, bool isInverse);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Must be explicitly defined on subclasses.
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
4736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                           const int16_t runs[]) override {
480c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// May not be called on BaseSuperBlitter because it blits out of order.
5136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void blitV(int x, int y, int height, SkAlpha alpha) override {
520c00f21fee3f5cfa3aa7e5d46ff94cb8cf340451tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprotected:
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkBlitter*  fRealBlitter;
5705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Current y coordinate, in destination coordinates.
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int         fCurrIY;
5905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Widest row of region to be blitted, in destination coordinates.
6005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fWidth;
6105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Leftmost x coordinate in any row, in destination coordinates.
6205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fLeft;
6305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Leftmost x coordinate in any row, in supersampled coordinates.
6405fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int         fSuperLeft;
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkDEBUGCODE(int fCurrX;)
6705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Current y coordinate in supersampled coordinates.
68fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    int fCurrY;
6905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Initial y coordinate (top of bounds).
70045e62d715f5ee9b03deb5af3c750f8318096179reed@google.com    int fTop;
71bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed
72bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    SkIRect fSectBounds;
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
75bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedBaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlit, const SkIRect& ir, const SkRegion& clip,
76bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed                                   bool isInverse) {
77bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    fRealBlitter = realBlit;
78bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed
79bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    SkIRect sectBounds;
80bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    if (isInverse) {
81c553b7a7172bab052eed8432856c85fd01601b27reed        // We use the clip bounds instead of the ir, since we may be asked to
82c553b7a7172bab052eed8432856c85fd01601b27reed        //draw outside of the rect when we're a inverse filltype
83bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        sectBounds = clip.getBounds();
84bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    } else {
85bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        if (!sectBounds.intersect(ir, clip.getBounds())) {
86bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed            sectBounds.setEmpty();
87bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        }
88bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    }
8955b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
90bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    const int left = sectBounds.left();
91bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    const int right = sectBounds.right();
92fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fLeft = left;
948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fSuperLeft = left << SHIFT;
958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fWidth = right - left;
96bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    fTop = sectBounds.top();
97bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    fCurrIY = fTop - 1;
98bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    fCurrY = (fTop << SHIFT) - 1;
99bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed
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:
106bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip, bool isInverse);
1078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~SuperBlitter() {
1098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->flush();
1108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
1118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Once fRuns contains a complete supersampled row, flush() blits
11305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// it out through the wrapped blitter.
1148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void flush();
1158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
11605fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Blits a row of pixels, with location and width specified
11705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// in supersampled coordinates.
11836352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void blitH(int x, int y, int width) override;
11905fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// Blits a rectangle of pixels, with location and size specified
12005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    /// in supersampled coordinates.
12136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void blitRect(int x, int y, int width, int height) override;
1228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
1238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
1242ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // The next three variables are used to track a circular buffer that
1252ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // contains the values used in SkAlphaRuns. These variables should only
1262ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // ever be updated in advanceRuns(), and fRuns should always point to
1272ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // a valid SkAlphaRuns...
1282ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int         fRunsToBuffer;
1292ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    void*       fRunsBuffer;
1302ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int         fCurrentRun;
1318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkAlphaRuns fRuns;
1322ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
1332ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // extra one to store the zero at the end
1342ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    int getRunsSz() const { return (fWidth + 1 + (fWidth + 2)/2) * sizeof(int16_t); }
1352ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
1362ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // This function updates the fRuns variable to point to the next buffer space
1372ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // with adequate storage for a SkAlphaRuns. It mostly just advances fCurrentRun
1382ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    // and resets fRuns to point to an empty scanline.
1392ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    void advanceRuns() {
1402ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        const size_t kRunsSz = this->getRunsSz();
1412ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fCurrentRun = (fCurrentRun + 1) % fRunsToBuffer;
1422ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.fRuns = reinterpret_cast<int16_t*>(
1432ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski            reinterpret_cast<uint8_t*>(fRunsBuffer) + fCurrentRun * kRunsSz);
1442ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.fAlpha = reinterpret_cast<SkAlpha*>(fRuns.fRuns + fWidth + 1);
1452ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski        fRuns.reset(fWidth);
1462ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski    }
1472ec93fc1d3206db4dcf74ccfc1c995badbc135e9krajcevski
148fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    int         fOffsetX;
1498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
1508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
151bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedSuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
152bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed                           bool isInverse)
153bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        : BaseSuperBlitter(realBlitter, ir, clip, isInverse)
154bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed{
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    return aa;
1898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
1908a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
191ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com/** coverage_to_exact_alpha() is being used by our blitter, which wants
192ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    a final value in [0, 255].
193ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com*/
19449eac192faa35159752525b23345563252721c64tomhudson@google.comstatic inline int coverage_to_exact_alpha(int aa) {
19531bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    int alpha = (256 >> SHIFT) * aa;
19631bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    // clamp 256->255
19731bab3934c773c2bd4c1e5e9ba8eb87c1c623b09tomhudson@google.com    return alpha - (alpha >> 8);
19849eac192faa35159752525b23345563252721c64tomhudson@google.com}
19949eac192faa35159752525b23345563252721c64tomhudson@google.com
2009f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid SuperBlitter::blitH(int x, int y, int width) {
201967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(width > 0);
202967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
2038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int iy = y >> SHIFT;
2048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(iy >= fCurrIY);
2058a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x -= fSuperLeft;
2078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
2089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (x < 0) {
2098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        width += x;
2108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x = 0;
2118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(y != fCurrY || x >= fCurrX);
2158a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
216fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    SkASSERT(y >= fCurrY);
217fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    if (fCurrY != y) {
218fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com        fOffsetX = 0;
219fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com        fCurrY = y;
220fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com    }
221fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
2229f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (iy != fCurrIY) {  // new scanline
2238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        this->flush();
2248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fCurrIY = iy;
2258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
2268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2275a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int start = x;
2285a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int stop = x + width;
2295a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com
2305a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    SkASSERT(start >= 0 && stop > start);
23105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // integer-pixel-aligned ends of blit, rounded out
23205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fb = start & MASK;
23305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fe = stop & MASK;
2345a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
2355a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com
2365a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    if (n < 0) {
2375a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        fb = fe - fb;
2385a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        n = 0;
2395a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        fe = 0;
2405a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com    } else {
2415a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com        if (fb == 0) {
2425a1e79595f7d1f951fb777cb16ad730bae649c84reed@google.com            n += 1;
2439f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        } else {
24449eac192faa35159752525b23345563252721c64tomhudson@google.com            fb = SCALE - fb;
2458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
2468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
247fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com
248ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com    fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb),
249ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com                         n, coverage_to_partial_alpha(fe),
250fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com                         (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
251fa57ae7d1ec7404a654e0f32c09b698feec1b7fareed@google.com                         fOffsetX);
2528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
2538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
2548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
2558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrX = x + width;
2568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
2578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
2588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
259803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#if 0 // UNUSED
260a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.comstatic void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
261a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com                               int n, U8CPU riteA) {
262a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(leftA <= 0xFF);
263a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(riteA <= 0xFF);
264a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
265a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    int16_t* run = runs.fRuns;
266a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    uint8_t* aa = runs.fAlpha;
267a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
268a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (ileft > 0) {
269a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run[0] = ileft;
270a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa[0] = 0;
271a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run += ileft;
272a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa += ileft;
273a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
274a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
275a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(leftA < 0xFF);
276a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (leftA > 0) {
277a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *run++ = 1;
278a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *aa++ = leftA;
279a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
280a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
281a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (n > 0) {
282a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run[0] = n;
283a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa[0] = 0xFF;
284a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        run += n;
285a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        aa += n;
286a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
287a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
288a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    SkASSERT(riteA < 0xFF);
289a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    if (riteA > 0) {
290a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *run++ = 1;
291a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com        *aa++ = riteA;
292a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    }
293a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com    run[0] = 0;
294a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com}
295803eceb6afd13f07416df0b4a9bb714e9370f081caryclark@google.com#endif
296a89c77b5cafcc13d76cb07c3240e48705cb30d8freed@google.com
297967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.comvoid SuperBlitter::blitRect(int x, int y, int width, int height) {
298967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(width > 0);
299967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(height > 0);
300967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
30105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // blit leading rows
30205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    while ((y & MASK)) {
303967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        this->blitH(x, y++, width);
304967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (--height <= 0) {
305967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            return;
306967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        }
307967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
308967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    SkASSERT(height > 0);
309967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
31005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // Since this is a rect, instead of blitting supersampled rows one at a
31105fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // time and then resolving to the destination canvas, we can blit
31205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    // directly to the destintion canvas one row per SCALE supersampled rows.
313967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int start_y = y >> SHIFT;
314967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int stop_y = (y + height) >> SHIFT;
315967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    int count = stop_y - start_y;
316967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    if (count > 0) {
317967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        y += count << SHIFT;
318967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        height -= count << SHIFT;
319967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
320967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // save original X for our tail blitH() loop at the bottom
321967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int origX = x;
322967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
323967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        x -= fSuperLeft;
324967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // hack, until I figure out why my cubics (I think) go beyond the bounds
325967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (x < 0) {
326967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            width += x;
327967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            x = 0;
328967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        }
329967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
33049eac192faa35159752525b23345563252721c64tomhudson@google.com        // There is always a left column, a middle, and a right column.
33149eac192faa35159752525b23345563252721c64tomhudson@google.com        // ileft is the destination x of the first pixel of the entire rect.
33249eac192faa35159752525b23345563252721c64tomhudson@google.com        // xleft is (SCALE - # of covered supersampled pixels) in that
33349eac192faa35159752525b23345563252721c64tomhudson@google.com        // destination pixel.
334967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int ileft = x >> SHIFT;
33505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com        int xleft = x & MASK;
33649eac192faa35159752525b23345563252721c64tomhudson@google.com        // irite is the destination x of the last pixel of the OPAQUE section.
33749eac192faa35159752525b23345563252721c64tomhudson@google.com        // xrite is the number of supersampled pixels extending beyond irite;
33849eac192faa35159752525b23345563252721c64tomhudson@google.com        // xrite/SCALE should give us alpha.
339967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int irite = (x + width) >> SHIFT;
34005fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com        int xrite = (x + width) & MASK;
34149eac192faa35159752525b23345563252721c64tomhudson@google.com        if (!xrite) {
34249eac192faa35159752525b23345563252721c64tomhudson@google.com            xrite = SCALE;
34349eac192faa35159752525b23345563252721c64tomhudson@google.com            irite--;
34449eac192faa35159752525b23345563252721c64tomhudson@google.com        }
34549eac192faa35159752525b23345563252721c64tomhudson@google.com
3464714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        // Need to call flush() to clean up pending draws before we
3474714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        // even consider blitV(), since otherwise it can look nonmonotonic.
3484714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        SkASSERT(start_y > fCurrIY);
3494714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        this->flush();
3504714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com
351967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        int n = irite - ileft - 1;
352967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        if (n < 0) {
3534714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // If n < 0, we'll only have a single partially-transparent column
3544714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // of pixels to render.
355967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            xleft = xrite - xleft;
35649eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(xleft <= SCALE);
35749eac192faa35159752525b23345563252721c64tomhudson@google.com            SkASSERT(xleft > 0);
358967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com            xrite = 0;
35949eac192faa35159752525b23345563252721c64tomhudson@google.com            fRealBlitter->blitV(ileft + fLeft, start_y, count,
36049eac192faa35159752525b23345563252721c64tomhudson@google.com                coverage_to_exact_alpha(xleft));
361967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        } else {
3624714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // With n = 0, we have two possibly-transparent columns of pixels
3634714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // to render; with n > 0, we have opaque columns between them.
3644714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com
36549eac192faa35159752525b23345563252721c64tomhudson@google.com            xleft = SCALE - xleft;
366967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3674714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            // Using coverage_to_exact_alpha is not consistent with blitH()
3684714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            const int coverageL = coverage_to_exact_alpha(xleft);
3694714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            const int coverageR = coverage_to_exact_alpha(xrite);
37049eac192faa35159752525b23345563252721c64tomhudson@google.com
3714714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
3724714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
373967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3744714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com            fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
3754714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com                                       coverageL, coverageR);
3764714359ec091b34a4f88eb9708868a58a22177d3tomhudson@google.com        }
377967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
378967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        // preamble for our next call to blitH()
379967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fCurrIY = stop_y - 1;
380967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fOffsetX = 0;
381967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fCurrY = y - 1;
382967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        fRuns.reset(fWidth);
383967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        x = origX;
384967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
385967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
38649eac192faa35159752525b23345563252721c64tomhudson@google.com    // catch any remaining few rows
38705fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    SkASSERT(height <= MASK);
388967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    while (--height >= 0) {
389967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com        this->blitH(x, y++, width);
390967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com    }
391967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com}
392967a35d8c5bc46261764b972d5295629d3b02d0dreed@google.com
3938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
3948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
39505fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com/// Masked supersampling antialiased blitter.
3968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comclass MaskSuperBlitter : public BaseSuperBlitter {
3978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.compublic:
398bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion&, bool isInverse);
3998a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    virtual ~MaskSuperBlitter() {
4008a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        fRealBlitter->blitMask(fMask, fClipRect);
4018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
4028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
40336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void blitH(int x, int y, int width) override;
4048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    static bool CanHandleRect(const SkIRect& bounds) {
4069f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_RLE
4079f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        return false;
4089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif
4098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int width = bounds.width();
410f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        int64_t rb = SkAlign4(width);
411f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        // use 64bits to detect overflow
412f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com        int64_t storage = rb * bounds.height();
41355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
415f9f258c65635fb8dcc61e1f39ba84d1a4b4234d7reed@google.com               (storage <= MaskSuperBlitter::kMAX_STORAGE);
4168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
41755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comprivate:
4198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum {
4209f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#ifdef FORCE_SUPERMASK
4219f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        kMAX_WIDTH = 2048,
4229f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        kMAX_STORAGE = 1024 * 1024 * 2
4239f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#else
4248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMAX_WIDTH = 32,    // so we don't try to do very wide things, where the RLE blitter would be faster
4258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kMAX_STORAGE = 1024
4269f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#endif
4278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
4288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkMask      fMask;
4308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect     fClipRect;
4318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
4328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // perform a test to see if stopAlpha != 0
4338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint32_t    fStorage[(kMAX_STORAGE >> 2) + 1];
4348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
4358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
436bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reedMaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir, const SkRegion& clip,
437bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed                                   bool isInverse)
438bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    : BaseSuperBlitter(realBlitter, ir, clip, isInverse)
439bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed{
4408a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(CanHandleRect(ir));
441bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    SkASSERT(!isInverse);
4428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fImage    = (uint8_t*)fStorage;
4448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fBounds   = ir;
4458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fRowBytes = ir.width();
4468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fMask.fFormat   = SkMask::kA8_Format;
447fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
4488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fClipRect = ir;
449f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips    if (!fClipRect.intersect(clip.getBounds())) {
450f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips        SkASSERT(0);
451f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips        fClipRect.setEmpty();
452f4e5995ac70d4614e0a05b92a8a03e2b7d76bd9crobertphillips    }
45355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
4548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // For valgrind, write 1 extra byte at the end so we don't read
4558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // uninitialized memory. See comment in add_aa_span and fStorage[].
4568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
4578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4599f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
4608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    /*  I should be able to just add alpha[x] + startAlpha.
4618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        However, if the trailing edge of the previous span and the leading
4628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        edge of the current span round to the same super-sampled x value,
4638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        I might overflow to 256 with this add, hence the funny subtract.
4648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    */
4658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    unsigned tmp = *alpha + startAlpha;
4668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(tmp <= 256);
4678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    *alpha = SkToU8(tmp - (tmp >> 8));
4688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
4698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4709f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic inline uint32_t quadplicate_byte(U8CPU value) {
4719f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    uint32_t pair = (value << 8) | value;
4729f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    return (pair << 16) | pair;
4739f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com}
4749f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
4756997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// Perform this tricky subtract, to avoid overflowing to 256. Our caller should
4766997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// only ever call us with at most enough to hit 256 (never larger), so it is
4776997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// enough to just subtract the high-bit. Actually clamping with a branch would
4786997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com// be slower (e.g. if (tmp > 255) tmp = 255;)
4796997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com//
4806997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.comstatic inline void saturated_add(uint8_t* ptr, U8CPU add) {
4816997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    unsigned tmp = *ptr + add;
4826997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    SkASSERT(tmp <= 256);
4836997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    *ptr = SkToU8(tmp - (tmp >> 8));
4846997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com}
4856997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com
4869f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com// minimum count before we want to setup an inner loop, adding 4-at-a-time
4879f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com#define MIN_COUNT_FOR_QUAD_LOOP  16
4889f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
4899f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
4909f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com                        U8CPU stopAlpha, U8CPU maxValue) {
4918a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(middleCount >= 0);
4928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4936997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    saturated_add(alpha, startAlpha);
4946997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    alpha += 1;
4958a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
4969f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
4979f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        // loop until we're quad-byte aligned
4989f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        while (SkTCast<intptr_t>(alpha) & 0x3) {
4999f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            alpha[0] = SkToU8(alpha[0] + maxValue);
5009f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            alpha += 1;
5019f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            middleCount -= 1;
5029f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        }
5039f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5049f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        int bigCount = middleCount >> 2;
5059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
5069f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        uint32_t qval = quadplicate_byte(maxValue);
5079f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        do {
5089f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com            *qptr++ += qval;
5099f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        } while (--bigCount > 0);
5109f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5119f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        middleCount &= 3;
5129f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        alpha = reinterpret_cast<uint8_t*> (qptr);
5139f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com        // fall through to the following while-loop
5149f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    }
5159f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com
5169f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    while (--middleCount >= 0) {
5178a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        alpha[0] = SkToU8(alpha[0] + maxValue);
5188a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        alpha += 1;
5198a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // potentially this can be off the end of our "legal" alpha values, but that
5228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
5238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // every time (slow), we just do it, and ensure that we've allocated extra space
5248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // (see the + 1 comment in fStorage[]
5256997e5d282fd9fa8e0d0afea7f3bd10dee96056ereed@google.com    saturated_add(alpha, stopAlpha);
5268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5289f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.comvoid MaskSuperBlitter::blitH(int x, int y, int width) {
5298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int iy = (y >> SHIFT);
53055b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
5318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
5328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    iy -= fMask.fBounds.fTop;   // make it relative to 0
5338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
534c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // This should never happen, but it does.  Until the true cause is
535c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // discovered, let's skip this span instead of crashing.
536c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    // See http://crbug.com/17569.
537c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    if (iy < 0) {
538c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org        return;
539c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    }
540c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org
5418a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
5428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    {
5438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        int ix = x >> SHIFT;
5448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
5458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
54755b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
5488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    x -= (fMask.fBounds.fLeft << SHIFT);
5498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
5519f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (x < 0) {
5528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        width += x;
5538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        x = 0;
5548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
5578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int start = x;
5598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int stop = x + width;
5608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkASSERT(start >= 0 && stop > start);
56205fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fb = start & MASK;
56305fffdcc912cb9678e03d39529577e2a29b9209etomhudson@google.com    int fe = stop & MASK;
5648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
5658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5679f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (n < 0) {
568feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
569feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
570ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com        add_aa_span(row, coverage_to_partial_alpha(fe - fb));
5719f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    } else {
57249eac192faa35159752525b23345563252721c64tomhudson@google.com        fb = SCALE - fb;
573feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
574feef49c4d10cce91556f54986989f0851f8d3608senorblanco@chromium.org        SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
575ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com        add_aa_span(row,  coverage_to_partial_alpha(fb),
576ffc92488ae7fcb2610e707b5bed1c09b8b4d16aatomhudson@google.com                    n, coverage_to_partial_alpha(fe),
5778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                    (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
5788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
5798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
5818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    fCurrX = x + width;
5828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
5838a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
5848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
5858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com///////////////////////////////////////////////////////////////////////////////
5868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
58707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool fitsInsideLimit(const SkRect& r, SkScalar max) {
58807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    const SkScalar min = -max;
58907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    return  r.fLeft > min && r.fTop > min &&
59007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com            r.fRight < max && r.fBottom < max;
59107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com}
59207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com
59317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int overflows_short_shift(int value, int shift) {
59417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    const int s = 16 + shift;
59517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    return (value << s >> s) - value;
59617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com}
59717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
59817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com/**
59917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com  Would any of the coordinates of this rectangle not fit in a short,
60017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com  when left-shifted by shift?
60117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com*/
60217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.comstatic int rect_overflows_short_shift(SkIRect rect, int shift) {
60317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(!overflows_short_shift(8191, SHIFT));
60417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(overflows_short_shift(8192, SHIFT));
60517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(!overflows_short_shift(32767, 0));
60617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkASSERT(overflows_short_shift(32768, 0));
60717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
60817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // Since we expect these to succeed, we bit-or together
60917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // for a tiny extra bit of speed.
61017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    return overflows_short_shift(rect.fLeft, SHIFT) |
61117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fRight, SHIFT) |
61217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fTop, SHIFT) |
61317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           overflows_short_shift(rect.fBottom, SHIFT);
61417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com}
61517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
61607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.comstatic bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) {
61707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    const SkScalar maxScalar = SkIntToScalar(maxInt);
6188f4d2306fa866a26f9448048ff63f692b2ba43aareed@google.com
61907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    if (fitsInsideLimit(src, maxScalar)) {
62007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        src.roundOut(dst);
62107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        return true;
62207db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    }
62307db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    return false;
6248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
6258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6265546ef2dd9edad601383b85907f677118f857332reed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip,
6272c508f2dc22027d61437b79326297ba055041561reed@google.com                          SkBlitter* blitter, bool forceRLE) {
6285546ef2dd9edad601383b85907f677118f857332reed@google.com    if (origClip.isEmpty()) {
6298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
632bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    const bool isInverse = path.isInverseFillType();
633d252db03d9650013b545ef9781fe993c07f8f314reed@android.com    SkIRect ir;
63407db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com
63507db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) {
63607db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#if 0
63707db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        const SkRect& r = path.getBounds();
63807db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        SkDebugf("--- bounds can't fit in SkIRect\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
63907db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com#endif
64007db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com        return;
64107db86126a5bc30d4eaf00e69890e89d4add4370reed@google.com    }
6428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (ir.isEmpty()) {
643bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        if (isInverse) {
6445546ef2dd9edad601383b85907f677118f857332reed@google.com            blitter->blitRegion(origClip);
645ee068aae552e8cfb3e23f9c972a377e75a07e822reed@google.com        }
6468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
6488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
64917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // If the intersection of the path bounds and the clip bounds
65017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // will overflow 32767 when << by SHIFT, we can't supersample,
65117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // so draw without antialiasing.
65217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    SkIRect clippedIR;
653bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    if (isInverse) {
65417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       // If the path is an inverse fill, it's going to fill the entire
65517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       // clip, and we care whether the entire clip exceeds our limits.
65617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       clippedIR = origClip.getBounds();
65717b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    } else {
65817b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       if (!clippedIR.intersect(ir, origClip.getBounds())) {
65917b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com           return;
66017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com       }
66117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    }
66217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    if (rect_overflows_short_shift(clippedIR, SHIFT)) {
66317b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com        SkScan::FillPath(path, origClip, blitter);
66417b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com        return;
66517b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    }
66617b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com
6675546ef2dd9edad601383b85907f677118f857332reed@google.com    // Our antialiasing can't handle a clip larger than 32767, so we restrict
6685546ef2dd9edad601383b85907f677118f857332reed@google.com    // the clip to that limit here. (the runs[] uses int16_t for its index).
6695546ef2dd9edad601383b85907f677118f857332reed@google.com    //
67017b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // A more general solution (one that could also eliminate the need to
67117b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // disable aa based on ir bounds (see overflows_short_shift) would be
67217b6ba41f2144cd3ff446d52da9df23ca7d77b90tomhudson@google.com    // to tile the clip/target...
6735546ef2dd9edad601383b85907f677118f857332reed@google.com    SkRegion tmpClipStorage;
6745546ef2dd9edad601383b85907f677118f857332reed@google.com    const SkRegion* clipRgn = &origClip;
6755546ef2dd9edad601383b85907f677118f857332reed@google.com    {
6765546ef2dd9edad601383b85907f677118f857332reed@google.com        static const int32_t kMaxClipCoord = 32767;
6775546ef2dd9edad601383b85907f677118f857332reed@google.com        const SkIRect& bounds = origClip.getBounds();
6785546ef2dd9edad601383b85907f677118f857332reed@google.com        if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
6795546ef2dd9edad601383b85907f677118f857332reed@google.com            SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
6805546ef2dd9edad601383b85907f677118f857332reed@google.com            tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
6815546ef2dd9edad601383b85907f677118f857332reed@google.com            clipRgn = &tmpClipStorage;
6825546ef2dd9edad601383b85907f677118f857332reed@google.com        }
6835546ef2dd9edad601383b85907f677118f857332reed@google.com    }
6845546ef2dd9edad601383b85907f677118f857332reed@google.com    // for here down, use clipRgn, not origClip
6855546ef2dd9edad601383b85907f677118f857332reed@google.com
6865546ef2dd9edad601383b85907f677118f857332reed@google.com    SkScanClipper   clipper(blitter, clipRgn, ir);
6878a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    const SkIRect*  clipRect = clipper.getClipRect();
6888a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
6898a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    if (clipper.getBlitter() == NULL) { // clipped out
690bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        if (isInverse) {
6915546ef2dd9edad601383b85907f677118f857332reed@google.com            blitter->blitRegion(*clipRgn);
6928a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        }
6938a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return;
6948a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
69555b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
6968a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // now use the (possibly wrapped) blitter
6978a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    blitter = clipper.getBlitter();
6988a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
699bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    if (isInverse) {
7005546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_blit_above(blitter, ir, *clipRgn);
7018a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7028a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7038a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkIRect superRect, *superClipRect = NULL;
7048a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
7059f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    if (clipRect) {
7068a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        superRect.set(  clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
7078a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com                        clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
7088a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        superClipRect = &superRect;
7098a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
7108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
711c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org    SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
712c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org
7138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
7148a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    // if we're an inverse filltype
715bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    if (!isInverse && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
716bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        MaskSuperBlitter    superBlit(blitter, ir, *clipRgn, isInverse);
717c41513c4dac51d68570b309ec28a315d974edea7senorblanco@chromium.org        SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
7185546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
7199f2f0a84d5a1b7c67c1d2a253bc2d7ee6f3f4625reed@google.com    } else {
720bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed        SuperBlitter    superBlit(blitter, ir, *clipRgn, isInverse);
7215546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
7228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
72355b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com
724bcba2c9f9fcd14ac7123f9a7ac58fb834abba4e3reed    if (isInverse) {
7255546ef2dd9edad601383b85907f677118f857332reed@google.com        sk_blit_below(blitter, ir, *clipRgn);
72655b6b58d8f6e7529c9b9cea606a6e3637c8e2e39reed@google.com    }
7278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com}
7281ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7291ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com///////////////////////////////////////////////////////////////////////////////
7301ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7311ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com#include "SkRasterClip.h"
7321ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7331ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
7341ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com                          SkBlitter* blitter) {
7351ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isEmpty()) {
7361ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        return;
7371ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
738fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7391ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isBW()) {
7401ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        FillPath(path, clip.bwRgn(), blitter);
7411ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    } else {
7421ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkRegion        tmp;
7431ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkAAClipBlitter aaBlitter;
744fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
7451ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        tmp.setRect(clip.getBounds());
7461ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
7471ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkScan::FillPath(path, tmp, &aaBlitter);
7481ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7491ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com}
7501ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7511ba7137fc0dcace0c1be1367fe977202c63746bareed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
7521ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com                          SkBlitter* blitter) {
7531ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isEmpty()) {
7541ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        return;
7551ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7561ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7571ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    if (clip.isBW()) {
7581ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        AntiFillPath(path, clip.bwRgn(), blitter);
7591ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    } else {
7601ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkRegion        tmp;
7611ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkAAClipBlitter aaBlitter;
7621ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com
7631ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        tmp.setRect(clip.getBounds());
7641ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
7651ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com        SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
7661ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com    }
7671ba7137fc0dcace0c1be1367fe977202c63746bareed@google.com}
768