47 #include <private/qmath_p.h> 48 #include <private/qdatabuffer_p.h> 49 #include <private/qdrawhelper_p.h> 54 #define Q16Dot16ToFloat(i) ((i)/qreal(65536.)) 55 #define FloatToQ16Dot16(i) (int)((i) * qreal(65536.)) 56 #define IntToQ16Dot16(i) ((i) << 16) 57 #define Q16Dot16ToInt(i) ((i) >> 16) 58 #define Q16Dot16Factor 65536 60 #define Q16Dot16Multiply(x, y) (int)((qlonglong(x) * qlonglong(y)) >> 16) 61 #define Q16Dot16FastMultiply(x, y) (((x) * (y)) >> 16) 63 #define SPAN_BUFFER_SIZE 256 65 #define COORD_ROUNDING 1 // 0: round up, 1: round down 66 #define COORD_OFFSET 32 // 26.6, 32 is half a pixel 89 void addSpan(
int x,
unsigned int len,
int y,
unsigned char coverage)
91 if (!coverage || !len)
124 #define CHUNK_SIZE 64 131 void begin(
int top,
int bottom,
int left,
int right,
164 void emitSpans(
int chunk);
166 inline void allocate(
int size);
191 template <
typename T>
281 b[1].
x = (b[0].
x + b[1].
x)/2;
282 b[5].
x = (b[2].
x + b[3].
x)/2;
283 b[2].
x = (b[1].
x + temp)/2;
284 b[4].
x = (b[5].
x + temp)/2;
285 b[3].
x = (b[2].
x + b[4].
x)/2;
290 b[1].
y = (b[0].
y + b[1].
y)/2;
291 b[5].
y = (b[2].
y + b[3].
y)/2;
292 b[2].
y = (b[1].
y + temp)/2;
293 b[4].
y = (b[5].
y + temp)/2;
294 b[3].
y = (b[2].
y + b[4].
y)/2;
318 template <
typename T>
328 for (; line < d.
m_lines.size() && d.
m_lines.at(line).top == y; ++line) {
343 if (!allVertical()) {
346 for (
int i = 1; i < numActive; ++i) {
357 for (
int i = 0; i < numActive; ++i) {
369 for (
int j = i; j < numActive - 1; ++j)
374 }
else if (!allVertical())
387 bool allVertical =
true;
388 for (
int i = 0; i <
m_lines.size(); ++i) {
404 const int chunkBottom = chunkTop +
CHUNK_SIZE;
405 for (
int i = 0; i <
m_lines.size(); ++i) {
408 if ((line.
bottom < chunkTop) || (line.
top > chunkBottom))
411 const int top =
qMax(0, line.
top - chunkTop);
412 const int bottom =
qMin(CHUNK_SIZE, line.
bottom + 1 - chunkTop);
421 for (; it !=
end; ++
it) {
428 for (; it !=
end; ++
it)
461 while (isect.
x != current->
x) {
462 int &next = isect.
x < current->
x ? current->
left : current->
right;
467 next = last - current;
492 while (b >= beziers) {
508 qAbs(b[0].x-b[2].x) +
qAbs(b[0].y-b[2].y);
510 belowThreshold = (d <= flatness);
513 if (belowThreshold || b == beziers + 3 * 32) {
529 if ((slopeFP > 0) ^ right)
532 Line line = { edgeFP, 0, iTop, iBottom, winding };
538 Q16Dot16 lastFP = xFP + slopeFP * (iBottom - iTop);
540 if (lastFP == edgeFP) {
541 if ((slopeFP < 0) ^
right)
544 Line line = { edgeFP, 0, iTop, iBottom, winding };
551 if ((lastFP < edgeFP) ^ (xFP < edgeFP)) {
554 if ((xFP < edgeFP) ^ right) {
557 int iMiddle = iTop + iHeight;
559 Line line = { edgeFP, 0, iTop, iMiddle, winding };
562 if (iMiddle != iBottom) {
563 xFP += slopeFP * (iHeight + 1);
570 int iMiddle = iTop + iHeight;
572 if (iMiddle != iBottom) {
573 Line line = { edgeFP, 0, iMiddle + 1, iBottom, winding };
580 }
else if ((xFP < edgeFP) ^ right) {
581 Line line = { edgeFP, 0, iTop, iBottom, winding };
606 if (iTop <= iBottom) {
621 if (
clip(xFP, iTop, iBottom, slopeFP,
m_leftFP, winding))
629 Line line = { xFP, slopeFP, iTop, iBottom, winding };
666 Q16Dot16 leftIntersectY, rightIntersectY;
669 rightIntersectY = leftIntersectY + invSlope;
672 rightIntersectY = leftIntersectY + invSlope;
675 if (leftIntersectX >= leftX && rightIntersectX <= rightX) {
676 return Q16Dot16Multiply(bottom - top, leftIntersectX - leftX + ((rightIntersectX - leftIntersectX) >> 1));
677 }
else if (leftIntersectX >= rightX) {
679 }
else if (leftIntersectX >= leftX) {
681 return (bottom - top) -
Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, rightIntersectY - top);
683 return (bottom - top) -
Q16Dot16FastMultiply((rightX - leftIntersectX) >> 1, bottom - rightIntersectY);
685 }
else if (rightIntersectX <= leftX) {
687 }
else if (rightIntersectX <= rightX) {
695 return (bottom - rightIntersectY) + ((rightIntersectY - leftIntersectY) >> 1);
697 return (rightIntersectY - top) + ((leftIntersectY - rightIntersectY) >> 1);
704 return int((p2 - p1) *
qreal(64.)) == 0;
709 #ifdef QT_USE_MATH_H_FLOATS 710 if (
sizeof(
qreal) ==
sizeof(
float))
734 return x > 0 ? 1e20 : -1e20;
744 qreal tmp = x * 65536.;
747 else if (tmp <
qreal(INT_MIN))
764 pa -= (0.5f * width) * delta;
765 pb += (0.5f * width) * delta;
771 if (!clip.contains(pa) || !clip.contains(pb)) {
775 const qreal o[2] = { pa.
x(), pa.
y() };
776 const qreal d[2] = { pb.
x() - pa.
x(), pb.
y() - pa.
y() };
778 const qreal low[2] = { clip.left(), clip.top() };
779 const qreal high[2] = { clip.right(), clip.bottom() };
781 for (
int i = 0; i < 2; ++i) {
783 if (o[i] <= low[i] || o[i] >= high[i])
787 const qreal d_inv = 1 / d[i];
788 qreal t_low = (low[i] - o[i]) * d_inv;
789 qreal t_high = (high[i] - o[i]) * d_inv;
791 qSwap(t_low, t_high);
800 QPointF npa = pa + (pb - pa) * t1;
801 QPointF npb = pa + (pb - pa) * t2;
817 const qreal w0 = d0.
x() * d0.
x() + d0.
y() * d0.
y();
821 const qreal w = d.
x() * d.
x() + d.
y() * d.
y();
827 width *= sqrt(w0 / w);
833 const qreal x = (pa.
x() + pb.
x()) * 0.5f;
837 const qreal dy = width * dx;
849 const qreal dy = pb.
y() - pa.
y();
850 const qreal halfWidth = 0.5f * width * dy;
877 if (iLeft == iRight) {
878 coverage[0] = (leftWidth + rightWidth) * 255;
882 coverage[0] = leftWidth * 255;
886 len[0] = iRight - iLeft;
887 }
else if (iRight - iLeft > 1) {
890 len[1] = iRight - iLeft - 1;
894 coverage[n] = rightWidth * 255;
911 for (
int i = 0; i < n; ++i) {
912 buffer.
addSpan(x[i], len[i], y,
917 int iTop = int(pa.
y() + 0.5f);
918 int iBottom = pb.
y() < 0.5f ? -1 : int(pb.
y() - 0.5f);
919 int iLeft = int(left + 0.5f);
920 int iRight = right < 0.5f ? -1 : int(right - 0.5f);
922 int iWidth = iRight - iLeft + 1;
923 for (
int y = iTop; y <= iBottom; ++y)
924 buffer.
addSpan(iLeft, iWidth, y, 255);
931 delta *= 0.5f * width;
939 if (pa.x() < pb.
x()) {
959 const QPointF topLeftEdge = left - top;
960 const QPointF topRightEdge = right - top;
993 if (iLeftFP < iTopFP)
994 leftIntersectBf =
FloatToQ16Dot16(left.x() + (int(topBound) - left.y()) * bottomLeftSlope);
996 if (iRightFP < iTopFP)
997 rightIntersectBf =
FloatToQ16Dot16(right.x() + (int(topBound) - right.y()) * bottomRightSlope);
999 Q16Dot16 rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
1000 Q16Dot16 topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
1001 Q16Dot16 bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
1003 int leftMin, leftMax, rightMin, rightMax;
1010 rowTop =
qMax(iTopFP, yTopFP);
1011 topLeftIntersectAf = leftIntersectAf +
1013 topRightIntersectAf = rightIntersectAf +
1017 while (yFP <= iBottomFP) {
1020 rowTopLeft =
qMax(yFP, yLeftFP);
1021 rowTopRight =
qMax(yFP, yRightFP);
1024 if (yFP == iLeftFP) {
1026 leftIntersectBf =
FloatToQ16Dot16(left.x() + (y - left.y()) * bottomLeftSlope);
1027 topLeftIntersectBf = leftIntersectBf +
Q16Dot16Multiply(bottomLeftSlopeFP, rowTopLeft - yFP);
1028 bottomLeftIntersectAf = leftIntersectAf +
Q16Dot16Multiply(topLeftSlopeFP, rowBottomLeft - yFP);
1030 topLeftIntersectBf = leftIntersectBf;
1031 bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
1034 if (yFP == iRightFP) {
1036 rightIntersectBf =
FloatToQ16Dot16(right.x() + (y - right.y()) * bottomRightSlope);
1037 topRightIntersectBf = rightIntersectBf +
Q16Dot16Multiply(bottomRightSlopeFP, rowTopRight - yFP);
1038 bottomRightIntersectAf = rightIntersectAf +
Q16Dot16Multiply(topRightSlopeFP, rowBottomRight - yFP);
1040 topRightIntersectBf = rightIntersectBf;
1041 bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
1044 if (yFP == iBottomFP) {
1045 bottomLeftIntersectBf = leftIntersectBf +
Q16Dot16Multiply(bottomLeftSlopeFP, rowBottom - yFP);
1046 bottomRightIntersectBf = rightIntersectBf +
Q16Dot16Multiply(bottomRightSlopeFP, rowBottom - yFP);
1048 bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
1049 bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
1052 if (yFP < iLeftFP) {
1055 }
else if (yFP == iLeftFP) {
1066 if (yFP < iRightFP) {
1069 }
else if (yFP == iRightFP) {
1080 if (leftMax > rightMax)
1082 if (rightMin < leftMin)
1085 Q16Dot16 rowHeight = rowBottom - rowTop;
1088 while (x <= leftMax) {
1093 bottomLeftIntersectAf, topLeftIntersectAf,
1094 topLeftSlopeFP, invTopLeftSlopeFP);
1097 topLeftIntersectBf, bottomLeftIntersectBf,
1098 bottomLeftSlopeFP, invBottomLeftSlopeFP);
1100 if (x >= rightMin) {
1101 if (yFP <= iRightFP)
1102 excluded += (rowBottomRight - rowTop) -
intersectPixelFP(x, rowTop, rowBottomRight,
1103 topRightIntersectAf, bottomRightIntersectAf,
1104 topRightSlopeFP, invTopRightSlopeFP);
1105 if (yFP >= iRightFP)
1106 excluded += (rowBottom - rowTopRight) -
intersectPixelFP(x, rowTopRight, rowBottom,
1107 bottomRightIntersectBf, topRightIntersectBf,
1108 bottomRightSlopeFP, invBottomRightSlopeFP);
1111 Q16Dot16 coverage = rowHeight - excluded;
1121 while (x <= rightMax) {
1123 if (yFP <= iRightFP)
1124 excluded += (rowBottomRight - rowTop) -
intersectPixelFP(x, rowTop, rowBottomRight,
1125 topRightIntersectAf, bottomRightIntersectAf,
1126 topRightSlopeFP, invTopRightSlopeFP);
1127 if (yFP >= iRightFP)
1128 excluded += (rowBottom - rowTopRight) -
intersectPixelFP(x, rowTopRight, rowBottom,
1129 bottomRightIntersectBf, topRightIntersectBf,
1130 bottomRightSlopeFP, invBottomRightSlopeFP);
1132 Q16Dot16 coverage = rowHeight - excluded;
1138 leftIntersectAf += topLeftSlopeFP;
1139 leftIntersectBf += bottomLeftSlopeFP;
1140 rightIntersectAf += topRightSlopeFP;
1141 rightIntersectBf += bottomRightSlopeFP;
1142 topLeftIntersectAf = leftIntersectAf;
1143 topRightIntersectAf = rightIntersectAf;
1149 int iTop = int(top.y() + 0.5f);
1150 int iLeft = left.y() < 0.5f ? -1 : int(left.y() - 0.5f);
1151 int iRight = right.y() < 0.5f ? -1 : int(right.y() - 0.5f);
1152 int iBottom = bottom.
y() < 0.5f? -1 : int(bottom.
y() - 0.5f);
1153 int iMiddle =
qMin(iLeft, iRight);
1162 #define DO_SEGMENT(next, li, ri, ls, rs) \ 1163 ny = qMin(next + 1, d->clipRect.top()); \ 1165 li += ls * (ny - y); \ 1166 ri += rs * (ny - y); \ 1169 if (next > d->clipRect.bottom()) \ 1170 next = d->clipRect.bottom(); \ 1171 for (; y <= next; ++y) { \ 1172 const int x1 = qMax(Q16Dot16ToInt(li), d->clipRect.left()); \ 1173 const int x2 = qMin(Q16Dot16ToInt(ri), d->clipRect.right()); \ 1175 buffer.addSpan(x1, x2 - x1 + 1, y, 255); \ 1180 DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, topLeftSlopeFP, topRightSlopeFP)
1181 DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, bottomLeftSlopeFP, topRightSlopeFP)
1182 DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, topLeftSlopeFP, bottomRightSlopeFP);
1183 DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, bottomLeftSlopeFP, bottomRightSlopeFP);
1201 QT_FT_Pos min_y = points[0].
y, max_y = points[0].
y;
1202 for (
int i = 1; i < outline->
n_points; ++i) {
1204 min_y =
qMin(p.
y, min_y);
1205 max_y =
qMax(p.
y, max_y);
1211 if (iTopBound > iBottomBound)
1217 for (
int i = 0; i < outline->
n_contours; ++i) {
1218 const int last = outline->
contours[i];
1219 for (
int j = first; j < last; ++j) {
1247 if (iTopBound > iBottomBound)
1252 int subpathStart = 0;
1269 if (first.
x != last.
x || first.
y != last.
y)
1295 if (first.
x != last.
x || first.
y != last.
y)
ElementType type
the type of element
void mergeIntersection(Intersection *head, const Intersection &isect)
void initialize(ProcessSpans blend, void *data)
void begin(int top, int bottom, int left, int right, Qt::FillRule fillRule, QSpanBuffer *spanBuffer)
bool isEmpty() const
Returns true if either there are no elements in this path, or if the only element is a MoveToElement;...
#define QT_FT_CURVE_TAG_CUBIC
#define DO_SEGMENT(next, li, ri, ls, rs)
friend void qScanConvert(QScanConverter &d, T allVertical)
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
void mergeCurve(const QT_FT_Vector &a, const QT_FT_Vector &b, const QT_FT_Vector &c, const QT_FT_Vector &d)
#define QT_END_NAMESPACE
This macro expands to.
static Q16Dot16 intersectPixelFP(int x, Q16Dot16 top, Q16Dot16 bottom, Q16Dot16 leftIntersectX, Q16Dot16 rightIntersectX, Q16Dot16 slope, Q16Dot16 invSlope)
QSpanBuffer * m_spanBuffer
static int qSafeFloatToQ16Dot16(qreal x)
#define it(className, varName)
The QPainterPath class provides a container for painting operations, enabling graphical shapes to be ...
void rasterize(const QT_FT_Outline *outline, Qt::FillRule fillRule)
QDataBuffer< Line > m_lines
The QPointF class defines a point in the plane using floating point precision.
void addSpan(int x, unsigned int len, int y, unsigned char coverage)
QScanConverter scanConverter
QT_FT_SpanFunc ProcessSpans
int left() const
Returns the x-coordinate of the rectangle's left edge.
static qreal qSafeDivide(qreal x, qreal y)
static bool q26Dot6Compare(qreal p1, qreal p2)
void qScanConvert(QScanConverter &d, T allVertical)
bool clip(Q16Dot16 &xFP, int &iTop, int &iBottom, Q16Dot16 slopeFP, Q16Dot16 edgeFP, int winding)
long ASN1_INTEGER_get ASN1_INTEGER * a
int bottom() const
Returns the y-coordinate of the rectangle's bottom edge.
QDataBuffer< Line * > m_active
Q_DECL_CONSTEXPR T qAbs(const T &t)
QT_FT_Span m_spans[SPAN_BUFFER_SIZE]
const QPainterPath::Element & elementAt(int i) const
Returns the element at the given index in the painter path.
Q_CORE_EXPORT QTextStream & right(QTextStream &s)
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
static bool topOrder(const QScanConverter::Line &a, const QScanConverter::Line &b)
qreal x() const
Returns the x-coordinate of this point.
void setAntialiased(bool antialiased)
#define Q16Dot16Multiply(x, y)
#define QT_BEGIN_NAMESPACE
This macro expands to.
qreal & rx()
Returns a reference to the x coordinate of this point.
The QRectF class defines a rectangle in the plane using floating point precision. ...
QPoint bottomRight() const
Returns the position of the rectangle's bottom-right corner.
#define Q16Dot16ToFloat(i)
#define QT_PREPEND_NAMESPACE(name)
This macro qualifies identifier with the full namespace.
void rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap=false)
static const char * data(const QByteArray &arr)
static void split(QT_FT_Vector *b)
static QT_FT_Vector PointToVector(const QPointF &p)
#define Q16Dot16FastMultiply(x, y)
void qSort(RandomAccessIterator start, RandomAccessIterator end)
void qSwap(T &value1, T &value2)
static qreal qFloorF(qreal v)
#define FloatToQ16Dot16(i)
static bool xOrder(const QScanConverter::Line *a, const QScanConverter::Line *b)
bool isEmpty() const
Returns true if the rectangle is empty, otherwise returns false.
static QPointF snapTo26Dot6Grid(const QPointF &p)
int top() const
Returns the y-coordinate of the rectangle's top edge.
void mergeLine(QT_FT_Vector a, QT_FT_Vector b)
int right() const
Returns the x-coordinate of the rectangle's right edge.
QRectF controlPointRect() const
Returns the rectangle containing all the points and control points in this path.
The QPoint class defines a point in the plane using integer precision.
Q_DECL_CONSTEXPR const T & qBound(const T &min, const T &val, const T &max)
The QRect class defines a rectangle in the plane using integer precision.
qreal & ry()
Returns a reference to the y coordinate of this point.
QSpanBuffer(ProcessSpans blend, void *data, const QRect &clipRect)
qreal y() const
Returns the y-coordinate of this point.
QT_FT_BEGIN_HEADER typedef signed int QT_FT_Pos
qreal top() const
Returns the y-coordinate of the rectangle's top edge.
void emitNode(const Intersection *node)
void setClipRect(const QRect &clipRect)
int elementCount() const
Returns the number of path elements in the painter path.
qreal bottom() const
Returns the y-coordinate of the rectangle's bottom edge.
static const KeyPair *const end
Intersection * m_intersections
Q_CORE_EXPORT QTextStream & left(QTextStream &s)
void emitSpans(int chunk)
QPoint topLeft() const
Returns the position of the rectangle's top-left corner.