| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. | 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> | 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> |
| 4 * Copyright (C) 2013 Google Inc. All rights reserved. | 4 * Copyright (C) 2013 Google Inc. All rights reserved. |
| 5 * | 5 * |
| 6 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
| 7 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
| 8 * are met: | 8 * are met: |
| 9 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
| 10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 26 */ | 26 */ |
| 27 | 27 |
| 28 #include "platform/graphics/Gradient.h" | 28 #include "platform/graphics/Gradient.h" |
| 29 | 29 |
| 30 #include "platform/geometry/FloatRect.h" | 30 #include "platform/geometry/FloatRect.h" |
| 31 #include "platform/graphics/GraphicsContext.h" | 31 #include "platform/graphics/GraphicsContext.h" |
| 32 #include "platform/graphics/skia/SkiaUtils.h" | 32 #include "platform/graphics/skia/SkiaUtils.h" |
| 33 #include "third_party/skia/include/core/SkColor.h" | 33 #include "third_party/skia/include/core/SkColor.h" |
| 34 #include "third_party/skia/include/core/SkMatrix.h" |
| 34 #include "third_party/skia/include/core/SkShader.h" | 35 #include "third_party/skia/include/core/SkShader.h" |
| 35 #include "third_party/skia/include/effects/SkGradientShader.h" | 36 #include "third_party/skia/include/effects/SkGradientShader.h" |
| 36 #include <algorithm> | 37 #include <algorithm> |
| 37 | 38 |
| 38 typedef Vector<SkScalar, 8> ColorStopOffsetVector; | 39 typedef Vector<SkScalar, 8> ColorStopOffsetVector; |
| 39 typedef Vector<SkColor, 8> ColorStopColorVector; | 40 typedef Vector<SkColor, 8> ColorStopColorVector; |
| 40 | 41 |
| 41 namespace blink { | 42 namespace blink { |
| 42 | 43 |
| 43 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1) | 44 Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1) |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 77 | 78 |
| 78 void Gradient::addColorStop(const Gradient::ColorStop& stop) | 79 void Gradient::addColorStop(const Gradient::ColorStop& stop) |
| 79 { | 80 { |
| 80 if (m_stops.isEmpty()) { | 81 if (m_stops.isEmpty()) { |
| 81 m_stopsSorted = true; | 82 m_stopsSorted = true; |
| 82 } else { | 83 } else { |
| 83 m_stopsSorted = m_stopsSorted && compareStops(m_stops.last(), stop); | 84 m_stopsSorted = m_stopsSorted && compareStops(m_stops.last(), stop); |
| 84 } | 85 } |
| 85 | 86 |
| 86 m_stops.append(stop); | 87 m_stops.append(stop); |
| 87 m_gradient.reset(); | 88 m_cachedShader.reset(); |
| 88 } | 89 } |
| 89 | 90 |
| 90 void Gradient::sortStopsIfNecessary() | 91 void Gradient::sortStopsIfNecessary() |
| 91 { | 92 { |
| 92 if (m_stopsSorted) | 93 if (m_stopsSorted) |
| 93 return; | 94 return; |
| 94 | 95 |
| 95 m_stopsSorted = true; | 96 m_stopsSorted = true; |
| 96 | 97 |
| 97 if (!m_stops.size()) | 98 if (!m_stops.size()) |
| 98 return; | 99 return; |
| 99 | 100 |
| 100 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); | 101 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); |
| 101 } | 102 } |
| 102 | 103 |
| 103 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod) | 104 void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod) |
| 104 { | 105 { |
| 105 // FIXME: Should it become necessary, allow calls to this method after m_gra
dient has been set. | 106 // FIXME: Should it become necessary, allow calls to this method after m_gra
dient has been set. |
| 106 ASSERT(!m_gradient); | 107 DCHECK(!m_cachedShader); |
| 107 | 108 |
| 108 if (m_spreadMethod == spreadMethod) | 109 if (m_spreadMethod == spreadMethod) |
| 109 return; | 110 return; |
| 110 | 111 |
| 111 m_spreadMethod = spreadMethod; | 112 m_spreadMethod = spreadMethod; |
| 112 } | 113 } |
| 113 | 114 |
| 114 void Gradient::setDrawsInPMColorSpace(bool drawInPMColorSpace) | 115 void Gradient::setDrawsInPMColorSpace(bool drawInPMColorSpace) |
| 115 { | 116 { |
| 116 if (drawInPMColorSpace == m_drawInPMColorSpace) | 117 if (drawInPMColorSpace == m_drawInPMColorSpace) |
| 117 return; | 118 return; |
| 118 | 119 |
| 119 m_drawInPMColorSpace = drawInPMColorSpace; | 120 m_drawInPMColorSpace = drawInPMColorSpace; |
| 120 m_gradient.reset(); | 121 m_cachedShader.reset(); |
| 121 } | |
| 122 | |
| 123 void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTra
nsformation) | |
| 124 { | |
| 125 if (m_gradientSpaceTransformation == gradientSpaceTransformation) | |
| 126 return; | |
| 127 | |
| 128 m_gradientSpaceTransformation = gradientSpaceTransformation; | |
| 129 m_gradient.reset(); | |
| 130 } | 122 } |
| 131 | 123 |
| 132 // Determine the total number of stops needed, including pseudo-stops at the | 124 // Determine the total number of stops needed, including pseudo-stops at the |
| 133 // ends as necessary. | 125 // ends as necessary. |
| 134 static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count
) | 126 static size_t totalStopsNeeded(const Gradient::ColorStop* stopData, size_t count
) |
| 135 { | 127 { |
| 136 // N.B.: The tests in this function should kept in sync with the ones in | 128 // N.B.: The tests in this function should kept in sync with the ones in |
| 137 // fillStops(), or badness happens. | 129 // fillStops(), or badness happens. |
| 138 const Gradient::ColorStop* stop = stopData; | 130 const Gradient::ColorStop* stop = stopData; |
| 139 size_t countUsed = count; | 131 size_t countUsed = count; |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 182 } | 174 } |
| 183 | 175 |
| 184 // Copy the last stop to 1.0 if needed. See comment above about this float | 176 // Copy the last stop to 1.0 if needed. See comment above about this float |
| 185 // comparison. | 177 // comparison. |
| 186 if (count < 1 || (--stop)->stop < 1.0) { | 178 if (count < 1 || (--stop)->stop < 1.0) { |
| 187 pos[start + count] = WebCoreFloatToSkScalar(1.0); | 179 pos[start + count] = WebCoreFloatToSkScalar(1.0); |
| 188 colors[start + count] = colors[start + count - 1]; | 180 colors[start + count] = colors[start + count - 1]; |
| 189 } | 181 } |
| 190 } | 182 } |
| 191 | 183 |
| 192 sk_sp<SkShader> Gradient::createShader() | 184 sk_sp<SkShader> Gradient::createShader(const SkMatrix& localMatrix) |
| 193 { | 185 { |
| 194 sortStopsIfNecessary(); | 186 sortStopsIfNecessary(); |
| 195 ASSERT(m_stopsSorted); | 187 ASSERT(m_stopsSorted); |
| 196 | 188 |
| 197 size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size()); | 189 size_t countUsed = totalStopsNeeded(m_stops.data(), m_stops.size()); |
| 198 ASSERT(countUsed >= 2); | 190 ASSERT(countUsed >= 2); |
| 199 ASSERT(countUsed >= m_stops.size()); | 191 ASSERT(countUsed >= m_stops.size()); |
| 200 | 192 |
| 201 ColorStopOffsetVector pos(countUsed); | 193 ColorStopOffsetVector pos(countUsed); |
| 202 ColorStopColorVector colors(countUsed); | 194 ColorStopColorVector colors(countUsed); |
| 203 fillStops(m_stops.data(), m_stops.size(), pos, colors); | 195 fillStops(m_stops.data(), m_stops.size(), pos, colors); |
| 204 | 196 |
| 205 SkShader::TileMode tile = SkShader::kClamp_TileMode; | 197 SkShader::TileMode tile = SkShader::kClamp_TileMode; |
| 206 switch (m_spreadMethod) { | 198 switch (m_spreadMethod) { |
| 207 case SpreadMethodReflect: | 199 case SpreadMethodReflect: |
| 208 tile = SkShader::kMirror_TileMode; | 200 tile = SkShader::kMirror_TileMode; |
| 209 break; | 201 break; |
| 210 case SpreadMethodRepeat: | 202 case SpreadMethodRepeat: |
| 211 tile = SkShader::kRepeat_TileMode; | 203 tile = SkShader::kRepeat_TileMode; |
| 212 break; | 204 break; |
| 213 case SpreadMethodPad: | 205 case SpreadMethodPad: |
| 214 tile = SkShader::kClamp_TileMode; | 206 tile = SkShader::kClamp_TileMode; |
| 215 break; | 207 break; |
| 216 } | 208 } |
| 217 | 209 |
| 218 sk_sp<SkShader> shader; | 210 sk_sp<SkShader> shader; |
| 219 uint32_t shouldDrawInPMColorSpace = m_drawInPMColorSpace ? SkGradientShader:
:kInterpolateColorsInPremul_Flag : 0; | 211 uint32_t shouldDrawInPMColorSpace = m_drawInPMColorSpace ? SkGradientShader:
:kInterpolateColorsInPremul_Flag : 0; |
| 220 if (m_radial) { | 212 if (m_radial) { |
| 221 if (aspectRatio() != 1) { | 213 SkMatrix adjustedLocalMatrix = localMatrix; |
| 214 |
| 215 if (m_aspectRatio != 1) { |
| 222 // CSS3 elliptical gradients: apply the elliptical scaling at the | 216 // CSS3 elliptical gradients: apply the elliptical scaling at the |
| 223 // gradient center point. | 217 // gradient center point. |
| 224 m_gradientSpaceTransformation.translate(m_p0.x(), m_p0.y()); | 218 adjustedLocalMatrix.preTranslate(m_p0.x(), m_p0.y()); |
| 225 m_gradientSpaceTransformation.scale(1, 1 / aspectRatio()); | 219 adjustedLocalMatrix.preScale(1, 1 / m_aspectRatio); |
| 226 m_gradientSpaceTransformation.translate(-m_p0.x(), -m_p0.y()); | 220 adjustedLocalMatrix.preTranslate(-m_p0.x(), -m_p0.y()); |
| 227 ASSERT(m_p0 == m_p1); | 221 ASSERT(m_p0 == m_p1); |
| 228 } | 222 } |
| 229 SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransfor
mation); | |
| 230 | 223 |
| 231 // Since the two-point radial gradient is slower than the plain radial, | 224 // Since the two-point radial gradient is slower than the plain radial, |
| 232 // only use it if we have to. | 225 // only use it if we have to. |
| 233 if (m_p0 == m_p1 && m_r0 <= 0.0f) { | 226 if (m_p0 == m_p1 && m_r0 <= 0.0f) { |
| 234 shader = SkGradientShader::MakeRadial(m_p1.data(), m_r1, colors.data
(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &lo
calMatrix); | 227 shader = SkGradientShader::MakeRadial(m_p1.data(), m_r1, colors.data
(), pos.data(), |
| 228 static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &ad
justedLocalMatrix); |
| 235 } else { | 229 } else { |
| 236 // The radii we give to Skia must be positive. If we're given a | 230 // The radii we give to Skia must be positive. If we're given a |
| 237 // negative radius, ask for zero instead. | 231 // negative radius, ask for zero instead. |
| 238 SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; | 232 SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; |
| 239 SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; | 233 SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; |
| 240 shader = SkGradientShader::MakeTwoPointConical(m_p0.data(), radius0,
m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), t
ile, shouldDrawInPMColorSpace, &localMatrix); | 234 shader = SkGradientShader::MakeTwoPointConical(m_p0.data(), radius0,
m_p1.data(), |
| 235 radius1, colors.data(), pos.data(), static_cast<int>(countUsed),
tile, |
| 236 shouldDrawInPMColorSpace, &adjustedLocalMatrix); |
| 241 } | 237 } |
| 242 } else { | 238 } else { |
| 243 SkPoint pts[2] = { m_p0.data(), m_p1.data() }; | 239 SkPoint pts[2] = { m_p0.data(), m_p1.data() }; |
| 244 SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransfor
mation); | 240 shader = SkGradientShader::MakeLinear(pts, colors.data(), pos.data(), |
| 245 shader = SkGradientShader::MakeLinear(pts, colors.data(), pos.data(), st
atic_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix); | 241 static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localM
atrix); |
| 246 } | 242 } |
| 247 | 243 |
| 248 if (!shader) { | 244 if (!shader) { |
| 249 // use last color, since our "geometry" was degenerate (e.g. radius==0) | 245 // use last color, since our "geometry" was degenerate (e.g. radius==0) |
| 250 shader = SkShader::MakeColorShader(colors[countUsed - 1]); | 246 shader = SkShader::MakeColorShader(colors[countUsed - 1]); |
| 251 } | 247 } |
| 252 | 248 |
| 253 return shader; | 249 return shader; |
| 254 } | 250 } |
| 255 | 251 |
| 256 void Gradient::applyToPaint(SkPaint& paint) | 252 void Gradient::applyToPaint(SkPaint& paint, const SkMatrix& localMatrix) |
| 257 { | 253 { |
| 258 if (!m_gradient) | 254 if (!m_cachedShader || localMatrix != m_cachedShader->getLocalMatrix()) |
| 259 m_gradient = createShader(); | 255 m_cachedShader = createShader(localMatrix); |
| 260 | 256 |
| 261 paint.setShader(m_gradient); | 257 paint.setShader(m_cachedShader); |
| 262 | 258 |
| 263 // Legacy behavior: gradients are always dithered. | 259 // Legacy behavior: gradients are always dithered. |
| 264 paint.setDither(true); | 260 paint.setDither(true); |
| 265 } | 261 } |
| 266 | 262 |
| 267 } // namespace blink | 263 } // namespace blink |
| OLD | NEW |