blob: 4ec2d5e44314e99833f0aae5c6f9bf4589543dcd [file] [log] [blame]
/*
* Copyright (C) 2011 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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 APPLE AND ITS CONTRIBUTORS "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 APPLE OR ITS 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.
*/
#include "third_party/blink/renderer/core/scroll/scrollbar_theme_overlay.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/renderer/core/scroll/scrollbar.h"
#include "third_party/blink/renderer/platform/graphics/graphics_context.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_recorder.h"
#include "third_party/blink/renderer/platform/transforms/transformation_matrix.h"
#include "third_party/blink/renderer/platform/wtf/math_extras.h"
#include <algorithm>
namespace blink {
ScrollbarThemeOverlay& ScrollbarThemeOverlay::GetInstance() {
DEFINE_STATIC_LOCAL(
ScrollbarThemeOverlay, theme,
(Platform::Current()
->ThemeEngine()
->GetSize(WebThemeEngine::kPartScrollbarVerticalThumb)
.width(),
0));
return theme;
}
ScrollbarThemeOverlay::ScrollbarThemeOverlay(int thumb_thickness_dip,
int scrollbar_margin_dip)
: thumb_thickness_dip_(thumb_thickness_dip),
scrollbar_margin_dip_(scrollbar_margin_dip) {}
bool ScrollbarThemeOverlay::ShouldRepaintAllPartsOnInvalidation() const {
return false;
}
ScrollbarPart ScrollbarThemeOverlay::PartsToInvalidateOnThumbPositionChange(
const Scrollbar&,
float old_position,
float new_position) const {
return kNoPart;
}
int ScrollbarThemeOverlay::ScrollbarThickness(float scale_from_dip) {
return ThumbThickness(scale_from_dip) + ScrollbarMargin(scale_from_dip);
}
int ScrollbarThemeOverlay::ScrollbarMargin(float scale_from_dip) const {
return scrollbar_margin_dip_ * scale_from_dip;
}
bool ScrollbarThemeOverlay::UsesOverlayScrollbars() const {
return true;
}
base::TimeDelta ScrollbarThemeOverlay::OverlayScrollbarFadeOutDelay() const {
WebThemeEngine::ScrollbarStyle style;
DCHECK(Platform::Current()->ThemeEngine());
Platform::Current()->ThemeEngine()->GetOverlayScrollbarStyle(&style);
return style.fade_out_delay;
}
base::TimeDelta ScrollbarThemeOverlay::OverlayScrollbarFadeOutDuration() const {
WebThemeEngine::ScrollbarStyle style;
DCHECK(Platform::Current()->ThemeEngine());
Platform::Current()->ThemeEngine()->GetOverlayScrollbarStyle(&style);
return style.fade_out_duration;
}
int ScrollbarThemeOverlay::ThumbLength(const Scrollbar& scrollbar) {
int track_len = TrackLength(scrollbar);
if (!scrollbar.TotalSize())
return track_len;
float proportion =
static_cast<float>(scrollbar.VisibleSize()) / scrollbar.TotalSize();
int length = round(proportion * track_len);
int min_len = std::min(MinimumThumbLength(scrollbar), track_len);
length = clampTo(length, min_len, track_len);
return length;
}
bool ScrollbarThemeOverlay::HasThumb(const Scrollbar& scrollbar) {
return true;
}
IntRect ScrollbarThemeOverlay::BackButtonRect(const Scrollbar&) {
return IntRect();
}
IntRect ScrollbarThemeOverlay::ForwardButtonRect(const Scrollbar&) {
return IntRect();
}
IntRect ScrollbarThemeOverlay::TrackRect(const Scrollbar& scrollbar) {
IntRect rect = scrollbar.FrameRect();
if (scrollbar.Orientation() == kHorizontalScrollbar)
rect.InflateX(-ScrollbarMargin(scrollbar.ScaleFromDIP()));
else
rect.InflateY(-ScrollbarMargin(scrollbar.ScaleFromDIP()));
return rect;
}
IntRect ScrollbarThemeOverlay::ThumbRect(const Scrollbar& scrollbar) {
IntRect rect = ScrollbarTheme::ThumbRect(scrollbar);
if (scrollbar.Orientation() == kHorizontalScrollbar) {
rect.SetHeight(ThumbThickness(scrollbar.ScaleFromDIP()));
} else {
if (scrollbar.IsLeftSideVerticalScrollbar())
rect.Move(ScrollbarMargin(scrollbar.ScaleFromDIP()), 0);
rect.SetWidth(ThumbThickness(scrollbar.ScaleFromDIP()));
}
return rect;
}
void ScrollbarThemeOverlay::PaintThumb(GraphicsContext& context,
const Scrollbar& scrollbar,
const IntRect& rect) {
if (DrawingRecorder::UseCachedDrawingIfPossible(context, scrollbar,
DisplayItem::kScrollbarThumb))
return;
DrawingRecorder recorder(context, scrollbar, DisplayItem::kScrollbarThumb,
rect);
WebThemeEngine::State state = WebThemeEngine::kStateNormal;
if (!scrollbar.Enabled())
state = WebThemeEngine::kStateDisabled;
else if (scrollbar.PressedPart() == kThumbPart)
state = WebThemeEngine::kStatePressed;
else if (scrollbar.HoveredPart() == kThumbPart)
state = WebThemeEngine::kStateHover;
cc::PaintCanvas* canvas = context.Canvas();
WebThemeEngine::Part part = WebThemeEngine::kPartScrollbarHorizontalThumb;
if (scrollbar.Orientation() == kVerticalScrollbar)
part = WebThemeEngine::kPartScrollbarVerticalThumb;
blink::WebThemeEngine::ExtraParams params;
params.scrollbar_thumb.scrollbar_theme =
static_cast<WebScrollbarOverlayColorTheme>(
scrollbar.GetScrollbarOverlayColorTheme());
// Horizontally flip the canvas if it is left vertical scrollbar.
if (scrollbar.IsLeftSideVerticalScrollbar()) {
canvas->save();
canvas->translate(rect.Width(), 0);
canvas->scale(-1, 1);
}
Platform::Current()->ThemeEngine()->Paint(canvas, part, state,
gfx::Rect(rect), &params,
scrollbar.UsedColorScheme());
if (scrollbar.IsLeftSideVerticalScrollbar())
canvas->restore();
}
ScrollbarPart ScrollbarThemeOverlay::HitTest(const Scrollbar& scrollbar,
const IntPoint& position) {
ScrollbarPart part = ScrollbarTheme::HitTest(scrollbar, position);
if (part != kThumbPart)
return kNoPart;
return kThumbPart;
}
bool ScrollbarThemeOverlay::UsesNinePatchThumbResource() const {
DCHECK(Platform::Current()->ThemeEngine());
// Thumb orientation doesn't matter here.
return Platform::Current()->ThemeEngine()->SupportsNinePatch(
WebThemeEngine::kPartScrollbarVerticalThumb);
}
IntSize ScrollbarThemeOverlay::NinePatchThumbCanvasSize(
const Scrollbar& scrollbar) const {
DCHECK(UsesNinePatchThumbResource());
WebThemeEngine::Part part =
scrollbar.Orientation() == kVerticalScrollbar
? WebThemeEngine::kPartScrollbarVerticalThumb
: WebThemeEngine::kPartScrollbarHorizontalThumb;
DCHECK(Platform::Current()->ThemeEngine());
return IntSize(Platform::Current()->ThemeEngine()->NinePatchCanvasSize(part));
}
IntRect ScrollbarThemeOverlay::NinePatchThumbAperture(
const Scrollbar& scrollbar) const {
DCHECK(UsesNinePatchThumbResource());
WebThemeEngine::Part part = WebThemeEngine::kPartScrollbarHorizontalThumb;
if (scrollbar.Orientation() == kVerticalScrollbar)
part = WebThemeEngine::kPartScrollbarVerticalThumb;
DCHECK(Platform::Current()->ThemeEngine());
return IntRect(Platform::Current()->ThemeEngine()->NinePatchAperture(part));
}
int ScrollbarThemeOverlay::MinimumThumbLength(const Scrollbar& scrollbar) {
if (scrollbar.Orientation() == kVerticalScrollbar) {
return Platform::Current()
->ThemeEngine()
->GetSize(WebThemeEngine::kPartScrollbarVerticalThumb)
.height();
}
return Platform::Current()
->ThemeEngine()
->GetSize(WebThemeEngine::kPartScrollbarHorizontalThumb)
.width();
}
} // namespace blink