|
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 |