Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(505)

Unified Diff: Source/core/css/CSSGradientValue.cpp

Issue 631753002: Adding support for color interpolation hints to CSS gradients. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: offset1->offsetLeft Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/core/css/CSSGradientValue.h ('k') | Source/core/css/parser/CSSPropertyParser.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/core/css/CSSGradientValue.cpp
diff --git a/Source/core/css/CSSGradientValue.cpp b/Source/core/css/CSSGradientValue.cpp
index b4a8229c7ef31dc99b63226ecbba4e2596ab1f9f..59aa9420fd79ba6fd62225e48583cc729b9cc689 100644
--- a/Source/core/css/CSSGradientValue.cpp
+++ b/Source/core/css/CSSGradientValue.cpp
@@ -37,6 +37,7 @@
#include "platform/graphics/Gradient.h"
#include "platform/graphics/GradientGeneratedImage.h"
#include "platform/graphics/Image.h"
+#include "platform/graphics/skia/SkiaUtils.h"
#include "wtf/text/StringBuilder.h"
#include "wtf/text/WTFString.h"
@@ -114,12 +115,13 @@ struct GradientStop {
PassRefPtrWillBeRawPtr<CSSGradientValue> CSSGradientValue::gradientWithStylesResolved(const TextLinkColors& textLinkColors, Color currentColor)
{
bool derived = false;
- for (unsigned i = 0; i < m_stops.size(); i++)
- if (m_stops[i].m_color->colorIsDerivedFromElement()) {
- m_stops[i].m_colorIsDerivedFromElement = true;
+ for (auto& stop : m_stops) {
+ if (!stop.isHint() && stop.m_color->colorIsDerivedFromElement()) {
+ stop.m_colorIsDerivedFromElement = true;
derived = true;
break;
}
+ }
RefPtrWillBeRawPtr<CSSGradientValue> result = nullptr;
if (!derived)
@@ -133,12 +135,102 @@ PassRefPtrWillBeRawPtr<CSSGradientValue> CSSGradientValue::gradientWithStylesRes
return nullptr;
}
- for (unsigned i = 0; i < result->m_stops.size(); i++)
- result->m_stops[i].m_resolvedColor = textLinkColors.colorFromPrimitiveValue(result->m_stops[i].m_color.get(), currentColor);
+ for (auto& stop : result->m_stops) {
+ if (!stop.isHint())
+ stop.m_resolvedColor = textLinkColors.colorFromPrimitiveValue(stop.m_color.get(), currentColor);
+ }
return result.release();
}
+static void replaceColorHintsWithColorStops(Vector<GradientStop>& stops, const Vector<CSSGradientColorStop, 2>& cssGradientStops)
+{
+ // This algorithm will replace each color interpolation hint with 9 regular
+ // color stops. The color values for the new color stops will be calculated
+ // using the color weighting formula defined in the spec. The new color
+ // stops will be positioned in such a way that all the pixels between the two
+ // user defined color stops have color values close to the interpolation curve.
+ // If the hint is closer to the left color stop, add 2 stops to the left and
+ // 6 to the right, else add 6 stops to the left and 2 to the right.
+ // The color stops on the side with more space start midway because
+ // the curve approximates a line in that region.
+ // Using this aproximation, it is possible to discern the color steps when
+ // the gradient is large. If this becomes an issue, we can consider improving
+ // the algorithm, or adding support for color interpolation hints to skia shaders.
+
+ int indexOffset = 0;
+
+ // The first and the last color stops cannot be color hints.
+ for (size_t i = 1; i < cssGradientStops.size() - 1; ++i) {
+ if (!cssGradientStops[i].isHint())
+ continue;
+
+ // The current index of the stops vector.
+ size_t x = i + indexOffset;
+ ASSERT(x >= 1);
+
+ // offsetLeft offset offsetRight
+ // |-------------------|---------------------------------|
+ // leftDist rightDist
+
+ float offsetLeft = stops[x - 1].offset;
+ float offsetRight = stops[x + 1].offset;
+ float offset = stops[x].offset;
+ float leftDist = offset - offsetLeft;
+ float rightDist = offsetRight - offset;
+ float totalDist = offsetRight - offsetLeft;
+
+ Color leftColor = stops[x - 1].color;
+ Color rightColor = stops[x + 1].color;
+
+ ASSERT(offsetLeft <= offset && offset <= offsetRight);
+
+ if (WebCoreFloatNearlyEqual(leftDist, rightDist)) {
+ stops.remove(x);
+ --indexOffset;
+ continue;
+ }
+
+ if (WebCoreFloatNearlyEqual(leftDist, .0f)) {
+ stops[x].color = rightColor;
+ continue;
+ }
+
+ if (WebCoreFloatNearlyEqual(rightDist, .0f)) {
+ stops[x].color = leftColor;
+ continue;
+ }
+
+ GradientStop newStops[9];
+ // Position the new color stops.
+ if (leftDist > rightDist) {
+ for (size_t y = 0; y < 7; ++y)
+ newStops[y].offset = offsetLeft + leftDist * (7 + y) / 13;
+ newStops[7].offset = offset + rightDist / 3;
+ newStops[8].offset = offset + rightDist * 2 / 3;
+ } else {
+ newStops[0].offset = offsetLeft + leftDist / 3;
+ newStops[1].offset = offsetLeft + leftDist * 2 / 3;
+ for (size_t y = 0; y < 7; ++y)
+ newStops[y + 2].offset = offset + rightDist * y / 13;
+ }
+
+ // calculate colors for the new color hints.
+ // The color weighting for the new color stops will be pointRelativeOffset^(ln(0.5)/ln(hintRelativeOffset)).
+ float hintRelativeOffset = leftDist / totalDist;
+ for (size_t y = 0; y < 9; ++y) {
+ float pointRelativeOffset = (newStops[y].offset - offsetLeft) / totalDist;
+ float weighting = powf(pointRelativeOffset, logf(.5f) / logf(hintRelativeOffset));
+ newStops[y].color = blend(leftColor, rightColor, weighting);
+ }
+
+ // Replace the color hint with the new color stops.
+ stops.remove(x);
+ stops.insert(x, newStops, 9);
+ indexOffset += 8;
+ }
+}
+
void CSSGradientValue::addStops(Gradient* gradient, const CSSToLengthConversionData& conversionData, float maxLengthForRepeat)
{
if (m_gradientType == CSSDeprecatedLinearGradient || m_gradientType == CSSDeprecatedRadialGradient) {
@@ -166,6 +258,8 @@ void CSSGradientValue::addStops(Gradient* gradient, const CSSToLengthConversionD
float gradientLength = 0;
bool computedGradientLength = false;
+ bool hasHints = false;
+
FloatPoint gradientStart = gradient->p0();
FloatPoint gradientEnd;
if (isLinearGradientValue())
@@ -176,7 +270,10 @@ void CSSGradientValue::addStops(Gradient* gradient, const CSSToLengthConversionD
for (size_t i = 0; i < numStops; ++i) {
const CSSGradientColorStop& stop = m_stops[i];
- stops[i].color = stop.m_resolvedColor;
+ if (stop.isHint())
+ hasHints = true;
+ else
+ stops[i].color = stop.m_resolvedColor;
if (stop.m_position) {
if (stop.m_position->isPercentage())
@@ -254,6 +351,12 @@ void CSSGradientValue::addStops(Gradient* gradient, const CSSToLengthConversionD
}
}
+ ASSERT(stops.size() == m_stops.size());
+ if (hasHints) {
+ replaceColorHintsWithColorStops(stops, m_stops);
+ numStops = stops.size();
+ }
+
// If the gradient is repeating, repeat the color stops.
// We can't just push this logic down into the platform-specific Gradient code,
// because we have to know the extent of the gradient, and possible move the end points.
@@ -469,8 +572,8 @@ bool CSSGradientValue::isCacheable() const
bool CSSGradientValue::knownToBeOpaque(const RenderObject*) const
{
- for (size_t i = 0; i < m_stops.size(); ++i) {
- if (m_stops[i].m_resolvedColor.hasAlpha())
+ for (auto& stop : m_stops) {
+ if (!stop.isHint() && stop.m_resolvedColor.hasAlpha())
return false;
}
return true;
@@ -580,11 +683,12 @@ String CSSLinearGradientValue::customCSSText() const
const CSSGradientColorStop& stop = m_stops[i];
if (i)
result.appendLiteral(", ");
- result.append(stop.m_color->cssText());
- if (stop.m_position) {
+ if (stop.m_color)
+ result.append(stop.m_color->cssText());
+ if (stop.m_color && stop.m_position)
result.append(' ');
+ if (stop.m_position)
result.append(stop.m_position->cssText());
- }
}
}
@@ -902,11 +1006,12 @@ String CSSRadialGradientValue::customCSSText() const
const CSSGradientColorStop& stop = m_stops[i];
if (i)
result.appendLiteral(", ");
- result.append(stop.m_color->cssText());
- if (stop.m_position) {
+ if (stop.m_color)
+ result.append(stop.m_color->cssText());
+ if (stop.m_color && stop.m_position)
result.append(' ');
+ if (stop.m_position)
result.append(stop.m_position->cssText());
- }
}
}
« no previous file with comments | « Source/core/css/CSSGradientValue.h ('k') | Source/core/css/parser/CSSPropertyParser.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698