OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkLinearBitmapPipeline_core_DEFINED | 8 #ifndef SkLinearBitmapPipeline_core_DEFINED |
9 #define SkLinearBitmapPipeline_core_DEFINED | 9 #define SkLinearBitmapPipeline_core_DEFINED |
10 | 10 |
| 11 #include <cmath> |
| 12 |
11 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 13 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. |
12 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 14 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
13 #define VECTORCALL __vectorcall | 15 #define VECTORCALL __vectorcall |
14 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | 16 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) |
15 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | 17 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) |
16 #else | 18 #else |
17 #define VECTORCALL | 19 #define VECTORCALL |
18 #endif | 20 #endif |
19 | 21 |
20 namespace { | 22 namespace { |
21 struct X { | 23 struct X { |
22 explicit X(SkScalar val) : fVal{val} { } | 24 explicit X(SkScalar val) : fVal{val} { } |
23 explicit X(SkPoint pt) : fVal{pt.fX} { } | 25 explicit X(SkPoint pt) : fVal{pt.fX} { } |
24 explicit X(SkSize s) : fVal{s.fWidth} { } | 26 explicit X(SkSize s) : fVal{s.fWidth} { } |
25 explicit X(SkISize s) : fVal(s.fWidth) { } | 27 explicit X(SkISize s) : fVal((SkScalar)s.fWidth) { } |
26 operator SkScalar () const {return fVal;} | 28 operator SkScalar () const {return fVal;} |
27 private: | 29 private: |
28 SkScalar fVal; | 30 SkScalar fVal; |
29 }; | 31 }; |
30 | 32 |
31 struct Y { | 33 struct Y { |
32 explicit Y(SkScalar val) : fVal{val} { } | 34 explicit Y(SkScalar val) : fVal{val} { } |
33 explicit Y(SkPoint pt) : fVal{pt.fY} { } | 35 explicit Y(SkPoint pt) : fVal{pt.fY} { } |
34 explicit Y(SkSize s) : fVal{s.fHeight} { } | 36 explicit Y(SkSize s) : fVal{s.fHeight} { } |
35 explicit Y(SkISize s) : fVal(s.fHeight) { } | 37 explicit Y(SkISize s) : fVal((SkScalar)s.fHeight) { } |
36 operator SkScalar () const {return fVal;} | 38 operator SkScalar () const {return fVal;} |
37 private: | 39 private: |
38 SkScalar fVal; | 40 SkScalar fVal; |
39 }; | 41 }; |
40 | 42 |
41 // The Span class enables efficient processing horizontal spans of pixels. | 43 // The Span class enables efficient processing horizontal spans of pixels. |
42 // * start - the point where to start the span. | 44 // * start - the point where to start the span. |
43 // * length - the number of pixels to traverse in source space. | 45 // * length - the number of pixels to traverse in source space. |
44 // * count - the number of pixels to produce in destination space. | 46 // * count - the number of pixels to produce in destination space. |
45 // Both start and length are mapped through the inversion matrix to produce valu
es in source | 47 // Both start and length are mapped through the inversion matrix to produce valu
es in source |
(...skipping 20 matching lines...) Expand all Loading... |
66 SkScalar length() const { return fLength; } | 68 SkScalar length() const { return fLength; } |
67 SkScalar startX() const { return X(fStart); } | 69 SkScalar startX() const { return X(fStart); } |
68 SkScalar endX() const { return startX() + length(); } | 70 SkScalar endX() const { return startX() + length(); } |
69 void clear() { | 71 void clear() { |
70 fCount = 0; | 72 fCount = 0; |
71 } | 73 } |
72 | 74 |
73 bool completelyWithin(SkScalar xMin, SkScalar xMax) const { | 75 bool completelyWithin(SkScalar xMin, SkScalar xMax) const { |
74 SkScalar sMin, sMax; | 76 SkScalar sMin, sMax; |
75 std::tie(sMin, sMax) = std::minmax(startX(), endX()); | 77 std::tie(sMin, sMax) = std::minmax(startX(), endX()); |
76 return xMin <= sMin && sMax <= xMax; | 78 return xMin <= sMin && sMax < xMax; |
77 } | 79 } |
78 | 80 |
79 void offset(SkScalar offsetX) { | 81 void offset(SkScalar offsetX) { |
80 fStart.offset(offsetX, 0.0f); | 82 fStart.offset(offsetX, 0.0f); |
81 } | 83 } |
82 | 84 |
83 Span breakAt(SkScalar breakX, SkScalar dx) { | 85 Span breakAt(SkScalar breakX, SkScalar dx) { |
84 SkASSERT(std::isfinite(breakX)); | 86 SkASSERT(std::isfinite(breakX)); |
85 SkASSERT(std::isfinite(dx)); | 87 SkASSERT(std::isfinite(dx)); |
86 SkASSERT(dx != 0.0f); | 88 SkASSERT(dx != 0.0f); |
87 | 89 |
88 if (this->isEmpty()) { | 90 if (this->isEmpty()) { |
89 return Span{{0.0, 0.0}, 0.0f, 0}; | 91 return Span{{0.0, 0.0}, 0.0f, 0}; |
90 } | 92 } |
91 | 93 |
92 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx); | 94 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx); |
| 95 |
| 96 // Calculate the values for the span to cleave off. |
| 97 SkScalar newLength = dxSteps * dx; |
| 98 |
93 if (dxSteps < 0) { | 99 if (dxSteps < 0) { |
94 // The span is wholly after breakX. | 100 // The span is wholly after breakX. |
95 return Span{{0.0, 0.0}, 0.0f, 0}; | 101 return Span{{0.0, 0.0}, 0.0f, 0}; |
96 } else if (dxSteps > fCount) { | 102 } else if (dxSteps >= fCount) { |
97 // The span is wholly before breakX. | 103 // The span is wholly before breakX. |
98 Span answer = *this; | 104 Span answer = *this; |
99 this->clear(); | 105 this->clear(); |
100 return answer; | 106 return answer; |
101 } | 107 } |
102 | 108 |
103 // Calculate the values for the span to cleave off. | 109 // If the last (or first if count = 1) sample lands directly on the boun
dary. Include it |
| 110 // when dx < 0 and exclude it when dx > 0. |
| 111 // Reasoning: |
| 112 // dx > 0: The sample point on the boundary is part of the next span be
cause the entire |
| 113 // pixel is after the boundary. |
| 114 // dx < 0: The sample point on the boundary is part of the current span
because the |
| 115 // entire pixel is before the boundary. |
| 116 if (startX() + newLength == breakX && dx > 0) { |
| 117 if (dxSteps != 0) { |
| 118 dxSteps -= 1; |
| 119 newLength -= dx; |
| 120 } else { |
| 121 return Span{{0.0, 0.0}, 0.0f, 0}; |
| 122 } |
| 123 } |
| 124 |
104 SkPoint newStart = fStart; | 125 SkPoint newStart = fStart; |
105 SkScalar newLength = dxSteps * dx; | |
106 int newCount = dxSteps + 1; | 126 int newCount = dxSteps + 1; |
107 SkASSERT(newCount > 0); | 127 SkASSERT(newCount > 0); |
108 | 128 |
109 // Update this span to reflect the break. | 129 // Update this span to reflect the break. |
110 SkScalar lengthToStart = newLength + dx; | 130 SkScalar lengthToStart = newLength + dx; |
111 fLength -= lengthToStart; | 131 fLength -= lengthToStart; |
112 fCount -= newCount; | 132 fCount -= newCount; |
113 fStart = {this->startX() + lengthToStart, Y(fStart)}; | 133 fStart = {this->startX() + lengthToStart, Y(fStart)}; |
114 | 134 |
115 return Span{newStart, newLength, newCount}; | 135 return Span{newStart, newLength, newCount}; |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
202 // never used. | 222 // never used. |
203 while (count > 0) { | 223 while (count > 0) { |
204 next->bilerpList(xs, ys); | 224 next->bilerpList(xs, ys); |
205 xs = xs + dx; | 225 xs = xs + dx; |
206 count -= 1; | 226 count -= 1; |
207 } | 227 } |
208 } | 228 } |
209 } // namespace | 229 } // namespace |
210 | 230 |
211 #endif // SkLinearBitmapPipeline_core_DEFINED | 231 #endif // SkLinearBitmapPipeline_core_DEFINED |
OLD | NEW |