1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com/*
3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Copyright 2006 The Android Open Source Project
4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com *
5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com * found in the LICENSE file.
7ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com */
8ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com
98a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
108a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifndef SkEdge_DEFINED
118a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#define SkEdge_DEFINED
128a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
138a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#include "SkRect.h"
14b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com#include "SkFDot6.h"
15b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com#include "SkMath.h"
168a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
17e4646db4dc747b568e2b61cab300606d57cf645areed@google.com// This correctly favors the lower-pixel when y0 is on a 1/2 pixel boundary
18e4646db4dc747b568e2b61cab300606d57cf645areed@google.com#define SkEdge_Compute_DY(top, y0)  ((top << 6) + 32 - (y0))
1909a029b687465190c828bde896173e23aa350c4creed@google.com
208a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkEdge {
218a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    enum Type {
228a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kLine_Type,
238a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kQuad_Type,
248a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        kCubic_Type
258a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    };
268a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
278a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge* fNext;
288a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkEdge* fPrev;
298a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
308a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fX;
318a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fDX;
328a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t fFirstY;
338a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int32_t fLastY;
348a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int8_t fCurveCount;    // only used by kQuad(+) and kCubic(-)
358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t fCurveShift;    // appled to all Dx/DDx/DDDx except for fCubicDShift exception
368a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    uint8_t fCubicDShift;   // applied to fCDx and fCDy only in cubic
378a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int8_t  fWinding;       // 1 or -1
388a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
39e053ca4380713a5b9e6a31119a1bdd6d529208aareed    int setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, int shiftUp);
40b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    // call this version if you know you don't have a clip
41b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    inline int setLine(const SkPoint& p0, const SkPoint& p1, int shiftUp);
428a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inline int updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by);
438a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void chopLineWithClip(const SkIRect& clip);
448a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
458a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    inline bool intersectsClip(const SkIRect& clip) const {
468a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fFirstY < clip.fBottom);
478a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        return fLastY >= clip.fTop;
488a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
498a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
508a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#ifdef SK_DEBUG
518a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void dump() const {
528a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkDebugf("edge: firstY:%d lastY:%d x:%g dx:%g w:%d\n", fFirstY, fLastY, SkFixedToFloat(fX), SkFixedToFloat(fDX), fWinding);
538a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
548a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
558a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    void validate() const {
568a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fPrev && fNext);
578a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fPrev->fNext == this);
588a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fNext->fPrev == this);
598a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
608a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(fFirstY <= fLastY);
618a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com        SkASSERT(SkAbs32(fWinding) == 1);
628a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    }
638a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
648a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
658a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
668a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkQuadraticEdge : public SkEdge {
678a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fQx, fQy;
688a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fQDx, fQDy;
698a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fQDDx, fQDDy;
708a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fQLastX, fQLastY;
718a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
72c07d23a6e220c0aff36e3e4e06c1b685a440108ereed@android.com    int setQuadratic(const SkPoint pts[3], int shiftUp);
738a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int updateQuadratic();
748a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
758a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
768a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.comstruct SkCubicEdge : public SkEdge {
778a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fCx, fCy;
788a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fCDx, fCDy;
798a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fCDDx, fCDDy;
808a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fCDDDx, fCDDDy;
818a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    SkFixed fCLastX, fCLastY;
828a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
83e053ca4380713a5b9e6a31119a1bdd6d529208aareed    int setCubic(const SkPoint pts[4], int shiftUp);
848a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com    int updateCubic();
858a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com};
868a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com
87b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.comint SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) {
88b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    SkFDot6 x0, y0, x1, y1;
89fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
90b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    {
912f26528e59908856e36e88aa3be94d84014e9a58george#ifdef SK_RASTERIZE_EVEN_ROUNDING
922f26528e59908856e36e88aa3be94d84014e9a58george        x0 = SkScalarRoundToFDot6(p0.fX, shift);
932f26528e59908856e36e88aa3be94d84014e9a58george        y0 = SkScalarRoundToFDot6(p0.fY, shift);
942f26528e59908856e36e88aa3be94d84014e9a58george        x1 = SkScalarRoundToFDot6(p1.fX, shift);
952f26528e59908856e36e88aa3be94d84014e9a58george        y1 = SkScalarRoundToFDot6(p1.fY, shift);
962f26528e59908856e36e88aa3be94d84014e9a58george#else
97b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        float scale = float(1 << (shift + 6));
98b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        x0 = int(p0.fX * scale);
99b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        y0 = int(p0.fY * scale);
100b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        x1 = int(p1.fX * scale);
101b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        y1 = int(p1.fY * scale);
1022f26528e59908856e36e88aa3be94d84014e9a58george#endif
103b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    }
104fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
105b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    int winding = 1;
106fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
107b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    if (y0 > y1) {
108b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        SkTSwap(x0, x1);
109b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        SkTSwap(y0, y1);
110b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        winding = -1;
111b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    }
112fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
113b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    int top = SkFDot6Round(y0);
114b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    int bot = SkFDot6Round(y1);
115fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
116b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    // are we a zero-height line?
117b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    if (top == bot) {
118b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com        return 0;
119b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    }
120fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
121b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0);
1221c762161d88f0ace8cee1eea43d1b7350c06242eqiankun.miao    const SkFDot6 dy  = SkEdge_Compute_DY(top, y0);
123fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
12409a029b687465190c828bde896173e23aa350c4creed@google.com    fX          = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy));   // + SK_Fixed1/2
125b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fDX         = slope;
126b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fFirstY     = top;
127b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fLastY      = bot - 1;
128b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fCurveCount = 0;
129b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fWinding    = SkToS8(winding);
130b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    fCurveShift = 0;
131b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com    return 1;
132b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com}
133b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com
134b6a2ba7b483a164a59ec0ded0795590329eab923reed@google.com
1358a1c16ff38322f0210116fa7293eb8817c7e477ereed@android.com#endif
136