OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright 2016 Google Inc. |
| 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 #ifndef SkLinearBitmapPipeline_tile_DEFINED |
| 9 #define SkLinearBitmapPipeline_tile_DEFINED |
| 10 |
| 11 #include "SkLinearBitmapPipeline_core.h" |
| 12 #include "SkPM4f.h" |
| 13 #include <algorithm> |
| 14 #include <cmath> |
| 15 #include <limits> |
| 16 |
| 17 namespace { |
| 18 class ClampStrategy { |
| 19 public: |
| 20 ClampStrategy(X max) |
| 21 : fXMin{0.0f}, fXMax{max - 1.0f} { } |
| 22 |
| 23 ClampStrategy(Y max) |
| 24 : fYMin{0.0f}, fYMax{max - 1.0f} { } |
| 25 |
| 26 ClampStrategy(SkSize max) |
| 27 : fXMin{0.0f}, fYMin{0.0f}, fXMax{X(max) - 1.0f}, fYMax{Y(max) - 1.0f} {
} |
| 28 |
| 29 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 30 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax); |
| 31 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax); |
| 32 } |
| 33 |
| 34 template<typename Next> |
| 35 bool maybeProcessSpan(Span originalSpan, Next* next) { |
| 36 SkASSERT(!originalSpan.isEmpty()); |
| 37 SkPoint start; |
| 38 SkScalar length; |
| 39 int count; |
| 40 std::tie(start, length, count) = originalSpan; |
| 41 SkScalar xMin = fXMin[0]; |
| 42 SkScalar xMax = fXMax[0] + 1.0f; |
| 43 SkScalar yMin = fYMin[0]; |
| 44 SkScalar yMax = fYMax[0]; |
| 45 SkScalar x = X(start); |
| 46 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); |
| 47 |
| 48 Span span{{x, y}, length, count}; |
| 49 |
| 50 if (span.completelyWithin(xMin, xMax)) { |
| 51 next->pointSpan(span); |
| 52 return true; |
| 53 } |
| 54 if (1 == count || 0.0f == length) { |
| 55 return false; |
| 56 } |
| 57 |
| 58 SkScalar dx = length / (count - 1); |
| 59 |
| 60 // A B C |
| 61 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ |
| 62 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*-
--||*---*.... |
| 63 // | | | || | | | ... | |
|| |
| 64 // | | | || | | | | |
|| |
| 65 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ |
| 66 // ^
^ |
| 67 // | xMin xMax-
1 | xMax |
| 68 // |
| 69 // *---*---*---... - track of samples. * = sample |
| 70 // |
| 71 // +-+ || |
| 72 // | | - pixels in source space. || - tile border. |
| 73 // +-+ || |
| 74 // |
| 75 // The length from A to B is the length in source space or 4 * dx or (co
unt - 1) * dx |
| 76 // where dx is the distance between samples. There are 5 destination pix
els |
| 77 // corresponding to 5 samples specified in the A, B span. The distance f
rom A to the next |
| 78 // span starting at C is 5 * dx, so count * dx. |
| 79 // Remember, count is the number of pixels needed for the destination an
d the number of |
| 80 // samples. |
| 81 // Overall Strategy: |
| 82 // * Under - for portions of the span < xMin, take the color at pixel {x
Min, y} and use it |
| 83 // to fill in the 5 pixel sampled from A to B. |
| 84 // * Middle - for the portion of the span between xMin and xMax sample n
ormally. |
| 85 // * Over - for the portion of the span > xMax, take the color at pixel
{xMax-1, y} and |
| 86 // use it to fill in the rest of the destination pixels. |
| 87 if (dx >= 0) { |
| 88 Span leftClamped = span.breakAt(xMin, dx); |
| 89 if (!leftClamped.isEmpty()) { |
| 90 leftClamped.clampToSinglePixel({xMin, y}); |
| 91 next->pointSpan(leftClamped); |
| 92 } |
| 93 Span middle = span.breakAt(xMax, dx); |
| 94 if (!middle.isEmpty()) { |
| 95 next->pointSpan(middle); |
| 96 } |
| 97 if (!span.isEmpty()) { |
| 98 span.clampToSinglePixel({xMax - 1, y}); |
| 99 next->pointSpan(span); |
| 100 } |
| 101 } else { |
| 102 Span rightClamped = span.breakAt(xMax, dx); |
| 103 if (!rightClamped.isEmpty()) { |
| 104 rightClamped.clampToSinglePixel({xMax - 1, y}); |
| 105 next->pointSpan(rightClamped); |
| 106 } |
| 107 Span middle = span.breakAt(xMin, dx); |
| 108 if (!middle.isEmpty()) { |
| 109 next->pointSpan(middle); |
| 110 } |
| 111 if (!span.isEmpty()) { |
| 112 span.clampToSinglePixel({xMin, y}); |
| 113 next->pointSpan(span); |
| 114 } |
| 115 } |
| 116 return true; |
| 117 } |
| 118 |
| 119 template <typename Next> |
| 120 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { |
| 121 return false; |
| 122 } |
| 123 |
| 124 private: |
| 125 const Sk4s fXMin{SK_FloatNegativeInfinity}; |
| 126 const Sk4s fYMin{SK_FloatNegativeInfinity}; |
| 127 const Sk4s fXMax{SK_FloatInfinity}; |
| 128 const Sk4s fYMax{SK_FloatInfinity}; |
| 129 }; |
| 130 |
| 131 class RepeatStrategy { |
| 132 public: |
| 133 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f / max} { } |
| 134 |
| 135 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f / max} { } |
| 136 |
| 137 RepeatStrategy(SkSize max) |
| 138 : fXMax{X(max)}, fXInvMax{1.0f / X(max)}, fYMax{Y(max)}, fYInvMax{1.0f /
Y(max)} { } |
| 139 |
| 140 void processPoints(Sk4s* xs, Sk4s* ys) { |
| 141 Sk4s divX = (*xs * fXInvMax).floor(); |
| 142 Sk4s divY = (*ys * fYInvMax).floor(); |
| 143 Sk4s baseX = (divX * fXMax); |
| 144 Sk4s baseY = (divY * fYMax); |
| 145 *xs = *xs - baseX; |
| 146 *ys = *ys - baseY; |
| 147 } |
| 148 |
| 149 template<typename Next> |
| 150 bool maybeProcessSpan(Span originalSpan, Next* next) { |
| 151 SkASSERT(!originalSpan.isEmpty()); |
| 152 SkPoint start; |
| 153 SkScalar length; |
| 154 int count; |
| 155 std::tie(start, length, count) = originalSpan; |
| 156 // Make x and y in range on the tile. |
| 157 SkScalar x = TileMod(X(start), fXMax[0]); |
| 158 SkScalar y = TileMod(Y(start), fYMax[0]); |
| 159 SkScalar xMax = fXMax[0]; |
| 160 SkScalar xMin = 0.0f; |
| 161 SkScalar dx = length / (count - 1); |
| 162 |
| 163 // No need trying to go fast because the steps are larger than a tile or
there is one point. |
| 164 if (SkScalarAbs(dx) >= xMax || count <= 1) { |
| 165 return false; |
| 166 } |
| 167 |
| 168 // A B C D Z |
| 169 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ |
| 170 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*|
|| |
| 171 // | | | || | | || ... | |
|| |
| 172 // | | | || | | || | |
|| |
| 173 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ |
| 174 // ^^ ^^
^^ |
| 175 // xMax || xMin xMax || xMin xM
ax || xMin |
| 176 // |
| 177 // *---*---*---... - track of samples. * = sample |
| 178 // |
| 179 // +-+ || |
| 180 // | | - pixels in source space. || - tile border. |
| 181 // +-+ || |
| 182 // |
| 183 // |
| 184 // The given span starts at A and continues on through several tiles to
sample point Z. |
| 185 // The idea is to break this into several spans one on each tile the ent
ire span |
| 186 // intersects. The A to B span only covers a partial tile and has a coun
t of 3 and the |
| 187 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from
A to the start of |
| 188 // the next span is count * dx or 3 * dx. Span C to D covers an entire t
ile has a count |
| 189 // of 5 and a length of 4 * dx. Remember, count is the number of pixels
needed for the |
| 190 // destination and the number of samples. |
| 191 // |
| 192 // Overall Strategy: |
| 193 // While the span hangs over the edge of the tile, draw the span coverin
g the tile then |
| 194 // slide the span over to the next tile. |
| 195 |
| 196 // The guard could have been count > 0, but then a bunch of math would b
e done in the |
| 197 // common case. |
| 198 |
| 199 Span span({x, y}, length, count); |
| 200 if (dx > 0) { |
| 201 while (!span.isEmpty() && span.endX() > xMax) { |
| 202 Span toDraw = span.breakAt(xMax, dx); |
| 203 next->pointSpan(toDraw); |
| 204 span.offset(-xMax); |
| 205 } |
| 206 } else { |
| 207 while (!span.isEmpty() && span.endX() < xMin) { |
| 208 Span toDraw = span.breakAt(xMin, dx); |
| 209 next->pointSpan(toDraw); |
| 210 span.offset(xMax); |
| 211 } |
| 212 } |
| 213 |
| 214 // All on a single tile. |
| 215 if (!span.isEmpty()) { |
| 216 next->pointSpan(span); |
| 217 } |
| 218 |
| 219 return true; |
| 220 } |
| 221 |
| 222 template <typename Next> |
| 223 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) { |
| 224 return false; |
| 225 } |
| 226 |
| 227 private: |
| 228 SkScalar TileMod(SkScalar x, SkScalar base) { |
| 229 return x - std::floor(x / base) * base; |
| 230 } |
| 231 const Sk4s fXMax{0.0f}; |
| 232 const Sk4s fXInvMax{0.0f}; |
| 233 const Sk4s fYMax{0.0f}; |
| 234 const Sk4s fYInvMax{0.0f}; |
| 235 }; |
| 236 |
| 237 } // namespace |
| 238 #endif // SkLinearBitmapPipeline_tile_DEFINED |
OLD | NEW |