Home | History | Annotate | Download | only in chromium
      1 /*
      2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
      3  * Copyright (C) 2008, 2009 Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "core/platform/chromium/ScrollbarThemeChromiumWin.h"
     29 
     30 #include <windows.h>
     31 #include <vsstyle.h>
     32 
     33 #include "core/platform/LayoutTestSupport.h"
     34 #include "core/platform/PlatformMouseEvent.h"
     35 #include "core/platform/Scrollbar.h"
     36 #include "core/platform/graphics/GraphicsContext.h"
     37 #include "core/platform/win/SystemInfo.h"
     38 #include "public/platform/Platform.h"
     39 #include "public/platform/WebRect.h"
     40 #include "public/platform/win/WebThemeEngine.h"
     41 
     42 namespace WebCore {
     43 
     44 ScrollbarTheme* ScrollbarTheme::nativeTheme()
     45 {
     46     static ScrollbarThemeChromiumWin theme;
     47     return &theme;
     48 }
     49 
     50 // The scrollbar size in DumpRenderTree on the Mac - so we can match their
     51 // layout results.  Entries are for regular, small, and mini scrollbars.
     52 // Metrics obtained using [NSScroller scrollerWidthForControlSize:]
     53 static const int kMacScrollbarSize[3] = { 15, 11, 15 };
     54 
     55 // Constants used to figure the drag rect outside which we should snap the
     56 // scrollbar thumb back to its origin.  These calculations are based on
     57 // observing the behavior of the MSVC8 main window scrollbar + some
     58 // guessing/extrapolation.
     59 static const int kOffEndMultiplier = 3;
     60 static const int kOffSideMultiplier = 8;
     61 
     62 int ScrollbarThemeChromiumWin::scrollbarThickness(ScrollbarControlSize controlSize)
     63 {
     64     static int thickness;
     65     if (!thickness) {
     66         if (isRunningLayoutTest())
     67             return kMacScrollbarSize[controlSize];
     68         thickness = IntSize(WebKit::Platform::current()->themeEngine()->getSize(SBP_ARROWBTN)).width();
     69     }
     70     return thickness;
     71 }
     72 
     73 bool ScrollbarThemeChromiumWin::invalidateOnMouseEnterExit()
     74 {
     75     return windowsVersion() >= WindowsVista;
     76 }
     77 
     78 bool ScrollbarThemeChromiumWin::shouldSnapBackToDragOrigin(ScrollbarThemeClient* scrollbar, const PlatformMouseEvent& evt)
     79 {
     80     // Find the rect within which we shouldn't snap, by expanding the track rect
     81     // in both dimensions.
     82     IntRect rect = trackRect(scrollbar);
     83     const bool horz = scrollbar->orientation() == HorizontalScrollbar;
     84     const int thickness = scrollbarThickness(scrollbar->controlSize());
     85     rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
     86     rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);
     87 
     88     // Convert the event to local coordinates.
     89     IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.position());
     90     mousePosition.move(scrollbar->x(), scrollbar->y());
     91 
     92     // We should snap iff the event is outside our calculated rect.
     93     return !rect.contains(mousePosition);
     94 }
     95 
     96 void ScrollbarThemeChromiumWin::paintTrackPiece(GraphicsContext* gc, ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart partType)
     97 {
     98     bool horz = scrollbar->orientation() == HorizontalScrollbar;
     99 
    100     int partId;
    101     if (partType == BackTrackPart)
    102         partId = horz ? SBP_UPPERTRACKHORZ : SBP_UPPERTRACKVERT;
    103     else
    104         partId = horz ? SBP_LOWERTRACKHORZ : SBP_LOWERTRACKVERT;
    105 
    106     IntRect alignRect = trackRect(scrollbar, false);
    107 
    108     WebKit::WebCanvas* canvas = gc->canvas();
    109     // Draw the track area before/after the thumb on the scroll bar.
    110     WebKit::Platform::current()->themeEngine()->paintScrollbarTrack(canvas, partId, getThemeState(scrollbar, partType), getClassicThemeState(scrollbar, partType), WebKit::WebRect(rect), WebKit::WebRect(alignRect));
    111 }
    112 
    113 void ScrollbarThemeChromiumWin::paintButton(GraphicsContext* gc, ScrollbarThemeClient* scrollbar, const IntRect& rect, ScrollbarPart part)
    114 {
    115     bool horz = scrollbar->orientation() == HorizontalScrollbar;
    116 
    117     int partId;
    118     if (part == BackButtonStartPart || part == ForwardButtonStartPart)
    119         partId = horz ? DFCS_SCROLLLEFT : DFCS_SCROLLUP;
    120     else
    121         partId = horz ? DFCS_SCROLLRIGHT : DFCS_SCROLLDOWN;
    122 
    123     WebKit::WebCanvas* canvas = gc->canvas();
    124     // Draw the thumb (the box you drag in the scroll bar to scroll).
    125     WebKit::Platform::current()->themeEngine()->paintScrollbarArrow(canvas, getThemeArrowState(scrollbar, part), partId | getClassicThemeState(scrollbar, part), WebKit::WebRect(rect));
    126 }
    127 
    128 void ScrollbarThemeChromiumWin::paintThumb(GraphicsContext* gc, ScrollbarThemeClient* scrollbar, const IntRect& rect)
    129 {
    130     bool horz = scrollbar->orientation() == HorizontalScrollbar;
    131 
    132     WebKit::WebCanvas* canvas = gc->canvas();
    133     // Draw the thumb (the box you drag in the scroll bar to scroll).
    134     WebKit::Platform::current()->themeEngine()->paintScrollbarThumb(canvas, horz ? SBP_THUMBBTNHORZ : SBP_THUMBBTNVERT, getThemeState(scrollbar, ThumbPart), getClassicThemeState(scrollbar, ThumbPart), WebKit::WebRect(rect));
    135 
    136     // Draw the gripper (the three little lines on the thumb).
    137     WebKit::Platform::current()->themeEngine()->paintScrollbarThumb(canvas, horz ? SBP_GRIPPERHORZ : SBP_GRIPPERVERT, getThemeState(scrollbar, ThumbPart), getClassicThemeState(scrollbar, ThumbPart), WebKit::WebRect(rect));
    138 }
    139 
    140 int ScrollbarThemeChromiumWin::getThemeState(ScrollbarThemeClient* scrollbar, ScrollbarPart part) const
    141 {
    142     // When dragging the thumb, draw thumb pressed and other segments normal
    143     // regardless of where the cursor actually is.  See also four places in
    144     // getThemeArrowState().
    145     if (scrollbar->pressedPart() == ThumbPart) {
    146         if (part == ThumbPart)
    147             return SCRBS_PRESSED;
    148         return (windowsVersion() < WindowsVista) ? SCRBS_NORMAL : SCRBS_HOVER;
    149     }
    150     if (!scrollbar->enabled())
    151         return SCRBS_DISABLED;
    152     if (scrollbar->hoveredPart() != part || part == BackTrackPart || part == ForwardTrackPart)
    153         return (scrollbar->hoveredPart() == NoPart || (windowsVersion() < WindowsVista)) ? SCRBS_NORMAL : SCRBS_HOVER;
    154     if (scrollbar->pressedPart() == NoPart)
    155         return SCRBS_HOT;
    156     return (scrollbar->pressedPart() == part) ? SCRBS_PRESSED : SCRBS_NORMAL;
    157 }
    158 
    159 int ScrollbarThemeChromiumWin::getThemeArrowState(ScrollbarThemeClient* scrollbar, ScrollbarPart part) const
    160 {
    161     // We could take advantage of knowing the values in the state enum to write
    162     // some simpler code, but treating the state enum as a black box seems
    163     // clearer and more future-proof.
    164     if (part == BackButtonStartPart || part == ForwardButtonStartPart) {
    165         if (scrollbar->orientation() == HorizontalScrollbar) {
    166             if (scrollbar->pressedPart() == ThumbPart)
    167                 return (windowsVersion() < WindowsVista) ? ABS_LEFTNORMAL : ABS_LEFTHOVER;
    168             if (!scrollbar->enabled())
    169                 return ABS_LEFTDISABLED;
    170             if (scrollbar->hoveredPart() != part)
    171                 return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_LEFTNORMAL : ABS_LEFTHOVER;
    172             if (scrollbar->pressedPart() == NoPart)
    173                 return ABS_LEFTHOT;
    174             return (scrollbar->pressedPart() == part) ?
    175                 ABS_LEFTPRESSED : ABS_LEFTNORMAL;
    176         }
    177         if (scrollbar->pressedPart() == ThumbPart)
    178             return (windowsVersion() < WindowsVista) ? ABS_UPNORMAL : ABS_UPHOVER;
    179         if (!scrollbar->enabled())
    180             return ABS_UPDISABLED;
    181         if (scrollbar->hoveredPart() != part)
    182             return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_UPNORMAL : ABS_UPHOVER;
    183         if (scrollbar->pressedPart() == NoPart)
    184             return ABS_UPHOT;
    185         return (scrollbar->pressedPart() == part) ? ABS_UPPRESSED : ABS_UPNORMAL;
    186     }
    187     if (scrollbar->orientation() == HorizontalScrollbar) {
    188         if (scrollbar->pressedPart() == ThumbPart)
    189             return (windowsVersion() < WindowsVista) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER;
    190         if (!scrollbar->enabled())
    191             return ABS_RIGHTDISABLED;
    192         if (scrollbar->hoveredPart() != part)
    193             return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_RIGHTNORMAL : ABS_RIGHTHOVER;
    194         if (scrollbar->pressedPart() == NoPart)
    195             return ABS_RIGHTHOT;
    196         return (scrollbar->pressedPart() == part) ? ABS_RIGHTPRESSED : ABS_RIGHTNORMAL;
    197     }
    198     if (scrollbar->pressedPart() == ThumbPart)
    199         return (windowsVersion() < WindowsVista) ? ABS_DOWNNORMAL : ABS_DOWNHOVER;
    200     if (!scrollbar->enabled())
    201         return ABS_DOWNDISABLED;
    202     if (scrollbar->hoveredPart() != part)
    203         return ((scrollbar->hoveredPart() == NoPart) || (windowsVersion() < WindowsVista)) ? ABS_DOWNNORMAL : ABS_DOWNHOVER;
    204     if (scrollbar->pressedPart() == NoPart)
    205         return ABS_DOWNHOT;
    206     return (scrollbar->pressedPart() == part) ? ABS_DOWNPRESSED : ABS_DOWNNORMAL;
    207 }
    208 
    209 int ScrollbarThemeChromiumWin::getClassicThemeState(ScrollbarThemeClient* scrollbar, ScrollbarPart part) const
    210 {
    211     // When dragging the thumb, draw the buttons normal even when hovered.
    212     if (scrollbar->pressedPart() == ThumbPart)
    213         return 0;
    214     if (!scrollbar->enabled())
    215         return DFCS_INACTIVE;
    216     if (scrollbar->hoveredPart() != part || part == BackTrackPart || part == ForwardTrackPart)
    217         return 0;
    218     if (scrollbar->pressedPart() == NoPart)
    219         return DFCS_HOT;
    220     return (scrollbar->pressedPart() == part) ? (DFCS_PUSHED | DFCS_FLAT) : 0;
    221 }
    222 
    223 bool ScrollbarThemeChromiumWin::shouldCenterOnThumb(ScrollbarThemeClient*, const PlatformMouseEvent& evt)
    224 {
    225     return evt.shiftKey() && evt.button() == LeftButton;
    226 }
    227 
    228 IntSize ScrollbarThemeChromiumWin::buttonSize(ScrollbarThemeClient* scrollbar)
    229 {
    230     // Our desired rect is essentially thickness by thickness.
    231 
    232     // Our actual rect will shrink to half the available space when we have < 2
    233     // times thickness pixels left.  This allows the scrollbar to scale down
    234     // and function even at tiny sizes.
    235 
    236     int thickness = scrollbarThickness(scrollbar->controlSize());
    237 
    238     // In layout test mode, we force the button "girth" (i.e., the length of
    239     // the button along the axis of the scrollbar) to be a fixed size.
    240     // FIXME: This is retarded!  scrollbarThickness is already fixed in layout
    241     // test mode so that should be enough to result in repeatable results, but
    242     // preserving this hack avoids having to rebaseline pixel tests.
    243     const int kLayoutTestModeGirth = 17;
    244     int girth = isRunningLayoutTest() ? kLayoutTestModeGirth : thickness;
    245 
    246     if (scrollbar->orientation() == HorizontalScrollbar) {
    247         int width = scrollbar->width() < 2 * girth ? scrollbar->width() / 2 : girth;
    248         return IntSize(width, thickness);
    249     }
    250 
    251     int height = scrollbar->height() < 2 * girth ? scrollbar->height() / 2 : girth;
    252     return IntSize(thickness, height);
    253 }
    254 
    255 
    256 } // namespace WebCore
    257