771 if (a == b || !(width > 0.0) || d->clipRect.isEmpty())
778 QPointF delta = pb - pa;
779 pa -= (0.5f * width) * delta;
780 pb += (0.5f * width) * delta;
783 QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5;
784 const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs);
785 if (qClipLine(&pa, &pb, clip))
790 const QPointF d0 = a - b;
791 const qreal w0 = d0.x() * d0.x() + d0.y() * d0.y();
794 const QPointF d = pa - pb;
795 const qreal w = d.x() * d.x() + d.y() * d.y();
801 width *= qSqrt(w0 / w);
806 if (q26Dot6Compare(pa.y(), pb.y())) {
807 const qreal x = (pa.x() + pb.x()) * 0.5f;
808 const qreal dx = qAbs(pb.x() - pa.x()) * 0.5f;
810 const qreal y = pa.y();
811 const qreal dy = width * dx;
813 pa = QPointF(x, y - dy);
814 pb = QPointF(x, y + dy);
819 if (q26Dot6Compare(pa.x(), pb.x())) {
823 const qreal dy = pb.y() - pa.y();
824 const qreal halfWidth = 0.5f * width * dy;
826 qreal left = pa.x() - halfWidth;
827 qreal right = pa.x() + halfWidth;
829 left = qBound(qreal(d->clipRect.left()), left, qreal(d->clipRect.right() + 1));
830 right = qBound(qreal(d->clipRect.left()), right, qreal(d->clipRect.right() + 1));
832 pa.ry() = qBound(qreal(d->clipRect.top()), pa.y(), qreal(d->clipRect.bottom() + 1));
833 pb.ry() = qBound(qreal(d->clipRect.top()), pb.y(), qreal(d->clipRect.bottom() + 1));
835 if (q26Dot6Compare(left, right) || q26Dot6Compare(pa.y(), pb.y()))
839 const int iLeft =
int(left);
840 const int iRight =
int(right);
842 - qSafeFloatToQScFixed(left);
843 const QScFixed rightWidth = qSafeFloatToQScFixed(right)
851 if (iLeft == iRight) {
853 coverage[0] = rightWidth * 255;
859 coverage[0] = leftWidth * 255;
863 len[0] = iRight - iLeft;
864 }
else if (iRight - iLeft > 1) {
867 len[1] = iRight - iLeft - 1;
871 coverage[n] = rightWidth * 255;
880 const QScFixed yPa = qSafeFloatToQScFixed(pa.y());
881 const QScFixed yPb = qSafeFloatToQScFixed(pb.y());
886 if (y > d->clipRect.bottom())
888 for (
int i = 0; i < n; ++i) {
894 int iTop =
int(pa.y() + 0.5f);
895 int iBottom = pb.y() < 0.5f ? -1 :
int(pb.y() - 0.5f);
896 int iLeft =
int(left + 0.5f);
897 int iRight = right < 0.5f ? -1 :
int(right - 0.5f);
899 int iWidth = iRight - iLeft + 1;
900 for (
int y = iTop; y <= iBottom; ++y)
907 QPointF delta = pb - pa;
908 delta *= 0.5f * width;
909 const QPointF perp(delta.y(), -delta.x());
916 if (pa.x() < pb.x()) {
928 top = snapTo26Dot6Grid(top);
929 bottom = snapTo26Dot6Grid(bottom);
930 left = snapTo26Dot6Grid(left);
931 right = snapTo26Dot6Grid(right);
933 const qreal topBound = qBound(qreal(d->clipRect.top()), top.y(), qreal(d->clipRect.bottom()));
934 const qreal bottomBound = qBound(qreal(d->clipRect.top()), bottom.y(), qreal(d->clipRect.bottom()));
936 const QPointF topLeftEdge = left - top;
937 const QPointF topRightEdge = right - top;
938 const QPointF bottomLeftEdge = bottom - left;
939 const QPointF bottomRightEdge = bottom - right;
941 const qreal topLeftSlope = qSafeDivide(topLeftEdge.x(), topLeftEdge.y());
942 const qreal bottomLeftSlope = qSafeDivide(bottomLeftEdge.x(), bottomLeftEdge.y());
944 const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
945 const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
947 const QScFixed topLeftSlopeFP = qSafeFloatToQScFixed(topLeftSlope);
948 const QScFixed topRightSlopeFP = qSafeFloatToQScFixed(topRightSlope);
950 const QScFixed bottomLeftSlopeFP = qSafeFloatToQScFixed(bottomLeftSlope);
951 const QScFixed bottomRightSlopeFP = qSafeFloatToQScFixed(bottomRightSlope);
953 const QScFixed invTopLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topLeftSlope));
954 const QScFixed invTopRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topRightSlope));
956 const QScFixed invBottomLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomLeftSlope));
957 const QScFixed invBottomRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomRightSlope));
965 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topLeftSlope);
966 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topRightSlope);
970 if (iLeftFP < iTopFP)
971 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (
int(topBound) - left.y()) * bottomLeftSlope);
973 if (iRightFP < iTopFP)
974 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (
int(topBound) - right.y()) * bottomRightSlope);
976 QScFixed rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
977 QScFixed topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
978 QScFixed bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
980 int leftMin, leftMax, rightMin, rightMax;
982 const QScFixed yTopFP = qSafeFloatToQScFixed(top.y());
983 const QScFixed yLeftFP = qSafeFloatToQScFixed(left.y());
984 const QScFixed yRightFP = qSafeFloatToQScFixed(right.y());
985 const QScFixed yBottomFP = qSafeFloatToQScFixed(bottom.y());
987 rowTop = qMax(iTopFP, yTopFP);
988 topLeftIntersectAf = leftIntersectAf +
990 topRightIntersectAf = rightIntersectAf +
994 while (yFP <= iBottomFP) {
997 rowTopLeft = qMax(yFP, yLeftFP);
998 rowTopRight = qMax(yFP, yRightFP);
1001 if (yFP == iLeftFP) {
1003 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (y - left.y()) * bottomLeftSlope);
1004 topLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowTopLeft - yFP);
1005 bottomLeftIntersectAf = leftIntersectAf +
QScFixedMultiply(topLeftSlopeFP, rowBottomLeft - yFP);
1007 topLeftIntersectBf = leftIntersectBf;
1008 bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
1011 if (yFP == iRightFP) {
1013 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (y - right.y()) * bottomRightSlope);
1014 topRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowTopRight - yFP);
1015 bottomRightIntersectAf = rightIntersectAf +
QScFixedMultiply(topRightSlopeFP, rowBottomRight - yFP);
1017 topRightIntersectBf = rightIntersectBf;
1018 bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
1021 if (yFP == iBottomFP) {
1022 bottomLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowBottom - yFP);
1023 bottomRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowBottom - yFP);
1025 bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
1026 bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
1029 if (yFP < iLeftFP) {
1032 }
else if (yFP == iLeftFP) {
1033 leftMin =
QScFixedToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
1034 leftMax =
QScFixedToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
1040 leftMin = qBound(d->clipRect.left(), leftMin, d->clipRect.right());
1041 leftMax = qBound(d->clipRect.left(), leftMax, d->clipRect.right());
1043 if (yFP < iRightFP) {
1046 }
else if (yFP == iRightFP) {
1047 rightMin =
QScFixedToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
1048 rightMax =
QScFixedToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
1054 rightMin = qBound(d->clipRect.left(), rightMin, d->clipRect.right());
1055 rightMax = qBound(d->clipRect.left(), rightMax, d->clipRect.right());
1057 if (leftMax > rightMax)
1059 if (rightMin < leftMin)
1062 QScFixed rowHeight = rowBottom - rowTop;
1065 while (x <= leftMax) {
1068 if (yFP <= iLeftFP && rowBottomLeft > rowTop)
1070 bottomLeftIntersectAf
, topLeftIntersectAf
,
1071 topLeftSlopeFP
, invTopLeftSlopeFP
);
1072 if (yFP >= iLeftFP && rowBottom > rowTopLeft)
1074 topLeftIntersectBf
, bottomLeftIntersectBf
,
1075 bottomLeftSlopeFP
, invBottomLeftSlopeFP
);
1076 if (x >= rightMin) {
1077 if (yFP <= iRightFP && rowBottomRight > rowTop)
1079 topRightIntersectAf
, bottomRightIntersectAf
,
1080 topRightSlopeFP
, invTopRightSlopeFP
);
1081 if (yFP >= iRightFP && rowBottom > rowTopRight)
1083 bottomRightIntersectBf
, topRightIntersectBf
,
1084 bottomRightSlopeFP
, invBottomRightSlopeFP
);
1087 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1088 QScFixed coverage = rowHeight - excluded;
1098 while (x <= rightMax) {
1100 if (yFP <= iRightFP && rowBottomRight > rowTop)
1102 topRightIntersectAf
, bottomRightIntersectAf
,
1103 topRightSlopeFP
, invTopRightSlopeFP
);
1104 if (yFP >= iRightFP && rowBottom > rowTopRight)
1106 bottomRightIntersectBf
, topRightIntersectBf
,
1107 bottomRightSlopeFP
, invBottomRightSlopeFP
);
1109 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1110 QScFixed coverage = rowHeight - excluded;
1116 leftIntersectAf += topLeftSlopeFP;
1117 leftIntersectBf += bottomLeftSlopeFP;
1118 rightIntersectAf += topRightSlopeFP;
1119 rightIntersectBf += bottomRightSlopeFP;
1120 topLeftIntersectAf = leftIntersectAf;
1121 topRightIntersectAf = rightIntersectAf;
1127 int iTop =
int(top.y() + 0.5f);
1128 int iLeft = left.y() < 0.5f ? -1 :
int(left.y() - 0.5f);
1129 int iRight = right.y() < 0.5f ? -1 :
int(right.y() - 0.5f);
1130 int iBottom = bottom.y() < 0.5f? -1 :
int(bottom.y() - 0.5f);
1131 int iMiddle = qMin(iLeft, iRight);
1133 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
1134 QScFixed leftIntersectBf = qSafeFloatToQScFixed(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
1135 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
1136 QScFixed rightIntersectBf = qSafeFloatToQScFixed(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
1140#define DO_SEGMENT(next, li, ri, ls, rs)
1141 ny = qMin(next + 1
, d->clipRect.top());
1143 li += ls * (ny - y);
1144 ri += rs * (ny - y);
1147 if (next > d->clipRect.bottom())
1148 next = d->clipRect.bottom();
1149 for (; y <= next; ++y) {
1151 const int x2 = qMin(QScFixedToInt(ri), d->clipRect.right());
1153 buffer.addSpan(x1, x2 - x1 + 1
, y, 255
);
1158 DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, topLeftSlopeFP, topRightSlopeFP)
1159 DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, bottomLeftSlopeFP, topRightSlopeFP)
1160 DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, topLeftSlopeFP, bottomRightSlopeFP);
1161 DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, bottomLeftSlopeFP, bottomRightSlopeFP);
1220 QRectF bounds = path.controlPointRect();
1222 int iTopBound = qMax(d->clipRect.top(),
int(bounds.top() + 0.5));
1223 int iBottomBound = qMin(d->clipRect.bottom(),
int(bounds.bottom() - 0.5));
1225 if (iTopBound > iBottomBound)
1228 d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, &buffer);
1230 int subpathStart = 0;
1231 QT_FT_Vector last = { 0, 0 };
1232 for (
int i = 0; i < path.elementCount(); ++i) {
1233 switch (path.elementAt(i).type) {
1234 case QPainterPath::LineToElement:
1236 QT_FT_Vector p1 = last;
1237 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1238 d->scanConverter.mergeLine(p1, p2);
1242 case QPainterPath::MoveToElement:
1245 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1247 if (first.x != last.x || first.y != last.y)
1248 d->scanConverter.mergeLine(last, first);
1251 last = PointToVector(path.elementAt(i));
1254 case QPainterPath::CurveToElement:
1256 QT_FT_Vector p1 = last;
1257 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1258 QT_FT_Vector p3 = PointToVector(path.elementAt(++i));
1259 QT_FT_Vector p4 = PointToVector(path.elementAt(++i));
1260 d->scanConverter.mergeCurve(p1, p2, p3, p4);
1270 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1273 if (first.x != last.x || first.y != last.y)
1274 d->scanConverter.mergeLine(last, first);
1276 d->scanConverter.end();