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 "android_graphics.h"
     30 #include "Document.h"
     31 #include "IntRect.h"
     32 #include "Node.h"
     33 #include "RenderObject.h"
     34 #include "RenderSkinMediaButton.h"
     35 #include "RenderSlider.h"
     36 #include "SkCanvas.h"
     37 #include "SkNinePatch.h"
     38 #include "SkRect.h"
     39 #include <androidfw/AssetManager.h>
     40 #include <utils/Debug.h>
     41 #include <utils/Log.h>
     42 #include <wtf/text/CString.h>
     43 
     44 extern android::AssetManager* globalAssetManager();
     45 
     46 struct PatchData {
     47     const char* name;
     48     int8_t outset, margin;
     49 };
     50 
     51 static const PatchData gFiles[] =
     52     {
     53         { "scrubber_primary_holo.9.png", 0, 0 }, // SLIDER_TRACK, left of the SLIDER_THUMB
     54         { "ic_media_pause.png", 0, 0}, // PAUSE
     55         { "ic_media_play.png", 0, 0 }, // PLAY
     56         { "ic_media_pause.png", 0, 0 }, // MUTE
     57         { "ic_media_rew.png", 0, 0 }, // REWIND
     58         { "ic_media_ff.png", 0, 0 }, // FORWARD
     59         { "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN
     60         { "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER
     61         { "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER
     62         { "ic_media_video_poster.png", 0, 0 }, // VIDEO
     63         { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
     64         { "scrubber_track_holo_dark.9.png", 0, 0 },  // SLIDER_TRACK
     65         { "scrubber_control_normal_holo.png", 0, 0 }      // SLIDER_THUMB
     66     };
     67 
     68 static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
     69 static bool gDecoded;
     70 static bool gDecodingFailed;
     71 
     72 namespace WebCore {
     73 
     74 void RenderSkinMediaButton::Decode()
     75 {
     76     String drawableDirectory = RenderSkinAndroid::DrawableDirectory();
     77 
     78     gDecoded = true;
     79     gDecodingFailed = false;
     80     android::AssetManager* am = globalAssetManager();
     81     for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
     82         String path = drawableDirectory + gFiles[i].name;
     83         if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
     84             gDecodingFailed = true;
     85             ALOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
     86             break;
     87         }
     88     }
     89 }
     90 
     91 void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r, int buttonType,
     92                                  bool translucent, RenderObject* o, bool drawBackground)
     93 {
     94     if (!gDecoded) {
     95         Decode();
     96     }
     97 
     98     if (!canvas)
     99         return;
    100 
    101     // If we failed to decode, do nothing.  This way the browser still works,
    102     // and webkit will still draw the label and layout space for us.
    103     if (gDecodingFailed)
    104         return;
    105 
    106     bool drawsNinePatch = false;
    107     bool drawsImage = true;
    108 
    109     int ninePatchIndex = 0;
    110     int imageIndex = 0;
    111 
    112     SkRect bounds(r);
    113     SkScalar imageMargin = 8;
    114     SkPaint paint;
    115 
    116     int alpha = 255;
    117     if (translucent)
    118         alpha = 190;
    119 
    120     SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34);
    121     SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
    122     paint.setColor(backgroundColor);
    123     paint.setFlags(SkPaint::kFilterBitmap_Flag);
    124 
    125     switch (buttonType) {
    126     case PAUSE:
    127     case PLAY:
    128     case MUTE:
    129     case REWIND:
    130     case FORWARD:
    131     case FULLSCREEN:
    132     {
    133          imageIndex = buttonType + 1;
    134          paint.setColor(backgroundColor);
    135          break;
    136     }
    137     case SPINNER_OUTER:
    138     case SPINNER_INNER:
    139     case VIDEO:
    140     {
    141          imageIndex = buttonType + 1;
    142          break;
    143     }
    144     case BACKGROUND_SLIDER:
    145     {
    146          drawsImage = false;
    147          break;
    148     }
    149     case SLIDER_TRACK:
    150     {
    151          drawsNinePatch = true;
    152          drawsImage = false;
    153          ninePatchIndex = buttonType + 1;
    154          break;
    155     }
    156     case SLIDER_THUMB:
    157     {
    158          imageMargin = 0;
    159          imageIndex = buttonType + 1;
    160          break;
    161     }
    162     default:
    163          return;
    164     }
    165 
    166     if (drawBackground) {
    167         canvas->drawRect(r, paint);
    168     }
    169 
    170     if (drawsNinePatch) {
    171         const PatchData& pd = gFiles[ninePatchIndex];
    172         int marginValue = pd.margin + pd.outset;
    173 
    174         SkIRect margin;
    175         margin.set(marginValue, marginValue, marginValue, marginValue);
    176         if (buttonType == SLIDER_TRACK) {
    177             // Cut the height in half (with some extra slop determined by trial
    178             // and error to get the placement just right.
    179             SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height()));
    180             bounds.fTop += quarterHeight + SkScalarHalf(3);
    181             bounds.fBottom += -quarterHeight + SK_ScalarHalf;
    182             if (o && o->isSlider()) {
    183                 RenderSlider* slider = toRenderSlider(o);
    184                 IntRect thumb = slider->thumbRect();
    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