708 if (a == b || !(width > 0.0) || d->clipRect.isEmpty())
715 QPointF delta = pb - pa;
716 pa -= (0.5f * width) * delta;
717 pb += (0.5f * width) * delta;
720 QPointF offs = QPointF(qAbs(b.y() - a.y()), qAbs(b.x() - a.x())) * width * 0.5;
721 const QRectF clip(d->clipRect.topLeft() - offs, d->clipRect.bottomRight() + QPoint(1, 1) + offs);
722 if (qClipLine(&pa, &pb, clip))
727 const QPointF d0 = a - b;
728 const qreal w0 = d0.x() * d0.x() + d0.y() * d0.y();
731 const QPointF d = pa - pb;
732 const qreal w = d.x() * d.x() + d.y() * d.y();
738 width *= qSqrt(w0 / w);
743 if (q26Dot6Compare(pa.y(), pb.y())) {
744 const qreal x = (pa.x() + pb.x()) * 0.5f;
745 const qreal dx = qAbs(pb.x() - pa.x()) * 0.5f;
747 const qreal y = pa.y();
748 const qreal dy = width * dx;
750 pa = QPointF(x, y - dy);
751 pb = QPointF(x, y + dy);
756 if (q26Dot6Compare(pa.x(), pb.x())) {
760 const qreal dy = pb.y() - pa.y();
761 const qreal halfWidth = 0.5f * width * dy;
763 qreal left = pa.x() - halfWidth;
764 qreal right = pa.x() + halfWidth;
766 left = qBound(qreal(d->clipRect.left()), left, qreal(d->clipRect.right() + 1));
767 right = qBound(qreal(d->clipRect.left()), right, qreal(d->clipRect.right() + 1));
769 pa.ry() = qBound(qreal(d->clipRect.top()), pa.y(), qreal(d->clipRect.bottom() + 1));
770 pb.ry() = qBound(qreal(d->clipRect.top()), pb.y(), qreal(d->clipRect.bottom() + 1));
772 if (q26Dot6Compare(left, right) || q26Dot6Compare(pa.y(), pb.y()))
776 const int iLeft =
int(left);
777 const int iRight =
int(right);
779 - qSafeFloatToQScFixed(left);
780 const QScFixed rightWidth = qSafeFloatToQScFixed(right)
788 if (iLeft == iRight) {
790 coverage[0] = rightWidth * 255;
796 coverage[0] = leftWidth * 255;
800 len[0] = iRight - iLeft;
801 }
else if (iRight - iLeft > 1) {
804 len[1] = iRight - iLeft - 1;
808 coverage[n] = rightWidth * 255;
817 const QScFixed yPa = qSafeFloatToQScFixed(pa.y());
818 const QScFixed yPb = qSafeFloatToQScFixed(pb.y());
823 if (y > d->clipRect.bottom())
825 for (
int i = 0; i < n; ++i) {
831 int iTop =
int(pa.y() + 0.5f);
832 int iBottom = pb.y() < 0.5f ? -1 :
int(pb.y() - 0.5f);
833 int iLeft =
int(left + 0.5f);
834 int iRight = right < 0.5f ? -1 :
int(right - 0.5f);
836 int iWidth = iRight - iLeft + 1;
837 for (
int y = iTop; y <= iBottom; ++y)
844 QPointF delta = pb - pa;
845 delta *= 0.5f * width;
846 const QPointF perp(delta.y(), -delta.x());
853 if (pa.x() < pb.x()) {
865 top = snapTo26Dot6Grid(top);
866 bottom = snapTo26Dot6Grid(bottom);
867 left = snapTo26Dot6Grid(left);
868 right = snapTo26Dot6Grid(right);
870 const qreal topBound = qBound(qreal(d->clipRect.top()), top.y(), qreal(d->clipRect.bottom()));
871 const qreal bottomBound = qBound(qreal(d->clipRect.top()), bottom.y(), qreal(d->clipRect.bottom()));
873 const QPointF topLeftEdge = left - top;
874 const QPointF topRightEdge = right - top;
875 const QPointF bottomLeftEdge = bottom - left;
876 const QPointF bottomRightEdge = bottom - right;
878 const qreal topLeftSlope = qSafeDivide(topLeftEdge.x(), topLeftEdge.y());
879 const qreal bottomLeftSlope = qSafeDivide(bottomLeftEdge.x(), bottomLeftEdge.y());
881 const qreal topRightSlope = qSafeDivide(topRightEdge.x(), topRightEdge.y());
882 const qreal bottomRightSlope = qSafeDivide(bottomRightEdge.x(), bottomRightEdge.y());
884 const QScFixed topLeftSlopeFP = qSafeFloatToQScFixed(topLeftSlope);
885 const QScFixed topRightSlopeFP = qSafeFloatToQScFixed(topRightSlope);
887 const QScFixed bottomLeftSlopeFP = qSafeFloatToQScFixed(bottomLeftSlope);
888 const QScFixed bottomRightSlopeFP = qSafeFloatToQScFixed(bottomRightSlope);
890 const QScFixed invTopLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topLeftSlope));
891 const QScFixed invTopRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, topRightSlope));
893 const QScFixed invBottomLeftSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomLeftSlope));
894 const QScFixed invBottomRightSlopeFP = qSafeFloatToQScFixed(qSafeDivide(1, bottomRightSlope));
902 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topLeftSlope);
903 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() + (
int(topBound) - top.y()) * topRightSlope);
907 if (iLeftFP < iTopFP)
908 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (
int(topBound) - left.y()) * bottomLeftSlope);
910 if (iRightFP < iTopFP)
911 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (
int(topBound) - right.y()) * bottomRightSlope);
913 QScFixed rowTop, rowBottomLeft, rowBottomRight, rowTopLeft, rowTopRight, rowBottom;
914 QScFixed topLeftIntersectAf, topLeftIntersectBf, topRightIntersectAf, topRightIntersectBf;
915 QScFixed bottomLeftIntersectAf, bottomLeftIntersectBf, bottomRightIntersectAf, bottomRightIntersectBf;
917 int leftMin, leftMax, rightMin, rightMax;
919 const QScFixed yTopFP = qSafeFloatToQScFixed(top.y());
920 const QScFixed yLeftFP = qSafeFloatToQScFixed(left.y());
921 const QScFixed yRightFP = qSafeFloatToQScFixed(right.y());
922 const QScFixed yBottomFP = qSafeFloatToQScFixed(bottom.y());
924 rowTop = qMax(iTopFP, yTopFP);
925 topLeftIntersectAf = leftIntersectAf +
927 topRightIntersectAf = rightIntersectAf +
931 while (yFP <= iBottomFP) {
934 rowTopLeft = qMax(yFP, yLeftFP);
935 rowTopRight = qMax(yFP, yRightFP);
938 if (yFP == iLeftFP) {
940 leftIntersectBf = qSafeFloatToQScFixed(left.x() + (y - left.y()) * bottomLeftSlope);
941 topLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowTopLeft - yFP);
942 bottomLeftIntersectAf = leftIntersectAf +
QScFixedMultiply(topLeftSlopeFP, rowBottomLeft - yFP);
944 topLeftIntersectBf = leftIntersectBf;
945 bottomLeftIntersectAf = leftIntersectAf + topLeftSlopeFP;
948 if (yFP == iRightFP) {
950 rightIntersectBf = qSafeFloatToQScFixed(right.x() + (y - right.y()) * bottomRightSlope);
951 topRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowTopRight - yFP);
952 bottomRightIntersectAf = rightIntersectAf +
QScFixedMultiply(topRightSlopeFP, rowBottomRight - yFP);
954 topRightIntersectBf = rightIntersectBf;
955 bottomRightIntersectAf = rightIntersectAf + topRightSlopeFP;
958 if (yFP == iBottomFP) {
959 bottomLeftIntersectBf = leftIntersectBf +
QScFixedMultiply(bottomLeftSlopeFP, rowBottom - yFP);
960 bottomRightIntersectBf = rightIntersectBf +
QScFixedMultiply(bottomRightSlopeFP, rowBottom - yFP);
962 bottomLeftIntersectBf = leftIntersectBf + bottomLeftSlopeFP;
963 bottomRightIntersectBf = rightIntersectBf + bottomRightSlopeFP;
969 }
else if (yFP == iLeftFP) {
970 leftMin =
QScFixedToInt(qMax(bottomLeftIntersectAf, topLeftIntersectBf));
971 leftMax =
QScFixedToInt(qMax(topLeftIntersectAf, bottomLeftIntersectBf));
977 leftMin = qBound(d->clipRect.left(), leftMin, d->clipRect.right());
978 leftMax = qBound(d->clipRect.left(), leftMax, d->clipRect.right());
980 if (yFP < iRightFP) {
983 }
else if (yFP == iRightFP) {
984 rightMin =
QScFixedToInt(qMin(topRightIntersectAf, bottomRightIntersectBf));
985 rightMax =
QScFixedToInt(qMin(bottomRightIntersectAf, topRightIntersectBf));
991 rightMin = qBound(d->clipRect.left(), rightMin, d->clipRect.right());
992 rightMax = qBound(d->clipRect.left(), rightMax, d->clipRect.right());
994 if (leftMax > rightMax)
996 if (rightMin < leftMin)
999 QScFixed rowHeight = rowBottom - rowTop;
1002 while (x <= leftMax) {
1005 if (yFP <= iLeftFP && rowBottomLeft > rowTop)
1007 bottomLeftIntersectAf
, topLeftIntersectAf
,
1008 topLeftSlopeFP
, invTopLeftSlopeFP
);
1009 if (yFP >= iLeftFP && rowBottom > rowTopLeft)
1011 topLeftIntersectBf
, bottomLeftIntersectBf
,
1012 bottomLeftSlopeFP
, invBottomLeftSlopeFP
);
1013 if (x >= rightMin) {
1014 if (yFP <= iRightFP && rowBottomRight > rowTop)
1016 topRightIntersectAf
, bottomRightIntersectAf
,
1017 topRightSlopeFP
, invTopRightSlopeFP
);
1018 if (yFP >= iRightFP && rowBottom > rowTopRight)
1020 bottomRightIntersectBf
, topRightIntersectBf
,
1021 bottomRightSlopeFP
, invBottomRightSlopeFP
);
1024 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1025 QScFixed coverage = rowHeight - excluded;
1035 while (x <= rightMax) {
1037 if (yFP <= iRightFP && rowBottomRight > rowTop)
1039 topRightIntersectAf
, bottomRightIntersectAf
,
1040 topRightSlopeFP
, invTopRightSlopeFP
);
1041 if (yFP >= iRightFP && rowBottom > rowTopRight)
1043 bottomRightIntersectBf
, topRightIntersectBf
,
1044 bottomRightSlopeFP
, invBottomRightSlopeFP
);
1046 Q_ASSERT(excluded >= 0 && excluded <= rowHeight);
1047 QScFixed coverage = rowHeight - excluded;
1053 leftIntersectAf += topLeftSlopeFP;
1054 leftIntersectBf += bottomLeftSlopeFP;
1055 rightIntersectAf += topRightSlopeFP;
1056 rightIntersectBf += bottomRightSlopeFP;
1057 topLeftIntersectAf = leftIntersectAf;
1058 topRightIntersectAf = rightIntersectAf;
1064 int iTop =
int(top.y() + 0.5f);
1065 int iLeft = left.y() < 0.5f ? -1 :
int(left.y() - 0.5f);
1066 int iRight = right.y() < 0.5f ? -1 :
int(right.y() - 0.5f);
1067 int iBottom = bottom.y() < 0.5f? -1 :
int(bottom.y() - 0.5f);
1068 int iMiddle = qMin(iLeft, iRight);
1070 QScFixed leftIntersectAf = qSafeFloatToQScFixed(top.x() + 0.5f + (iTop + 0.5f - top.y()) * topLeftSlope);
1071 QScFixed leftIntersectBf = qSafeFloatToQScFixed(left.x() + 0.5f + (iLeft + 1.5f - left.y()) * bottomLeftSlope);
1072 QScFixed rightIntersectAf = qSafeFloatToQScFixed(top.x() - 0.5f + (iTop + 0.5f - top.y()) * topRightSlope);
1073 QScFixed rightIntersectBf = qSafeFloatToQScFixed(right.x() - 0.5f + (iRight + 1.5f - right.y()) * bottomRightSlope);
1077#define DO_SEGMENT(next, li, ri, ls, rs)
1078 ny = qMin(next + 1
, d->clipRect.top());
1080 li += ls * (ny - y);
1081 ri += rs * (ny - y);
1084 if (next > d->clipRect.bottom())
1085 next = d->clipRect.bottom();
1086 for (; y <= next; ++y) {
1088 const int x2 = qMin(QScFixedToInt(ri), d->clipRect.right());
1090 buffer.addSpan(x1, x2 - x1 + 1
, y, 255
);
1095 DO_SEGMENT(iMiddle, leftIntersectAf, rightIntersectAf, topLeftSlopeFP, topRightSlopeFP)
1096 DO_SEGMENT(iRight, leftIntersectBf, rightIntersectAf, bottomLeftSlopeFP, topRightSlopeFP)
1097 DO_SEGMENT(iLeft, leftIntersectAf, rightIntersectBf, topLeftSlopeFP, bottomRightSlopeFP);
1098 DO_SEGMENT(iBottom, leftIntersectBf, rightIntersectBf, bottomLeftSlopeFP, bottomRightSlopeFP);
1157 QRectF bounds = path.controlPointRect();
1159 int iTopBound = qMax(d->clipRect.top(),
int(bounds.top() + 0.5));
1160 int iBottomBound = qMin(d->clipRect.bottom(),
int(bounds.bottom() - 0.5));
1162 if (iTopBound > iBottomBound)
1165 d->scanConverter.begin(iTopBound, iBottomBound, d->clipRect.left(), d->clipRect.right(), fillRule, &buffer);
1167 int subpathStart = 0;
1168 QT_FT_Vector last = { 0, 0 };
1169 for (
int i = 0; i < path.elementCount(); ++i) {
1170 switch (path.elementAt(i).type) {
1171 case QPainterPath::LineToElement:
1173 QT_FT_Vector p1 = last;
1174 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1175 d->scanConverter.mergeLine(p1, p2);
1179 case QPainterPath::MoveToElement:
1182 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1184 if (first.x != last.x || first.y != last.y)
1185 d->scanConverter.mergeLine(last, first);
1188 last = PointToVector(path.elementAt(i));
1191 case QPainterPath::CurveToElement:
1193 QT_FT_Vector p1 = last;
1194 QT_FT_Vector p2 = PointToVector(path.elementAt(i));
1195 QT_FT_Vector p3 = PointToVector(path.elementAt(++i));
1196 QT_FT_Vector p4 = PointToVector(path.elementAt(++i));
1197 d->scanConverter.mergeCurve(p1, p2, p3, p4);
1207 QT_FT_Vector first = PointToVector(path.elementAt(subpathStart));
1210 if (first.x != last.x || first.y != last.y)
1211 d->scanConverter.mergeLine(last, first);
1213 d->scanConverter.end();