• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
platformResource(const char * name)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).releaseRef()) {
51         gMediaControlImageMap->set(name, image);
52         return image;
53     }
54     ASSERT_NOT_REACHED();
55     return 0;
56 }
57 
hasSource(const HTMLMediaElement * mediaElement)58 static bool hasSource(const HTMLMediaElement* mediaElement)
59 {
60     return mediaElement->networkState() != HTMLMediaElement::NETWORK_EMPTY
61         && mediaElement->networkState() != HTMLMediaElement::NETWORK_NO_SOURCE;
62 }
63 
paintMediaButton(GraphicsContext * context,const IntRect & rect,Image * image)64 static bool paintMediaButton(GraphicsContext* context, const IntRect& rect, Image* image)
65 {
66     IntRect imageRect = image->rect();
67     context->drawImage(image, ColorSpaceDeviceRGB, rect);
68     return true;
69 }
70 
paintMediaMuteButton(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)71 static bool paintMediaMuteButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
72 {
73     HTMLMediaElement* mediaElement = toParentMediaElement(object);
74     if (!mediaElement)
75       return false;
76 
77     static Image* soundFull = platformResource("mediaSoundFull");
78     static Image* soundNone = platformResource("mediaSoundNone");
79     static Image* soundDisabled = platformResource("mediaSoundDisabled");
80 
81     if (!hasSource(mediaElement) || !mediaElement->hasAudio())
82         return paintMediaButton(paintInfo.context, rect, soundDisabled);
83 
84     return paintMediaButton(paintInfo.context, rect, mediaElement->muted() ? soundNone: soundFull);
85 }
86 
paintMediaPlayButton(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)87 static bool paintMediaPlayButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
88 {
89     HTMLMediaElement* mediaElement = toParentMediaElement(object);
90     if (!mediaElement)
91         return false;
92 
93     static Image* mediaPlay = platformResource("mediaPlay");
94     static Image* mediaPause = platformResource("mediaPause");
95     static Image* mediaPlayDisabled = platformResource("mediaPlayDisabled");
96 
97     if (!hasSource(mediaElement))
98         return paintMediaButton(paintInfo.context, rect, mediaPlayDisabled);
99 
100     return paintMediaButton(paintInfo.context, rect, mediaElement->canPlay() ? mediaPlay : mediaPause);
101 }
102 
getMediaSliderThumb()103 static Image* getMediaSliderThumb()
104 {
105     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
106     return mediaSliderThumb;
107 }
108 
paintMediaSlider(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)109 static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
110 {
111     HTMLMediaElement* mediaElement = toParentMediaElement(object);
112     if (!mediaElement)
113         return false;
114 
115     RenderStyle* style = object->style();
116     GraphicsContext* context = paintInfo.context;
117 
118     // Draw the border of the time bar.
119     // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first.
120     // https://bugs.webkit.org/show_bug.cgi?id=30143
121     context->save();
122     context->setShouldAntialias(true);
123     context->setStrokeStyle(SolidStroke);
124     context->setStrokeColor(style->visitedDependentColor(CSSPropertyBorderLeftColor), ColorSpaceDeviceRGB);
125     context->setStrokeThickness(style->borderLeftWidth());
126     context->setFillColor(style->visitedDependentColor(CSSPropertyBackgroundColor), ColorSpaceDeviceRGB);
127     context->drawRect(rect);
128     context->restore();
129 
130     // Draw the buffered ranges.
131     // FIXME: Draw multiple ranges if there are multiple buffered ranges.
132     IntRect bufferedRect = rect;
133     bufferedRect.inflate(-style->borderLeftWidth());
134 
135     double bufferedWidth = 0.0;
136     if (mediaElement->percentLoaded() > 0.0) {
137         // Account for the width of the slider thumb.
138         Image* mediaSliderThumb = getMediaSliderThumb();
139         double thumbWidth = mediaSliderThumb->width() / 2.0 + 1.0;
140         double rectWidth = bufferedRect.width() - thumbWidth;
141         if (rectWidth < 0.0)
142             rectWidth = 0.0;
143         bufferedWidth = rectWidth * mediaElement->percentLoaded() + thumbWidth;
144     }
145     bufferedRect.setWidth(bufferedWidth);
146 
147     // Don't bother drawing an empty area.
148     if (!bufferedRect.isEmpty()) {
149         IntPoint sliderTopLeft = bufferedRect.location();
150         IntPoint sliderTopRight = sliderTopLeft;
151         sliderTopRight.move(0, bufferedRect.height());
152 
153         RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight);
154         Color startColor = object->style()->visitedDependentColor(CSSPropertyColor);
155         gradient->addColorStop(0.0, startColor);
156         gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
157 
158         context->save();
159         context->setStrokeStyle(NoStroke);
160         context->setFillGradient(gradient);
161         context->fillRect(bufferedRect);
162         context->restore();
163     }
164 
165     return true;
166 }
167 
paintMediaSliderThumb(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)168 static bool paintMediaSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
169 {
170     if (!object->parent()->isSlider())
171         return false;
172 
173     HTMLMediaElement* mediaElement = toParentMediaElement(object->parent());
174     if (!mediaElement)
175         return false;
176 
177     if (!hasSource(mediaElement))
178         return true;
179 
180     Image* mediaSliderThumb = getMediaSliderThumb();
181     return paintMediaButton(paintInfo.context, rect, mediaSliderThumb);
182 }
183 
paintMediaVolumeSlider(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)184 static bool paintMediaVolumeSlider(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
185 {
186     HTMLMediaElement* mediaElement = toParentMediaElement(object);
187     if (!mediaElement)
188         return false;
189 
190     GraphicsContext* context = paintInfo.context;
191     Color originalColor = context->strokeColor();
192     if (originalColor != Color::white)
193         context->setStrokeColor(Color::white, ColorSpaceDeviceRGB);
194 
195     int x = rect.x() + rect.width() / 2;
196     context->drawLine(IntPoint(x, rect.y()),  IntPoint(x, rect.y() + rect.height()));
197 
198     if (originalColor != Color::white)
199         context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
200     return true;
201 }
202 
paintMediaVolumeSliderThumb(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)203 static bool paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
204 {
205     if (!object->parent()->isSlider())
206         return false;
207 
208     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
209     return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
210 }
211 
paintMediaTimelineContainer(RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)212 static bool paintMediaTimelineContainer(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
213 {
214     HTMLMediaElement* mediaElement = toParentMediaElement(object);
215     if (!mediaElement)
216         return false;
217 
218     if (!rect.isEmpty()) {
219         GraphicsContext* context = paintInfo.context;
220         Color originalColor = context->strokeColor();
221         float originalThickness = context->strokeThickness();
222         StrokeStyle originalStyle = context->strokeStyle();
223 
224         context->setStrokeStyle(SolidStroke);
225 
226         // Draw the left border using CSS defined width and color.
227         context->setStrokeThickness(object->style()->borderLeftWidth());
228         context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderLeftColor).rgb(), ColorSpaceDeviceRGB);
229         context->drawLine(IntPoint(rect.x() + 1, rect.y()),
230                           IntPoint(rect.x() + 1, rect.y() + rect.height()));
231 
232         // Draw the right border using CSS defined width and color.
233         context->setStrokeThickness(object->style()->borderRightWidth());
234         context->setStrokeColor(object->style()->visitedDependentColor(CSSPropertyBorderRightColor).rgb(), ColorSpaceDeviceRGB);
235         context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
236                           IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
237 
238         context->setStrokeColor(originalColor, ColorSpaceDeviceRGB);
239         context->setStrokeThickness(originalThickness);
240         context->setStrokeStyle(originalStyle);
241     }
242     return true;
243 }
244 
paintMediaControlsPart(MediaControlElementType part,RenderObject * object,const PaintInfo & paintInfo,const IntRect & rect)245 bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect)
246 {
247     switch (part) {
248     case MediaMuteButton:
249     case MediaUnMuteButton:
250         return paintMediaMuteButton(object, paintInfo, rect);
251     case MediaPauseButton:
252     case MediaPlayButton:
253         return paintMediaPlayButton(object, paintInfo, rect);
254     case MediaSlider:
255         return paintMediaSlider(object, paintInfo, rect);
256     case MediaSliderThumb:
257         return paintMediaSliderThumb(object, paintInfo, rect);
258     case MediaVolumeSlider:
259         return paintMediaVolumeSlider(object, paintInfo, rect);
260     case MediaVolumeSliderThumb:
261         return paintMediaVolumeSliderThumb(object, paintInfo, rect);
262     case MediaTimelineContainer:
263         return paintMediaTimelineContainer(object, paintInfo, rect);
264     case MediaVolumeSliderMuteButton:
265     case MediaFullscreenButton:
266     case MediaSeekBackButton:
267     case MediaSeekForwardButton:
268     case MediaVolumeSliderContainer:
269     case MediaCurrentTimeDisplay:
270     case MediaTimeRemainingDisplay:
271     case MediaControlsPanel:
272     case MediaRewindButton:
273     case MediaReturnToRealtimeButton:
274     case MediaStatusDisplay:
275     case MediaShowClosedCaptionsButton:
276     case MediaHideClosedCaptionsButton:
277         ASSERT_NOT_REACHED();
278         break;
279     }
280     return false;
281 }
282 
adjustMediaSliderThumbSize(RenderObject * object)283 void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderObject* object)
284 {
285     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
286     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
287 
288     Image* thumbImage = 0;
289     if (object->style()->appearance() == MediaSliderThumbPart)
290         thumbImage = mediaSliderThumb;
291     else if (object->style()->appearance() == MediaVolumeSliderThumbPart)
292         thumbImage = mediaVolumeSliderThumb;
293 
294     float zoomLevel = object->style()->effectiveZoom();
295     if (thumbImage) {
296         object->style()->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed));
297         object->style()->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed));
298     }
299 }
300 
301 #endif  // #if ENABLE(VIDEO)
302 
303 } // namespace WebCore
304