| 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 |