770 if (a == b || !(width > 0.0) || d->clipRect.isEmpty())
777 QPointF delta = pb - pa;
778 pa -= (0.5f * width) * delta;
779 pb += (0.5f * width) * delta;
782 QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5;
783 const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs);
784 if (qClipLine(&pa, &pb, clip))
789 const QPointF d0 = a - b;
790 const qreal w0 = d0.x() * d0.x() + d0.y() * d0.y();
793 const QPointF d = pa - pb;
794 const qreal w = d.x() * d.x() + d.y() * d.y();
800 width *= qSqrt(w0 / w);
805 if (q26Dot6Compare(pa.y(), pb.y())) {
806 const qreal x = (pa.x() + pb.x()) * 0.5f;
807 const qreal dx = qAbs(pb.x() - pa.x()) * 0.5f;
809 const qreal y = pa.y();
810 const qreal dy = width * dx;
812 pa = QPointF(x, y - dy);
813 pb = QPointF(x, y + dy);
818 if (q26Dot6Compare(pa.x(), pb.x())) {
822 const qreal dy = pb.y() - pa.y();
823 const qreal halfWidth = 0.5f * width * dy;
825 qreal left = pa.x() - halfWidth;
826 qreal right = pa.x() + halfWidth;
828 left = qBound(qreal(d->clipRect.left()), left, qreal(d->clipRect.right() + 1));
829 right = qBound(qreal(d->clipRect.left()), right, qreal(d->clipRect.right() + 1));
831 pa.ry() = qBound(qreal(d->clipRect.top()), pa.y(), qreal(d->clipRect.bottom() + 1));
832 pb.ry() = qBound(qreal(d->clipRect.top()), pb.y(), qreal(d->clipRect.bottom() + 1));
834 if (q26Dot6Compare(left, right) || q26Dot6Compare(pa.y(), pb.y()))
838 const int iLeft =
int(left);
839 const int iRight =
int(right);
841 - qSafeFloatToQScFixed(left);
842 const QScFixed rightWidth = qSafeFloatToQScFixed(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;
879 const QScFixed yPa = qSafeFloatToQScFixed(pa.y());
880 const QScFixed yPb = qSafeFloatToQScFixed(pb.y());
885 if (y > d->clipRect.bottom())
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)
906 QPointF delta = pb - pa;
907 delta *= 0.5f * width;
908 const QPointF perp(delta.y(), -delta.x());
915 if (pa.x() < pb.x()) {
927 top = snapTo26Dot6Grid(top);
928 bottom = snapTo26Dot6Grid(bottom);
929 left = snapTo26Dot6Grid(left);
930 right = snapTo26Dot6Grid(right);
932 const qreal topBound = qBound(qreal(d->clipRect.top()), top.y(), qreal(d->clipRect.bottom()));
933 const qreal bottomBound = qBound(qreal(d->clipRect.top()), bottom.y(), qreal(d->clipRect.bottom()));
935 const QPointF topLeftEdge = left - top;
936 const QPointF topRightEdge = right - top;
937 const QPointF bottomLeftEdge = bottom - left;
938 const QPointF bottomRightEdge = bottom - right;
940 const qreal topLeftSlope = qSafeDivide(topLeftEdge.x(), topLeftEdge.y());
941 const qreal bottomLeftSlope = qSafeDivide(bottomLeftEdge.x(), bottomLeftEdge.y());
943 const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
944 const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
946 const QScFixed topLeftSlopeFP = qSafeFloatToQScFixed(topLeftSlope);
947 const QScFixed topRightSlopeFP = qSafeFloatToQScFixed(topRightSlope);
949 const QScFixed bottomLeftSlopeFP = qSafeFloatToQScFixed(bottomLeftSlope);
950 const QScFixed bottomRightSlopeFP = qSafeFloatToQScFixed(bottomRightSlope);
952 const QScFixed invTopLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topLeftSlope));
953 const QScFixed invTopRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topRightSlope));
955 const QScFixed invBottomLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomLeftSlope));
956 const QScFixed invBottomRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomRightSlope));
964 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topLeftSlope);
965 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topRightSlope);
969 if (iLeftFP < iTopFP)
970 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (
int(topBound) - left.y()) * bottomLeftSlope);
972 if (iRightFP < iTopFP)
973 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (
int(topBound) - right.y()) * bottomRightSlope);
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;
981 const QScFixed yTopFP = qSafeFloatToQScFixed(top.y());
982 const QScFixed yLeftFP = qSafeFloatToQScFixed(left.y());
983 const QScFixed yRightFP = qSafeFloatToQScFixed(right.y());
984 const QScFixed yBottomFP = qSafeFloatToQScFixed(bottom.y());
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) {
1002 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (y - left.y()) * bottomLeftSlope);
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) {
1012 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (y - right.y()) * bottomRightSlope);
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) {
1032 leftMin =
QScFixedToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
1033 leftMax =
QScFixedToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
1039 leftMin = qBound(d->clipRect.left(), leftMin, d->clipRect.right());
1040 leftMax = qBound(d->clipRect.left(), leftMax, d->clipRect.right());
1042 if (yFP < iRightFP) {
1045 }
else if (yFP == iRightFP) {
1046 rightMin =
QScFixedToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
1047 rightMax =
QScFixedToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
1053 rightMin = qBound(d->clipRect.left(), rightMin, d->clipRect.right());
1054 rightMax = qBound(d->clipRect.left(), rightMax, d->clipRect.right());
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)
1078 topRightIntersectAf
, bottomRightIntersectAf
,
1079 topRightSlopeFP
, invTopRightSlopeFP
);
1080 if (yFP >= iRightFP && rowBottom > rowTopRight)
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)
1101 topRightIntersectAf
, bottomRightIntersectAf
,
1102 topRightSlopeFP
, invTopRightSlopeFP
);
1103 if (yFP >= iRightFP && rowBottom > rowTopRight)
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);
1132 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
1133 QScFixed leftIntersectBf = qSafeFloatToQScFixed(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
1134 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
1135 QScFixed rightIntersectBf = qSafeFloatToQScFixed(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
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) {
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);
1219 QRectF bounds = path.controlPointRect();
1221 int iTopBound = qMax(d->clipRect.top(),
int(bounds.top() + 0.5));
1222 int iBottomBound = qMin(d->clipRect.bottom(),
int(bounds.bottom() - 0.5));
1224 if (iTopBound > iBottomBound)
1227 d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, &buffer);
1229 int subpathStart = 0;
1230 QT_FT_Vector last = { 0, 0 };
1231 for (
int i = 0; i < path.elementCount(); ++i) {
1232 switch (path.elementAt(i).type) {
1233 case QPainterPath::LineToElement:
1235 QT_FT_Vector p1 = last;
1236 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1237 d->scanConverter.mergeLine(p1, p2);
1241 case QPainterPath::MoveToElement:
1244 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1246 if (first.x != last.x || first.y != last.y)
1247 d->scanConverter.mergeLine(last, first);
1250 last = PointToVector(path.elementAt(i));
1253 case QPainterPath::CurveToElement:
1255 QT_FT_Vector p1 = last;
1256 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1257 QT_FT_Vector p3 = PointToVector(path.elementAt(++i));
1258 QT_FT_Vector p4 = PointToVector(path.elementAt(++i));
1259 d->scanConverter.mergeCurve(p1, p2, p3, p4);
1269 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1272 if (first.x != last.x || first.y != last.y)
1273 d->scanConverter.mergeLine(last, first);
1275 d->scanConverter.end();