SkAntiRun.h 5.8 KB

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