Home | History | Annotate | Download | only in core
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 
      9 #ifndef SkAntiRun_DEFINED
     10 #define SkAntiRun_DEFINED
     11 
     12 #include "SkBlitter.h"
     13 
     14 /** Sparse array of run-length-encoded alpha (supersampling coverage) values.
     15     Sparseness allows us to independently compose several paths into the
     16     same SkAlphaRuns buffer.
     17 */
     18 
     19 class SkAlphaRuns {
     20 public:
     21     int16_t*    fRuns;
     22     uint8_t*     fAlpha;
     23 
     24     // Return 0-255 given 0-256
     25     static inline SkAlpha CatchOverflow(int alpha) {
     26         SkASSERT(alpha >= 0 && alpha <= 256);
     27         return alpha - (alpha >> 8);
     28     }
     29 
     30     /// Returns true if the scanline contains only a single run,
     31     /// of alpha value 0.
     32     bool empty() const {
     33         SkASSERT(fRuns[0] > 0);
     34         return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
     35     }
     36 
     37     /// Reinitialize for a new scanline.
     38     void    reset(int width);
     39 
     40     /**
     41      *  Insert into the buffer a run starting at (x-offsetX):
     42      *      if startAlpha > 0
     43      *          one pixel with value += startAlpha,
     44      *              max 255
     45      *      if middleCount > 0
     46      *          middleCount pixels with value += maxValue
     47      *      if stopAlpha > 0
     48      *          one pixel with value += stopAlpha
     49      *  Returns the offsetX value that should be passed on the next call,
     50      *  assuming we're on the same scanline. If the caller is switching
     51      *  scanlines, then offsetX should be 0 when this is called.
     52      */
     53     SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
     54                              U8CPU maxValue, int offsetX) {
     55         SkASSERT(middleCount >= 0);
     56         SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
     57 
     58         SkASSERT(fRuns[offsetX] >= 0);
     59 
     60         int16_t*    runs = fRuns + offsetX;
     61         uint8_t*    alpha = fAlpha + offsetX;
     62         uint8_t*    lastAlpha = alpha;
     63         x -= offsetX;
     64 
     65         if (startAlpha) {
     66             SkAlphaRuns::Break(runs, alpha, x, 1);
     67             /*  I should be able to just add alpha[x] + startAlpha.
     68                 However, if the trailing edge of the previous span and the leading
     69                 edge of the current span round to the same super-sampled x value,
     70                 I might overflow to 256 with this add, hence the funny subtract (crud).
     71             */
     72             unsigned tmp = alpha[x] + startAlpha;
     73             SkASSERT(tmp <= 256);
     74             alpha[x] = SkToU8(tmp - (tmp >> 8));    // was (tmp >> 7), but that seems wrong if we're trying to catch 256
     75 
     76             runs += x + 1;
     77             alpha += x + 1;
     78             x = 0;
     79             SkDEBUGCODE(this->validate();)
     80         }
     81 
     82         if (middleCount) {
     83             SkAlphaRuns::Break(runs, alpha, x, middleCount);
     84             alpha += x;
     85             runs += x;
     86             x = 0;
     87             do {
     88                 alpha[0] = SkToU8(CatchOverflow(alpha[0] + maxValue));
     89                 int n = runs[0];
     90                 SkASSERT(n <= middleCount);
     91                 alpha += n;
     92                 runs += n;
     93                 middleCount -= n;
     94             } while (middleCount > 0);
     95             SkDEBUGCODE(this->validate();)
     96             lastAlpha = alpha;
     97         }
     98 
     99         if (stopAlpha) {
    100             SkAlphaRuns::Break(runs, alpha, x, 1);
    101             alpha += x;
    102             alpha[0] = SkToU8(alpha[0] + stopAlpha);
    103             SkDEBUGCODE(this->validate();)
    104             lastAlpha = alpha;
    105         }
    106 
    107         return SkToS32(lastAlpha - fAlpha);  // new offsetX
    108     }
    109 
    110     SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
    111     SkDEBUGCODE(void dump() const;)
    112 
    113     /**
    114      * Break the runs in the buffer at offsets x and x+count, properly
    115      * updating the runs to the right and left.
    116      *   i.e. from the state AAAABBBB, run-length encoded as A4B4,
    117      *   Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
    118      * Allows add() to sum another run to some of the new sub-runs.
    119      *   i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
    120      */
    121     static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
    122         SkASSERT(count > 0 && x >= 0);
    123 
    124         //  SkAlphaRuns::BreakAt(runs, alpha, x);
    125         //  SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
    126 
    127         int16_t* next_runs = runs + x;
    128         uint8_t*  next_alpha = alpha + x;
    129 
    130         while (x > 0) {
    131             int n = runs[0];
    132             SkASSERT(n > 0);
    133 
    134             if (x < n) {
    135                 alpha[x] = alpha[0];
    136                 runs[0] = SkToS16(x);
    137                 runs[x] = SkToS16(n - x);
    138                 break;
    139             }
    140             runs += n;
    141             alpha += n;
    142             x -= n;
    143         }
    144 
    145         runs = next_runs;
    146         alpha = next_alpha;
    147         x = count;
    148 
    149         for (;;) {
    150             int n = runs[0];
    151             SkASSERT(n > 0);
    152 
    153             if (x < n) {
    154                 alpha[x] = alpha[0];
    155                 runs[0] = SkToS16(x);
    156                 runs[x] = SkToS16(n - x);
    157                 break;
    158             }
    159             x -= n;
    160             if (x <= 0) {
    161                 break;
    162             }
    163             runs += n;
    164             alpha += n;
    165         }
    166     }
    167 
    168     /**
    169      * Cut (at offset x in the buffer) a run into two shorter runs with
    170      * matching alpha values.
    171      * Used by the RectClipBlitter to trim a RLE encoding to match the
    172      * clipping rectangle.
    173      */
    174     static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
    175         while (x > 0) {
    176             int n = runs[0];
    177             SkASSERT(n > 0);
    178 
    179             if (x < n) {
    180                 alpha[x] = alpha[0];
    181                 runs[0] = SkToS16(x);
    182                 runs[x] = SkToS16(n - x);
    183                 break;
    184             }
    185             runs += n;
    186             alpha += n;
    187             x -= n;
    188         }
    189     }
    190 
    191 private:
    192     SkDEBUGCODE(int fWidth;)
    193     SkDEBUGCODE(void validate() const;)
    194 };
    195 
    196 #endif
    197