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