| /* |
| * 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_rect.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(int thumb_thickness, |
| int scrollbar_margin, |
| HitTestBehavior allow_hit_test, |
| Color color) |
| : ScrollbarTheme(), |
| thumb_thickness_(thumb_thickness), |
| scrollbar_margin_(scrollbar_margin), |
| allow_hit_test_(allow_hit_test), |
| color_(color), |
| use_solid_color_(true) {} |
| |
| ScrollbarThemeOverlay::ScrollbarThemeOverlay(int thumb_thickness, |
| int scrollbar_margin, |
| HitTestBehavior allow_hit_test) |
| : ScrollbarTheme(), |
| thumb_thickness_(thumb_thickness), |
| scrollbar_margin_(scrollbar_margin), |
| allow_hit_test_(allow_hit_test), |
| use_solid_color_(false) {} |
| |
| bool ScrollbarThemeOverlay::ShouldRepaintAllPartsOnInvalidation() const { |
| return false; |
| } |
| |
| ScrollbarPart ScrollbarThemeOverlay::InvalidateOnThumbPositionChange( |
| const Scrollbar&, |
| float old_position, |
| float new_position) const { |
| return kNoPart; |
| } |
| |
| int ScrollbarThemeOverlay::ScrollbarThickness( |
| ScrollbarControlSize control_size) { |
| return thumb_thickness_ + scrollbar_margin_; |
| } |
| |
| int ScrollbarThemeOverlay::ScrollbarMargin() const { |
| return scrollbar_margin_; |
| } |
| |
| bool ScrollbarThemeOverlay::UsesOverlayScrollbars() const { |
| return true; |
| } |
| |
| TimeDelta ScrollbarThemeOverlay::OverlayScrollbarFadeOutDelay() const { |
| // TODO(bokan): Unit tests run without a theme engine. This is normally fine |
| // because they expect to use ScrollbarThemeMock which doesn't use a theme |
| // engine. If overlays are turned on though, this class is used even if mock |
| // scrollbars are on. We should either provide mock out a web theme engine for |
| // unit tests or provide a mock version of this class. |
| if (!Platform::Current()->ThemeEngine()) |
| return TimeDelta(); |
| WebThemeEngine::ScrollbarStyle style; |
| Platform::Current()->ThemeEngine()->GetOverlayScrollbarStyle(&style); |
| return style.fade_out_delay; |
| } |
| |
| TimeDelta ScrollbarThemeOverlay::OverlayScrollbarFadeOutDuration() const { |
| if (!Platform::Current()->ThemeEngine()) |
| return TimeDelta(); |
| WebThemeEngine::ScrollbarStyle style; |
| 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&, |
| ScrollbarPart, |
| bool) { |
| return IntRect(); |
| } |
| |
| IntRect ScrollbarThemeOverlay::ForwardButtonRect(const Scrollbar&, |
| ScrollbarPart, |
| bool) { |
| return IntRect(); |
| } |
| |
| IntRect ScrollbarThemeOverlay::TrackRect(const Scrollbar& scrollbar, bool) { |
| IntRect rect = scrollbar.FrameRect(); |
| if (scrollbar.Orientation() == kHorizontalScrollbar) |
| rect.InflateX(-scrollbar_margin_); |
| else |
| rect.InflateY(-scrollbar_margin_); |
| return rect; |
| } |
| |
| int ScrollbarThemeOverlay::ThumbThickness(const Scrollbar&) { |
| return thumb_thickness_; |
| } |
| |
| 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); |
| |
| IntRect thumb_rect = rect; |
| if (scrollbar.Orientation() == kHorizontalScrollbar) { |
| thumb_rect.SetHeight(thumb_rect.Height() - scrollbar_margin_); |
| } else { |
| thumb_rect.SetWidth(thumb_rect.Width() - scrollbar_margin_); |
| if (scrollbar.IsLeftSideVerticalScrollbar()) |
| thumb_rect.SetX(thumb_rect.X() + scrollbar_margin_); |
| } |
| |
| if (use_solid_color_ || !Platform::Current()->ThemeEngine()) { |
| context.FillRect(thumb_rect, color_); |
| return; |
| } |
| |
| 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, WebRect(rect), |
| ¶ms); |
| |
| if (scrollbar.IsLeftSideVerticalScrollbar()) |
| canvas->restore(); |
| } |
| |
| ScrollbarPart ScrollbarThemeOverlay::HitTest(const Scrollbar& scrollbar, |
| const IntPoint& position) { |
| if (allow_hit_test_ == kDisallowHitTest) |
| return kNoPart; |
| |
| ScrollbarPart part = ScrollbarTheme::HitTest(scrollbar, position); |
| if (part != kThumbPart) |
| return kNoPart; |
| |
| return kThumbPart; |
| } |
| |
| // static |
| ScrollbarThemeOverlay& ScrollbarThemeOverlay::MobileTheme() { |
| static ScrollbarThemeOverlay* theme; |
| if (!theme) { |
| WebThemeEngine::ScrollbarStyle style = {3, 3, 0x80808080}; // default style |
| if (Platform::Current()->ThemeEngine()) { |
| Platform::Current()->ThemeEngine()->GetOverlayScrollbarStyle(&style); |
| } |
| theme = new ScrollbarThemeOverlay( |
| style.thumb_thickness, style.scrollbar_margin, |
| ScrollbarThemeOverlay::kDisallowHitTest, Color(style.color)); |
| theme->is_mobile_theme_ = true; |
| } |
| return *theme; |
| } |
| |
| bool ScrollbarThemeOverlay::IsMobileTheme() const { |
| return is_mobile_theme_; |
| } |
| |
| bool ScrollbarThemeOverlay::UsesNinePatchThumbResource() const { |
| WebThemeEngine* engine = Platform::Current()->ThemeEngine(); |
| if (!engine) |
| return false; |
| |
| // Thumb orientation doesn't matter here. |
| return engine->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 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 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 |