blob: 2355da9ab512e6c74c852b6bec001320ee4c653e [file] [log] [blame]
hyatt@apple.comf18feec2008-09-15 00:56:11 +00001/*
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
26#include "config.h"
27#include "ScrollbarThemeComposite.h"
28
aroben@apple.coma7c639a2009-12-18 17:38:45 +000029#include "Chrome.h"
hyatt@apple.com065494e2008-09-15 06:33:40 +000030#include "ChromeClient.h"
31#include "Frame.h"
32#include "FrameView.h"
33#include "GraphicsContext.h"
34#include "Page.h"
hyatt@apple.com63739ce2008-09-15 23:44:10 +000035#include "PlatformMouseEvent.h"
hyatt@apple.com065494e2008-09-15 06:33:40 +000036#include "Scrollbar.h"
weinig@apple.comd7d77c32011-01-21 20:15:04 +000037#include "ScrollableArea.h"
hyatt@apple.com065494e2008-09-15 06:33:40 +000038#include "Settings.h"
39
weinig@apple.comfe3ba1a2011-01-27 21:23:06 +000040using namespace std;
41
hyatt@apple.comf18feec2008-09-15 00:56:11 +000042namespace WebCore {
43
hyatt@apple.com065494e2008-09-15 06:33:40 +000044bool ScrollbarThemeComposite::paint(Scrollbar* scrollbar, GraphicsContext* graphicsContext, const IntRect& damageRect)
45{
46 // Create the ScrollbarControlPartMask based on the damageRect
47 ScrollbarControlPartMask scrollMask = NoPart;
48
hyatt@apple.comd48dbf32008-09-20 03:21:14 +000049 IntRect backButtonStartPaintRect;
50 IntRect backButtonEndPaintRect;
51 IntRect forwardButtonStartPaintRect;
52 IntRect forwardButtonEndPaintRect;
hyatt@apple.com065494e2008-09-15 06:33:40 +000053 if (hasButtons(scrollbar)) {
hyatt@apple.comd48dbf32008-09-20 03:21:14 +000054 backButtonStartPaintRect = backButtonRect(scrollbar, BackButtonStartPart, true);
55 if (damageRect.intersects(backButtonStartPaintRect))
hyatt@apple.com57b2d522008-09-19 23:39:26 +000056 scrollMask |= BackButtonStartPart;
hyatt@apple.comd48dbf32008-09-20 03:21:14 +000057 backButtonEndPaintRect = backButtonRect(scrollbar, BackButtonEndPart, true);
58 if (damageRect.intersects(backButtonEndPaintRect))
59 scrollMask |= BackButtonEndPart;
60 forwardButtonStartPaintRect = forwardButtonRect(scrollbar, ForwardButtonStartPart, true);
61 if (damageRect.intersects(forwardButtonStartPaintRect))
62 scrollMask |= ForwardButtonStartPart;
63 forwardButtonEndPaintRect = forwardButtonRect(scrollbar, ForwardButtonEndPart, true);
64 if (damageRect.intersects(forwardButtonEndPaintRect))
hyatt@apple.com57b2d522008-09-19 23:39:26 +000065 scrollMask |= ForwardButtonEndPart;
hyatt@apple.com065494e2008-09-15 06:33:40 +000066 }
67
68 IntRect startTrackRect;
69 IntRect thumbRect;
70 IntRect endTrackRect;
71 IntRect trackPaintRect = trackRect(scrollbar, true);
hyatt@apple.comf2452672008-10-11 07:50:03 +000072 if (damageRect.intersects(trackPaintRect))
73 scrollMask |= TrackBGPart;
hyatt@apple.com065494e2008-09-15 06:33:40 +000074 bool thumbPresent = hasThumb(scrollbar);
75 if (thumbPresent) {
76 IntRect track = trackRect(scrollbar);
77 splitTrack(scrollbar, track, startTrackRect, thumbRect, endTrackRect);
hyatt@apple.com2e4835d2008-10-10 02:33:16 +000078 if (damageRect.intersects(thumbRect))
hyatt@apple.com065494e2008-09-15 06:33:40 +000079 scrollMask |= ThumbPart;
hyatt@apple.com065494e2008-09-15 06:33:40 +000080 if (damageRect.intersects(startTrackRect))
81 scrollMask |= BackTrackPart;
82 if (damageRect.intersects(endTrackRect))
83 scrollMask |= ForwardTrackPart;
jamesr@google.come53ce642011-04-14 06:51:50 +000084 }
hyatt@apple.com065494e2008-09-15 06:33:40 +000085
hyatt@apple.com2e4835d2008-10-10 02:33:16 +000086 // Paint the scrollbar background (only used by custom CSS scrollbars).
87 paintScrollbarBackground(graphicsContext, scrollbar);
88
hyatt@apple.comc92f8c22008-10-10 20:12:14 +000089 // Paint the back and forward buttons.
90 if (scrollMask & BackButtonStartPart)
91 paintButton(graphicsContext, scrollbar, backButtonStartPaintRect, BackButtonStartPart);
92 if (scrollMask & BackButtonEndPart)
93 paintButton(graphicsContext, scrollbar, backButtonEndPaintRect, BackButtonEndPart);
94 if (scrollMask & ForwardButtonStartPart)
95 paintButton(graphicsContext, scrollbar, forwardButtonStartPaintRect, ForwardButtonStartPart);
96 if (scrollMask & ForwardButtonEndPart)
97 paintButton(graphicsContext, scrollbar, forwardButtonEndPaintRect, ForwardButtonEndPart);
98
hyatt@apple.comf2452672008-10-11 07:50:03 +000099 if (scrollMask & TrackBGPart)
hyatt@apple.com2e4835d2008-10-10 02:33:16 +0000100 paintTrackBackground(graphicsContext, scrollbar, trackPaintRect);
101
hyatt@apple.comf2452672008-10-11 07:50:03 +0000102 if ((scrollMask & ForwardTrackPart) || (scrollMask & BackTrackPart)) {
hyatt@apple.com739b8f02008-10-11 06:12:14 +0000103 // Paint the track pieces above and below the thumb.
hyatt@apple.com2e4835d2008-10-10 02:33:16 +0000104 if (scrollMask & BackTrackPart)
105 paintTrackPiece(graphicsContext, scrollbar, startTrackRect, BackTrackPart);
106 if (scrollMask & ForwardTrackPart)
107 paintTrackPiece(graphicsContext, scrollbar, endTrackRect, ForwardTrackPart);
darin@chromium.org2b367922008-11-24 23:12:03 +0000108
109 paintTickmarks(graphicsContext, scrollbar, trackPaintRect);
hyatt@apple.com065494e2008-09-15 06:33:40 +0000110 }
111
hyatt@apple.com065494e2008-09-15 06:33:40 +0000112 // Paint the thumb.
113 if (scrollMask & ThumbPart)
114 paintThumb(graphicsContext, scrollbar, thumbRect);
115
116 return true;
hyatt@apple.comf18feec2008-09-15 00:56:11 +0000117}
118
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000119ScrollbarPart ScrollbarThemeComposite::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt)
120{
121 ScrollbarPart result = NoPart;
hyatt@apple.comd1a01242008-09-18 01:32:42 +0000122 if (!scrollbar->enabled())
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000123 return result;
124
125 IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos());
126 mousePosition.move(scrollbar->x(), scrollbar->y());
hyatt@apple.comf2452672008-10-11 07:50:03 +0000127
128 if (!scrollbar->frameRect().contains(mousePosition))
129 return NoPart;
130
131 result = ScrollbarBGPart;
132
hyatt@apple.comc92f8c22008-10-10 20:12:14 +0000133 IntRect track = trackRect(scrollbar);
134 if (track.contains(mousePosition)) {
135 IntRect beforeThumbRect;
136 IntRect thumbRect;
137 IntRect afterThumbRect;
138 splitTrack(scrollbar, track, beforeThumbRect, thumbRect, afterThumbRect);
hyatt@apple.com4c767e22008-10-11 06:04:02 +0000139 if (thumbRect.contains(mousePosition))
hyatt@apple.comc92f8c22008-10-10 20:12:14 +0000140 result = ThumbPart;
hyatt@apple.com4c767e22008-10-11 06:04:02 +0000141 else if (beforeThumbRect.contains(mousePosition))
142 result = BackTrackPart;
hyatt@apple.comf2452672008-10-11 07:50:03 +0000143 else if (afterThumbRect.contains(mousePosition))
hyatt@apple.comc92f8c22008-10-10 20:12:14 +0000144 result = ForwardTrackPart;
hyatt@apple.comf2452672008-10-11 07:50:03 +0000145 else
146 result = TrackBGPart;
hyatt@apple.comc92f8c22008-10-10 20:12:14 +0000147 } else if (backButtonRect(scrollbar, BackButtonStartPart).contains(mousePosition))
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000148 result = BackButtonStartPart;
hyatt@apple.comea254e22008-09-20 00:42:36 +0000149 else if (backButtonRect(scrollbar, BackButtonEndPart).contains(mousePosition))
150 result = BackButtonEndPart;
151 else if (forwardButtonRect(scrollbar, ForwardButtonStartPart).contains(mousePosition))
152 result = ForwardButtonStartPart;
153 else if (forwardButtonRect(scrollbar, ForwardButtonEndPart).contains(mousePosition))
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000154 result = ForwardButtonEndPart;
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000155 return result;
156}
157
158void ScrollbarThemeComposite::invalidatePart(Scrollbar* scrollbar, ScrollbarPart part)
159{
160 if (part == NoPart)
161 return;
162
163 IntRect result;
164 switch (part) {
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000165 case BackButtonStartPart:
hyatt@apple.comea254e22008-09-20 00:42:36 +0000166 result = backButtonRect(scrollbar, BackButtonStartPart, true);
167 break;
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000168 case BackButtonEndPart:
hyatt@apple.comea254e22008-09-20 00:42:36 +0000169 result = backButtonRect(scrollbar, BackButtonEndPart, true);
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000170 break;
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000171 case ForwardButtonStartPart:
hyatt@apple.comea254e22008-09-20 00:42:36 +0000172 result = forwardButtonRect(scrollbar, ForwardButtonStartPart, true);
173 break;
hyatt@apple.com57b2d522008-09-19 23:39:26 +0000174 case ForwardButtonEndPart:
hyatt@apple.comea254e22008-09-20 00:42:36 +0000175 result = forwardButtonRect(scrollbar, ForwardButtonEndPart, true);
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000176 break;
hyatt@apple.com668b6712008-10-12 04:26:47 +0000177 case TrackBGPart:
178 result = trackRect(scrollbar, true);
179 break;
180 case ScrollbarBGPart:
181 result = scrollbar->frameRect();
182 break;
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000183 default: {
184 IntRect beforeThumbRect, thumbRect, afterThumbRect;
185 splitTrack(scrollbar, trackRect(scrollbar), beforeThumbRect, thumbRect, afterThumbRect);
186 if (part == BackTrackPart)
187 result = beforeThumbRect;
188 else if (part == ForwardTrackPart)
189 result = afterThumbRect;
190 else
191 result = thumbRect;
192 }
193 }
leviw@chromium.org35e01312011-06-03 02:41:09 +0000194 result.moveBy(-scrollbar->location());
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000195 scrollbar->invalidateRect(result);
196}
197
hyatt@apple.com0578b132008-10-12 04:20:26 +0000198void ScrollbarThemeComposite::splitTrack(Scrollbar* scrollbar, const IntRect& unconstrainedTrackRect, IntRect& beforeThumbRect, IntRect& thumbRect, IntRect& afterThumbRect)
hyatt@apple.com8e809932008-09-16 02:29:09 +0000199{
200 // This function won't even get called unless we're big enough to have some combination of these three rects where at least
201 // one of them is non-empty.
hyatt@apple.com0578b132008-10-12 04:20:26 +0000202 IntRect trackRect = constrainTrackRectToTrackPieces(scrollbar, unconstrainedTrackRect);
hyatt@apple.com2e4835d2008-10-10 02:33:16 +0000203 int thickness = scrollbar->orientation() == HorizontalScrollbar ? scrollbar->height() : scrollbar->width();
hyatt@apple.com8e809932008-09-16 02:29:09 +0000204 int thumbPos = thumbPosition(scrollbar);
hyatt@apple.com0578b132008-10-12 04:20:26 +0000205 if (scrollbar->orientation() == HorizontalScrollbar) {
206 thumbRect = IntRect(trackRect.x() + thumbPos, trackRect.y() + (trackRect.height() - thickness) / 2, thumbLength(scrollbar), thickness);
207 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), thumbPos + thumbRect.width() / 2, trackRect.height());
hyatt@apple.comaa0cba02011-02-01 21:39:47 +0000208 afterThumbRect = IntRect(trackRect.x() + beforeThumbRect.width(), trackRect.y(), trackRect.maxX() - beforeThumbRect.maxX(), trackRect.height());
hyatt@apple.com8e809932008-09-16 02:29:09 +0000209 } else {
hyatt@apple.com0578b132008-10-12 04:20:26 +0000210 thumbRect = IntRect(trackRect.x() + (trackRect.width() - thickness) / 2, trackRect.y() + thumbPos, thickness, thumbLength(scrollbar));
211 beforeThumbRect = IntRect(trackRect.x(), trackRect.y(), trackRect.width(), thumbPos + thumbRect.height() / 2);
hyatt@apple.comaa0cba02011-02-01 21:39:47 +0000212 afterThumbRect = IntRect(trackRect.x(), trackRect.y() + beforeThumbRect.height(), trackRect.width(), trackRect.maxY() - beforeThumbRect.maxY());
hyatt@apple.com8e809932008-09-16 02:29:09 +0000213 }
214}
215
weinig@apple.comfe3ba1a2011-01-27 21:23:06 +0000216// Returns the size represented by track taking into account scrolling past
217// the end of the document.
218static float usedTotalSize(Scrollbar* scrollbar)
219{
220 float overhangAtStart = -scrollbar->currentPos();
221 float overhangAtEnd = scrollbar->currentPos() + scrollbar->visibleSize() - scrollbar->totalSize();
222 float overhang = max(0.0f, max(overhangAtStart, overhangAtEnd));
223 return scrollbar->totalSize() + overhang;
224}
225
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000226int ScrollbarThemeComposite::thumbPosition(Scrollbar* scrollbar)
227{
commit-queue@webkit.org0e0315b2011-07-22 03:00:52 +0000228 if (scrollbar->enabled()) {
229 float pos = max(0.0f, scrollbar->currentPos()) * (trackLength(scrollbar) - thumbLength(scrollbar)) / (usedTotalSize(scrollbar) - scrollbar->visibleSize());
230 return (pos < 1 && pos > 0) ? 1 : pos;
231 }
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000232 return 0;
233}
234
235int ScrollbarThemeComposite::thumbLength(Scrollbar* scrollbar)
236{
hyatt@apple.comd1a01242008-09-18 01:32:42 +0000237 if (!scrollbar->enabled())
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000238 return 0;
239
weinig@apple.comfe3ba1a2011-01-27 21:23:06 +0000240 float proportion = scrollbar->visibleSize() / usedTotalSize(scrollbar);
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000241 int trackLen = trackLength(scrollbar);
242 int length = proportion * trackLen;
hyatt@apple.com8e809932008-09-16 02:29:09 +0000243 length = max(length, minimumThumbLength(scrollbar));
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000244 if (length > trackLen)
245 length = 0; // Once the thumb is below the track length, it just goes away (to make more room for the track).
246 return length;
247}
248
hyatt@apple.com8e809932008-09-16 02:29:09 +0000249int ScrollbarThemeComposite::minimumThumbLength(Scrollbar* scrollbar)
250{
251 return scrollbarThickness(scrollbar->controlSize());
252}
253
hyatt@apple.com1cd4bcc2008-09-16 06:53:34 +0000254int ScrollbarThemeComposite::trackPosition(Scrollbar* scrollbar)
255{
hyatt@apple.com0578b132008-10-12 04:20:26 +0000256 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, trackRect(scrollbar));
257 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackRect.x() - scrollbar->x() : constrainedTrackRect.y() - scrollbar->y();
hyatt@apple.com1cd4bcc2008-09-16 06:53:34 +0000258}
259
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000260int ScrollbarThemeComposite::trackLength(Scrollbar* scrollbar)
261{
hyatt@apple.com0578b132008-10-12 04:20:26 +0000262 IntRect constrainedTrackRect = constrainTrackRectToTrackPieces(scrollbar, trackRect(scrollbar));
263 return (scrollbar->orientation() == HorizontalScrollbar) ? constrainedTrackRect.width() : constrainedTrackRect.height();
hyatt@apple.com63739ce2008-09-15 23:44:10 +0000264}
265
andersca@apple.comaabadfa2011-10-03 22:31:24 +0000266void ScrollbarThemeComposite::paintScrollCorner(ScrollView*, GraphicsContext* context, const IntRect& cornerRect)
hyatt@apple.com3b82dce2008-10-01 17:51:02 +0000267{
krit@webkit.org2f1d5352010-10-20 13:09:50 +0000268 context->fillRect(cornerRect, Color::white, ColorSpaceDeviceRGB);
hyatt@apple.com3b82dce2008-10-01 17:51:02 +0000269}
270
commit-queue@webkit.orgf6a1fd22011-08-16 18:45:35 +0000271void ScrollbarThemeComposite::paintOverhangAreas(ScrollView*, GraphicsContext* context, const IntRect& horizontalOverhangRect, const IntRect& verticalOverhangRect, const IntRect& dirtyRect)
272{
273 context->setFillColor(Color::white, ColorSpaceDeviceRGB);
274 if (!horizontalOverhangRect.isEmpty())
275 context->fillRect(intersection(horizontalOverhangRect, dirtyRect));
276
277 context->setFillColor(Color::white, ColorSpaceDeviceRGB);
278 if (!verticalOverhangRect.isEmpty())
279 context->fillRect(intersection(verticalOverhangRect, dirtyRect));
280}
281
hyatt@apple.comf18feec2008-09-15 00:56:11 +0000282}