diff options
author | liyuqian <liyuqian@google.com> | 2016-10-04 11:23:22 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-10-04 11:23:22 -0700 |
commit | 38911a7cb53474575e1cd1cb545902b50ee00889 (patch) | |
tree | e8186ee1c91bb4f9206457debdb0103c1a38218f /src/core/SkAnalyticEdge.cpp | |
parent | 421a3c1cc1b227084c7c84618d0b6a6804faabef (diff) |
Resubmit issue 2221103002 to fix the iOS build by declaring the flag in
SkCommonFlags.h
TBR=reed@google.com,caryclark@google.com
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2393643002
Review-Url: https://codereview.chromium.org/2393643002
Diffstat (limited to 'src/core/SkAnalyticEdge.cpp')
-rw-r--r-- | src/core/SkAnalyticEdge.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/src/core/SkAnalyticEdge.cpp b/src/core/SkAnalyticEdge.cpp new file mode 100644 index 0000000000..fde37e09db --- /dev/null +++ b/src/core/SkAnalyticEdge.cpp @@ -0,0 +1,245 @@ +/* + * Copyright 2006 The Android Open Source Project + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + + +#include "SkAnalyticEdge.h" +#include "SkFDot6.h" +#include "SkMathPriv.h" +#include "SkAAAConstants.h" + +class QuickFDot6Inverse { +private: + static constexpr const SkFDot6* table = gFDot6INVERSE + kInverseTableSize; +public: + inline static SkFixed Lookup(SkFDot6 x) { + SkASSERT(SkAbs32(x) < kInverseTableSize); + return table[x]; + } +}; + +static inline SkFixed quickSkFDot6Div(SkFDot6 a, SkFDot6 b) { + if (SkAbs32(b) < kInverseTableSize) { + SkASSERT((int64_t)a * QuickFDot6Inverse::Lookup(b) <= SK_MaxS32); + SkFixed ourAnswer = (a * QuickFDot6Inverse::Lookup(b)) >> 6; + #ifdef SK_DEBUG + SkFixed directAnswer = SkFDot6Div(a, b); + SkASSERT( + (directAnswer == 0 && ourAnswer == 0) || + SkFixedDiv(SkAbs32(directAnswer - ourAnswer), SkAbs32(directAnswer)) <= 1 << 10 + ); + #endif + return ourAnswer; + } else { + return SkFDot6Div(a, b); + } +} + +// This will become a bottleneck for small ovals rendering if we call SkFixedDiv twice here. +// Therefore, we'll let the outter function compute the slope once and send in the value. +// Moreover, we'll compute fDY by quickly lookup the inverse table (if possible). +bool SkAnalyticEdge::updateLine(SkFixed x0, SkFixed y0, SkFixed x1, SkFixed y1, SkFixed slope) { + // Since we send in the slope, we can no longer snap y inside this function. + // If we don't send in the slope, or we do some more sophisticated snapping, this function + // could be a performance bottleneck. + SkASSERT(fWinding == 1 || fWinding == -1); + SkASSERT(fCurveCount != 0); + + SkASSERT(y0 <= y1); + + SkFDot6 dx = SkFixedToFDot6(x1 - x0); + SkFDot6 dy = SkFixedToFDot6(y1 - y0); + + // are we a zero-height line? + if (dy == 0) { + return false; + } + + SkASSERT(slope < SK_MaxS32); + + SkFDot6 absSlope = SkAbs32(SkFixedToFDot6(slope)); + fX = x0; + fDX = slope; + fUpperX = x0; + fY = y0; + fUpperY = y0; + fLowerY = y1; + fDY = (absSlope | dx) == 0 + ? SK_MaxS32 + : absSlope < kInverseTableSize + ? QuickFDot6Inverse::Lookup(absSlope) + : SkAbs32(quickSkFDot6Div(dy, dx)); + + return true; +} + +void SkAnalyticEdge::chopLineWithClip(const SkIRect& clip) { + int top = SkFixedFloorToInt(fUpperY); + + SkASSERT(top < clip.fBottom); + + // clip the line to the clip top + if (top < clip.fTop) { + SkASSERT(SkFixedCeilToInt(fLowerY) > clip.fTop); + SkFixed newY = SkIntToFixed(clip.fTop); + this->goY(newY); + fUpperY = newY; + } +} + +bool SkAnalyticQuadraticEdge::setQuadratic(const SkPoint pts[3]) { + if (!fQEdge.setQuadraticWithoutUpdate(pts, 2)) { + return false; + } + fQEdge.fQx >>= 2; + fQEdge.fQy >>= 2; + fQEdge.fQDx >>= 2; + fQEdge.fQDy >>= 2; + fQEdge.fQDDx >>= 2; + fQEdge.fQDDy >>= 2; + fQEdge.fQLastX >>= 2; + fQEdge.fQLastY >>= 2; + fQEdge.fQy = snapY(fQEdge.fQy); + fQEdge.fQLastY = snapY(fQEdge.fQLastY); + + fWinding = fQEdge.fWinding; + fCurveCount = fQEdge.fCurveCount; + fCurveShift = fQEdge.fCurveShift; + + fSnappedX = fQEdge.fQx; + fSnappedY = fQEdge.fQy; + + return this->updateQuadratic(); +} + +bool SkAnalyticQuadraticEdge::updateQuadratic() { + int success = 0; // initialize to fail! + int count = fCurveCount; + SkFixed oldx = fQEdge.fQx; + SkFixed oldy = fQEdge.fQy; + SkFixed dx = fQEdge.fQDx; + SkFixed dy = fQEdge.fQDy; + SkFixed newx, newy, newSnappedX, newSnappedY; + int shift = fCurveShift; + + SkASSERT(count > 0); + + do { + SkFixed slope; + if (--count > 0) + { + newx = oldx + (dx >> shift); + newy = snapY(oldy + (dy >> shift)); + slope = dy >> 10 > 0 ? quickSkFDot6Div(dx >> 10, dy >> 10) : SK_MaxS32; + if (SkAbs32(dy) >= SK_Fixed1 * 2) { // only snap when dy is large enough + newSnappedY = SkTMin<SkFixed>(fQEdge.fQLastY, SkFixedRoundToFixed(newy)); + newSnappedX = newx + SkFixedMul_lowprec(slope, newSnappedY - newy); + } else { + newSnappedY = newy; + newSnappedX = newx; + } + dx += fQEdge.fQDDx; + dy += fQEdge.fQDDy; + } + else // last segment + { + newx = fQEdge.fQLastX; + newy = fQEdge.fQLastY; + newSnappedY = newy; + newSnappedX = newx; + slope = (newSnappedY - fSnappedY) >> 10 + ? quickSkFDot6Div((newx - fSnappedX) >> 10, (newy - fSnappedY) >> 10) + : SK_MaxS32; + } + if (slope < SK_MaxS32) { + success = this->updateLine(fSnappedX, fSnappedY, newSnappedX, newSnappedY, slope); + } + oldx = newx; + oldy = newy; + } while (count > 0 && !success); + + SkASSERT(newSnappedY <= fQEdge.fQLastY); + + fQEdge.fQx = newx; + fQEdge.fQy = newy; + fQEdge.fQDx = dx; + fQEdge.fQDy = dy; + fSnappedX = newSnappedX; + fSnappedY = newSnappedY; + fCurveCount = SkToS8(count); + return success; +} + +bool SkAnalyticCubicEdge::setCubic(const SkPoint pts[4]) { + if (!fCEdge.setCubicWithoutUpdate(pts, 2)) { + return false; + } + + fCEdge.fCx >>= 2; + fCEdge.fCy >>= 2; + fCEdge.fCDx >>= 2; + fCEdge.fCDy >>= 2; + fCEdge.fCDDx >>= 2; + fCEdge.fCDDy >>= 2; + fCEdge.fCDDDx >>= 2; + fCEdge.fCDDDy >>= 2; + fCEdge.fCLastX >>= 2; + fCEdge.fCLastY >>= 2; + fCEdge.fCy = snapY(fCEdge.fCy); + fCEdge.fCLastY = snapY(fCEdge.fCLastY); + + fWinding = fCEdge.fWinding; + fCurveCount = fCEdge.fCurveCount; + fCurveShift = fCEdge.fCurveShift; + fCubicDShift = fCEdge.fCubicDShift; + + return this->updateCubic(); +} + +bool SkAnalyticCubicEdge::updateCubic() { + int success; + int count = fCurveCount; + SkFixed oldx = fCEdge.fCx; + SkFixed oldy = fCEdge.fCy; + SkFixed newx, newy; + const int ddshift = fCurveShift; + const int dshift = fCubicDShift; + + SkASSERT(count < 0); + + do { + if (++count < 0) { + newx = oldx + (fCEdge.fCDx >> dshift); + fCEdge.fCDx += fCEdge.fCDDx >> ddshift; + fCEdge.fCDDx += fCEdge.fCDDDx; + + newy = oldy + (fCEdge.fCDy >> dshift); + fCEdge.fCDy += fCEdge.fCDDy >> ddshift; + fCEdge.fCDDy += fCEdge.fCDDDy; + } + else { // last segment + newx = fCEdge.fCLastX; + newy = fCEdge.fCLastY; + } + + // we want to say SkASSERT(oldy <= newy), but our finite fixedpoint + // doesn't always achieve that, so we have to explicitly pin it here. + if (newy < oldy) { + newy = oldy; + } + + success = this->updateLine(oldx, oldy, newx, newy, + SkFixedToFDot6(newy - oldy) == 0 ? SK_MaxS32 : + SkFDot6Div(SkFixedToFDot6(newx - oldx), SkFixedToFDot6(newy - oldy))); + oldx = newx; + oldy = newy; + } while (count < 0 && !success); + + fCEdge.fCx = newx; + fCEdge.fCy = newy; + fCurveCount = SkToS8(count); + return success; +} |