aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkAnalyticEdge.cpp
diff options
context:
space:
mode:
authorGravatar liyuqian <liyuqian@google.com>2016-10-04 11:23:22 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-10-04 11:23:22 -0700
commit38911a7cb53474575e1cd1cb545902b50ee00889 (patch)
treee8186ee1c91bb4f9206457debdb0103c1a38218f /src/core/SkAnalyticEdge.cpp
parent421a3c1cc1b227084c7c84618d0b6a6804faabef (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.cpp245
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;
+}