e804771c05781ba265ae9bb9973e6b8d46279af6
[WebKit-https.git] / Source / WebCore / rendering / RenderMediaControlsChromium.cpp
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 #include "PaintInfo.h"
36
37 namespace WebCore {
38
39 #if ENABLE(VIDEO)
40
41 typedef WTF::HashMap<const char*, Image*> MediaControlImageMap;
42 static MediaControlImageMap* gMediaControlImageMap = 0;
43
44 static Image* platformResource(const char* name)
45 {
46     if (!gMediaControlImageMap)
47         gMediaControlImageMap = new MediaControlImageMap();
48     if (Image* image = gMediaControlImageMap->get(name))
49         return image;
50     if (Image* image = Image::loadPlatformResource(name).leakRef()) {
51         gMediaControlImageMap->set(name, image);
52         return image;
53     }
54     ASSERT_NOT_REACHED();
55     return 0;
56 }
57
58 static bool hasSource(const HTMLMediaElement* mediaElement)
59 {
60     return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY
61         && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE;
62 }
63
64 static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
65 {
66     context->drawImage(image, ColorSpaceDeviceRGB, 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->canPlay() ? 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), ColorSpaceDeviceRGB);
124     context->setStrokeThickness(style->borderLeftWidth());
125     context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB);
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     ASSERT(object->node());
170     Node* hostNode = object->node()->shadowAncestorNode();
171     ASSERT(hostNode);
172     HTMLMediaElement* mediaElement = toParentMediaElement(hostNode);
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, ColorSpaceDeviceRGB);
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, ColorSpaceDeviceRGB);
199     return true;
200 }
201
202 static bool paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
203 {
204     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
205     return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
206 }
207
208 static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
209 {
210     HTMLMediaElement* mediaElement = toParentMediaElement(object);
211     if (!mediaElement)
212         return false;
213
214     if (!rect.isEmpty()) {
215         GraphicsContext* context = paintInfo.context;
216         Color originalColor = context->strokeColor();
217         float originalThickness = context->strokeThickness();
218         StrokeStyle originalStyle = context->strokeStyle();
219
220         context->setStrokeStyle(SolidStroke);
221
222         // Draw the left border using CSS defined width and color.
223         context->setStrokeThickness(object->style()->borderLeftWidth());
224         context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), ColorSpaceDeviceRGB);
225         context->drawLine(IntPoint(rect.x() + 1, rect.y()),
226                           IntPoint(rect.x() + 1, rect.y() + rect.height()));
227
228         // Draw the right border using CSS defined width and color.
229         context->setStrokeThickness(object->style()->borderRightWidth());
230         context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), ColorSpaceDeviceRGB);
231         context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
232                           IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
233
234         context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
235         context->setStrokeThickness(originalThickness);
236         context->setStrokeStyle(originalStyle);
237     }
238     return true;
239 }
240
241 bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
242 {
243     switch (part) {
244     case MediaMuteButton:
245     case MediaUnMuteButton:
246         return paintMediaMuteButton(object, paintInfo, rect);
247     case MediaPauseButton:
248     case MediaPlayButton:
249         return paintMediaPlayButton(object, paintInfo, rect);
250     case MediaSlider:
251         return paintMediaSlider(object, paintInfo, rect);
252     case MediaSliderThumb:
253         return paintMediaSliderThumb(object, paintInfo, rect);
254     case MediaVolumeSlider:
255         return paintMediaVolumeSlider(object, paintInfo, rect);
256     case MediaVolumeSliderThumb:
257         return paintMediaVolumeSliderThumb(object, paintInfo, rect);
258     case MediaTimelineContainer:
259         return paintMediaTimelineContainer(object, paintInfo, rect);
260     case MediaVolumeSliderMuteButton:
261     case MediaFullscreenButton:
262     case MediaSeekBackButton:
263     case MediaSeekForwardButton:
264     case MediaVolumeSliderContainer:
265     case MediaCurrentTimeDisplay:
266     case MediaTimeRemainingDisplay:
267     case MediaControlsPanel:
268     case MediaRewindButton:
269     case MediaReturnToRealtimeButton:
270     case MediaStatusDisplay:
271     case MediaShowClosedCaptionsButton:
272     case MediaHideClosedCaptionsButton:
273         ASSERT_NOT_REACHED();
274         break;
275     }
276     return false;
277 }
278
279 void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderStyle* style)
280 {
281     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
282     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
283
284     Image* thumbImage = 0;
285     if (style->appearance() == MediaSliderThumbPart)
286         thumbImage = mediaSliderThumb;
287     else if (style->appearance() == MediaVolumeSliderThumbPart)
288         thumbImage = mediaVolumeSliderThumb;
289
290     float zoomLevel = style->effectiveZoom();
291     if (thumbImage) {
292         style->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed));
293         style->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed));
294     }
295 }
296
297 #endif  // #if ENABLE(VIDEO)
298
299 } // namespace WebCore