| Index: third_party/WebKit/Source/platform/graphics/Gradient.cpp
|
| diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
|
| index caef1c6d7d2ee8dec3f9fbc5fb9ca325ecbd6203..2ed0e01614269ba26327a1b8845be2e3234a1f70 100644
|
| --- a/third_party/WebKit/Source/platform/graphics/Gradient.cpp
|
| +++ b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
|
| @@ -27,6 +27,7 @@
|
|
|
| #include "platform/graphics/Gradient.h"
|
|
|
| +#include <algorithm>
|
| #include "platform/geometry/FloatRect.h"
|
| #include "platform/graphics/GraphicsContext.h"
|
| #include "platform/graphics/paint/PaintShader.h"
|
| @@ -34,44 +35,18 @@
|
| #include "third_party/skia/include/core/SkColor.h"
|
| #include "third_party/skia/include/core/SkMatrix.h"
|
| #include "third_party/skia/include/core/SkShader.h"
|
| +#include "third_party/skia/include/core/SkTLazy.h"
|
| #include "third_party/skia/include/effects/SkGradientShader.h"
|
| -#include <algorithm>
|
| -
|
| -typedef Vector<SkScalar, 8> ColorStopOffsetVector;
|
| -typedef Vector<SkColor, 8> ColorStopColorVector;
|
|
|
| namespace blink {
|
|
|
| -Gradient::Gradient(const FloatPoint& p0,
|
| - const FloatPoint& p1,
|
| +Gradient::Gradient(Type type,
|
| GradientSpreadMethod spreadMethod,
|
| ColorInterpolation interpolation)
|
| - : m_p0(p0),
|
| - m_p1(p1),
|
| - m_r0(0),
|
| - m_r1(0),
|
| - m_aspectRatio(1),
|
| - m_radial(false),
|
| - m_stopsSorted(false),
|
| + : m_type(type),
|
| m_spreadMethod(spreadMethod),
|
| - m_colorInterpolation(interpolation) {}
|
| -
|
| -Gradient::Gradient(const FloatPoint& p0,
|
| - float r0,
|
| - const FloatPoint& p1,
|
| - float r1,
|
| - float aspectRatio,
|
| - GradientSpreadMethod spreadMethod,
|
| - ColorInterpolation interpolation)
|
| - : m_p0(p0),
|
| - m_p1(p1),
|
| - m_r0(r0),
|
| - m_r1(r1),
|
| - m_aspectRatio(aspectRatio),
|
| - m_radial(true),
|
| - m_stopsSorted(false),
|
| - m_spreadMethod(spreadMethod),
|
| - m_colorInterpolation(interpolation) {}
|
| + m_colorInterpolation(interpolation),
|
| + m_stopsSorted(true) {}
|
|
|
| Gradient::~Gradient() {}
|
|
|
| @@ -118,23 +93,21 @@ static inline SkColor makeSkColor(const Color& c) {
|
| // TODO(fmalita): theoretically Skia should provide the same 0.0/1.0 padding
|
| // (making this logic redundant), but in practice there are rendering diffs;
|
| // investigate.
|
| -static void fillStops(const Vector<Gradient::ColorStop, 2>& stops,
|
| - ColorStopOffsetVector& pos,
|
| - ColorStopColorVector& colors) {
|
| - if (stops.isEmpty()) {
|
| +void Gradient::fillSkiaStops(ColorBuffer& colors, OffsetBuffer& pos) const {
|
| + if (m_stops.isEmpty()) {
|
| // A gradient with no stops must be transparent black.
|
| pos.push_back(WebCoreFloatToSkScalar(0));
|
| colors.push_back(SK_ColorTRANSPARENT);
|
| - } else if (stops.front().stop > 0) {
|
| + } else if (m_stops.front().stop > 0) {
|
| // Copy the first stop to 0.0. The first stop position may have a slight
|
| // rounding error, but we don't care in this float comparison, since
|
| // 0.0 comes through cleanly and people aren't likely to want a gradient
|
| // with a stop at (0 + epsilon).
|
| pos.push_back(WebCoreFloatToSkScalar(0));
|
| - colors.push_back(makeSkColor(stops.front().color));
|
| + colors.push_back(makeSkColor(m_stops.front().color));
|
| }
|
|
|
| - for (const auto& stop : stops) {
|
| + for (const auto& stop : m_stops) {
|
| pos.push_back(WebCoreFloatToSkScalar(stop.stop));
|
| colors.push_back(makeSkColor(stop.color));
|
| }
|
| @@ -148,17 +121,17 @@ static void fillStops(const Vector<Gradient::ColorStop, 2>& stops,
|
| }
|
| }
|
|
|
| -sk_sp<PaintShader> Gradient::createShader(const SkMatrix& localMatrix) {
|
| +sk_sp<PaintShader> Gradient::createShaderInternal(const SkMatrix& localMatrix) {
|
| sortStopsIfNecessary();
|
| - ASSERT(m_stopsSorted);
|
| + DCHECK(m_stopsSorted);
|
|
|
| - ColorStopOffsetVector pos;
|
| - ColorStopColorVector colors;
|
| - pos.reserveCapacity(m_stops.size());
|
| + ColorBuffer colors;
|
| colors.reserveCapacity(m_stops.size());
|
| + OffsetBuffer pos;
|
| + pos.reserveCapacity(m_stops.size());
|
|
|
| - fillStops(m_stops, pos, colors);
|
| - DCHECK_GE(pos.size(), 2ul);
|
| + fillSkiaStops(colors, pos);
|
| + DCHECK_GE(colors.size(), 2ul);
|
| DCHECK_EQ(pos.size(), colors.size());
|
|
|
| SkShader::TileMode tile = SkShader::kClamp_TileMode;
|
| @@ -174,60 +147,132 @@ sk_sp<PaintShader> Gradient::createShader(const SkMatrix& localMatrix) {
|
| break;
|
| }
|
|
|
| - sk_sp<SkShader> shader;
|
| uint32_t flags = m_colorInterpolation == ColorInterpolation::Premultiplied
|
| ? SkGradientShader::kInterpolateColorsInPremul_Flag
|
| : 0;
|
| - if (m_radial) {
|
| - SkMatrix adjustedLocalMatrix = localMatrix;
|
| + sk_sp<SkShader> shader = createShader(colors, pos, tile, flags, localMatrix);
|
| + if (!shader) {
|
| + // use last color, since our "geometry" was degenerate (e.g. radius==0)
|
| + shader = SkShader::MakeColorShader(colors.back());
|
| + }
|
| +
|
| + return WrapSkShader(std::move(shader));
|
| +}
|
| +
|
| +void Gradient::applyToFlags(PaintFlags& flags, const SkMatrix& localMatrix) {
|
| + if (!m_cachedShader || localMatrix != m_cachedShader->getLocalMatrix())
|
| + m_cachedShader = createShaderInternal(localMatrix);
|
| +
|
| + flags.setShader(m_cachedShader);
|
|
|
| + // Legacy behavior: gradients are always dithered.
|
| + flags.setDither(true);
|
| +}
|
| +
|
| +namespace {
|
| +
|
| +class LinearGradient final : public Gradient {
|
| + public:
|
| + LinearGradient(const FloatPoint& p0,
|
| + const FloatPoint& p1,
|
| + GradientSpreadMethod spreadMethod,
|
| + ColorInterpolation interpolation)
|
| + : Gradient(Type::Linear, spreadMethod, interpolation),
|
| + m_p0(p0),
|
| + m_p1(p1) {}
|
| +
|
| + protected:
|
| + sk_sp<SkShader> createShader(const ColorBuffer& colors,
|
| + const OffsetBuffer& pos,
|
| + SkShader::TileMode tileMode,
|
| + uint32_t flags,
|
| + const SkMatrix& localMatrix) const override {
|
| + SkPoint pts[2] = {m_p0.data(), m_p1.data()};
|
| + return SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
|
| + static_cast<int>(colors.size()),
|
| + tileMode, flags, &localMatrix);
|
| + }
|
| +
|
| + private:
|
| + FloatPoint m_p0;
|
| + FloatPoint m_p1;
|
| +};
|
| +
|
| +class RadialGradient final : public Gradient {
|
| + public:
|
| + RadialGradient(const FloatPoint& p0,
|
| + float r0,
|
| + const FloatPoint& p1,
|
| + float r1,
|
| + float aspectRatio,
|
| + GradientSpreadMethod spreadMethod,
|
| + ColorInterpolation interpolation)
|
| + : Gradient(Type::Radial, spreadMethod, interpolation),
|
| + m_p0(p0),
|
| + m_p1(p1),
|
| + m_r0(r0),
|
| + m_r1(r1),
|
| + m_aspectRatio(aspectRatio) {}
|
| +
|
| + protected:
|
| + sk_sp<SkShader> createShader(const ColorBuffer& colors,
|
| + const OffsetBuffer& pos,
|
| + SkShader::TileMode tileMode,
|
| + uint32_t flags,
|
| + const SkMatrix& localMatrix) const override {
|
| + SkTCopyOnFirstWrite<SkMatrix> adjustedLocalMatrix(localMatrix);
|
| if (m_aspectRatio != 1) {
|
| // CSS3 elliptical gradients: apply the elliptical scaling at the
|
| // gradient center point.
|
| - adjustedLocalMatrix.preTranslate(m_p0.x(), m_p0.y());
|
| - adjustedLocalMatrix.preScale(1, 1 / m_aspectRatio);
|
| - adjustedLocalMatrix.preTranslate(-m_p0.x(), -m_p0.y());
|
| - ASSERT(m_p0 == m_p1);
|
| + DCHECK(m_p0 == m_p1);
|
| + adjustedLocalMatrix.writable()->preScale(1, 1 / m_aspectRatio, m_p0.x(),
|
| + m_p0.y());
|
| }
|
|
|
| // Since the two-point radial gradient is slower than the plain radial,
|
| // only use it if we have to.
|
| if (m_p0 == m_p1 && m_r0 <= 0.0f) {
|
| - shader = SkGradientShader::MakeRadial(
|
| - m_p1.data(), m_r1, colors.data(), pos.data(),
|
| - static_cast<int>(colors.size()), tile, flags, &adjustedLocalMatrix);
|
| - } else {
|
| - // The radii we give to Skia must be positive. If we're given a
|
| - // negative radius, ask for zero instead.
|
| - SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0;
|
| - SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0;
|
| - shader = SkGradientShader::MakeTwoPointConical(
|
| - m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(),
|
| - static_cast<int>(colors.size()), tile, flags, &adjustedLocalMatrix);
|
| + return SkGradientShader::MakeRadial(m_p1.data(), m_r1, colors.data(),
|
| + pos.data(),
|
| + static_cast<int>(colors.size()),
|
| + tileMode, flags, adjustedLocalMatrix);
|
| }
|
| - } else {
|
| - SkPoint pts[2] = {m_p0.data(), m_p1.data()};
|
| - shader = SkGradientShader::MakeLinear(pts, colors.data(), pos.data(),
|
| - static_cast<int>(colors.size()), tile,
|
| - flags, &localMatrix);
|
| - }
|
|
|
| - if (!shader) {
|
| - // use last color, since our "geometry" was degenerate (e.g. radius==0)
|
| - shader = SkShader::MakeColorShader(colors.back());
|
| + // The radii we give to Skia must be positive. If we're given a
|
| + // negative radius, ask for zero instead.
|
| + const SkScalar radius0 = std::max(WebCoreFloatToSkScalar(m_r0), 0.0f);
|
| + const SkScalar radius1 = std::max(WebCoreFloatToSkScalar(m_r1), 0.0f);
|
| + return SkGradientShader::MakeTwoPointConical(
|
| + m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(),
|
| + static_cast<int>(colors.size()), tileMode, flags, adjustedLocalMatrix);
|
| }
|
|
|
| - return WrapSkShader(shader);
|
| + private:
|
| + FloatPoint m_p0;
|
| + FloatPoint m_p1;
|
| + float m_r0;
|
| + float m_r1;
|
| + float m_aspectRatio; // For elliptical gradient, width / height.
|
| +};
|
| +
|
| +} // anonymous ns
|
| +
|
| +PassRefPtr<Gradient> Gradient::createLinear(const FloatPoint& p0,
|
| + const FloatPoint& p1,
|
| + GradientSpreadMethod spreadMethod,
|
| + ColorInterpolation interpolation) {
|
| + return adoptRef(new LinearGradient(p0, p1, spreadMethod, interpolation));
|
| }
|
|
|
| -void Gradient::applyToFlags(PaintFlags& flags, const SkMatrix& localMatrix) {
|
| - if (!m_cachedShader || localMatrix != m_cachedShader->getLocalMatrix())
|
| - m_cachedShader = createShader(localMatrix);
|
| -
|
| - flags.setShader(m_cachedShader);
|
| -
|
| - // Legacy behavior: gradients are always dithered.
|
| - flags.setDither(true);
|
| +PassRefPtr<Gradient> Gradient::createRadial(const FloatPoint& p0,
|
| + float r0,
|
| + const FloatPoint& p1,
|
| + float r1,
|
| + float aspectRatio,
|
| + GradientSpreadMethod spreadMethod,
|
| + ColorInterpolation interpolation) {
|
| + return adoptRef(new RadialGradient(p0, r0, p1, r1, aspectRatio, spreadMethod,
|
| + interpolation));
|
| }
|
|
|
| } // namespace blink
|
|
|