michael@0: michael@0: /* michael@0: * Copyright 2006 The Android Open Source Project michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: #ifndef SkEdge_DEFINED michael@0: #define SkEdge_DEFINED michael@0: michael@0: #include "SkRect.h" michael@0: #include "SkFDot6.h" michael@0: #include "SkMath.h" michael@0: michael@0: // This correctly favors the lower-pixel when y0 is on a 1/2 pixel boundary michael@0: #define SkEdge_Compute_DY(top, y0) ((top << 6) + 32 - (y0)) michael@0: michael@0: struct SkEdge { michael@0: enum Type { michael@0: kLine_Type, michael@0: kQuad_Type, michael@0: kCubic_Type michael@0: }; michael@0: michael@0: SkEdge* fNext; michael@0: SkEdge* fPrev; michael@0: michael@0: SkFixed fX; michael@0: SkFixed fDX; michael@0: int32_t fFirstY; michael@0: int32_t fLastY; michael@0: int8_t fCurveCount; // only used by kQuad(+) and kCubic(-) michael@0: uint8_t fCurveShift; // appled to all Dx/DDx/DDDx except for fCubicDShift exception michael@0: uint8_t fCubicDShift; // applied to fCDx and fCDy only in cubic michael@0: int8_t fWinding; // 1 or -1 michael@0: michael@0: int setLine(const SkPoint& p0, const SkPoint& p1, const SkIRect* clip, michael@0: int shiftUp); michael@0: // call this version if you know you don't have a clip michael@0: inline int setLine(const SkPoint& p0, const SkPoint& p1, int shiftUp); michael@0: inline int updateLine(SkFixed ax, SkFixed ay, SkFixed bx, SkFixed by); michael@0: void chopLineWithClip(const SkIRect& clip); michael@0: michael@0: inline bool intersectsClip(const SkIRect& clip) const { michael@0: SkASSERT(fFirstY < clip.fBottom); michael@0: return fLastY >= clip.fTop; michael@0: } michael@0: michael@0: #ifdef SK_DEBUG michael@0: void dump() const { michael@0: SkDebugf("edge: firstY:%d lastY:%d x:%g dx:%g w:%d\n", fFirstY, fLastY, SkFixedToFloat(fX), SkFixedToFloat(fDX), fWinding); michael@0: } michael@0: michael@0: void validate() const { michael@0: SkASSERT(fPrev && fNext); michael@0: SkASSERT(fPrev->fNext == this); michael@0: SkASSERT(fNext->fPrev == this); michael@0: michael@0: SkASSERT(fFirstY <= fLastY); michael@0: SkASSERT(SkAbs32(fWinding) == 1); michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: struct SkQuadraticEdge : public SkEdge { michael@0: SkFixed fQx, fQy; michael@0: SkFixed fQDx, fQDy; michael@0: SkFixed fQDDx, fQDDy; michael@0: SkFixed fQLastX, fQLastY; michael@0: michael@0: int setQuadratic(const SkPoint pts[3], int shiftUp); michael@0: int updateQuadratic(); michael@0: }; michael@0: michael@0: struct SkCubicEdge : public SkEdge { michael@0: SkFixed fCx, fCy; michael@0: SkFixed fCDx, fCDy; michael@0: SkFixed fCDDx, fCDDy; michael@0: SkFixed fCDDDx, fCDDDy; michael@0: SkFixed fCLastX, fCLastY; michael@0: michael@0: int setCubic(const SkPoint pts[4], const SkIRect* clip, int shiftUp); michael@0: int updateCubic(); michael@0: }; michael@0: michael@0: int SkEdge::setLine(const SkPoint& p0, const SkPoint& p1, int shift) { michael@0: SkFDot6 x0, y0, x1, y1; michael@0: michael@0: { michael@0: float scale = float(1 << (shift + 6)); michael@0: x0 = int(p0.fX * scale); michael@0: y0 = int(p0.fY * scale); michael@0: x1 = int(p1.fX * scale); michael@0: y1 = int(p1.fY * scale); michael@0: } michael@0: michael@0: int winding = 1; michael@0: michael@0: if (y0 > y1) { michael@0: SkTSwap(x0, x1); michael@0: SkTSwap(y0, y1); michael@0: winding = -1; michael@0: } michael@0: michael@0: int top = SkFDot6Round(y0); michael@0: int bot = SkFDot6Round(y1); michael@0: michael@0: // are we a zero-height line? michael@0: if (top == bot) { michael@0: return 0; michael@0: } michael@0: michael@0: SkFixed slope = SkFDot6Div(x1 - x0, y1 - y0); michael@0: const int dy = SkEdge_Compute_DY(top, y0); michael@0: michael@0: fX = SkFDot6ToFixed(x0 + SkFixedMul(slope, dy)); // + SK_Fixed1/2 michael@0: fDX = slope; michael@0: fFirstY = top; michael@0: fLastY = bot - 1; michael@0: fCurveCount = 0; michael@0: fWinding = SkToS8(winding); michael@0: fCurveShift = 0; michael@0: return 1; michael@0: } michael@0: michael@0: michael@0: #endif