• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Decode()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 
Draw(SkCanvas * canvas,const IntRect & r,int buttonType,bool translucent,RenderObject * o,bool drawBackground)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