1 /* 2 * Copyright (C) 2008 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "CSSGradientValue.h" 28 29 #include "CSSStyleSelector.h" 30 #include "GeneratedImage.h" 31 #include "Gradient.h" 32 #include "Image.h" 33 #include "IntSize.h" 34 #include "IntSizeHash.h" 35 #include "PlatformString.h" 36 #include "RenderObject.h" 37 38 using namespace std; 39 40 namespace WebCore { 41 42 String CSSGradientValue::cssText() const 43 { 44 String result = "-webkit-gradient("; 45 if (m_type == CSSLinearGradient) 46 result += "linear, "; 47 else 48 result += "radial, "; 49 result += m_firstX->cssText() + " "; 50 result += m_firstY->cssText() + ", "; 51 if (m_type == CSSRadialGradient) 52 result += m_firstRadius->cssText() + ", "; 53 result += m_secondX->cssText() + " "; 54 result += m_secondY->cssText(); 55 if (m_type == CSSRadialGradient) { 56 result += ", "; 57 result += m_secondRadius->cssText(); 58 } 59 for (unsigned i = 0; i < m_stops.size(); i++) { 60 result += ", "; 61 if (m_stops[i].m_stop == 0) 62 result += "from(" + m_stops[i].m_color->cssText() + ")"; 63 else if (m_stops[i].m_stop == 1) 64 result += "to(" + m_stops[i].m_color->cssText() + ")"; 65 else 66 result += "color-stop(" + String::number(m_stops[i].m_stop) + ", " + m_stops[i].m_color->cssText() + ")"; 67 } 68 result += ")"; 69 return result; 70 } 71 72 PassRefPtr<Gradient> CSSGradientValue::createGradient(RenderObject* renderer, const IntSize& size) 73 { 74 ASSERT(!size.isEmpty()); 75 76 float zoomFactor = renderer->style()->effectiveZoom(); 77 78 FloatPoint firstPoint = resolvePoint(m_firstX.get(), m_firstY.get(), size, zoomFactor); 79 FloatPoint secondPoint = resolvePoint(m_secondX.get(), m_secondY.get(), size, zoomFactor); 80 81 RefPtr<Gradient> gradient; 82 if (m_type == CSSLinearGradient) 83 gradient = Gradient::create(firstPoint, secondPoint); 84 else { 85 float firstRadius = resolveRadius(m_firstRadius.get(), zoomFactor); 86 float secondRadius = resolveRadius(m_secondRadius.get(), zoomFactor); 87 gradient = Gradient::create(firstPoint, firstRadius, secondPoint, secondRadius); 88 } 89 90 // Now add the stops. 91 sortStopsIfNeeded(); 92 93 // We have to resolve colors. 94 for (unsigned i = 0; i < m_stops.size(); i++) { 95 Color color = renderer->document()->styleSelector()->getColorFromPrimitiveValue(m_stops[i].m_color.get()); 96 gradient->addColorStop(m_stops[i].m_stop, color); 97 } 98 99 // The back end already sorted the stops. 100 gradient->setStopsSorted(true); 101 102 return gradient.release(); 103 } 104 105 Image* CSSGradientValue::image(RenderObject* renderer, const IntSize& size) 106 { 107 ASSERT(m_clients.contains(renderer)); 108 109 // Need to look up our size. Create a string of width*height to use as a hash key. 110 Image* result = getImage(renderer, size); 111 if (result) 112 return result; 113 114 if (size.isEmpty()) 115 return 0; 116 117 // We need to create an image. 118 RefPtr<Image> newImage = GeneratedImage::create(createGradient(renderer, size), size); 119 result = newImage.get(); 120 putImage(size, newImage.release()); 121 122 return result; 123 } 124 125 static inline bool compareStops(const CSSGradientColorStop& a, const CSSGradientColorStop& b) 126 { 127 return a.m_stop < b.m_stop; 128 } 129 130 void CSSGradientValue::sortStopsIfNeeded() 131 { 132 if (!m_stopsSorted) { 133 if (m_stops.size()) 134 std::stable_sort(m_stops.begin(), m_stops.end(), compareStops); 135 m_stopsSorted = true; 136 } 137 } 138 139 FloatPoint CSSGradientValue::resolvePoint(CSSPrimitiveValue* first, CSSPrimitiveValue* second, const IntSize& size, float zoomFactor) 140 { 141 FloatPoint result; 142 if (first->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) 143 result.setX(first->getFloatValue() * zoomFactor); 144 else if (first->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) 145 result.setX(first->getFloatValue() / 100.f * size.width()); 146 if (second->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) 147 result.setY(second->getFloatValue() * zoomFactor); 148 else if (second->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) 149 result.setY(second->getFloatValue() / 100.f * size.height()); 150 151 return result; 152 } 153 154 float CSSGradientValue::resolveRadius(CSSPrimitiveValue* radius, float zoomFactor) 155 { 156 float result = 0.f; 157 if (radius->primitiveType() == CSSPrimitiveValue::CSS_NUMBER) 158 result = radius->getFloatValue() * zoomFactor; 159 return result; 160 } 161 162 } // namespace WebCore 163