gfx/skia/trunk/src/core/SkAntiRun.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/core/SkAntiRun.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,192 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#ifndef SkAntiRun_DEFINED
    1.14 +#define SkAntiRun_DEFINED
    1.15 +
    1.16 +#include "SkBlitter.h"
    1.17 +
    1.18 +/** Sparse array of run-length-encoded alpha (supersampling coverage) values.
    1.19 +    Sparseness allows us to independently compose several paths into the
    1.20 +    same SkAlphaRuns buffer.
    1.21 +*/
    1.22 +
    1.23 +class SkAlphaRuns {
    1.24 +public:
    1.25 +    int16_t*    fRuns;
    1.26 +    uint8_t*     fAlpha;
    1.27 +
    1.28 +    /// Returns true if the scanline contains only a single run,
    1.29 +    /// of alpha value 0.
    1.30 +    bool empty() const {
    1.31 +        SkASSERT(fRuns[0] > 0);
    1.32 +        return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
    1.33 +    }
    1.34 +
    1.35 +    /// Reinitialize for a new scanline.
    1.36 +    void    reset(int width);
    1.37 +
    1.38 +    /**
    1.39 +     *  Insert into the buffer a run starting at (x-offsetX):
    1.40 +     *      if startAlpha > 0
    1.41 +     *          one pixel with value += startAlpha,
    1.42 +     *              max 255
    1.43 +     *      if middleCount > 0
    1.44 +     *          middleCount pixels with value += maxValue
    1.45 +     *      if stopAlpha > 0
    1.46 +     *          one pixel with value += stopAlpha
    1.47 +     *  Returns the offsetX value that should be passed on the next call,
    1.48 +     *  assuming we're on the same scanline. If the caller is switching
    1.49 +     *  scanlines, then offsetX should be 0 when this is called.
    1.50 +     */
    1.51 +    SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
    1.52 +                             U8CPU maxValue, int offsetX) {
    1.53 +        SkASSERT(middleCount >= 0);
    1.54 +        SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
    1.55 +
    1.56 +        SkASSERT(fRuns[offsetX] >= 0);
    1.57 +
    1.58 +        int16_t*    runs = fRuns + offsetX;
    1.59 +        uint8_t*    alpha = fAlpha + offsetX;
    1.60 +        uint8_t*    lastAlpha = alpha;
    1.61 +        x -= offsetX;
    1.62 +
    1.63 +        if (startAlpha) {
    1.64 +            SkAlphaRuns::Break(runs, alpha, x, 1);
    1.65 +            /*  I should be able to just add alpha[x] + startAlpha.
    1.66 +                However, if the trailing edge of the previous span and the leading
    1.67 +                edge of the current span round to the same super-sampled x value,
    1.68 +                I might overflow to 256 with this add, hence the funny subtract (crud).
    1.69 +            */
    1.70 +            unsigned tmp = alpha[x] + startAlpha;
    1.71 +            SkASSERT(tmp <= 256);
    1.72 +            alpha[x] = SkToU8(tmp - (tmp >> 8));    // was (tmp >> 7), but that seems wrong if we're trying to catch 256
    1.73 +
    1.74 +            runs += x + 1;
    1.75 +            alpha += x + 1;
    1.76 +            x = 0;
    1.77 +            lastAlpha += x; // we don't want the +1
    1.78 +            SkDEBUGCODE(this->validate();)
    1.79 +        }
    1.80 +
    1.81 +        if (middleCount) {
    1.82 +            SkAlphaRuns::Break(runs, alpha, x, middleCount);
    1.83 +            alpha += x;
    1.84 +            runs += x;
    1.85 +            x = 0;
    1.86 +            do {
    1.87 +                alpha[0] = SkToU8(alpha[0] + maxValue);
    1.88 +                int n = runs[0];
    1.89 +                SkASSERT(n <= middleCount);
    1.90 +                alpha += n;
    1.91 +                runs += n;
    1.92 +                middleCount -= n;
    1.93 +            } while (middleCount > 0);
    1.94 +            SkDEBUGCODE(this->validate();)
    1.95 +            lastAlpha = alpha;
    1.96 +        }
    1.97 +
    1.98 +        if (stopAlpha) {
    1.99 +            SkAlphaRuns::Break(runs, alpha, x, 1);
   1.100 +            alpha += x;
   1.101 +            alpha[0] = SkToU8(alpha[0] + stopAlpha);
   1.102 +            SkDEBUGCODE(this->validate();)
   1.103 +            lastAlpha = alpha;
   1.104 +        }
   1.105 +
   1.106 +        return SkToS32(lastAlpha - fAlpha);  // new offsetX
   1.107 +    }
   1.108 +
   1.109 +    SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
   1.110 +    SkDEBUGCODE(void dump() const;)
   1.111 +
   1.112 +    /**
   1.113 +     * Break the runs in the buffer at offsets x and x+count, properly
   1.114 +     * updating the runs to the right and left.
   1.115 +     *   i.e. from the state AAAABBBB, run-length encoded as A4B4,
   1.116 +     *   Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
   1.117 +     * Allows add() to sum another run to some of the new sub-runs.
   1.118 +     *   i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
   1.119 +     */
   1.120 +    static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
   1.121 +        SkASSERT(count > 0 && x >= 0);
   1.122 +
   1.123 +        //  SkAlphaRuns::BreakAt(runs, alpha, x);
   1.124 +        //  SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
   1.125 +
   1.126 +        int16_t* next_runs = runs + x;
   1.127 +        uint8_t*  next_alpha = alpha + x;
   1.128 +
   1.129 +        while (x > 0) {
   1.130 +            int n = runs[0];
   1.131 +            SkASSERT(n > 0);
   1.132 +
   1.133 +            if (x < n) {
   1.134 +                alpha[x] = alpha[0];
   1.135 +                runs[0] = SkToS16(x);
   1.136 +                runs[x] = SkToS16(n - x);
   1.137 +                break;
   1.138 +            }
   1.139 +            runs += n;
   1.140 +            alpha += n;
   1.141 +            x -= n;
   1.142 +        }
   1.143 +
   1.144 +        runs = next_runs;
   1.145 +        alpha = next_alpha;
   1.146 +        x = count;
   1.147 +
   1.148 +        for (;;) {
   1.149 +            int n = runs[0];
   1.150 +            SkASSERT(n > 0);
   1.151 +
   1.152 +            if (x < n) {
   1.153 +                alpha[x] = alpha[0];
   1.154 +                runs[0] = SkToS16(x);
   1.155 +                runs[x] = SkToS16(n - x);
   1.156 +                break;
   1.157 +            }
   1.158 +            x -= n;
   1.159 +            if (x <= 0) {
   1.160 +                break;
   1.161 +            }
   1.162 +            runs += n;
   1.163 +            alpha += n;
   1.164 +        }
   1.165 +    }
   1.166 +
   1.167 +    /**
   1.168 +     * Cut (at offset x in the buffer) a run into two shorter runs with
   1.169 +     * matching alpha values.
   1.170 +     * Used by the RectClipBlitter to trim a RLE encoding to match the
   1.171 +     * clipping rectangle.
   1.172 +     */
   1.173 +    static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
   1.174 +        while (x > 0) {
   1.175 +            int n = runs[0];
   1.176 +            SkASSERT(n > 0);
   1.177 +
   1.178 +            if (x < n) {
   1.179 +                alpha[x] = alpha[0];
   1.180 +                runs[0] = SkToS16(x);
   1.181 +                runs[x] = SkToS16(n - x);
   1.182 +                break;
   1.183 +            }
   1.184 +            runs += n;
   1.185 +            alpha += n;
   1.186 +            x -= n;
   1.187 +        }
   1.188 +    }
   1.189 +
   1.190 +private:
   1.191 +    SkDEBUGCODE(int fWidth;)
   1.192 +    SkDEBUGCODE(void validate() const;)
   1.193 +};
   1.194 +
   1.195 +#endif

mercurial