1/* 2 * Copyright (C) 2006, 2007, 2008, 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "Gradient.h" 29 30#include "Color.h" 31#include "FloatRect.h" 32#include <wtf/HashFunctions.h> 33#include <wtf/StringHasher.h> 34 35using WTF::pairIntHash; 36 37namespace WebCore { 38 39Gradient::Gradient(const FloatPoint& p0, const FloatPoint& p1) 40 : m_radial(false) 41 , m_p0(p0) 42 , m_p1(p1) 43 , m_r0(0) 44 , m_r1(0) 45 , m_aspectRatio(1) 46 , m_stopsSorted(false) 47 , m_spreadMethod(SpreadMethodPad) 48 , m_cachedHash(0) 49{ 50 platformInit(); 51} 52 53Gradient::Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio) 54 : m_radial(true) 55 , m_p0(p0) 56 , m_p1(p1) 57 , m_r0(r0) 58 , m_r1(r1) 59 , m_aspectRatio(aspectRatio) 60 , m_stopsSorted(false) 61 , m_spreadMethod(SpreadMethodPad) 62 , m_cachedHash(0) 63{ 64 platformInit(); 65} 66 67Gradient::~Gradient() 68{ 69 platformDestroy(); 70} 71 72void Gradient::adjustParametersForTiledDrawing(FloatSize& size, FloatRect& srcRect) 73{ 74 if (m_radial) 75 return; 76 77 if (srcRect.isEmpty()) 78 return; 79 80 if (m_p0.x() == m_p1.x()) { 81 size.setWidth(1); 82 srcRect.setWidth(1); 83 srcRect.setX(0); 84 return; 85 } 86 if (m_p0.y() != m_p1.y()) 87 return; 88 89 size.setHeight(1); 90 srcRect.setHeight(1); 91 srcRect.setY(0); 92} 93 94void Gradient::addColorStop(float value, const Color& color) 95{ 96 float r; 97 float g; 98 float b; 99 float a; 100 color.getRGBA(r, g, b, a); 101 m_stops.append(ColorStop(value, r, g, b, a)); 102 103 m_stopsSorted = false; 104 platformDestroy(); 105 106 invalidateHash(); 107} 108 109void Gradient::addColorStop(const Gradient::ColorStop& stop) 110{ 111 m_stops.append(stop); 112 113 m_stopsSorted = false; 114 platformDestroy(); 115 116 invalidateHash(); 117} 118 119static inline bool compareStops(const Gradient::ColorStop& a, const Gradient::ColorStop& b) 120{ 121 return a.stop < b.stop; 122} 123 124void Gradient::sortStopsIfNecessary() 125{ 126 if (m_stopsSorted) 127 return; 128 129 m_stopsSorted = true; 130 131 if (!m_stops.size()) 132 return; 133 134 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); 135 136 invalidateHash(); 137} 138 139bool Gradient::hasAlpha() const 140{ 141 for (size_t i = 0; i < m_stops.size(); i++) { 142 if (m_stops[i].alpha < 1) 143 return true; 144 } 145 146 return false; 147} 148 149void Gradient::setSpreadMethod(GradientSpreadMethod spreadMethod) 150{ 151 // FIXME: Should it become necessary, allow calls to this method after m_gradient has been set. 152 ASSERT(m_gradient == 0); 153 154 if (m_spreadMethod == spreadMethod) 155 return; 156 157 m_spreadMethod = spreadMethod; 158 159 invalidateHash(); 160} 161 162void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation) 163{ 164 if (m_gradientSpaceTransformation == gradientSpaceTransformation) 165 return; 166 167 m_gradientSpaceTransformation = gradientSpaceTransformation; 168 setPlatformGradientSpaceTransform(gradientSpaceTransformation); 169 170 invalidateHash(); 171} 172 173#if !USE(CAIRO) 174void Gradient::setPlatformGradientSpaceTransform(const AffineTransform&) 175{ 176} 177#endif 178 179unsigned Gradient::hash() const 180{ 181 if (m_cachedHash) 182 return m_cachedHash; 183 184 struct { 185 AffineTransform gradientSpaceTransformation; 186 FloatPoint p0; 187 FloatPoint p1; 188 float r0; 189 float r1; 190 float aspectRatio; 191 GradientSpreadMethod spreadMethod; 192 bool radial; 193 } parameters; 194 195 // StringHasher requires that the memory it hashes be a multiple of two in size. 196 COMPILE_ASSERT(!(sizeof(parameters) % 2), Gradient_parameters_size_should_be_multiple_of_two); 197 COMPILE_ASSERT(!(sizeof(ColorStop) % 2), Color_stop_size_should_be_multiple_of_two); 198 199 // Ensure that any padding in the struct is zero-filled, so it will not affect the hash value. 200 memset(¶meters, 0, sizeof(parameters)); 201 202 parameters.gradientSpaceTransformation = m_gradientSpaceTransformation; 203 parameters.p0 = m_p0; 204 parameters.p1 = m_p1; 205 parameters.r0 = m_r0; 206 parameters.r1 = m_r1; 207 parameters.aspectRatio = m_aspectRatio; 208 parameters.spreadMethod = m_spreadMethod; 209 parameters.radial = m_radial; 210 211 unsigned parametersHash = StringHasher::hashMemory(¶meters, sizeof(parameters)); 212 unsigned stopHash = StringHasher::hashMemory(m_stops.data(), m_stops.size() * sizeof(ColorStop)); 213 214 m_cachedHash = pairIntHash(parametersHash, stopHash); 215 216 return m_cachedHash; 217} 218 219} //namespace 220