PageRenderTime 147ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/trunk/WebCore/platform/win/ScrollbarThemeWin.cpp

https://github.com/weissms/owb-mirror
C++ | 374 lines | 278 code | 50 blank | 46 comment | 82 complexity | 3a567e6b3366191297893b9961a2451f MD5 | raw file
  1. /*
  2. * Copyright (C) 2008 Apple Inc. All Rights Reserved.
  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. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. 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 APPLE INC. ``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 APPLE INC. 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. #include "config.h"
  26. #include "ScrollbarThemeWin.h"
  27. #include "GraphicsContext.h"
  28. #include "PlatformMouseEvent.h"
  29. #include "Scrollbar.h"
  30. #include "SoftLinking.h"
  31. #include "SystemInfo.h"
  32. // Generic state constants
  33. #define TS_NORMAL 1
  34. #define TS_HOVER 2
  35. #define TS_ACTIVE 3
  36. #define TS_DISABLED 4
  37. #define SP_BUTTON 1
  38. #define SP_THUMBHOR 2
  39. #define SP_THUMBVERT 3
  40. #define SP_TRACKSTARTHOR 4
  41. #define SP_TRACKENDHOR 5
  42. #define SP_TRACKSTARTVERT 6
  43. #define SP_TRACKENDVERT 7
  44. #define SP_GRIPPERHOR 8
  45. #define SP_GRIPPERVERT 9
  46. #define TS_UP_BUTTON 0
  47. #define TS_DOWN_BUTTON 4
  48. #define TS_LEFT_BUTTON 8
  49. #define TS_RIGHT_BUTTON 12
  50. #define TS_UP_BUTTON_HOVER 17
  51. #define TS_DOWN_BUTTON_HOVER 18
  52. #define TS_LEFT_BUTTON_HOVER 19
  53. #define TS_RIGHT_BUTTON_HOVER 20
  54. using namespace std;
  55. namespace WebCore {
  56. static HANDLE scrollbarTheme;
  57. static bool runningVista;
  58. // FIXME: Refactor the soft-linking code so that it can be shared with RenderThemeWin
  59. SOFT_LINK_LIBRARY(uxtheme)
  60. SOFT_LINK(uxtheme, OpenThemeData, HANDLE, WINAPI, (HWND hwnd, LPCWSTR pszClassList), (hwnd, pszClassList))
  61. SOFT_LINK(uxtheme, CloseThemeData, HRESULT, WINAPI, (HANDLE hTheme), (hTheme))
  62. SOFT_LINK(uxtheme, DrawThemeBackground, HRESULT, WINAPI, (HANDLE hTheme, HDC hdc, int iPartId, int iStateId, const RECT* pRect, const RECT* pClipRect), (hTheme, hdc, iPartId, iStateId, pRect, pClipRect))
  63. SOFT_LINK(uxtheme, IsThemeActive, BOOL, WINAPI, (), ())
  64. SOFT_LINK(uxtheme, IsThemeBackgroundPartiallyTransparent, BOOL, WINAPI, (HANDLE hTheme, int iPartId, int iStateId), (hTheme, iPartId, iStateId))
  65. // Constants used to figure the drag rect outside which we should snap the
  66. // scrollbar thumb back to its origin. These calculations are based on
  67. // observing the behavior of the MSVC8 main window scrollbar + some
  68. // guessing/extrapolation.
  69. static const int kOffEndMultiplier = 3;
  70. static const int kOffSideMultiplier = 8;
  71. static void checkAndInitScrollbarTheme()
  72. {
  73. if (uxthemeLibrary() && !scrollbarTheme && IsThemeActive())
  74. scrollbarTheme = OpenThemeData(0, L"Scrollbar");
  75. }
  76. #if !USE(SAFARI_THEME)
  77. ScrollbarTheme* ScrollbarTheme::nativeTheme()
  78. {
  79. static ScrollbarThemeWin winTheme;
  80. return &winTheme;
  81. }
  82. #endif
  83. ScrollbarThemeWin::ScrollbarThemeWin()
  84. {
  85. static bool initialized;
  86. if (!initialized) {
  87. initialized = true;
  88. checkAndInitScrollbarTheme();
  89. runningVista = isRunningOnVistaOrLater();
  90. }
  91. }
  92. ScrollbarThemeWin::~ScrollbarThemeWin()
  93. {
  94. }
  95. int ScrollbarThemeWin::scrollbarThickness(ScrollbarControlSize)
  96. {
  97. static int thickness;
  98. if (!thickness)
  99. thickness = ::GetSystemMetrics(SM_CXVSCROLL);
  100. return thickness;
  101. }
  102. void ScrollbarThemeWin::themeChanged()
  103. {
  104. if (!scrollbarTheme)
  105. return;
  106. CloseThemeData(scrollbarTheme);
  107. scrollbarTheme = 0;
  108. }
  109. bool ScrollbarThemeWin::invalidateOnMouseEnterExit()
  110. {
  111. return runningVista;
  112. }
  113. bool ScrollbarThemeWin::hasThumb(Scrollbar* scrollbar)
  114. {
  115. return thumbLength(scrollbar) > 0;
  116. }
  117. IntRect ScrollbarThemeWin::backButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
  118. {
  119. // Windows just has single arrows.
  120. if (part == BackButtonEndPart)
  121. return IntRect();
  122. // Our desired rect is essentially 17x17.
  123. // Our actual rect will shrink to half the available space when
  124. // we have < 34 pixels left. This allows the scrollbar
  125. // to scale down and function even at tiny sizes.
  126. int thickness = scrollbarThickness();
  127. if (scrollbar->orientation() == HorizontalScrollbar)
  128. return IntRect(scrollbar->x(), scrollbar->y(),
  129. scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness, thickness);
  130. return IntRect(scrollbar->x(), scrollbar->y(),
  131. thickness, scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness);
  132. }
  133. IntRect ScrollbarThemeWin::forwardButtonRect(Scrollbar* scrollbar, ScrollbarPart part, bool)
  134. {
  135. // Windows just has single arrows.
  136. if (part == ForwardButtonStartPart)
  137. return IntRect();
  138. // Our desired rect is essentially 17x17.
  139. // Our actual rect will shrink to half the available space when
  140. // we have < 34 pixels left. This allows the scrollbar
  141. // to scale down and function even at tiny sizes.
  142. int thickness = scrollbarThickness();
  143. if (scrollbar->orientation() == HorizontalScrollbar) {
  144. int w = scrollbar->width() < 2 * thickness ? scrollbar->width() / 2 : thickness;
  145. return IntRect(scrollbar->x() + scrollbar->width() - w, scrollbar->y(), w, thickness);
  146. }
  147. int h = scrollbar->height() < 2 * thickness ? scrollbar->height() / 2 : thickness;
  148. return IntRect(scrollbar->x(), scrollbar->y() + scrollbar->height() - h, thickness, h);
  149. }
  150. IntRect ScrollbarThemeWin::trackRect(Scrollbar* scrollbar, bool)
  151. {
  152. int thickness = scrollbarThickness();
  153. if (scrollbar->orientation() == HorizontalScrollbar) {
  154. if (scrollbar->width() < 2 * thickness)
  155. return IntRect();
  156. return IntRect(scrollbar->x() + thickness, scrollbar->y(), scrollbar->width() - 2 * thickness, thickness);
  157. }
  158. if (scrollbar->height() < 2 * thickness)
  159. return IntRect();
  160. return IntRect(scrollbar->x(), scrollbar->y() + thickness, thickness, scrollbar->height() - 2 * thickness);
  161. }
  162. bool ScrollbarThemeWin::shouldCenterOnThumb(Scrollbar*, const PlatformMouseEvent& evt)
  163. {
  164. return evt.shiftKey() && evt.button() == LeftButton;
  165. }
  166. bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt)
  167. {
  168. // Find the rect within which we shouldn't snap, by expanding the track rect
  169. // in both dimensions.
  170. IntRect rect = trackRect(scrollbar);
  171. const bool horz = scrollbar->orientation() == HorizontalScrollbar;
  172. const int thickness = scrollbarThickness(scrollbar->controlSize());
  173. rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness);
  174. rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness);
  175. // Convert the event to local coordinates.
  176. IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos());
  177. mousePosition.move(scrollbar->x(), scrollbar->y());
  178. // We should snap iff the event is outside our calculated rect.
  179. return !rect.contains(mousePosition);
  180. }
  181. void ScrollbarThemeWin::paintTrackBackground(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
  182. {
  183. // Just assume a forward track part. We only paint the track as a single piece when there is no thumb.
  184. if (!hasThumb(scrollbar))
  185. paintTrackPiece(context, scrollbar, rect, ForwardTrackPart);
  186. }
  187. void ScrollbarThemeWin::paintTrackPiece(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart partType)
  188. {
  189. checkAndInitScrollbarTheme();
  190. bool start = partType == BackTrackPart;
  191. int part;
  192. if (scrollbar->orientation() == HorizontalScrollbar)
  193. part = start ? SP_TRACKSTARTHOR : SP_TRACKENDHOR;
  194. else
  195. part = start ? SP_TRACKSTARTVERT : SP_TRACKENDVERT;
  196. int state;
  197. if (!scrollbar->enabled())
  198. state = TS_DISABLED;
  199. else if ((scrollbar->hoveredPart() == BackTrackPart && start) ||
  200. (scrollbar->hoveredPart() == ForwardTrackPart && !start))
  201. state = (scrollbar->pressedPart() == scrollbar->hoveredPart() ? TS_ACTIVE : TS_HOVER);
  202. else
  203. state = TS_NORMAL;
  204. bool alphaBlend = false;
  205. if (scrollbarTheme)
  206. alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, part, state);
  207. HDC hdc = context->getWindowsContext(rect, alphaBlend);
  208. RECT themeRect(rect);
  209. if (scrollbarTheme)
  210. DrawThemeBackground(scrollbarTheme, hdc, part, state, &themeRect, 0);
  211. else {
  212. DWORD color3DFace = ::GetSysColor(COLOR_3DFACE);
  213. DWORD colorScrollbar = ::GetSysColor(COLOR_SCROLLBAR);
  214. DWORD colorWindow = ::GetSysColor(COLOR_WINDOW);
  215. if ((color3DFace != colorScrollbar) && (colorWindow != colorScrollbar))
  216. ::FillRect(hdc, &themeRect, HBRUSH(COLOR_SCROLLBAR+1));
  217. else {
  218. static WORD patternBits[8] = { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 };
  219. HBITMAP patternBitmap = ::CreateBitmap(8, 8, 1, 1, patternBits);
  220. HBRUSH brush = ::CreatePatternBrush(patternBitmap);
  221. SaveDC(hdc);
  222. ::SetTextColor(hdc, ::GetSysColor(COLOR_3DHILIGHT));
  223. ::SetBkColor(hdc, ::GetSysColor(COLOR_3DFACE));
  224. ::SetBrushOrgEx(hdc, rect.x(), rect.y(), NULL);
  225. ::SelectObject(hdc, brush);
  226. ::FillRect(hdc, &themeRect, brush);
  227. ::RestoreDC(hdc, -1);
  228. ::DeleteObject(brush);
  229. ::DeleteObject(patternBitmap);
  230. }
  231. }
  232. context->releaseWindowsContext(hdc, rect, alphaBlend);
  233. }
  234. void ScrollbarThemeWin::paintButton(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect, ScrollbarPart part)
  235. {
  236. checkAndInitScrollbarTheme();
  237. bool start = (part == BackButtonStartPart);
  238. int xpState = 0;
  239. int classicState = 0;
  240. if (scrollbar->orientation() == HorizontalScrollbar)
  241. xpState = start ? TS_LEFT_BUTTON : TS_RIGHT_BUTTON;
  242. else
  243. xpState = start ? TS_UP_BUTTON : TS_DOWN_BUTTON;
  244. classicState = xpState / 4;
  245. if (!scrollbar->enabled()) {
  246. xpState += TS_DISABLED;
  247. classicState |= DFCS_INACTIVE;
  248. } else if ((scrollbar->hoveredPart() == BackButtonStartPart && start) ||
  249. (scrollbar->hoveredPart() == ForwardButtonEndPart && !start)) {
  250. if (scrollbar->pressedPart() == scrollbar->hoveredPart()) {
  251. xpState += TS_ACTIVE;
  252. classicState |= DFCS_PUSHED | DFCS_FLAT;
  253. } else
  254. xpState += TS_HOVER;
  255. } else {
  256. if (scrollbar->hoveredPart() == NoPart || !runningVista)
  257. xpState += TS_NORMAL;
  258. else {
  259. if (scrollbar->orientation() == HorizontalScrollbar)
  260. xpState = start ? TS_LEFT_BUTTON_HOVER : TS_RIGHT_BUTTON_HOVER;
  261. else
  262. xpState = start ? TS_UP_BUTTON_HOVER : TS_DOWN_BUTTON_HOVER;
  263. }
  264. }
  265. bool alphaBlend = false;
  266. if (scrollbarTheme)
  267. alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, SP_BUTTON, xpState);
  268. HDC hdc = context->getWindowsContext(rect, alphaBlend);
  269. RECT themeRect(rect);
  270. if (scrollbarTheme)
  271. DrawThemeBackground(scrollbarTheme, hdc, SP_BUTTON, xpState, &themeRect, 0);
  272. else
  273. ::DrawFrameControl(hdc, &themeRect, DFC_SCROLL, classicState);
  274. context->releaseWindowsContext(hdc, rect, alphaBlend);
  275. }
  276. static IntRect gripperRect(int thickness, const IntRect& thumbRect)
  277. {
  278. // Center in the thumb.
  279. int gripperThickness = thickness / 2;
  280. return IntRect(thumbRect.x() + (thumbRect.width() - gripperThickness) / 2,
  281. thumbRect.y() + (thumbRect.height() - gripperThickness) / 2,
  282. gripperThickness, gripperThickness);
  283. }
  284. static void paintGripper(Scrollbar* scrollbar, HDC hdc, const IntRect& rect)
  285. {
  286. if (!scrollbarTheme)
  287. return; // Classic look has no gripper.
  288. int state;
  289. if (!scrollbar->enabled())
  290. state = TS_DISABLED;
  291. else if (scrollbar->pressedPart() == ThumbPart)
  292. state = TS_ACTIVE; // Thumb always stays active once pressed.
  293. else if (scrollbar->hoveredPart() == ThumbPart)
  294. state = TS_HOVER;
  295. else
  296. state = TS_NORMAL;
  297. RECT themeRect(rect);
  298. DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_GRIPPERHOR : SP_GRIPPERVERT, state, &themeRect, 0);
  299. }
  300. void ScrollbarThemeWin::paintThumb(GraphicsContext* context, Scrollbar* scrollbar, const IntRect& rect)
  301. {
  302. checkAndInitScrollbarTheme();
  303. int state;
  304. if (!scrollbar->enabled())
  305. state = TS_DISABLED;
  306. else if (scrollbar->pressedPart() == ThumbPart)
  307. state = TS_ACTIVE; // Thumb always stays active once pressed.
  308. else if (scrollbar->hoveredPart() == ThumbPart)
  309. state = TS_HOVER;
  310. else
  311. state = TS_NORMAL;
  312. bool alphaBlend = false;
  313. if (scrollbarTheme)
  314. alphaBlend = IsThemeBackgroundPartiallyTransparent(scrollbarTheme, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state);
  315. HDC hdc = context->getWindowsContext(rect, alphaBlend);
  316. RECT themeRect(rect);
  317. if (scrollbarTheme) {
  318. DrawThemeBackground(scrollbarTheme, hdc, scrollbar->orientation() == HorizontalScrollbar ? SP_THUMBHOR : SP_THUMBVERT, state, &themeRect, 0);
  319. paintGripper(scrollbar, hdc, gripperRect(scrollbarThickness(), rect));
  320. } else
  321. ::DrawEdge(hdc, &themeRect, EDGE_RAISED, BF_RECT | BF_MIDDLE);
  322. context->releaseWindowsContext(hdc, rect, alphaBlend);
  323. }
  324. }