| Index: src/core/SkLinearBitmapPipeline_tile.h
|
| diff --git a/src/core/SkLinearBitmapPipeline_tile.h b/src/core/SkLinearBitmapPipeline_tile.h
|
| index 761e3c57ebc7755ee3cdd584e08b3776f5100f82..60cc2a5ef09acb8eb01f4f71d1f5608ebe0484f3 100644
|
| --- a/src/core/SkLinearBitmapPipeline_tile.h
|
| +++ b/src/core/SkLinearBitmapPipeline_tile.h
|
| @@ -15,39 +15,30 @@
|
| #include <limits>
|
|
|
| namespace {
|
| -class ClampStrategy {
|
| +class XClampStrategy {
|
| public:
|
| - ClampStrategy(X max)
|
| - : fXMin{0.0f}, fXMax{max - 1.0f} { }
|
| + XClampStrategy(int32_t max)
|
| + : fXsMax{SkScalar(max - 0.5f)}
|
| + , fXMax{SkScalar(max)} { }
|
|
|
| - ClampStrategy(Y max)
|
| - : fYMin{0.0f}, fYMax{max - 1.0f} { }
|
| -
|
| - ClampStrategy(SkSize max)
|
| - : fXMin{0.0f}, fYMin{0.0f}, fXMax{X(max) - 1.0f}, fYMax{Y(max) - 1.0f} { }
|
| -
|
| - void processPoints(Sk4s* xs, Sk4s* ys) {
|
| - *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax);
|
| - *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax);
|
| + void tileXPoints(Sk4s* xs) {
|
| + *xs = Sk4s::Min(Sk4s::Max(*xs, 0.0f), fXsMax);
|
| + SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax);
|
| + SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax);
|
| + SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax);
|
| + SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax);
|
| }
|
|
|
| template<typename Next>
|
| bool maybeProcessSpan(Span originalSpan, Next* next) {
|
| SkASSERT(!originalSpan.isEmpty());
|
| - SkPoint start;
|
| - SkScalar length;
|
| - int count;
|
| + SkPoint start; SkScalar length; int count;
|
| std::tie(start, length, count) = originalSpan;
|
| - SkScalar xMin = fXMin[0];
|
| - SkScalar xMax = fXMax[0] + 1.0f;
|
| - SkScalar yMin = fYMin[0];
|
| - SkScalar yMax = fYMax[0];
|
| SkScalar x = X(start);
|
| - SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax);
|
| -
|
| + SkScalar y = Y(start);
|
| Span span{{x, y}, length, count};
|
|
|
| - if (span.completelyWithin(xMin, xMax)) {
|
| + if (span.completelyWithin(0.0f, fXMax)) {
|
| next->pointSpan(span);
|
| return true;
|
| }
|
| @@ -85,84 +76,100 @@ public:
|
| // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and
|
| // use it to fill in the rest of the destination pixels.
|
| if (dx >= 0) {
|
| - Span leftClamped = span.breakAt(xMin, dx);
|
| + Span leftClamped = span.breakAt(0.0f, dx);
|
| if (!leftClamped.isEmpty()) {
|
| - leftClamped.clampToSinglePixel({xMin, y});
|
| + leftClamped.clampToSinglePixel({0.0f, y});
|
| next->pointSpan(leftClamped);
|
| }
|
| - Span middle = span.breakAt(xMax, dx);
|
| - if (!middle.isEmpty()) {
|
| - next->pointSpan(middle);
|
| + Span center = span.breakAt(fXMax, dx);
|
| + if (!center.isEmpty()) {
|
| + next->pointSpan(center);
|
| }
|
| if (!span.isEmpty()) {
|
| - span.clampToSinglePixel({xMax - 1, y});
|
| + span.clampToSinglePixel({fXMax - 1, y});
|
| next->pointSpan(span);
|
| }
|
| } else {
|
| - Span rightClamped = span.breakAt(xMax, dx);
|
| + Span center = span.breakAt(fXMax, dx);
|
|
|
| - if (!rightClamped.isEmpty()) {
|
| - rightClamped.clampToSinglePixel({xMax - 1, y});
|
| - next->pointSpan(rightClamped);
|
| - }
|
| - Span middle = span.breakAt(xMin, dx);
|
| - if (!middle.isEmpty()) {
|
| - next->pointSpan(middle);
|
| - }
|
| if (!span.isEmpty()) {
|
| - span.clampToSinglePixel({xMin, y});
|
| + span.clampToSinglePixel({fXMax - 1, y});
|
| next->pointSpan(span);
|
| }
|
| + Span leftEdge = center.breakAt(0.0f, dx);
|
| + if (!center.isEmpty()) {
|
| + next->pointSpan(center);
|
| + }
|
| + if (!leftEdge.isEmpty()) {
|
| + leftEdge.clampToSinglePixel({0.0f, y});
|
| + next->pointSpan(leftEdge);
|
| + }
|
| }
|
| return true;
|
| }
|
|
|
| - template <typename Next>
|
| - bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
|
| - return false;
|
| - }
|
| -
|
| private:
|
| - const Sk4s fXMin{SK_FloatNegativeInfinity};
|
| - const Sk4s fYMin{SK_FloatNegativeInfinity};
|
| - const Sk4s fXMax{SK_FloatInfinity};
|
| - const Sk4s fYMax{SK_FloatInfinity};
|
| + const Sk4s fXsMax;
|
| + const SkScalar fXMax;
|
| };
|
|
|
| -class RepeatStrategy {
|
| +class YClampStrategy {
|
| public:
|
| - RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f / max} { }
|
| + YClampStrategy(int32_t max)
|
| + : fYMax{SkScalar(max) - 0.5f}
|
| + , fYsMax{SkScalar(max) - 0.5f} { }
|
|
|
| - RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f / max} { }
|
| + void tileYPoints(Sk4s* ys) {
|
| + *ys = Sk4s::Min(Sk4s::Max(*ys, 0.0f), fYsMax);
|
| + SkASSERT(0 <= (*ys)[0] && (*ys)[0] <= fYMax);
|
| + SkASSERT(0 <= (*ys)[1] && (*ys)[1] <= fYMax);
|
| + SkASSERT(0 <= (*ys)[2] && (*ys)[2] <= fYMax);
|
| + SkASSERT(0 <= (*ys)[3] && (*ys)[3] <= fYMax);
|
| + }
|
|
|
| - RepeatStrategy(SkSize max)
|
| - : fXMax{X(max)}, fXInvMax{1.0f / X(max)}, fYMax{Y(max)}, fYInvMax{1.0f / Y(max)} { }
|
| + SkScalar tileY(SkScalar y) {
|
| + return std::min(std::max<SkScalar>(0.0f, y), fYMax);
|
| + }
|
| +
|
| +private:
|
| + const SkScalar fYMax;
|
| + const Sk4s fYsMax;
|
| +};
|
| +
|
| +SkScalar tile_mod(SkScalar x, SkScalar base) {
|
| + return x - SkScalarFloorToScalar(x / base) * base;
|
| +}
|
|
|
| - void processPoints(Sk4s* xs, Sk4s* ys) {
|
| - Sk4s divX = (*xs * fXInvMax).floor();
|
| - Sk4s divY = (*ys * fYInvMax).floor();
|
| - Sk4s baseX = (divX * fXMax);
|
| - Sk4s baseY = (divY * fYMax);
|
| - *xs = *xs - baseX;
|
| - *ys = *ys - baseY;
|
| +class XRepeatStrategy {
|
| +public:
|
| + XRepeatStrategy(int32_t max)
|
| + : fXMax{SkScalar(max)}
|
| + , fXsMax{SkScalar(max)}
|
| + , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))}
|
| + , fXsInvMax{1.0f / SkScalar(max)} { }
|
| +
|
| + void tileXPoints(Sk4s* xs) {
|
| + Sk4s divX = *xs * fXsInvMax;
|
| + Sk4s modX = *xs - divX.floor() * fXsMax;
|
| + *xs = Sk4s::Min(fXsCap, modX);
|
| + SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXMax);
|
| + SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXMax);
|
| + SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXMax);
|
| + SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXMax);
|
| }
|
|
|
| template<typename Next>
|
| bool maybeProcessSpan(Span originalSpan, Next* next) {
|
| SkASSERT(!originalSpan.isEmpty());
|
| - SkPoint start;
|
| - SkScalar length;
|
| - int count;
|
| + SkPoint start; SkScalar length; int count;
|
| std::tie(start, length, count) = originalSpan;
|
| // Make x and y in range on the tile.
|
| - SkScalar x = TileMod(X(start), fXMax[0]);
|
| - SkScalar y = TileMod(Y(start), fYMax[0]);
|
| - SkScalar xMax = fXMax[0];
|
| - SkScalar xMin = 0.0f;
|
| + SkScalar x = tile_mod(X(start), fXMax);
|
| + SkScalar y = Y(start);
|
| SkScalar dx = length / (count - 1);
|
|
|
| // No need trying to go fast because the steps are larger than a tile or there is one point.
|
| - if (SkScalarAbs(dx) >= xMax || count <= 1) {
|
| + if (SkScalarAbs(dx) >= fXMax || count <= 1) {
|
| return false;
|
| }
|
|
|
| @@ -199,16 +206,16 @@ public:
|
|
|
| Span span({x, y}, length, count);
|
| if (dx > 0) {
|
| - while (!span.isEmpty() && span.endX() >= xMax) {
|
| - Span toDraw = span.breakAt(xMax, dx);
|
| + while (!span.isEmpty() && span.endX() >= fXMax) {
|
| + Span toDraw = span.breakAt(fXMax, dx);
|
| next->pointSpan(toDraw);
|
| - span.offset(-xMax);
|
| + span.offset(-fXMax);
|
| }
|
| } else {
|
| - while (!span.isEmpty() && span.endX() < xMin) {
|
| - Span toDraw = span.breakAt(xMin, dx);
|
| + while (!span.isEmpty() && span.endX() < 0.0f) {
|
| + Span toDraw = span.breakAt(0.0f, dx);
|
| next->pointSpan(toDraw);
|
| - span.offset(xMax);
|
| + span.offset(fXMax);
|
| }
|
| }
|
|
|
| @@ -220,19 +227,106 @@ public:
|
| return true;
|
| }
|
|
|
| - template <typename Next>
|
| - bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
|
| - return false;
|
| +private:
|
| + const SkScalar fXMax;
|
| + const Sk4s fXsMax;
|
| + const Sk4s fXsCap;
|
| + const Sk4s fXsInvMax;
|
| +};
|
| +
|
| +class YRepeatStrategy {
|
| +public:
|
| + YRepeatStrategy(int32_t max)
|
| + : fYMax{SkScalar(max)}
|
| + , fYsMax{SkScalar(max)}
|
| + , fYsInvMax{1.0f / SkScalar(max)} { }
|
| +
|
| + void tileYPoints(Sk4s* ys) {
|
| + Sk4s divY = *ys * fYsInvMax;
|
| + Sk4s modY = *ys - divY.floor() * fYsMax;
|
| + *ys = modY;
|
| + SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax);
|
| + SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax);
|
| + SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax);
|
| + SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax);
|
| + }
|
| +
|
| + SkScalar tileY(SkScalar y) {
|
| + SkScalar answer = tile_mod(y, fYMax);
|
| + SkASSERT(0 <= answer && answer < fYMax);
|
| + return answer;
|
| + }
|
| +
|
| +private:
|
| + const SkScalar fYMax;
|
| + const Sk4s fYsMax;
|
| + const Sk4s fYsInvMax;
|
| +};
|
| +// max = 40
|
| +// mq2[x_] := Abs[(x - 40) - Floor[(x - 40)/80] * 80 - 40]
|
| +class XMirrorStrategy {
|
| +public:
|
| + XMirrorStrategy(int32_t max)
|
| + : fXsMax{SkScalar(max)}
|
| + , fXsCap{SkScalar(nextafterf(SkScalar(max), 0.0f))}
|
| + , fXsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { }
|
| +
|
| + void tileXPoints(Sk4s* xs) {
|
| + Sk4f bias = *xs - fXsMax;
|
| + Sk4f div = bias * fXsDoubleInvMax;
|
| + Sk4f mod = bias - div.floor() * 2.0f * fXsMax;
|
| + Sk4f unbias = mod - fXsMax;
|
| + *xs = Sk4f::Min(unbias.abs(), fXsCap);
|
| + SkASSERT(0 <= (*xs)[0] && (*xs)[0] < fXsMax[0]);
|
| + SkASSERT(0 <= (*xs)[1] && (*xs)[1] < fXsMax[0]);
|
| + SkASSERT(0 <= (*xs)[2] && (*xs)[2] < fXsMax[0]);
|
| + SkASSERT(0 <= (*xs)[3] && (*xs)[3] < fXsMax[0]);
|
| }
|
|
|
| + template <typename Next>
|
| + bool maybeProcessSpan(Span originalSpan, Next* next) { return false; }
|
| +
|
| private:
|
| - SkScalar TileMod(SkScalar x, SkScalar base) {
|
| - return x - std::floor(x / base) * base;
|
| + Sk4f fXsMax;
|
| + Sk4f fXsCap;
|
| + Sk4f fXsDoubleInvMax;
|
| +};
|
| +
|
| +class YMirrorStrategy {
|
| +public:
|
| + YMirrorStrategy(int32_t max)
|
| + : fYMax{SkScalar(max)}
|
| + , fYsMax{SkScalar(max)}
|
| + , fYsCap{nextafterf(SkScalar(max), 0.0f)}
|
| + , fYsDoubleInvMax{1.0f / (2.0f * SkScalar(max))} { }
|
| +
|
| + void tileYPoints(Sk4s* ys) {
|
| + Sk4f bias = *ys - fYsMax;
|
| + Sk4f div = bias * fYsDoubleInvMax;
|
| + Sk4f mod = bias - div.floor() * 2.0f * fYsMax;
|
| + Sk4f unbias = mod - fYsMax;
|
| + *ys = Sk4f::Min(unbias.abs(), fYsCap);
|
| + SkASSERT(0 <= (*ys)[0] && (*ys)[0] < fYMax);
|
| + SkASSERT(0 <= (*ys)[1] && (*ys)[1] < fYMax);
|
| + SkASSERT(0 <= (*ys)[2] && (*ys)[2] < fYMax);
|
| + SkASSERT(0 <= (*ys)[3] && (*ys)[3] < fYMax);
|
| }
|
| - const Sk4s fXMax{0.0f};
|
| - const Sk4s fXInvMax{0.0f};
|
| - const Sk4s fYMax{0.0f};
|
| - const Sk4s fYInvMax{0.0f};
|
| +
|
| + SkScalar tileY(SkScalar y) {
|
| + SkScalar bias = y - fYMax;
|
| + SkScalar div = bias * fYsDoubleInvMax[0];
|
| + SkScalar mod = bias - SkScalarFloorToScalar(div) * 2.0f * fYMax;
|
| + SkScalar unbias = mod - fYMax;
|
| + SkScalar answer = SkMinScalar(SkScalarAbs(unbias), fYsCap[0]);
|
| + SkASSERT(0 <= answer && answer < fYMax);
|
| + return answer;
|
| + };
|
| +
|
| +private:
|
| + SkScalar fYMax;
|
| + Sk4f fYsMax;
|
| + Sk4f fYsCap;
|
| + Sk4f fYsDoubleInvMax;
|
| };
|
|
|
| } // namespace
|
|
|