blob: a2f19c3325e5712f63febce7b7702f926280d7fe [file] [log] [blame]
/*
* Copyright 2010, The Android Open Source Project
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define LOG_TAG "WebCore"
#include "config.h"
#include "RenderSkinMediaButton.h"
#include "Document.h"
#include "IntRect.h"
#include "Node.h"
#include "RenderObject.h"
#include "RenderSkinAndroid.h"
#include "RenderSlider.h"
#include "SkCanvas.h"
#include "SkNinePatch.h"
#include "SkRect.h"
#include <androidfw/AssetManager.h>
#include <utils/Debug.h>
#include <utils/Log.h>
#include <wtf/text/CString.h>
extern android::AssetManager* globalAssetManager();
struct PatchData {
const char* name;
int8_t outset, margin;
};
static const PatchData gFiles[] =
{
{ "scrubber_primary_holo.9.png", 0, 0 }, // SLIDER_TRACK, left of the SLIDER_THUMB
{ "ic_media_pause.png", 0, 0}, // PAUSE
{ "ic_media_play.png", 0, 0 }, // PLAY
{ "ic_media_pause.png", 0, 0 }, // MUTE
{ "ic_media_rew.png", 0, 0 }, // REWIND
{ "ic_media_ff.png", 0, 0 }, // FORWARD
{ "ic_media_fullscreen.png", 0, 0 }, // FULLSCREEN
{ "spinner_76_outer_holo.png", 0, 0 }, // SPINNER_OUTER
{ "spinner_76_inner_holo.png", 0, 0 }, // SPINNER_INNER
{ "ic_media_video_poster.png", 0, 0 }, // VIDEO
{ "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER
{ "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK
{ "scrubber_control_normal_holo.png", 0, 0 } // SLIDER_THUMB
};
static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])];
static bool gDecoded;
static bool gDecodingFailed;
namespace WebCore {
void RenderSkinMediaButton::Decode()
{
String drawableDirectory = RenderSkinAndroid::DrawableDirectory();
gDecoded = true;
gDecodingFailed = false;
android::AssetManager* am = globalAssetManager();
for (size_t i = 0; i < sizeof(gFiles)/sizeof(gFiles[0]); i++) {
String path = drawableDirectory + gFiles[i].name;
if (!RenderSkinAndroid::DecodeBitmap(am, path.utf8().data(), &gButton[i])) {
gDecodingFailed = true;
ALOGD("RenderSkinButton::Init: button assets failed to decode\n\tBrowser buttons will not draw");
break;
}
}
}
void RenderSkinMediaButton::Draw(SkCanvas* canvas, const IntRect& r,
MediaButton buttonType, bool translucent,
bool drawBackground, const IntRect& thumb)
{
if (!gDecoded) {
Decode();
}
if (!canvas)
return;
// If we failed to decode, do nothing. This way the browser still works,
// and webkit will still draw the label and layout space for us.
if (gDecodingFailed)
return;
bool drawsNinePatch = false;
bool drawsImage = true;
int ninePatchIndex = 0;
int imageIndex = 0;
SkRect bounds(r);
SkScalar imageMargin = 8;
SkPaint paint;
int alpha = 255;
if (translucent)
alpha = 190;
SkColor backgroundColor = SkColorSetARGB(alpha, 34, 34, 34);
SkColor trackBackgroundColor = SkColorSetARGB(255, 100, 100, 100);
paint.setColor(backgroundColor);
paint.setFlags(SkPaint::kFilterBitmap_Flag);
switch (buttonType) {
case PAUSE:
case PLAY:
case MUTE:
case REWIND:
case FORWARD:
case FULLSCREEN:
{
imageIndex = buttonType + 1;
paint.setColor(backgroundColor);
break;
}
case SPINNER_OUTER:
case SPINNER_INNER:
case VIDEO:
{
imageIndex = buttonType + 1;
break;
}
case BACKGROUND_SLIDER:
{
drawsImage = false;
break;
}
case SLIDER_TRACK:
{
drawsNinePatch = true;
drawsImage = false;
ninePatchIndex = buttonType + 1;
break;
}
case SLIDER_THUMB:
{
imageMargin = 0;
imageIndex = buttonType + 1;
break;
}
default:
return;
}
if (drawBackground) {
canvas->drawRect(r, paint);
}
if (drawsNinePatch) {
const PatchData& pd = gFiles[ninePatchIndex];
int marginValue = pd.margin + pd.outset;
SkIRect margin;
margin.set(marginValue, marginValue, marginValue, marginValue);
if (buttonType == SLIDER_TRACK) {
// Cut the height in half (with some extra slop determined by trial
// and error to get the placement just right.
SkScalar quarterHeight = SkScalarHalf(SkScalarHalf(bounds.height()));
bounds.fTop += quarterHeight + SkScalarHalf(3);
bounds.fBottom += -quarterHeight + SK_ScalarHalf;
if (!thumb.isEmpty()) {
// Inset the track by half the width of the thumb, so the track
// does not appear to go beyond the space where the thumb can
// be.
SkScalar thumbHalfWidth = SkIntToScalar(thumb.width()/2);
bounds.fLeft += thumbHalfWidth;
bounds.fRight -= thumbHalfWidth;
if (thumb.x() > 0) {
// The video is past the starting point. Show the area to
// left of the thumb as having been played.
SkScalar alreadyPlayed = SkIntToScalar(thumb.center().x() + r.x());
SkRect playedRect(bounds);
playedRect.fRight = alreadyPlayed;
SkNinePatch::DrawNine(canvas, playedRect, gButton[0], margin);
bounds.fLeft = alreadyPlayed;
}
}
}
SkNinePatch::DrawNine(canvas, bounds, gButton[ninePatchIndex], margin);
}
if (drawsImage) {
SkScalar SIZE = gButton[imageIndex].width();
SkScalar width = r.width();
SkScalar scale = SkScalarDiv(width - 2*imageMargin, SIZE);
int saveScaleCount = canvas->save();
canvas->translate(bounds.fLeft + imageMargin, bounds.fTop + imageMargin);
canvas->scale(scale, scale);
canvas->drawBitmap(gButton[imageIndex], 0, 0, &paint);
canvas->restoreToCount(saveScaleCount);
}
}
} // WebCore