Home | History | Annotate | Download | only in rendering
      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 RenderObject::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 RenderObject::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 bool paintMediaSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    103 {
    104     HTMLMediaElement* mediaElement = toParentMediaElement(object);
    105     if (!mediaElement)
    106         return false;
    107 
    108     RenderStyle* style = object->style();
    109     GraphicsContext* context = paintInfo.context;
    110 
    111     // Draw the border of the time bar.
    112     // FIXME: this should be a rounded rect but need to fix GraphicsContextSkia first.
    113     // https://bugs.webkit.org/show_bug.cgi?id=30143
    114     context->save();
    115     context->setShouldAntialias(true);
    116     context->setStrokeStyle(SolidStroke);
    117     context->setStrokeColor(style->borderLeftColor(), DeviceColorSpace);
    118     context->setStrokeThickness(style->borderLeftWidth());
    119     context->setFillColor(style->backgroundColor(), DeviceColorSpace);
    120     context->drawRect(rect);
    121     context->restore();
    122 
    123     // Draw the buffered ranges.
    124     // FIXME: Draw multiple ranges if there are multiple buffered ranges.
    125     IntRect bufferedRect = rect;
    126     bufferedRect.inflate(-style->borderLeftWidth());
    127     bufferedRect.setWidth((bufferedRect.width() * mediaElement->percentLoaded()));
    128 
    129     // Don't bother drawing an empty area.
    130     if (!bufferedRect.isEmpty()) {
    131         IntPoint sliderTopLeft = bufferedRect.location();
    132         IntPoint sliderTopRight = sliderTopLeft;
    133         sliderTopRight.move(0, bufferedRect.height());
    134 
    135         RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight);
    136         Color startColor = object->style()->color();
    137         gradient->addColorStop(0.0, startColor);
    138         gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha()));
    139 
    140         context->save();
    141         context->setStrokeStyle(NoStroke);
    142         context->setFillGradient(gradient);
    143         context->fillRect(bufferedRect);
    144         context->restore();
    145     }
    146 
    147     return true;
    148 }
    149 
    150 static bool paintMediaSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    151 {
    152     if (!object->parent()->isSlider())
    153         return false;
    154 
    155     HTMLMediaElement* mediaElement = toParentMediaElement(object->parent());
    156     if (!mediaElement)
    157         return false;
    158 
    159     if (!hasSource(mediaElement))
    160         return true;
    161 
    162     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
    163     return paintMediaButton(paintInfo.context, rect, mediaSliderThumb);
    164 }
    165 
    166 static bool paintMediaVolumeSlider(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    167 {
    168     HTMLMediaElement* mediaElement = toParentMediaElement(object);
    169     if (!mediaElement)
    170         return false;
    171 
    172     GraphicsContext* context = paintInfo.context;
    173     Color originalColor = context->strokeColor();
    174     if (originalColor != Color::white)
    175         context->setStrokeColor(Color::white, DeviceColorSpace);
    176 
    177     int x = rect.x() + rect.width() / 2;
    178     context->drawLine(IntPoint(x, rect.y()),  IntPoint(x, rect.y() + rect.height()));
    179 
    180     if (originalColor != Color::white)
    181         context->setStrokeColor(originalColor, DeviceColorSpace);
    182     return true;
    183 }
    184 
    185 static bool paintMediaVolumeSliderThumb(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    186 {
    187     if (!object->parent()->isSlider())
    188         return false;
    189 
    190     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
    191     return paintMediaButton(paintInfo.context, rect, mediaVolumeSliderThumb);
    192 }
    193 
    194 static bool paintMediaTimelineContainer(RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    195 {
    196     HTMLMediaElement* mediaElement = toParentMediaElement(object);
    197     if (!mediaElement)
    198         return false;
    199 
    200     if (!rect.isEmpty()) {
    201         GraphicsContext* context = paintInfo.context;
    202         Color originalColor = context->strokeColor();
    203         float originalThickness = context->strokeThickness();
    204         StrokeStyle originalStyle = context->strokeStyle();
    205 
    206         context->setStrokeStyle(SolidStroke);
    207 
    208         // Draw the left border using CSS defined width and color.
    209         context->setStrokeThickness(object->style()->borderLeftWidth());
    210         context->setStrokeColor(object->style()->borderLeftColor().rgb(), DeviceColorSpace);
    211         context->drawLine(IntPoint(rect.x() + 1, rect.y()),
    212                           IntPoint(rect.x() + 1, rect.y() + rect.height()));
    213 
    214         // Draw the right border using CSS defined width and color.
    215         context->setStrokeThickness(object->style()->borderRightWidth());
    216         context->setStrokeColor(object->style()->borderRightColor().rgb(), DeviceColorSpace);
    217         context->drawLine(IntPoint(rect.x() + rect.width() - 1, rect.y()),
    218                           IntPoint(rect.x() + rect.width() - 1, rect.y() + rect.height()));
    219 
    220         context->setStrokeColor(originalColor, DeviceColorSpace);
    221         context->setStrokeThickness(originalThickness);
    222         context->setStrokeStyle(originalStyle);
    223     }
    224     return true;
    225 }
    226 
    227 bool RenderMediaControlsChromium::shouldRenderMediaControlPart(ControlPart part, Element* e)
    228 {
    229     UNUSED_PARAM(e);
    230 
    231     switch (part) {
    232     case MediaMuteButtonPart:
    233     case MediaPlayButtonPart:
    234     case MediaSliderPart:
    235     case MediaSliderThumbPart:
    236     case MediaVolumeSliderContainerPart:
    237     case MediaVolumeSliderPart:
    238     case MediaVolumeSliderThumbPart:
    239     case MediaControlsBackgroundPart:
    240     case MediaCurrentTimePart:
    241     case MediaTimeRemainingPart:
    242         return true;
    243     default:
    244         ;
    245     }
    246     return false;
    247 }
    248 
    249 bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const RenderObject::PaintInfo& paintInfo, const IntRect& rect)
    250 {
    251     switch (part) {
    252     case MediaMuteButton:
    253     case MediaUnMuteButton:
    254         return paintMediaMuteButton(object, paintInfo, rect);
    255     case MediaPauseButton:
    256     case MediaPlayButton:
    257         return paintMediaPlayButton(object, paintInfo, rect);
    258     case MediaSlider:
    259         return paintMediaSlider(object, paintInfo, rect);
    260     case MediaSliderThumb:
    261         return paintMediaSliderThumb(object, paintInfo, rect);
    262     case MediaVolumeSlider:
    263         return paintMediaVolumeSlider(object, paintInfo, rect);
    264     case MediaVolumeSliderThumb:
    265         return paintMediaVolumeSliderThumb(object, paintInfo, rect);
    266     case MediaTimelineContainer:
    267         return paintMediaTimelineContainer(object, paintInfo, rect);
    268     case MediaFullscreenButton:
    269     case MediaSeekBackButton:
    270     case MediaSeekForwardButton:
    271     case MediaVolumeSliderContainer:
    272     case MediaCurrentTimeDisplay:
    273     case MediaTimeRemainingDisplay:
    274     case MediaControlsPanel:
    275     case MediaRewindButton:
    276     case MediaReturnToRealtimeButton:
    277     case MediaStatusDisplay:
    278     case MediaShowClosedCaptionsButton:
    279     case MediaHideClosedCaptionsButton:
    280         ASSERT_NOT_REACHED();
    281         break;
    282     }
    283     return false;
    284 }
    285 
    286 void RenderMediaControlsChromium::adjustMediaSliderThumbSize(RenderObject* object)
    287 {
    288     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
    289     static Image* mediaVolumeSliderThumb = platformResource("mediaVolumeSliderThumb");
    290 
    291     Image* thumbImage = 0;
    292     if (object->style()->appearance() == MediaSliderThumbPart)
    293         thumbImage = mediaSliderThumb;
    294     else if (object->style()->appearance() == MediaVolumeSliderThumbPart)
    295         thumbImage = mediaVolumeSliderThumb;
    296 
    297     float zoomLevel = object->style()->effectiveZoom();
    298     if (thumbImage) {
    299         object->style()->setWidth(Length(static_cast<int>(thumbImage->width() * zoomLevel), Fixed));
    300         object->style()->setHeight(Length(static_cast<int>(thumbImage->height() * zoomLevel), Fixed));
    301     }
    302 }
    303 
    304 #endif  // #if ENABLE(VIDEO)
    305 
    306 } // namespace WebCore
    307