Home | History | Annotate | Download | only in android
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *  * Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  *  * Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #define LOG_TAG "WebCore"
     27 
     28 #include "config.h"
     29 #include "RenderSkinMediaButton.h"
     30 
     31 #include "Document.h"
     32 #include "IntRect.h"
     33 #include "Node.h"
     34 #include "RenderObject.h"
     35 #include "RenderSkinAndroid.h"
     36 #include "RenderSlider.h"
     37 #include "SkCanvas.h"
     38 #include "SkNinePatch.h"
     39 #include "SkRect.h"
     40 #include <androidfw/AssetManager.h>
     41 #include <utils/Debug.h>
     42 #include <utils/Log.h>
     43 #include <wtf/text/CString.h>
     44 
     45 extern android::AssetManager* globalAssetManager();
     46 
     47 struct PatchData {
     48     const char* name;
     49     int8_t outset, margin;
     50 };
     51 
     52 static const PatchData gFiles[] =
     53     {
     54         { "scrubber_primary_holo.9.png", 0, 0 }, // SLIDER_TRACK, left of the SLIDER_THUMB
     55         { "ic_media_pause.png", 0, 0}, // PAUSE
     56         { "ic_media_play.png", 0, 0 }, // PLAY
     57         { "ic_media_pause.png", 0, 0 }, // MUTE
     58         { "ic_media_rew.png", 0, 0 }, // REWIND
     59         { "ic_media_ff.png", 0, 0 }, // FORWARD
     60         { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN
     61         { "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER
     62         { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER
     63         { "ic_media_video_poster.png", 0, 0 }, // VIDEO
     64         { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
     65         { "scrubber_track_holo_dark.9.png", 0, 0 },  // SLIDER_TRACK
     66         { "scrubber_control_normal_holo.png", 0, 0 }      // SLIDER_THUMB
     67     };
     68 
     69 static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
     70 static bool gDecoded;
     71 static bool gDecodingFailed;
     72 
     73 namespace WebCore {
     74 
     75 void RenderSkinMediaButton::Decode()
     76 {
     77     String drawableDirectory = RenderSkinAndroid::DrawableDirectory();
     78 
     79     gDecoded = true;
     80     gDecodingFailed = false;
     81     android::AssetManager* am = globalAssetManager();
     82     for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
     83         String path = drawableDirectory + gFiles[i].name;
     84         if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
     85             gDecodingFailed = true;
     86             ALOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
     87             break;
     88         }
     89     }
     90 }
     91 
     92 void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r,
     93                                  MediaButton buttonType, bool translucent,
     94                                  bool drawBackground, const IntRect& thumb)
     95 {
     96     if (!gDecoded) {
     97         Decode();
     98     }
     99 
    100     if (!canvas)
    101         return;
    102 
    103     // If we failed to decode, do nothing.  This way the browser still works,
    104     // and webkit will still draw the label and layout space for us.
    105     if (gDecodingFailed)
    106         return;
    107 
    108     bool drawsNinePatch = false;
    109     bool drawsImage = true;
    110 
    111     int ninePatchIndex = 0;
    112     int imageIndex = 0;
    113 
    114     SkRect bounds(r);
    115     SkScalar imageMargin = 8;
    116     SkPaint paint;
    117 
    118     int alpha = 255;
    119     if (translucent)
    120         alpha = 190;
    121 
    122     SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34);
    123     SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
    124     paint.setColor(backgroundColor);
    125     paint.setFlags(SkPaint::kFilterBitmap_Flag);
    126 
    127     switch (buttonType) {
    128     case PAUSE:
    129     case PLAY:
    130     case MUTE:
    131     case REWIND:
    132     case FORWARD:
    133     case FULLSCREEN:
    134     {
    135          imageIndex = buttonType + 1;
    136          paint.setColor(backgroundColor);
    137          break;
    138     }
    139     case SPINNER_OUTER:
    140     case SPINNER_INNER:
    141     case VIDEO:
    142     {
    143          imageIndex = buttonType + 1;
    144          break;
    145     }
    146     case BACKGROUND_SLIDER:
    147     {
    148          drawsImage = false;
    149          break;
    150     }
    151     case SLIDER_TRACK:
    152     {
    153          drawsNinePatch = true;
    154          drawsImage = false;
    155          ninePatchIndex = buttonType + 1;
    156          break;
    157     }
    158     case SLIDER_THUMB:
    159     {
    160          imageMargin = 0;
    161          imageIndex = buttonType + 1;
    162          break;
    163     }
    164     default:
    165          return;
    166     }
    167 
    168     if (drawBackground) {
    169         canvas->drawRect(r, paint);
    170     }
    171 
    172     if (drawsNinePatch) {
    173         const PatchData& pd = gFiles[ninePatchIndex];
    174         int marginValue = pd.margin + pd.outset;
    175 
    176         SkIRect margin;
    177         margin.set(marginValue, marginValue, marginValue, marginValue);
    178         if (buttonType == SLIDER_TRACK) {
    179             // Cut the height in half (with some extra slop determined by trial
    180             // and error to get the placement just right.
    181             SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height()));
    182             bounds.fTop += quarterHeight + SkScalarHalf(3);
    183             bounds.fBottom += -quarterHeight + SK_ScalarHalf;
    184             if (!thumb.isEmpty()) {
    185                 // Inset the track by half the width of the thumb, so the track
    186                 // does not appear to go beyond the space where the thumb can
    187                 // be.
    188                 SkScalar thumbHalfWidth = SkIntToScalar(thumb.width()/2);
    189                 bounds.fLeft += thumbHalfWidth;
    190                 bounds.fRight -= thumbHalfWidth;
    191                 if (thumb.x() > 0) {
    192                     // The video is past the starting point.  Show the area to
    193                     // left of the thumb as having been played.
    194                     SkScalar alreadyPlayed = SkIntToScalar(thumb.center().x() + r.x());
    195                     SkRect playedRect(bounds);
    196                     playedRect.fRight = alreadyPlayed;
    197                     SkNinePatch::DrawNine(canvas, playedRect, gButton[0], margin);
    198                     bounds.fLeft = alreadyPlayed;
    199                 }
    200 
    201             }
    202         }
    203         SkNinePatch::DrawNine(canvas, bounds, gButton[ninePatchIndex], margin);
    204     }
    205 
    206     if (drawsImage) {
    207         SkScalar SIZE = gButton[imageIndex].width();
    208         SkScalar width = r.width();
    209         SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE);
    210         int saveScaleCount = canvas->save();
    211         canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin);
    212         canvas->scale(scale, scale);
    213         canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint);
    214         canvas->restoreToCount(saveScaleCount);
    215     }
    216 }
    217 
    218 } // WebCore
    219