9#include <private/qmath_p.h>
10#include <private/qdatabuffer_p.h>
11#include <private/qdrawhelper_p.h>
13#include <QtGui/qpainterpath.h>
19#if Q_PROCESSOR_WORDSIZE == 8
24#define QScFixedToFloat(i) ((i) * (1./65536.))
25#define FloatToQScFixed(i) (QScFixed)((i) * 65536.)
26#define IntToQScFixed(i) ((QScFixed)(i) * (1 << 16))
27#define QScFixedToInt(i) ((i) >> 16)
28#define QScFixedFactor 65536
29#define FTPosToQScFixed(i) ((QScFixed)(i) * (1 << 10))
31#define QScFixedMultiply(x, y) (QScFixed)((qlonglong(x) * qlonglong(y)) >> 16)
32#define QScFixedFastMultiply(x, y) (((x) * (y)) >> 16)
34#define SPAN_BUFFER_SIZE 256
36#define COORD_ROUNDING 1
37#define COORD_OFFSET 32
51 , m_clipRect(clipRect)
62 if (!coverage || !
len)
65 Q_ASSERT(coverage >= 0 && coverage <= 255);
71 m_spans[m_spanCount].
x =
x;
72 m_spans[m_spanCount].
len =
len;
73 m_spans[m_spanCount].
y =
y;
74 m_spans[m_spanCount].
coverage = coverage;
83 m_blend(m_spanCount, m_spans, m_data);
131 inline void mergeIntersection(Intersection *head,
const Intersection &isect);
135 void emitNode(
const Intersection *node);
136 void emitSpans(
int chunk);
138 inline void allocate(
int size);
157 Intersection *m_intersections;
163 template <
bool AllVertical>
190 free(m_intersections);
205 m_spanBuffer = spanBuffer;
208void QScanConverter::prepareChunk()
213 memset(m_intersections, 0,
CHUNK_SIZE *
sizeof(Intersection));
216void QScanConverter::emitNode(
const Intersection *node)
220 emitNode(node + node->left);
222 if (m_winding & m_fillRuleMask)
223 m_spanBuffer->
addSpan(m_x, node->x - m_x, m_y, 0xff);
226 m_winding += node->winding;
234void QScanConverter::emitSpans(
int chunk)
241 emitNode(&m_intersections[dy]);
254 b[1].x = (
b[0].x +
b[1].x)/2;
255 b[5].x = (
b[2].x +
b[3].x)/2;
256 b[2].x = (
b[1].x + temp)/2;
257 b[4].x = (
b[5].x + temp)/2;
258 b[3].x = (
b[2].x +
b[4].x)/2;
263 b[1].y = (
b[0].y +
b[1].y)/2;
264 b[5].y = (
b[2].y +
b[3].y)/2;
265 b[2].y = (
b[1].y + temp)/2;
266 b[4].y = (
b[5].y + temp)/2;
267 b[3].y = (
b[2].y +
b[4].y)/2;
271template <
bool AllVertical>
272void QScanConverter::scanConvert()
274 if (!m_lines.size()) {
278 constexpr auto topOrder = [](
const Line &
a,
const Line &
b) {
279 return a.top <
b.top;
281 constexpr auto xOrder = [](
const Line *
a,
const Line *
b) {
285 std::sort(m_lines.data(), m_lines.data() + m_lines.size(), topOrder);
287 for (
int y = m_lines.first().top;
y <= m_bottom; ++
y) {
288 for (;
line < m_lines.size() && m_lines.at(
line).top ==
y; ++
line) {
290 if constexpr(AllVertical) {
292 m_active.resize(m_active.size() + 1);
294 for (
j = m_active.size() - 2;
j >= 0 && xOrder(l, m_active.at(
j)); --
j)
295 m_active.at(
j+1) = m_active.at(
j);
296 m_active.at(
j+1) = l;
298 m_active << &m_lines.at(
line);
302 int numActive = m_active.size();
303 if constexpr(!AllVertical) {
306 for (
int i = 1;
i < numActive; ++
i) {
309 for (
j =
i-1;
j >= 0 && xOrder(l, m_active.at(
j)); --
j)
310 m_active.at(
j+1) = m_active.at(
j);
311 m_active.at(
j+1) = l;
317 for (
int i = 0;
i < numActive; ++
i) {
321 if (winding & m_fillRuleMask)
322 m_spanBuffer->
addSpan(
x, current -
x,
y, 0xff);
329 for (
int j =
i;
j < numActive - 1; ++
j)
330 m_active.at(
j) = m_active.at(
j+1);
332 m_active.resize(--numActive);
335 if constexpr(!AllVertical)
345 if (m_lines.isEmpty())
348 if (m_lines.size() <= 32) {
349 bool allVertical =
true;
350 for (
int i = 0;
i < m_lines.size(); ++
i) {
351 if (m_lines.at(
i).delta) {
359 scanConvert<false>();
361 for (
int chunkTop = m_top; chunkTop <= m_bottom; chunkTop +=
CHUNK_SIZE) {
364 Intersection isect = { 0, 0, 0, 0 };
366 const int chunkBottom = chunkTop +
CHUNK_SIZE;
367 for (
int i = 0;
i < m_lines.size(); ++
i) {
370 if ((
line.bottom < chunkTop) || (
line.top > chunkBottom))
377 isect.winding =
line.winding;
379 Intersection *
it = m_intersections +
top;
380 Intersection *
end = m_intersections +
bottom;
386 mergeIntersection(
it, isect);
391 mergeIntersection(
it, isect);
399 if (m_alloc > 1024) {
400 free(m_intersections);
403 m_intersections =
nullptr;
406 if (m_lines.size() > 1024)
407 m_lines.shrink(1024);
410inline void QScanConverter::allocate(
int size)
412 if (m_alloc <
size) {
413 int newAlloc =
qMax(
size, 2 * m_alloc);
414 m_intersections = q_check_ptr((Intersection *)realloc(m_intersections, newAlloc *
sizeof(Intersection)));
419inline void QScanConverter::mergeIntersection(Intersection *
it,
const Intersection &isect)
421 Intersection *current =
it;
423 while (isect.x != current->x) {
424 int &
next = isect.x < current->x ? current->left : current->right;
428 Intersection *last = m_intersections + m_size;
429 next = last - current;
436 current->winding += isect.winding;
454 while (
b >= beziers) {
472 belowThreshold = (
d <= flatness);
475 if (belowThreshold ||
b == beziers + 3 * 32) {
486inline bool QScanConverter::clip(
QScFixed &xFP,
int &iTop,
int &iBottom,
QScFixed slopeFP,
QScFixed edgeFP,
int winding)
488 bool right = edgeFP == m_rightFP;
491 if ((slopeFP > 0) ^
right)
494 Line line = { edgeFP, 0, iTop, iBottom, winding };
500 QScFixed lastFP = xFP + slopeFP * (iBottom - iTop);
502 if (lastFP == edgeFP) {
503 if ((slopeFP < 0) ^
right)
506 Line line = { edgeFP, 0, iTop, iBottom, winding };
513 if ((lastFP < edgeFP) ^ (xFP < edgeFP)) {
516 if ((xFP < edgeFP) ^
right) {
519 int iMiddle = iTop + iHeight;
521 Line line = { edgeFP, 0, iTop, iMiddle, winding };
524 if (iMiddle != iBottom) {
525 xFP += slopeFP * (iHeight + 1);
532 int iMiddle = iTop + iHeight;
534 if (iMiddle != iBottom) {
535 Line line = { edgeFP, 0, iMiddle + 1, iBottom, winding };
542 }
else if ((xFP < edgeFP) ^
right) {
543 Line line = { edgeFP, 0, iTop, iBottom, winding };
560 int iTop =
qMax(m_top,
int((
a.y + 32) >> 6));
561 int iBottom =
qMin(m_bottom,
int((
b.y - 32) >> 6));
563 if (iTop <= iBottom) {
567 Line line = {
qBound(m_leftFP, aFP, m_rightFP), 0, iTop, iBottom, winding };
578 if (clip(xFP, iTop, iBottom, slopeFP, m_leftFP, winding))
581 if (clip(xFP, iTop, iBottom, slopeFP, m_rightFP, winding))
586 Line line = { xFP, slopeFP, iTop, iBottom, winding };
623 QScFixed leftIntersectY, rightIntersectY;
624 auto computeIntersectY = [&]() {
627 rightIntersectY = leftIntersectY + invSlope;
630 rightIntersectY = leftIntersectY + invSlope;
634 if (leftIntersectX >= leftX && rightIntersectX <= rightX) {
636 }
else if (leftIntersectX >= rightX) {
638 }
else if (leftIntersectX >= leftX) {
645 }
else if (rightIntersectX <= leftX) {
647 }
else if (rightIntersectX <= rightX) {
657 return (
bottom - rightIntersectY) + ((rightIntersectY - leftIntersectY) >> 1);
659 return (rightIntersectY -
top) + ((leftIntersectY - rightIntersectY) >> 1);
666 return int((
p2 -
p1) * 64.) == 0;
672 std::floor(
p.y() * 64) * (1 /
qreal(64)));
686 return x > 0 ? 1e20 : -1e20;
697#if Q_PROCESSOR_WORDSIZE == 8
703 if (tmp >
qreal(INT_MAX))
705 else if (tmp <
qreal(INT_MIN))
732 }
else if (
x1 > xmax) {
741 }
else if (
x2 > xmax) {
751 }
else if (
y1 > ymax) {
760 }
else if (
y2 > ymax) {
778 pa -= (0.5f *
width) * delta;
779 pb += (0.5f *
width) * delta;
790 const qreal w0 = d0.
x() * d0.
x() + d0.
y() * d0.
y();
794 const qreal w =
d.x() *
d.x() +
d.y() *
d.y();
806 const qreal x = (pa.
x() + pb.
x()) * 0.5f;
822 const qreal dy = pb.
y() - pa.
y();
838 const int iLeft = int(
left);
839 const int iRight = int(
right);
850 if (iLeft == iRight) {
852 coverage[0] = rightWidth * 255;
858 coverage[0] = leftWidth * 255;
862 len[0] = iRight - iLeft;
863 }
else if (iRight - iLeft > 1) {
866 len[1] = iRight - iLeft - 1;
870 coverage[
n] = rightWidth * 255;
887 for (
int i = 0;
i <
n; ++
i) {
893 int iTop = int(pa.
y() + 0.5f);
894 int iBottom = pb.
y() < 0.5f ? -1 : int(pb.
y() - 0.5f);
895 int iLeft = int(
left + 0.5f);
896 int iRight =
right < 0.5f ? -1 : int(
right - 0.5f);
898 int iWidth = iRight - iLeft + 1;
899 for (
int y = iTop;
y <= iBottom; ++
y)
900 buffer.addSpan(iLeft, iWidth,
y, 255);
907 delta *= 0.5f *
width;
915 if (pa.x() < pb.
x()) {
969 if (iLeftFP < iTopFP)
972 if (iRightFP < iTopFP)
975 QScFixed rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
976 QScFixed topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
977 QScFixed bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
979 int leftMin, leftMax, rightMin, rightMax;
986 rowTop =
qMax(iTopFP, yTopFP);
987 topLeftIntersectAf = leftIntersectAf +
989 topRightIntersectAf = rightIntersectAf +
993 while (yFP <= iBottomFP) {
996 rowTopLeft =
qMax(yFP, yLeftFP);
997 rowTopRight =
qMax(yFP, yRightFP);
1000 if (yFP == iLeftFP) {
1003 topLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowTopLeft - yFP);
1004 bottomLeftIntersectAf = leftIntersectAf +
QScFixedMultiply(topLeftSlopeFP, rowBottomLeft - yFP);
1006 topLeftIntersectBf = leftIntersectBf;
1007 bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
1010 if (yFP == iRightFP) {
1013 topRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowTopRight - yFP);
1014 bottomRightIntersectAf = rightIntersectAf +
QScFixedMultiply(topRightSlopeFP, rowBottomRight - yFP);
1016 topRightIntersectBf = rightIntersectBf;
1017 bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
1020 if (yFP == iBottomFP) {
1021 bottomLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowBottom - yFP);
1022 bottomRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowBottom - yFP);
1024 bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
1025 bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
1028 if (yFP < iLeftFP) {
1031 }
else if (yFP == iLeftFP) {
1042 if (yFP < iRightFP) {
1045 }
else if (yFP == iRightFP) {
1056 if (leftMax > rightMax)
1058 if (rightMin < leftMin)
1061 QScFixed rowHeight = rowBottom - rowTop;
1064 while (
x <= leftMax) {
1067 if (yFP <= iLeftFP && rowBottomLeft > rowTop)
1069 bottomLeftIntersectAf, topLeftIntersectAf,
1070 topLeftSlopeFP, invTopLeftSlopeFP);
1071 if (yFP >= iLeftFP && rowBottom > rowTopLeft)
1073 topLeftIntersectBf, bottomLeftIntersectBf,
1074 bottomLeftSlopeFP, invBottomLeftSlopeFP);
1075 if (
x >= rightMin) {
1076 if (yFP <= iRightFP && rowBottomRight > rowTop)
1077 excluded += (rowBottomRight - rowTop) -
intersectPixelFP(
x, rowTop, rowBottomRight,
1078 topRightIntersectAf, bottomRightIntersectAf,
1079 topRightSlopeFP, invTopRightSlopeFP);
1080 if (yFP >= iRightFP && rowBottom > rowTopRight)
1081 excluded += (rowBottom - rowTopRight) -
intersectPixelFP(
x, rowTopRight, rowBottom,
1082 bottomRightIntersectBf, topRightIntersectBf,
1083 bottomRightSlopeFP, invBottomRightSlopeFP);
1086 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1087 QScFixed coverage = rowHeight - excluded;
1097 while (
x <= rightMax) {
1099 if (yFP <= iRightFP && rowBottomRight > rowTop)
1100 excluded += (rowBottomRight - rowTop) -
intersectPixelFP(
x, rowTop, rowBottomRight,
1101 topRightIntersectAf, bottomRightIntersectAf,
1102 topRightSlopeFP, invTopRightSlopeFP);
1103 if (yFP >= iRightFP && rowBottom > rowTopRight)
1104 excluded += (rowBottom - rowTopRight) -
intersectPixelFP(
x, rowTopRight, rowBottom,
1105 bottomRightIntersectBf, topRightIntersectBf,
1106 bottomRightSlopeFP, invBottomRightSlopeFP);
1108 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1109 QScFixed coverage = rowHeight - excluded;
1115 leftIntersectAf += topLeftSlopeFP;
1116 leftIntersectBf += bottomLeftSlopeFP;
1117 rightIntersectAf += topRightSlopeFP;
1118 rightIntersectBf += bottomRightSlopeFP;
1119 topLeftIntersectAf = leftIntersectAf;
1120 topRightIntersectAf = rightIntersectAf;
1126 int iTop = int(
top.y() + 0.5f);
1127 int iLeft =
left.y() < 0.5f ? -1 : int(
left.y() - 0.5f);
1128 int iRight =
right.y() < 0.5f ? -1 : int(
right.y() - 0.5f);
1129 int iBottom =
bottom.y() < 0.5f? -1 : int(
bottom.y() - 0.5f);
1130 int iMiddle =
qMin(iLeft, iRight);
1139#define DO_SEGMENT(next, li, ri, ls, rs) \
1140 ny = qMin(next + 1, d->clipRect.top()); \
1142 li += ls * (ny - y); \
1143 ri += rs * (ny - y); \
1146 if (next > d->clipRect.bottom()) \
1147 next = d->clipRect.bottom(); \
1148 for (; y <= next; ++y) { \
1149 const int x1 = qMax(QScFixedToInt(li), d->clipRect.left()); \
1150 const int x2 = qMin(QScFixedToInt(ri), d->clipRect.right()); \
1152 buffer.addSpan(x1, x2 - x1 + 1, y, 255); \
1157 DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, topLeftSlopeFP, topRightSlopeFP)
1158 DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, bottomLeftSlopeFP, topRightSlopeFP)
1159 DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, topLeftSlopeFP, bottomRightSlopeFP);
1160 DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, bottomLeftSlopeFP, bottomRightSlopeFP);
1181 min_y =
qMin(
p.y, min_y);
1182 max_y =
qMax(
p.y, max_y);
1188 if (iTopBound > iBottomBound)
1196 for (
int j =
first;
j < last; ++
j) {
1224 if (iTopBound > iBottomBound)
1229 int subpathStart = 0;
1231 for (
int i = 0;
i <
path.elementCount(); ++
i) {
1232 switch (
path.elementAt(
i).type) {
\inmodule QtCore\reentrant
constexpr qreal & ry() noexcept
Returns a reference to the y coordinate of this point.
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
constexpr qreal & rx() noexcept
Returns a reference to the x coordinate of this point.
\inmodule QtCore\reentrant
QScanConverter scanConverter
void setAntialiased(bool antialiased)
void initialize(ProcessSpans blend, void *data)
void rasterizeLine(const QPointF &a, const QPointF &b, qreal width, bool squareCap=false)
void setClipRect(const QRect &clipRect)
void rasterize(const QT_FT_Outline *outline, Qt::FillRule fillRule)
\inmodule QtCore\reentrant
constexpr qreal bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr qreal left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr qreal top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr qreal right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
\inmodule QtCore\reentrant
constexpr bool isEmpty() const noexcept
Returns true if the rectangle is empty, otherwise returns false.
constexpr int bottom() const noexcept
Returns the y-coordinate of the rectangle's bottom edge.
constexpr QPoint topLeft() const noexcept
Returns the position of the rectangle's top-left corner.
constexpr int top() const noexcept
Returns the y-coordinate of the rectangle's top edge.
constexpr int left() const noexcept
Returns the x-coordinate of the rectangle's left edge.
constexpr QPoint bottomRight() const noexcept
Returns the position of the rectangle's bottom-right corner.
constexpr int right() const noexcept
Returns the x-coordinate of the rectangle's right edge.
void mergeCurve(const QT_FT_Vector &a, const QT_FT_Vector &b, const QT_FT_Vector &c, const QT_FT_Vector &d)
void begin(int top, int bottom, int left, int right, Qt::FillRule fillRule, QSpanBuffer *spanBuffer)
void mergeLine(QT_FT_Vector a, QT_FT_Vector b)
QSpanBuffer(ProcessSpans blend, void *data, const QRect &clipRect)
void addSpan(int x, int len, int y, int coverage)
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QT_FT_SpanFunc ProcessSpans
bool qIsFinite(qfloat16 f) noexcept
qfloat16 qSqrt(qfloat16 f)
constexpr const T & qMin(const T &a, const T &b)
constexpr const T & qBound(const T &min, const T &val, const T &max)
constexpr const T & qMax(const T &a, const T &b)
constexpr T qAbs(const T &t)
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint GLfloat GLfloat GLfloat x1
GLdouble GLdouble GLdouble GLdouble top
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLfixed GLfixed GLint GLint GLfixed points
GLfixed GLfixed GLfixed y2
GLsizei const GLchar *const * path
QT_FT_BEGIN_HEADER typedef signed int QT_FT_Pos
#define QT_FT_CURVE_TAG_CUBIC
static qreal qSafeDivide(qreal x, qreal y)
static bool q26Dot6Compare(qreal p1, qreal p2)
static void split(QT_FT_Vector *b)
#define FloatToQScFixed(i)
QT_BEGIN_NAMESPACE typedef int QScFixed
#define QScFixedToFloat(i)
#define QScFixedMultiply(x, y)
#define FTPosToQScFixed(i)
#define QScFixedFastMultiply(x, y)
static QScFixed intersectPixelFP(int x, QScFixed top, QScFixed bottom, QScFixed leftIntersectX, QScFixed rightIntersectX, QScFixed slope, QScFixed invSlope)
static QT_FT_Vector PointToVector(const QPointF &p)
static QPointF snapTo26Dot6Grid(const QPointF &p)
static bool qClipLine(QPointF *pt1, QPointF *pt2, const QRectF &clip)
static QScFixed qSafeFloatToQScFixed(qreal x)
#define DO_SEGMENT(next, li, ri, ls, rs)