|
1 /* |
|
2 * Copyright (C) 2009 Apple Inc. |
|
3 * Copyright (C) 2009 Google Inc. |
|
4 * All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions |
|
8 * are met: |
|
9 * 1. Redistributions of source code must retain the above copyright |
|
10 * notice, this list of conditions and the following disclaimer. |
|
11 * 2. Redistributions in binary form must reproduce the above copyright |
|
12 * notice, this list of conditions and the following disclaimer in the |
|
13 * documentation and/or other materials provided with the distribution. |
|
14 * |
|
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
|
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
|
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
|
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
|
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
|
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
|
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
|
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
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. |
|
26 */ |
|
27 |
|
28 #include "config.h" |
|
29 #include "RenderMediaControlsChromium.h" |
|
30 |
|
31 #include "Gradient.h" |
|
32 #include "GraphicsContext.h" |
|
33 #include "HTMLMediaElement.h" |
|
34 #include "HTMLNames.h" |
|
35 |
|
36 namespace WebCore { |
|
37 |
|
38 #if ENABLE(VIDEO) |
|
39 |
|
40 typedef WTF::HashMap<const char*, Image*> MediaControlImageMap; |
|
41 static MediaControlImageMap* gMediaControlImageMap = 0; |
|
42 |
|
43 static Image* platformResource(const char* name) |
|
44 { |
|
45 if (!gMediaControlImageMap) |
|
46 gMediaControlImageMap = new MediaControlImageMap(); |
|
47 if (Image* image = gMediaControlImageMap->get(name)) |
|
48 return image; |
|
49 if (Image* image = Image::loadPlatformResource(name).releaseRef()) { |
|
50 gMediaControlImageMap->set(name, image); |
|
51 return image; |
|
52 } |
|
53 ASSERT_NOT_REACHED(); |
|
54 return 0; |
|
55 } |
|
56 |
|
57 static bool hasSource(const HTMLMediaElement* mediaElement) |
|
58 { |
|
59 return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY |
|
60 && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE; |
|
61 } |
|
62 |
|
63 static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image) |
|
64 { |
|
65 IntRect imageRect = image->rect(); |
|
66 context->drawImage(image, DeviceColorSpace, rect); |
|
67 return true; |
|
68 } |
|
69 |
|
70 static bool paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
71 { |
|
72 HTMLMediaElement* mediaElement = toParentMediaElement(object); |
|
73 if (!mediaElement) |
|
74 return false; |
|
75 |
|
76 static Image* soundFull = platformResource("mediaSoundFull"); |
|
77 static Image* soundNone = platformResource("mediaSoundNone"); |
|
78 static Image* soundDisabled = platformResource("mediaSoundDisabled"); |
|
79 |
|
80 if (!hasSource(mediaElement) || !mediaElement->hasAudio()) |
|
81 return paintMediaButton(paintInfo.context, rect, soundDisabled); |
|
82 |
|
83 return paintMediaButton(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull); |
|
84 } |
|
85 |
|
86 static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
87 { |
|
88 HTMLMediaElement* mediaElement = toParentMediaElement(object); |
|
89 if (!mediaElement) |
|
90 return false; |
|
91 |
|
92 static Image* mediaPlay = platformResource("mediaPlay"); |
|
93 static Image* mediaPause = platformResource("mediaPause"); |
|
94 static Image* mediaPlayDisabled = platformResource("mediaPlayDisabled"); |
|
95 |
|
96 if (!hasSource(mediaElement)) |
|
97 return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled); |
|
98 |
|
99 return paintMediaButton(paintInfo.context, rect, mediaElement->paused() ? mediaPlay : mediaPause); |
|
100 } |
|
101 |
|
102 static Image* getMediaSliderThumb() |
|
103 { |
|
104 static Image* mediaSliderThumb = platformResource("mediaSliderThumb"); |
|
105 return mediaSliderThumb; |
|
106 } |
|
107 |
|
108 static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
109 { |
|
110 HTMLMediaElement* mediaElement = toParentMediaElement(object); |
|
111 if (!mediaElement) |
|
112 return false; |
|
113 |
|
114 RenderStyle* style = object->style(); |
|
115 GraphicsContext* context = paintInfo.context; |
|
116 |
|
117 // Draw the border of the time bar. |
|
118 // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first. |
|
119 // https://bugs.webkit.org/show_bug.cgi?id=30143 |
|
120 context->save(); |
|
121 context->setShouldAntialias(true); |
|
122 context->setStrokeStyle(SolidStroke); |
|
123 context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), DeviceColorSpace); |
|
124 context->setStrokeThickness(style->borderLeftWidth()); |
|
125 context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), DeviceColorSpace); |
|
126 context->drawRect(rect); |
|
127 context->restore(); |
|
128 |
|
129 // Draw the buffered ranges. |
|
130 // FIXME: Draw multiple ranges if there are multiple buffered ranges. |
|
131 IntRect bufferedRect = rect; |
|
132 bufferedRect.inflate(-style->borderLeftWidth()); |
|
133 |
|
134 double bufferedWidth = 0.0; |
|
135 if (mediaElement->percentLoaded() > 0.0) { |
|
136 // Account for the width of the slider thumb. |
|
137 Image* mediaSliderThumb = getMediaSliderThumb(); |
|
138 double thumbWidth = mediaSliderThumb->width() / 2.0 + 1.0; |
|
139 double rectWidth = bufferedRect.width() - thumbWidth; |
|
140 if (rectWidth < 0.0) |
|
141 rectWidth = 0.0; |
|
142 bufferedWidth = rectWidth * mediaElement->percentLoaded() + thumbWidth; |
|
143 } |
|
144 bufferedRect.setWidth(bufferedWidth); |
|
145 |
|
146 // Don't bother drawing an empty area. |
|
147 if (!bufferedRect.isEmpty()) { |
|
148 IntPoint sliderTopLeft = bufferedRect.location(); |
|
149 IntPoint sliderTopRight = sliderTopLeft; |
|
150 sliderTopRight.move(0, bufferedRect.height()); |
|
151 |
|
152 RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); |
|
153 Color startColor = object->style()->visitedDependentColor(CSSPropertyColor); |
|
154 gradient->addColorStop(0.0, startColor); |
|
155 gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); |
|
156 |
|
157 context->save(); |
|
158 context->setStrokeStyle(NoStroke); |
|
159 context->setFillGradient(gradient); |
|
160 context->fillRect(bufferedRect); |
|
161 context->restore(); |
|
162 } |
|
163 |
|
164 return true; |
|
165 } |
|
166 |
|
167 static bool paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
168 { |
|
169 if (!object->parent()->isSlider()) |
|
170 return false; |
|
171 |
|
172 HTMLMediaElement* mediaElement = toParentMediaElement(object->parent()); |
|
173 if (!mediaElement) |
|
174 return false; |
|
175 |
|
176 if (!hasSource(mediaElement)) |
|
177 return true; |
|
178 |
|
179 Image* mediaSliderThumb = getMediaSliderThumb(); |
|
180 return paintMediaButton(paintInfo.context, rect, mediaSliderThumb); |
|
181 } |
|
182 |
|
183 static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
184 { |
|
185 HTMLMediaElement* mediaElement = toParentMediaElement(object); |
|
186 if (!mediaElement) |
|
187 return false; |
|
188 |
|
189 GraphicsContext* context = paintInfo.context; |
|
190 Color originalColor = context->strokeColor(); |
|
191 if (originalColor != Color::white) |
|
192 context->setStrokeColor(Color::white, DeviceColorSpace); |
|
193 |
|
194 int x = rect.x() + rect.width() / 2; |
|
195 context->drawLine(IntPoint(x, rect.y()), IntPoint(x, rect.y() + rect.height())); |
|
196 |
|
197 if (originalColor != Color::white) |
|
198 context->setStrokeColor(originalColor, DeviceColorSpace); |
|
199 return true; |
|
200 } |
|
201 |
|
202 static bool paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
203 { |
|
204 if (!object->parent()->isSlider()) |
|
205 return false; |
|
206 |
|
207 static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb"); |
|
208 return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb); |
|
209 } |
|
210 |
|
211 static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
212 { |
|
213 HTMLMediaElement* mediaElement = toParentMediaElement(object); |
|
214 if (!mediaElement) |
|
215 return false; |
|
216 |
|
217 if (!rect.isEmpty()) { |
|
218 GraphicsContext* context = paintInfo.context; |
|
219 Color originalColor = context->strokeColor(); |
|
220 float originalThickness = context->strokeThickness(); |
|
221 StrokeStyle originalStyle = context->strokeStyle(); |
|
222 |
|
223 context->setStrokeStyle(SolidStroke); |
|
224 |
|
225 // Draw the left border using CSS defined width and color. |
|
226 context->setStrokeThickness(object->style()->borderLeftWidth()); |
|
227 context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), DeviceColorSpace); |
|
228 context->drawLine(IntPoint(rect.x() + 1, rect.y()), |
|
229 IntPoint(rect.x() + 1, rect.y() + rect.height())); |
|
230 |
|
231 // Draw the right border using CSS defined width and color. |
|
232 context->setStrokeThickness(object->style()->borderRightWidth()); |
|
233 context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), DeviceColorSpace); |
|
234 context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()), |
|
235 IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height())); |
|
236 |
|
237 context->setStrokeColor(originalColor, DeviceColorSpace); |
|
238 context->setStrokeThickness(originalThickness); |
|
239 context->setStrokeStyle(originalStyle); |
|
240 } |
|
241 return true; |
|
242 } |
|
243 |
|
244 bool RenderMediaControlsChromium::shouldRenderMediaControlPart(ControlPart part, Element* e) |
|
245 { |
|
246 UNUSED_PARAM(e); |
|
247 |
|
248 switch (part) { |
|
249 case MediaMuteButtonPart: |
|
250 case MediaPlayButtonPart: |
|
251 case MediaSliderPart: |
|
252 case MediaSliderThumbPart: |
|
253 case MediaVolumeSliderContainerPart: |
|
254 case MediaVolumeSliderPart: |
|
255 case MediaVolumeSliderThumbPart: |
|
256 case MediaControlsBackgroundPart: |
|
257 case MediaCurrentTimePart: |
|
258 case MediaTimeRemainingPart: |
|
259 return true; |
|
260 default: |
|
261 ; |
|
262 } |
|
263 return false; |
|
264 } |
|
265 |
|
266 bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) |
|
267 { |
|
268 switch (part) { |
|
269 case MediaMuteButton: |
|
270 case MediaUnMuteButton: |
|
271 return paintMediaMuteButton(object, paintInfo, rect); |
|
272 case MediaPauseButton: |
|
273 case MediaPlayButton: |
|
274 return paintMediaPlayButton(object, paintInfo, rect); |
|
275 case MediaSlider: |
|
276 return paintMediaSlider(object, paintInfo, rect); |
|
277 case MediaSliderThumb: |
|
278 return paintMediaSliderThumb(object, paintInfo, rect); |
|
279 case MediaVolumeSlider: |
|
280 return paintMediaVolumeSlider(object, paintInfo, rect); |
|
281 case MediaVolumeSliderThumb: |
|
282 return paintMediaVolumeSliderThumb(object, paintInfo, rect); |
|
283 case MediaTimelineContainer: |
|
284 return paintMediaTimelineContainer(object, paintInfo, rect); |
|
285 case MediaVolumeSliderMuteButton: |
|
286 case MediaFullscreenButton: |
|
287 case MediaSeekBackButton: |
|
288 case MediaSeekForwardButton: |
|
289 case MediaVolumeSliderContainer: |
|
290 case MediaCurrentTimeDisplay: |
|
291 case MediaTimeRemainingDisplay: |
|
292 case MediaControlsPanel: |
|
293 case MediaRewindButton: |
|
294 case MediaReturnToRealtimeButton: |
|
295 case MediaStatusDisplay: |
|
296 case MediaShowClosedCaptionsButton: |
|
297 case MediaHideClosedCaptionsButton: |
|
298 ASSERT_NOT_REACHED(); |
|
299 break; |
|
300 } |
|
301 return false; |
|
302 } |
|
303 |
|
304 void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderObject* object) |
|
305 { |
|
306 static Image* mediaSliderThumb = platformResource("mediaSliderThumb"); |
|
307 static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb"); |
|
308 |
|
309 Image* thumbImage = 0; |
|
310 if (object->style()->appearance() == MediaSliderThumbPart) |
|
311 thumbImage = mediaSliderThumb; |
|
312 else if (object->style()->appearance() == MediaVolumeSliderThumbPart) |
|
313 thumbImage = mediaVolumeSliderThumb; |
|
314 |
|
315 float zoomLevel = object->style()->effectiveZoom(); |
|
316 if (thumbImage) { |
|
317 object->style()->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed)); |
|
318 object->style()->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed)); |
|
319 } |
|
320 } |
|
321 |
|
322 #endif // #if ENABLE(VIDEO) |
|
323 |
|
324 } // namespace WebCore |