Skip to content

Instantly share code, notes, and snippets.

@annulen
Created July 13, 2016 17:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save annulen/2aaa66d6fbbef562bdb8b53996d57f63 to your computer and use it in GitHub Desktop.
Save annulen/2aaa66d6fbbef562bdb8b53996d57f63 to your computer and use it in GitHub Desktop.
void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2)
{
if (paintingDisabled())
return;
if (strokeStyle() == NoStroke)
return;
if (isRecording()) {
m_displayListRecorder->drawLine(point1, point2);
return;
}
const Color& strokeColor = this->strokeColor();
float thickness = strokeThickness();
bool isVerticalLine = (point1.x() + thickness == point2.x());
float strokeWidth = isVerticalLine ? point2.y() - point1.y() : point2.x() - point1.x();
if (!thickness || !strokeWidth)
return;
QPainter* p = platformContext();
const bool savedAntiAlias = p->testRenderHint(QPainter::Antialiasing);
p->setRenderHint(QPainter::Antialiasing, m_data->antiAliasingForRectsAndLines);
StrokeStyle strokeStyle = this->strokeStyle();
float cornerWidth = 0;
bool drawsDashedLine = strokeStyle == DottedStroke || strokeStyle == DashedStroke;
if (drawsDashedLine) {
// Figure out end points to ensure we always paint corners.
cornerWidth = strokeStyle == DottedStroke ? thickness : std::min(2 * thickness, std::max(thickness, strokeWidth / 3));
if (isVerticalLine) {
// fill FloatRect(point1.x(), point1.y(), thickness, cornerWidth)
// fill FloatRect(point1.x(), point2.y() - cornerWidth, thickness, cornerWidth)
} else {
// fill FloatRect(point1.x(), point1.y(), cornerWidth, thickness)
// fill FloatRect(point2.x() - cornerWidth, point1.y(), cornerWidth, thickness)
}
strokeWidth -= 2 * cornerWidth;
float patternWidth = strokeStyle == DottedStroke ? thickness : std::min(3 * thickness, std::max(thickness, strokeWidth / 3));
// Check if corner drawing sufficiently covers the line.
if (strokeWidth <= patternWidth + 1) {
// restore painter
return;
}
// Pattern starts with full fill and ends with the empty fill.
// 1. Let's start with the empty phase after the corner.
// 2. Check if we've got odd or even number of patterns and whether they fully cover the line.
// 3. In case of even number of patterns and/or remainder, move the pattern start position
// so that the pattern is balanced between the corners.
float patternOffset = patternWidth;
int numberOfSegments = std::floor(strokeWidth / patternWidth);
bool oddNumberOfSegments = numberOfSegments % 2;
float remainder = strokeWidth - (numberOfSegments * patternWidth);
if (oddNumberOfSegments && remainder)
patternOffset -= remainder / 2.f;
else if (!oddNumberOfSegments) {
if (remainder)
patternOffset += patternOffset - (patternWidth + remainder) / 2.f;
else
patternOffset += patternWidth / 2.f;
}
// FIXME
QPen pen = p->pen();
QVector<qreal> dashes { patternWidth, patternWidth };
pen.setDashPattern(dashes);
pen.setDashOffset(patternOffset);
// p->setPen(pen);
} else {
// Dotted here
}
FloatPoint p1 = point1;
FloatPoint p2 = point2;
// Center line and cut off corners for pattern patining.
if (isVerticalLine) {
float centerOffset = (p2.x() - p1.x()) / 2;
p1.move(centerOffset, cornerWidth);
p2.move(-centerOffset, -cornerWidth);
} else {
float centerOffset = (p2.y() - p1.y()) / 2;
p1.move(cornerWidth, centerOffset);
p2.move(-cornerWidth, -centerOffset);
}
// Qt interprets geometric units as end-point inclusive, while WebCore interprets geomtric units as endpoint exclusive.
// This means we need to subtract one from the endpoint, or the line will be painted one pixel too long.
if (p1.x() == p2.x())
p->drawLine(p1, p2 - FloatSize(0, 1));
else
p->drawLine(p1, p2 - FloatSize(1, 0));
// if (patWidth)
// p->restore();
p->setRenderHint(QPainter::Antialiasing, savedAntiAlias);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment