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 #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).releaseRef()) {
     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     IntRect imageRect = image->rect();
     67     context->drawImage(image, ColorSpaceDeviceRGB, rect);
     68     return true;
     69 }
     70 
     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 
     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 
    103 static Image* getMediaSliderThumb()
    104 {
    105     static Image* mediaSliderThumb = platformResource("mediaSliderThumb");
    106     return mediaSliderThumb;
    107 }
    108 
    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 
    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 
    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 
    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 
    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 
    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 
    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