1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2006 The Android Open Source Project
4685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkScanPriv.h"
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkPath.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkMatrix.h"
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkBlitter.h"
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkRegion.h"
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "SkAntiRun.h"
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define SHIFT   2
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define SCALE   (1 << SHIFT)
19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#define MASK    (SCALE - 1)
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com/** @file
2282e33805a561c6ce02383453c523749bbfc3e505reed@google.com    We have two techniques for capturing the output of the supersampler:
2382e33805a561c6ce02383453c523749bbfc3e505reed@google.com    - SUPERMASK, which records a large mask-bitmap
2482e33805a561c6ce02383453c523749bbfc3e505reed@google.com        this is often faster for small, complex objects
2582e33805a561c6ce02383453c523749bbfc3e505reed@google.com    - RLE, which records a rle-encoded scanline
2682e33805a561c6ce02383453c523749bbfc3e505reed@google.com        this is often faster for large objects with big spans
2782e33805a561c6ce02383453c523749bbfc3e505reed@google.com
2808d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    These blitters use two coordinate systems:
2908d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    - destination coordinates, scale equal to the output - often
3008d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com        abbreviated with 'i' or 'I' in variable names
3108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    - supersampled coordinates, scale equal to the output * SCALE
3208d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com
33ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com    Enabling SK_USE_LEGACY_AA_COVERAGE keeps the aa coverage calculations as
34ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com    they were before the fix that unified the output of the RLE and MASK
35ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com    supersamplers.
3682e33805a561c6ce02383453c523749bbfc3e505reed@google.com */
37ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com
38d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com//#define FORCE_SUPERMASK
39d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com//#define FORCE_RLE
40c5ae188b05cacee87cf66255c8bfafafef87a1d9reed@google.com//#define SK_USE_LEGACY_AA_COVERAGE
41d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
42d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com///////////////////////////////////////////////////////////////////////////////
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
4408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com/// Base class for a single-pass supersampled blitter.
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass BaseSuperBlitter : public SkBlitter {
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.compublic:
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                     const SkRegion& clip);
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
5008d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Must be explicitly defined on subclasses.
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    virtual void blitAntiH(int x, int y, const SkAlpha antialias[],
5272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com                           const int16_t runs[]) SK_OVERRIDE {
532d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
5508d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// May not be called on BaseSuperBlitter because it blits out of order.
5672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE {
572d7de2d243beab591671dfaf535a637b5d305735tomhudson@google.com        SkDEBUGFAIL("How did I get here?");
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comprotected:
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkBlitter*  fRealBlitter;
6208d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Current y coordinate, in destination coordinates.
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int         fCurrIY;
6408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Widest row of region to be blitted, in destination coordinates.
6508d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int         fWidth;
6608d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Leftmost x coordinate in any row, in destination coordinates.
6708d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int         fLeft;
6808d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Leftmost x coordinate in any row, in supersampled coordinates.
6908d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int         fSuperLeft;
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkDEBUGCODE(int fCurrX;)
7208d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Current y coordinate in supersampled coordinates.
73e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    int fCurrY;
7408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Initial y coordinate (top of bounds).
7526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    int fTop;
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comBaseSuperBlitter::BaseSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                   const SkRegion& clip) {
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRealBlitter = realBlitter;
81434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
82a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com    /*
83a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com     *  We use the clip bounds instead of the ir, since we may be asked to
84a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com     *  draw outside of the rect if we're a inverse filltype
85a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com     */
86a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com    const int left = clip.getBounds().fLeft;
87a7cb04e6879f0f71deee156cce701a13124f6a7ereed@google.com    const int right = clip.getBounds().fRight;
88935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fLeft = left;
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fSuperLeft = left << SHIFT;
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fWidth = right - left;
9226f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#if 0
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fCurrIY = -1;
9471f2996e36afd6a2f46ee09942169cee8edd392areed@google.com    fCurrY = -1;
9526f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#else
9626f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    fTop = ir.fTop;
9726f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    fCurrIY = ir.fTop - 1;
9826f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    fCurrY = (ir.fTop << SHIFT) - 1;
9926f5a398c38318eb7eab44f72e024ef784d247fareed@google.com#endif
10071f2996e36afd6a2f46ee09942169cee8edd392areed@google.com    SkDEBUGCODE(fCurrX = -1;)
101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
102bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
10308d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com/// Run-length-encoded supersampling antialiased blitter.
104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass SuperBlitter : public BaseSuperBlitter {
105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.compublic:
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                 const SkRegion& clip);
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    virtual ~SuperBlitter() {
110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->flush();
111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        sk_free(fRuns.fRuns);
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
11408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Once fRuns contains a complete supersampled row, flush() blits
11508d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// it out through the wrapped blitter.
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    void flush();
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
11808d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Blits a row of pixels, with location and width specified
11908d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// in supersampled coordinates.
12072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
12108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// Blits a rectangle of pixels, with location and size specified
12208d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    /// in supersampled coordinates.
12372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE;
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comprivate:
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkAlphaRuns fRuns;
127e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    int         fOffsetX;
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comSuperBlitter::SuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                           const SkRegion& clip)
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        : BaseSuperBlitter(realBlitter, ir, clip) {
133bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const int width = fWidth;
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // extra one to store the zero at the end
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRuns.fRuns = (int16_t*)sk_malloc_throw((width + 1 + (width + 2)/2) * sizeof(int16_t));
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRuns.fAlpha = (uint8_t*)(fRuns.fRuns + width + 1);
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRuns.reset(width);
139e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com
140e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    fOffsetX = 0;
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
143d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comvoid SuperBlitter::flush() {
14426f5a398c38318eb7eab44f72e024ef784d247fareed@google.com    if (fCurrIY >= fTop) {
145d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        if (!fRuns.empty()) {
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        //  SkDEBUGCODE(fRuns.dump();)
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fRealBlitter->blitAntiH(fLeft, fCurrIY, fRuns.fAlpha, fRuns.fRuns);
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            fRuns.reset(fWidth);
149e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com            fOffsetX = 0;
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
15126f5a398c38318eb7eab44f72e024ef784d247fareed@google.com        fCurrIY = fTop - 1;
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkDEBUGCODE(fCurrX = -1;)
153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
15654c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com/** coverage_to_partial_alpha() is being used by SkAlphaRuns, which
15754c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    *accumulates* SCALE pixels worth of "alpha" in [0,(256/SCALE)]
15854c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    to produce a final value in [0, 255] and handles clamping 256->255
15954c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    itself, with the same (alpha - (alpha >> 8)) correction as
16054c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    coverage_to_exact_alpha().
16154c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com*/
16254c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.comstatic inline int coverage_to_partial_alpha(int aa) {
163bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    aa <<= 8 - 2*SHIFT;
164ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com#ifdef SK_USE_LEGACY_AA_COVERAGE
165bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    aa -= aa >> (8 - SHIFT - 1);
16654c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com#endif
167ef99ee0006a8a0a7e0d90f709591644f422f1b1ereed@google.com    return aa;
168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
169bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
17054c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com/** coverage_to_exact_alpha() is being used by our blitter, which wants
17154c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    a final value in [0, 255].
17254c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com*/
1736130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.comstatic inline int coverage_to_exact_alpha(int aa) {
174d5a4a434a91cf65e53807785ac6a3d3747726fcetomhudson@google.com    int alpha = (256 >> SHIFT) * aa;
175d5a4a434a91cf65e53807785ac6a3d3747726fcetomhudson@google.com    // clamp 256->255
176d5a4a434a91cf65e53807785ac6a3d3747726fcetomhudson@google.com    return alpha - (alpha >> 8);
1776130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com}
1786130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com
179d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comvoid SuperBlitter::blitH(int x, int y, int width) {
18072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    SkASSERT(width > 0);
18172de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int iy = y >> SHIFT;
183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(iy >= fCurrIY);
184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    x -= fSuperLeft;
186bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
187d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (x < 0) {
188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        width += x;
189bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x = 0;
190bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
191bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
192bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(y != fCurrY || x >= fCurrX);
194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
195e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    SkASSERT(y >= fCurrY);
196e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    if (fCurrY != y) {
197e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com        fOffsetX = 0;
198e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com        fCurrY = y;
199e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com    }
200935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
201d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (iy != fCurrIY) {  // new scanline
202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        this->flush();
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fCurrIY = iy;
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
20697a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    int start = x;
20797a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    int stop = x + width;
20897a08960d3d82b295c3fce90d74be44a9e735019reed@google.com
20997a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    SkASSERT(start >= 0 && stop > start);
21008d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    // integer-pixel-aligned ends of blit, rounded out
21108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int fb = start & MASK;
21208d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int fe = stop & MASK;
21397a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
21497a08960d3d82b295c3fce90d74be44a9e735019reed@google.com
21597a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    if (n < 0) {
21697a08960d3d82b295c3fce90d74be44a9e735019reed@google.com        fb = fe - fb;
21797a08960d3d82b295c3fce90d74be44a9e735019reed@google.com        n = 0;
21897a08960d3d82b295c3fce90d74be44a9e735019reed@google.com        fe = 0;
21997a08960d3d82b295c3fce90d74be44a9e735019reed@google.com    } else {
22097a08960d3d82b295c3fce90d74be44a9e735019reed@google.com        if (fb == 0) {
22197a08960d3d82b295c3fce90d74be44a9e735019reed@google.com            n += 1;
222d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        } else {
2236130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            fb = SCALE - fb;
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
226e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com
22754c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com    fOffsetX = fRuns.add(x >> SHIFT, coverage_to_partial_alpha(fb),
22854c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com                         n, coverage_to_partial_alpha(fe),
229e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com                         (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT),
230e6af34a8082cc1f473aed6afe2cdeae796744717reed@google.com                         fOffsetX);
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fRuns.assertValid(y & MASK, (1 << (8 - SHIFT)));
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fCurrX = x + width;
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
2385ed43fcd5836738045d50d2cbd77d494a321a20bcaryclark@google.com#if 0 // UNUSED
239b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.comstatic void set_left_rite_runs(SkAlphaRuns& runs, int ileft, U8CPU leftA,
240b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com                               int n, U8CPU riteA) {
241b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    SkASSERT(leftA <= 0xFF);
242b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    SkASSERT(riteA <= 0xFF);
243b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
244b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    int16_t* run = runs.fRuns;
245b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    uint8_t* aa = runs.fAlpha;
246b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
247b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    if (ileft > 0) {
248b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        run[0] = ileft;
249b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        aa[0] = 0;
250b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        run += ileft;
251b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        aa += ileft;
252b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    }
253b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
254b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    SkASSERT(leftA < 0xFF);
255b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    if (leftA > 0) {
256b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        *run++ = 1;
257b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        *aa++ = leftA;
258b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    }
259b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
260b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    if (n > 0) {
261b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        run[0] = n;
262b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        aa[0] = 0xFF;
263b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        run += n;
264b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        aa += n;
265b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    }
266b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
267b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    SkASSERT(riteA < 0xFF);
268b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    if (riteA > 0) {
269b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        *run++ = 1;
270b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com        *aa++ = riteA;
271b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    }
272b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com    run[0] = 0;
273b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com}
2745ed43fcd5836738045d50d2cbd77d494a321a20bcaryclark@google.com#endif
275b575562fac6bbcc83c19bee8d4fbae67d5ebc4a4reed@google.com
27672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.comvoid SuperBlitter::blitRect(int x, int y, int width, int height) {
27772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    SkASSERT(width > 0);
27872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    SkASSERT(height > 0);
27972de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
28008d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    // blit leading rows
28108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    while ((y & MASK)) {
28272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        this->blitH(x, y++, width);
28372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        if (--height <= 0) {
28472de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com            return;
28572de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        }
28672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    }
28772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    SkASSERT(height > 0);
28872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
28908d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    // Since this is a rect, instead of blitting supersampled rows one at a
29008d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    // time and then resolving to the destination canvas, we can blit
29108d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    // directly to the destintion canvas one row per SCALE supersampled rows.
29272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    int start_y = y >> SHIFT;
29372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    int stop_y = (y + height) >> SHIFT;
29472de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    int count = stop_y - start_y;
29572de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    if (count > 0) {
29672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        y += count << SHIFT;
29772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        height -= count << SHIFT;
29872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
29972de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        // save original X for our tail blitH() loop at the bottom
30072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        int origX = x;
30172de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
30272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        x -= fSuperLeft;
30372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        // hack, until I figure out why my cubics (I think) go beyond the bounds
30472de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        if (x < 0) {
30572de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com            width += x;
30672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com            x = 0;
30772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        }
30872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
3096130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // There is always a left column, a middle, and a right column.
3106130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // ileft is the destination x of the first pixel of the entire rect.
3116130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // xleft is (SCALE - # of covered supersampled pixels) in that
3126130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // destination pixel.
31372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        int ileft = x >> SHIFT;
31408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com        int xleft = x & MASK;
3156130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // irite is the destination x of the last pixel of the OPAQUE section.
3166130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // xrite is the number of supersampled pixels extending beyond irite;
3176130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        // xrite/SCALE should give us alpha.
31872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        int irite = (x + width) >> SHIFT;
31908d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com        int xrite = (x + width) & MASK;
3206130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        if (!xrite) {
3216130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            xrite = SCALE;
3226130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            irite--;
3236130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        }
3246130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com
32567b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com        // Need to call flush() to clean up pending draws before we
32667b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com        // even consider blitV(), since otherwise it can look nonmonotonic.
32767b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com        SkASSERT(start_y > fCurrIY);
32867b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com        this->flush();
32967b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com
33072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        int n = irite - ileft - 1;
33172de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        if (n < 0) {
33267b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            // If n < 0, we'll only have a single partially-transparent column
33367b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            // of pixels to render.
33472de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com            xleft = xrite - xleft;
3356130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            SkASSERT(xleft <= SCALE);
3366130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            SkASSERT(xleft > 0);
33772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com            xrite = 0;
3386130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            fRealBlitter->blitV(ileft + fLeft, start_y, count,
3396130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com                coverage_to_exact_alpha(xleft));
34072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        } else {
34167b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            // With n = 0, we have two possibly-transparent columns of pixels
34267b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            // to render; with n > 0, we have opaque columns between them.
34367b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com
3446130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com            xleft = SCALE - xleft;
34572de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
34667b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            // Using coverage_to_exact_alpha is not consistent with blitH()
34767b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            const int coverageL = coverage_to_exact_alpha(xleft);
34867b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            const int coverageR = coverage_to_exact_alpha(xrite);
3496130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com
35067b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            SkASSERT(coverageL > 0 || n > 0 || coverageR > 0);
35167b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            SkASSERT((coverageL != 0) + n + (coverageR != 0) <= fWidth);
35272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
35367b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com            fRealBlitter->blitAntiRect(ileft + fLeft, start_y, n, count,
35467b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com                                       coverageL, coverageR);
35567b208a18899dc88de91c13182cd45f605fdc861tomhudson@google.com        }
35672de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
35772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        // preamble for our next call to blitH()
35872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        fCurrIY = stop_y - 1;
35972de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        fOffsetX = 0;
36072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        fCurrY = y - 1;
36172de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        fRuns.reset(fWidth);
36272de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        x = origX;
36372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    }
36472de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
3656130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com    // catch any remaining few rows
36608d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    SkASSERT(height <= MASK);
36772de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    while (--height >= 0) {
36872de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com        this->blitH(x, y++, width);
36972de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    }
37072de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com}
37172de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com
372bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
373bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
37408d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com/// Masked supersampling antialiased blitter.
375bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comclass MaskSuperBlitter : public BaseSuperBlitter {
376bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.compublic:
377bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
378bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                     const SkRegion& clip);
379bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    virtual ~MaskSuperBlitter() {
380bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        fRealBlitter->blitMask(fMask, fClipRect);
381bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
382bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
38372de73e8241cf6ac7b8f984caab52dbd038ad7cbreed@google.com    virtual void blitH(int x, int y, int width) SK_OVERRIDE;
384bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
385d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    static bool CanHandleRect(const SkIRect& bounds) {
386d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#ifdef FORCE_RLE
387d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        return false;
388d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#endif
389bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int width = bounds.width();
3900fd1581aef871cdbb38d29912e558cc4e2e04af5reed@google.com        int64_t rb = SkAlign4(width);
3910fd1581aef871cdbb38d29912e558cc4e2e04af5reed@google.com        // use 64bits to detect overflow
3920fd1581aef871cdbb38d29912e558cc4e2e04af5reed@google.com        int64_t storage = rb * bounds.height();
393434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
394bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return (width <= MaskSuperBlitter::kMAX_WIDTH) &&
3950fd1581aef871cdbb38d29912e558cc4e2e04af5reed@google.com               (storage <= MaskSuperBlitter::kMAX_STORAGE);
396bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
397434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
398bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comprivate:
399bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    enum {
400d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#ifdef FORCE_SUPERMASK
401d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        kMAX_WIDTH = 2048,
402d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        kMAX_STORAGE = 1024 * 1024 * 2
403d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#else
404bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kMAX_WIDTH = 32,    // so we don't try to do very wide things, where the RLE blitter would be faster
405bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        kMAX_STORAGE = 1024
406d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#endif
407bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    };
408bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
409bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkMask      fMask;
410bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkIRect     fClipRect;
411bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // we add 1 because add_aa_span can write (unchanged) 1 extra byte at the end, rather than
412bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // perform a test to see if stopAlpha != 0
413bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint32_t    fStorage[(kMAX_STORAGE >> 2) + 1];
414bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com};
415bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
416bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comMaskSuperBlitter::MaskSuperBlitter(SkBlitter* realBlitter, const SkIRect& ir,
417bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                   const SkRegion& clip)
418bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        : BaseSuperBlitter(realBlitter, ir, clip) {
419bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(CanHandleRect(ir));
420bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
421bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMask.fImage    = (uint8_t*)fStorage;
422bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMask.fBounds   = ir;
423bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMask.fRowBytes = ir.width();
424bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fMask.fFormat   = SkMask::kA8_Format;
425935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
426bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fClipRect = ir;
427bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fClipRect.intersect(clip.getBounds());
428434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
429bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // For valgrind, write 1 extra byte at the end so we don't read
430bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // uninitialized memory. See comment in add_aa_span and fStorage[].
431bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    memset(fStorage, 0, fMask.fBounds.height() * fMask.fRowBytes + 1);
432bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
433bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
434d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha) {
435bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    /*  I should be able to just add alpha[x] + startAlpha.
436bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        However, if the trailing edge of the previous span and the leading
437bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        edge of the current span round to the same super-sampled x value,
438bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        I might overflow to 256 with this add, hence the funny subtract.
439bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    */
440bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    unsigned tmp = *alpha + startAlpha;
441bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(tmp <= 256);
442bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    *alpha = SkToU8(tmp - (tmp >> 8));
443bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
444bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
445d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comstatic inline uint32_t quadplicate_byte(U8CPU value) {
446d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    uint32_t pair = (value << 8) | value;
447d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    return (pair << 16) | pair;
448d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com}
449d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
450335b90909ae2462290db6208f3ede204a74df33freed@google.com// Perform this tricky subtract, to avoid overflowing to 256. Our caller should
451335b90909ae2462290db6208f3ede204a74df33freed@google.com// only ever call us with at most enough to hit 256 (never larger), so it is
452335b90909ae2462290db6208f3ede204a74df33freed@google.com// enough to just subtract the high-bit. Actually clamping with a branch would
453335b90909ae2462290db6208f3ede204a74df33freed@google.com// be slower (e.g. if (tmp > 255) tmp = 255;)
454335b90909ae2462290db6208f3ede204a74df33freed@google.com//
455335b90909ae2462290db6208f3ede204a74df33freed@google.comstatic inline void saturated_add(uint8_t* ptr, U8CPU add) {
456335b90909ae2462290db6208f3ede204a74df33freed@google.com    unsigned tmp = *ptr + add;
457335b90909ae2462290db6208f3ede204a74df33freed@google.com    SkASSERT(tmp <= 256);
458335b90909ae2462290db6208f3ede204a74df33freed@google.com    *ptr = SkToU8(tmp - (tmp >> 8));
459335b90909ae2462290db6208f3ede204a74df33freed@google.com}
460335b90909ae2462290db6208f3ede204a74df33freed@google.com
461d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com// minimum count before we want to setup an inner loop, adding 4-at-a-time
462d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com#define MIN_COUNT_FOR_QUAD_LOOP  16
463d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
464d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comstatic void add_aa_span(uint8_t* alpha, U8CPU startAlpha, int middleCount,
465d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com                        U8CPU stopAlpha, U8CPU maxValue) {
466bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(middleCount >= 0);
467bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
468335b90909ae2462290db6208f3ede204a74df33freed@google.com    saturated_add(alpha, startAlpha);
469335b90909ae2462290db6208f3ede204a74df33freed@google.com    alpha += 1;
470bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
471d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (middleCount >= MIN_COUNT_FOR_QUAD_LOOP) {
472d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        // loop until we're quad-byte aligned
473d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        while (SkTCast<intptr_t>(alpha) & 0x3) {
474d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com            alpha[0] = SkToU8(alpha[0] + maxValue);
475d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com            alpha += 1;
476d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com            middleCount -= 1;
477d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        }
478d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
479d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        int bigCount = middleCount >> 2;
480d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        uint32_t* qptr = reinterpret_cast<uint32_t*>(alpha);
481d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        uint32_t qval = quadplicate_byte(maxValue);
482d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        do {
483d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com            *qptr++ += qval;
484d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        } while (--bigCount > 0);
485d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
486d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        middleCount &= 3;
487d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        alpha = reinterpret_cast<uint8_t*> (qptr);
488d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com        // fall through to the following while-loop
489d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    }
490d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com
491d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    while (--middleCount >= 0) {
492bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        alpha[0] = SkToU8(alpha[0] + maxValue);
493bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        alpha += 1;
494bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
495bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
496bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // potentially this can be off the end of our "legal" alpha values, but that
497bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // only happens if stopAlpha is also 0. Rather than test for stopAlpha != 0
498bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // every time (slow), we just do it, and ensure that we've allocated extra space
499bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // (see the + 1 comment in fStorage[]
500335b90909ae2462290db6208f3ede204a74df33freed@google.com    saturated_add(alpha, stopAlpha);
501bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
502bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
503d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.comvoid MaskSuperBlitter::blitH(int x, int y, int width) {
504bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int iy = (y >> SHIFT);
505434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
506bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(iy >= fMask.fBounds.fTop && iy < fMask.fBounds.fBottom);
507bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    iy -= fMask.fBounds.fTop;   // make it relative to 0
508bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
509300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    // This should never happen, but it does.  Until the true cause is
510300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    // discovered, let's skip this span instead of crashing.
511300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    // See http://crbug.com/17569.
512300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    if (iy < 0) {
513300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org        return;
514300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    }
515300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org
516bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
517bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    {
518bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int ix = x >> SHIFT;
519bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        SkASSERT(ix >= fMask.fBounds.fLeft && ix < fMask.fBounds.fRight);
520bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
521bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
522434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
523bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    x -= (fMask.fBounds.fLeft << SHIFT);
524bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
525bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // hack, until I figure out why my cubics (I think) go beyond the bounds
526d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (x < 0) {
527bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        width += x;
528bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x = 0;
529bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
530bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
531bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint8_t* row = fMask.fImage + iy * fMask.fRowBytes + (x >> SHIFT);
532bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
533bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int start = x;
534bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int stop = x + width;
535bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
536bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkASSERT(start >= 0 && stop > start);
53708d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int fb = start & MASK;
53808d7e7c286339679d4189e2b9e05fd80830ee776tomhudson@google.com    int fe = stop & MASK;
539bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int n = (stop >> SHIFT) - (start >> SHIFT) - 1;
540bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
541bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
542d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (n < 0) {
543456468215617b3233ea162687b69d1445cb0cf4csenorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
544456468215617b3233ea162687b69d1445cb0cf4csenorblanco@chromium.org        SkASSERT(row < fMask.fImage + kMAX_STORAGE + 1);
54554c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com        add_aa_span(row, coverage_to_partial_alpha(fe - fb));
546d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    } else {
5476130a9d1e6a8b20f7236d799786e9bd3e32658dctomhudson@google.com        fb = SCALE - fb;
548456468215617b3233ea162687b69d1445cb0cf4csenorblanco@chromium.org        SkASSERT(row >= fMask.fImage);
549456468215617b3233ea162687b69d1445cb0cf4csenorblanco@chromium.org        SkASSERT(row + n + 1 < fMask.fImage + kMAX_STORAGE + 1);
55054c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com        add_aa_span(row,  coverage_to_partial_alpha(fb),
55154c999a5f46956e6be79cc93c6d39f437bef1b7etomhudson@google.com                    n, coverage_to_partial_alpha(fe),
552bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                    (1 << (8 - SHIFT)) - (((y & MASK) + 1) >> SHIFT));
553bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
554bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
555bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#ifdef SK_DEBUG
556bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    fCurrX = x + width;
557bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#endif
558bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
559bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
560bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com///////////////////////////////////////////////////////////////////////////////
561bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
562e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.comstatic bool fitsInsideLimit(const SkRect& r, SkScalar max) {
563e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    const SkScalar min = -max;
564e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    return  r.fLeft > min && r.fTop > min &&
565e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com            r.fRight < max && r.fBottom < max;
566e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com}
567e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com
5686ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.comstatic int overflows_short_shift(int value, int shift) {
5696ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    const int s = 16 + shift;
5706ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    return (value << s >> s) - value;
5716ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com}
5726ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com
5736ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com/**
5746ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com  Would any of the coordinates of this rectangle not fit in a short,
5756ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com  when left-shifted by shift?
5766ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com*/
5776ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.comstatic int rect_overflows_short_shift(SkIRect rect, int shift) {
5786ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    SkASSERT(!overflows_short_shift(8191, SHIFT));
5796ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    SkASSERT(overflows_short_shift(8192, SHIFT));
5806ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    SkASSERT(!overflows_short_shift(32767, 0));
5816ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    SkASSERT(overflows_short_shift(32768, 0));
5826ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com
5836ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // Since we expect these to succeed, we bit-or together
5846ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // for a tiny extra bit of speed.
5856ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    return overflows_short_shift(rect.fLeft, SHIFT) |
5866ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com           overflows_short_shift(rect.fRight, SHIFT) |
5876ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com           overflows_short_shift(rect.fTop, SHIFT) |
5886ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com           overflows_short_shift(rect.fBottom, SHIFT);
5896ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com}
5906ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com
591e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.comstatic bool safeRoundOut(const SkRect& src, SkIRect* dst, int32_t maxInt) {
592e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com#ifdef SK_SCALAR_IS_FIXED
593e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com    // the max-int (shifted) is exactly what we want to compare against, to know
594e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com    // if we can survive shifting our fixed-point coordinates
595e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com    const SkFixed maxScalar = maxInt;
596e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com#else
597e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    const SkScalar maxScalar = SkIntToScalar(maxInt);
598e5e3655e289e2ab684f2ec49cbbe127ac6e22c6areed@google.com#endif
599e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    if (fitsInsideLimit(src, maxScalar)) {
600e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com        src.roundOut(dst);
601e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com        return true;
602e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    }
603e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    return false;
604bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
605bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
606f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRegion& origClip,
60750a8a51ccc3fa63409cd2059c5c2361ba8e642a1reed@google.com                          SkBlitter* blitter, bool forceRLE) {
608f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    if (origClip.isEmpty()) {
609bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
610bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
611bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
612155c4e804736576f9352aa60d70669ac3e3f9d52reed@android.com    SkIRect ir;
613e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com
614e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    if (!safeRoundOut(path.getBounds(), &ir, SK_MaxS32 >> SHIFT)) {
615e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com#if 0
616e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com        const SkRect& r = path.getBounds();
617e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com        SkDebugf("--- bounds can't fit in SkIRect\n", r.fLeft, r.fTop, r.fRight, r.fBottom);
618e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com#endif
619e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com        return;
620e926306bfed506f3fa5e767c5ed1d41f72284ac3reed@google.com    }
621bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (ir.isEmpty()) {
622273fc37241771f46adae5c4547b6f9afa90eb3bbreed@google.com        if (path.isInverseFillType()) {
623f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com            blitter->blitRegion(origClip);
624273fc37241771f46adae5c4547b6f9afa90eb3bbreed@google.com        }
625bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
626bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
627bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
6286ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // If the intersection of the path bounds and the clip bounds
6296ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // will overflow 32767 when << by SHIFT, we can't supersample,
6306ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // so draw without antialiasing.
6316ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    SkIRect clippedIR;
6326ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    if (path.isInverseFillType()) {
6336ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com       // If the path is an inverse fill, it's going to fill the entire
6346ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com       // clip, and we care whether the entire clip exceeds our limits.
6356ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com       clippedIR = origClip.getBounds();
6366ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    } else {
6376ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com       if (!clippedIR.intersect(ir, origClip.getBounds())) {
6386ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com           return;
6396ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com       }
6406ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    }
6416ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    if (rect_overflows_short_shift(clippedIR, SHIFT)) {
6426ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com        SkScan::FillPath(path, origClip, blitter);
6436ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com        return;
6446ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    }
6456ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com
646f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    // Our antialiasing can't handle a clip larger than 32767, so we restrict
647f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    // the clip to that limit here. (the runs[] uses int16_t for its index).
648f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    //
6496ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // A more general solution (one that could also eliminate the need to
6506ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // disable aa based on ir bounds (see overflows_short_shift) would be
6516ec256aa42b855a3086db1164a1086d4c0ca326ctomhudson@google.com    // to tile the clip/target...
652f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    SkRegion tmpClipStorage;
653f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    const SkRegion* clipRgn = &origClip;
654f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    {
655f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        static const int32_t kMaxClipCoord = 32767;
656f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        const SkIRect& bounds = origClip.getBounds();
657f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        if (bounds.fRight > kMaxClipCoord || bounds.fBottom > kMaxClipCoord) {
658f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com            SkIRect limit = { 0, 0, kMaxClipCoord, kMaxClipCoord };
659f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com            tmpClipStorage.op(origClip, limit, SkRegion::kIntersect_Op);
660f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com            clipRgn = &tmpClipStorage;
661f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        }
662f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    }
663f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    // for here down, use clipRgn, not origClip
664f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com
665f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com    SkScanClipper   clipper(blitter, clipRgn, ir);
666bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    const SkIRect*  clipRect = clipper.getClipRect();
667bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
668bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (clipper.getBlitter() == NULL) { // clipped out
669bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (path.isInverseFillType()) {
670f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com            blitter->blitRegion(*clipRgn);
671bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
672bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
673bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
674434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
675bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // now use the (possibly wrapped) blitter
676bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    blitter = clipper.getBlitter();
677bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
678bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (path.isInverseFillType()) {
679f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        sk_blit_above(blitter, ir, *clipRgn);
680bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
681bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
682bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    SkIRect superRect, *superClipRect = NULL;
683bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
684d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    if (clipRect) {
685bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        superRect.set(  clipRect->fLeft << SHIFT, clipRect->fTop << SHIFT,
686bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                        clipRect->fRight << SHIFT, clipRect->fBottom << SHIFT);
687bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        superClipRect = &superRect;
688bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
689bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
690300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org    SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
691300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org
692bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // MaskSuperBlitter can't handle drawing outside of ir, so we can't use it
693bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    // if we're an inverse filltype
69450a8a51ccc3fa63409cd2059c5c2361ba8e642a1reed@google.com    if (!path.isInverseFillType() && MaskSuperBlitter::CanHandleRect(ir) && !forceRLE) {
695f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        MaskSuperBlitter    superBlit(blitter, ir, *clipRgn);
696300cb7c6ae70259a3ea8c31c8a553e01fb43ec48senorblanco@chromium.org        SkASSERT(SkIntToScalar(ir.fTop) <= path.getBounds().fTop);
697f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
698d310543736e5f3b12eef432d1ef2727ace4fe246reed@google.com    } else {
699f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        SuperBlitter    superBlit(blitter, ir, *clipRgn);
700f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        sk_fill_path(path, superClipRect, &superBlit, ir.fTop, ir.fBottom, SHIFT, *clipRgn);
701bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
702434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com
703434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com    if (path.isInverseFillType()) {
704f3b3c41622fd2933e78170e6b4a8b9adb0b77617reed@google.com        sk_blit_below(blitter, ir, *clipRgn);
705434433e916bd10326a9e4d47409b1e2e5d594a38reed@google.com    }
706bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
707d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
708d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com///////////////////////////////////////////////////////////////////////////////
709d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
710d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com#include "SkRasterClip.h"
711d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
712d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.comvoid SkScan::FillPath(const SkPath& path, const SkRasterClip& clip,
713d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com                          SkBlitter* blitter) {
714d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    if (clip.isEmpty()) {
715d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        return;
716d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    }
717935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
718d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    if (clip.isBW()) {
719d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        FillPath(path, clip.bwRgn(), blitter);
720d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    } else {
721d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkRegion        tmp;
722d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkAAClipBlitter aaBlitter;
723935e9f4fafdfc64130e6be9ea2bb30e3bafd852armistry@google.com
724d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        tmp.setRect(clip.getBounds());
725d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
726d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkScan::FillPath(path, tmp, &aaBlitter);
727d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    }
728d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com}
729d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
730d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.comvoid SkScan::AntiFillPath(const SkPath& path, const SkRasterClip& clip,
731d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com                          SkBlitter* blitter) {
732d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    if (clip.isEmpty()) {
733d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        return;
734d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    }
735d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
736d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    if (clip.isBW()) {
737d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        AntiFillPath(path, clip.bwRgn(), blitter);
738d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    } else {
739d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkRegion        tmp;
740d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkAAClipBlitter aaBlitter;
741d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com
742d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        tmp.setRect(clip.getBounds());
743d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        aaBlitter.init(blitter, &clip.aaRgn());
744d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com        SkScan::AntiFillPath(path, tmp, &aaBlitter, true);
745d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com    }
746d48790d6ca44f1af207d36b3fcb191538fef24ebreed@google.com}
747