123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*
- * Copyright 2006 The Android Open Source Project
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #ifndef SkAntiRun_DEFINED
- #define SkAntiRun_DEFINED
- #include "include/private/SkTo.h"
- #include "src/core/SkBlitter.h"
- /** Sparse array of run-length-encoded alpha (supersampling coverage) values.
- Sparseness allows us to independently compose several paths into the
- same SkAlphaRuns buffer.
- */
- class SkAlphaRuns {
- public:
- int16_t* fRuns;
- uint8_t* fAlpha;
- // Return 0-255 given 0-256
- static inline SkAlpha CatchOverflow(int alpha) {
- SkASSERT(alpha >= 0 && alpha <= 256);
- return alpha - (alpha >> 8);
- }
- /// Returns true if the scanline contains only a single run,
- /// of alpha value 0.
- bool empty() const {
- SkASSERT(fRuns[0] > 0);
- return fAlpha[0] == 0 && fRuns[fRuns[0]] == 0;
- }
- /// Reinitialize for a new scanline.
- void reset(int width);
- /**
- * Insert into the buffer a run starting at (x-offsetX):
- * if startAlpha > 0
- * one pixel with value += startAlpha,
- * max 255
- * if middleCount > 0
- * middleCount pixels with value += maxValue
- * if stopAlpha > 0
- * one pixel with value += stopAlpha
- * Returns the offsetX value that should be passed on the next call,
- * assuming we're on the same scanline. If the caller is switching
- * scanlines, then offsetX should be 0 when this is called.
- */
- SK_ALWAYS_INLINE int add(int x, U8CPU startAlpha, int middleCount, U8CPU stopAlpha,
- U8CPU maxValue, int offsetX) {
- SkASSERT(middleCount >= 0);
- SkASSERT(x >= 0 && x + (startAlpha != 0) + middleCount + (stopAlpha != 0) <= fWidth);
- SkASSERT(fRuns[offsetX] >= 0);
- int16_t* runs = fRuns + offsetX;
- uint8_t* alpha = fAlpha + offsetX;
- uint8_t* lastAlpha = alpha;
- x -= offsetX;
- if (startAlpha) {
- SkAlphaRuns::Break(runs, alpha, x, 1);
- /* I should be able to just add alpha[x] + startAlpha.
- However, if the trailing edge of the previous span and the leading
- edge of the current span round to the same super-sampled x value,
- I might overflow to 256 with this add, hence the funny subtract (crud).
- */
- unsigned tmp = alpha[x] + startAlpha;
- SkASSERT(tmp <= 256);
- alpha[x] = SkToU8(tmp - (tmp >> 8)); // was (tmp >> 7), but that seems wrong if we're trying to catch 256
- runs += x + 1;
- alpha += x + 1;
- x = 0;
- SkDEBUGCODE(this->validate();)
- }
- if (middleCount) {
- SkAlphaRuns::Break(runs, alpha, x, middleCount);
- alpha += x;
- runs += x;
- x = 0;
- do {
- alpha[0] = SkToU8(CatchOverflow(alpha[0] + maxValue));
- int n = runs[0];
- SkASSERT(n <= middleCount);
- alpha += n;
- runs += n;
- middleCount -= n;
- } while (middleCount > 0);
- SkDEBUGCODE(this->validate();)
- lastAlpha = alpha;
- }
- if (stopAlpha) {
- SkAlphaRuns::Break(runs, alpha, x, 1);
- alpha += x;
- alpha[0] = SkToU8(alpha[0] + stopAlpha);
- SkDEBUGCODE(this->validate();)
- lastAlpha = alpha;
- }
- return SkToS32(lastAlpha - fAlpha); // new offsetX
- }
- SkDEBUGCODE(void assertValid(int y, int maxStep) const;)
- SkDEBUGCODE(void dump() const;)
- /**
- * Break the runs in the buffer at offsets x and x+count, properly
- * updating the runs to the right and left.
- * i.e. from the state AAAABBBB, run-length encoded as A4B4,
- * Break(..., 2, 5) would produce AAAABBBB rle as A2A2B3B1.
- * Allows add() to sum another run to some of the new sub-runs.
- * i.e. adding ..CCCCC. would produce AADDEEEB, rle as A2D2E3B1.
- */
- static void Break(int16_t runs[], uint8_t alpha[], int x, int count) {
- SkASSERT(count > 0 && x >= 0);
- // SkAlphaRuns::BreakAt(runs, alpha, x);
- // SkAlphaRuns::BreakAt(&runs[x], &alpha[x], count);
- int16_t* next_runs = runs + x;
- uint8_t* next_alpha = alpha + x;
- while (x > 0) {
- int n = runs[0];
- SkASSERT(n > 0);
- if (x < n) {
- alpha[x] = alpha[0];
- runs[0] = SkToS16(x);
- runs[x] = SkToS16(n - x);
- break;
- }
- runs += n;
- alpha += n;
- x -= n;
- }
- runs = next_runs;
- alpha = next_alpha;
- x = count;
- for (;;) {
- int n = runs[0];
- SkASSERT(n > 0);
- if (x < n) {
- alpha[x] = alpha[0];
- runs[0] = SkToS16(x);
- runs[x] = SkToS16(n - x);
- break;
- }
- x -= n;
- if (x <= 0) {
- break;
- }
- runs += n;
- alpha += n;
- }
- }
- /**
- * Cut (at offset x in the buffer) a run into two shorter runs with
- * matching alpha values.
- * Used by the RectClipBlitter to trim a RLE encoding to match the
- * clipping rectangle.
- */
- static void BreakAt(int16_t runs[], uint8_t alpha[], int x) {
- while (x > 0) {
- int n = runs[0];
- SkASSERT(n > 0);
- if (x < n) {
- alpha[x] = alpha[0];
- runs[0] = SkToS16(x);
- runs[x] = SkToS16(n - x);
- break;
- }
- runs += n;
- alpha += n;
- x -= n;
- }
- }
- private:
- SkDEBUGCODE(int fWidth;)
- SkDEBUGCODE(void validate() const;)
- };
- #endif
|