| Index: third_party/WebKit/Source/core/css/CSSGradientValue.cpp
|
| diff --git a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
|
| index 7bfdc5272e978212178863cc3fa13d12a5dd1ed1..0bed19512a45267777c92044beaa6f14bdc2a1f7 100644
|
| --- a/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
|
| +++ b/third_party/WebKit/Source/core/css/CSSGradientValue.cpp
|
| @@ -309,8 +309,10 @@ void CSSGradientValue::addDeprecatedStops(GradientDesc& desc,
|
| }
|
| }
|
|
|
| -static bool requiresStopsNormalization(const Vector<GradientStop>& stops,
|
| - CSSGradientValue::GradientDesc& desc) {
|
| +namespace {
|
| +
|
| +bool requiresStopsNormalization(const Vector<GradientStop>& stops,
|
| + CSSGradientValue::GradientDesc& desc) {
|
| // We need at least two stops to normalize
|
| if (stops.size() < 2)
|
| return false;
|
| @@ -329,8 +331,8 @@ static bool requiresStopsNormalization(const Vector<GradientStop>& stops,
|
|
|
| // Redistribute the stops such that they fully cover [0 , 1] and add them to the
|
| // gradient.
|
| -static bool normalizeAndAddStops(const Vector<GradientStop>& stops,
|
| - CSSGradientValue::GradientDesc& desc) {
|
| +bool normalizeAndAddStops(const Vector<GradientStop>& stops,
|
| + CSSGradientValue::GradientDesc& desc) {
|
| DCHECK_GT(stops.size(), 1u);
|
|
|
| const float firstOffset = stops.front().offset;
|
| @@ -371,7 +373,7 @@ static bool normalizeAndAddStops(const Vector<GradientStop>& stops,
|
|
|
| // Collapse all negative-offset stops to 0 and compute an interpolated color
|
| // value for that point.
|
| -static void clampNegativeOffsets(Vector<GradientStop>& stops) {
|
| +void clampNegativeOffsets(Vector<GradientStop>& stops) {
|
| float lastNegativeOffset = 0;
|
|
|
| for (size_t i = 0; i < stops.size(); ++i) {
|
| @@ -397,10 +399,9 @@ static void clampNegativeOffsets(Vector<GradientStop>& stops) {
|
| }
|
|
|
| // Update the linear gradient points to align with the given offset range.
|
| -static void adjustGradientPointsForOffsetRange(
|
| - CSSGradientValue::GradientDesc& desc,
|
| - float firstOffset,
|
| - float lastOffset) {
|
| +void adjustGradientPointsForOffsetRange(CSSGradientValue::GradientDesc& desc,
|
| + float firstOffset,
|
| + float lastOffset) {
|
| DCHECK_LE(firstOffset, lastOffset);
|
|
|
| const FloatPoint p0 = desc.p0;
|
| @@ -413,10 +414,9 @@ static void adjustGradientPointsForOffsetRange(
|
| }
|
|
|
| // Update the radial gradient radii to align with the given offset range.
|
| -static void adjustGradientRadiiForOffsetRange(
|
| - CSSGradientValue::GradientDesc& desc,
|
| - float firstOffset,
|
| - float lastOffset) {
|
| +void adjustGradientRadiiForOffsetRange(CSSGradientValue::GradientDesc& desc,
|
| + float firstOffset,
|
| + float lastOffset) {
|
| DCHECK_LE(firstOffset, lastOffset);
|
|
|
| // Radial offsets are relative to the [0 , endRadius] segment.
|
| @@ -447,6 +447,101 @@ static void adjustGradientRadiiForOffsetRange(
|
| desc.r1 = adjustedR1;
|
| }
|
|
|
| +// Helper for performing on-the-fly out of range color stop interpolation.
|
| +class ConicClamper {
|
| + STACK_ALLOCATED();
|
| +
|
| + public:
|
| + ConicClamper(CSSGradientValue::GradientDesc& desc) : m_desc(desc) {}
|
| +
|
| + void add(float offset, const Color& color) {
|
| + addInternal(offset, color);
|
| + m_prevOffset = offset;
|
| + m_prevColor = color;
|
| + }
|
| +
|
| + private:
|
| + void addUnique(float offset, const Color& color) {
|
| + // Skip duplicates.
|
| + if (m_desc.stops.isEmpty() || offset != m_desc.stops.back().stop ||
|
| + color != m_desc.stops.back().color) {
|
| + m_desc.stops.emplace_back(offset, color);
|
| + }
|
| + }
|
| +
|
| + void addInternal(float offset, const Color& color) {
|
| + if (offset < 0)
|
| + return;
|
| +
|
| + if (m_prevOffset < 0 && offset > 0) {
|
| + addUnique(0, blend(m_prevColor, color,
|
| + -m_prevOffset / (offset - m_prevOffset)));
|
| + }
|
| +
|
| + if (offset <= 1) {
|
| + addUnique(offset, color);
|
| + return;
|
| + }
|
| +
|
| + if (m_prevOffset < 1) {
|
| + addUnique(1, blend(m_prevColor, color,
|
| + (1 - m_prevOffset) / (offset - m_prevOffset)));
|
| + }
|
| + }
|
| +
|
| + CSSGradientValue::GradientDesc& m_desc;
|
| +
|
| + float m_prevOffset = 0;
|
| + Color m_prevColor;
|
| +};
|
| +
|
| +void normalizeAndAddConicStops(const Vector<GradientStop>& stops,
|
| + CSSGradientValue::GradientDesc& desc) {
|
| + DCHECK(!stops.isEmpty());
|
| + ConicClamper clamper(desc);
|
| +
|
| + if (desc.spreadMethod == SpreadMethodPad) {
|
| + for (const auto& stop : stops)
|
| + clamper.add(stop.offset, stop.color);
|
| + return;
|
| + }
|
| +
|
| + DCHECK_EQ(desc.spreadMethod, SpreadMethodRepeat);
|
| +
|
| + // The normalization trick we use for linear and radial doesn't work here,
|
| + // because the underlying Skia implementation doesn't support conic gradient
|
| + // tiling. So we emit synthetic stops to cover the whole unit interval.
|
| + float repeatSpan = stops.back().offset - stops.front().offset;
|
| + DCHECK_GE(repeatSpan, 0.0f);
|
| + if (repeatSpan < std::numeric_limits<float>::epsilon()) {
|
| + // All stops are coincident -> use a single solid color.
|
| + desc.stops.emplace_back(0, stops.back().color);
|
| + return;
|
| + }
|
| +
|
| + // Compute an offset base as a repetition of stops[0].offset such that
|
| + // [ offsetBase, offsetBase + repeatSpan ] contains 0
|
| + // (aka the largest repeat value for stops[0] less than 0).
|
| + float offset = fmodf(stops.front().offset, repeatSpan) -
|
| + (stops.front().offset < 0 ? 0 : repeatSpan);
|
| + DCHECK_LE(offset, 0);
|
| + DCHECK_GE(offset + repeatSpan, 0);
|
| +
|
| + // Start throwing repeating values at the clamper.
|
| + do {
|
| + const float offsetBase = offset;
|
| + for (const auto& stop : stops) {
|
| + offset = offsetBase + stop.offset - stops.front().offset;
|
| + clamper.add(offset, stop.color);
|
| +
|
| + if (offset >= 1)
|
| + break;
|
| + }
|
| + } while (offset < 1);
|
| +}
|
| +
|
| +} // anonymous ns
|
| +
|
| void CSSGradientValue::addStops(CSSGradientValue::GradientDesc& desc,
|
| const CSSToLengthConversionData& conversionData,
|
| const LayoutObject& object) {
|
| @@ -575,9 +670,7 @@ void CSSGradientValue::addStops(CSSGradientValue::GradientDesc& desc,
|
|
|
| // At this point we have a fully resolved set of stops. Time to perform
|
| // adjustments for repeat gradients and degenerate values if needed.
|
| - // Note: the normalization trick doesn't work for conic gradients, because
|
| - // the underlying Skia implementation doesn't support tiling.
|
| - if (isConicGradientValue() || !requiresStopsNormalization(stops, desc)) {
|
| + if (!requiresStopsNormalization(stops, desc)) {
|
| // No normalization required, just add the current stops.
|
| for (const auto& stop : stops)
|
| desc.stops.emplace_back(stop.offset, stop.color);
|
| @@ -604,6 +697,9 @@ void CSSGradientValue::addStops(CSSGradientValue::GradientDesc& desc,
|
| stops.back().offset);
|
| }
|
| break;
|
| + case ConicGradientClass:
|
| + normalizeAndAddConicStops(stops, desc);
|
| + break;
|
| default:
|
| NOTREACHED();
|
| }
|
| @@ -1398,9 +1494,8 @@ PassRefPtr<Gradient> CSSConicGradientValue::createGradient(
|
| m_repeating ? SpreadMethodRepeat : SpreadMethodPad);
|
| addStops(desc, conversionData, object);
|
|
|
| - RefPtr<Gradient> gradient =
|
| - Gradient::createConic(position, angle, desc.spreadMethod,
|
| - Gradient::ColorInterpolation::Premultiplied);
|
| + RefPtr<Gradient> gradient = Gradient::createConic(
|
| + position, angle, Gradient::ColorInterpolation::Premultiplied);
|
| gradient->addColorStops(desc.stops);
|
|
|
| return gradient.release();
|
|
|