diff options
author | Andy Nichols <andy.nichols@digia.com> | 2014-09-02 18:23:30 +0200 |
---|---|---|
committer | Andy Nichols <andy.nichols@digia.com> | 2014-09-09 13:26:54 +0300 |
commit | 7cfec8b936a10b579d0f97acc0cb681f82f6fa85 (patch) | |
tree | 4b88908edc9ef3a64002dca3b0882ff38de2c36f /src/plugins/scenegraph/softwarecontext | |
parent | 8e0372422cd83a6f934df3b09bb478c58ce4dd2b (diff) |
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 <simon.hausmann@digia.com>
Diffstat (limited to 'src/plugins/scenegraph/softwarecontext')
-rw-r--r-- | src/plugins/scenegraph/softwarecontext/rectanglenode.cpp | 89 |
1 files changed, 88 insertions, 1 deletions
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<int> 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; } |