From 7cfec8b936a10b579d0f97acc0cb681f82f6fa85 Mon Sep 17 00:00:00 2001 From: Andy Nichols Date: Tue, 2 Sep 2014 18:23:30 +0200 Subject: Support rendering Gradients when stops are not between 0 and 1 QGradient does not allow stops positions that are outside the bounds of 0 and 1. Gradients created from QML however can have stops outside of these bounds and so we must normalize these stops before giving them to QPainter to render. This change creates a new stop at 0 or 1 if a stop goes below or above the bounds respectively, and interpolates a new color value for the stop based on the original position. Change-Id: I10cc41d923e88a9b41bfd27de0326cea25464add Reviewed-by: Simon Hausmann --- .../scenegraph/softwarecontext/rectanglenode.cpp | 89 +++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp b/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp index 054ffd3ecf..39710bb736 100644 --- a/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp +++ b/src/plugins/scenegraph/softwarecontext/rectanglenode.cpp @@ -63,9 +63,96 @@ void RectangleNode::setPenWidth(qreal width) } } +//Move first stop by pos relative to seconds +static QGradientStop interpolateStop(const QGradientStop &firstStop, const QGradientStop &secondStop, double newPos) +{ + double distance = secondStop.first - firstStop.first; + double distanceDelta = newPos - firstStop.first; + double modifierValue = distanceDelta / distance; + int redDelta = (secondStop.second.red() - firstStop.second.red()) * modifierValue; + int greenDelta = (secondStop.second.green() - firstStop.second.green()) * modifierValue; + int blueDelta = (secondStop.second.blue() - firstStop.second.blue()) * modifierValue; + int alphaDelta = (secondStop.second.alpha() - firstStop.second.alpha()) * modifierValue; + + QGradientStop newStop; + newStop.first = newPos; + newStop.second = QColor(firstStop.second.red() + redDelta, + firstStop.second.green() + greenDelta, + firstStop.second.blue() + blueDelta, + firstStop.second.alpha() + alphaDelta); + + return newStop; +} + void RectangleNode::setGradientStops(const QGradientStops &stops) { - m_stops = stops; + //normalize stops + bool needsNormalization = false; + foreach (const QGradientStop &stop, stops) { + if (stop.first < 0.0 || stop.first > 1.0) { + needsNormalization = true; + continue; + } + } + + if (needsNormalization) { + QGradientStops normalizedStops; + if (stops.count() == 1) { + //If there is only one stop, then the position does not matter + //It is just treated as a color + QGradientStop stop = stops.at(0); + stop.first = 0.0; + normalizedStops.append(stop); + } else { + //Clip stops to only the first below 0.0 and above 1.0 + int below = -1; + int above = -1; + QVector between; + for (int i = 0; i < stops.count(); ++i) { + if (stops.at(i).first < 0.0) { + below = i; + } else if (stops.at(i).first > 1.0) { + above = i; + break; + } else { + between.append(i); + } + } + + //Interpoloate new color values for above and below + if (below != -1 ) { + //If there are more than one stops left, interpolate + if (below + 1 < stops.count()) { + normalizedStops.append(interpolateStop(stops.at(below), stops.at(below + 1), 0.0)); + } else { + QGradientStop singleStop; + singleStop.first = 0.0; + singleStop.second = stops.at(below).second; + normalizedStops.append(singleStop); + } + } + + for (int i = 0; i < between.count(); ++i) + normalizedStops.append(stops.at(between.at(i))); + + if (above != -1) { + //If there stops before above, interpolate + if (above >= 1) { + normalizedStops.append(interpolateStop(stops.at(above), stops.at(above - 1), 1.0)); + } else { + QGradientStop singleStop; + singleStop.first = 1.0; + singleStop.second = stops.at(above).second; + normalizedStops.append(singleStop); + } + } + } + + m_stops = normalizedStops; + + } else { + m_stops = stops; + } m_cornerPixmapIsDirty = true; } -- cgit v1.2.3