• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008, 2009 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 "RenderScrollbar.h"
28 
29 #include "RenderScrollbarPart.h"
30 #include "RenderScrollbarTheme.h"
31 
32 namespace WebCore {
33 
createCustomScrollbar(ScrollbarClient * client,ScrollbarOrientation orientation,RenderBox * renderer)34 PassRefPtr<Scrollbar> RenderScrollbar::createCustomScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer)
35 {
36     return adoptRef(new RenderScrollbar(client, orientation, renderer));
37 }
38 
RenderScrollbar(ScrollbarClient * client,ScrollbarOrientation orientation,RenderBox * renderer)39 RenderScrollbar::RenderScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, RenderBox* renderer)
40     : Scrollbar(client, orientation, RegularScrollbar, RenderScrollbarTheme::renderScrollbarTheme())
41     , m_owner(renderer)
42 {
43     // FIXME: We need to do this because RenderScrollbar::styleChanged is called as soon as the scrollbar is created.
44 
45     // Update the scrollbar size.
46     updateScrollbarPart(ScrollbarBGPart);
47     RenderScrollbarPart* part = m_parts.get(ScrollbarBGPart);
48     if (!part)
49         return;
50 
51     part->layout();
52     setFrameRect(IntRect(0, 0, part->width(), part->height()));
53 }
54 
~RenderScrollbar()55 RenderScrollbar::~RenderScrollbar()
56 {
57     ASSERT(m_parts.isEmpty());
58 }
59 
setParent(ScrollView * parent)60 void RenderScrollbar::setParent(ScrollView* parent)
61 {
62     Scrollbar::setParent(parent);
63     if (!parent) {
64         // Destroy all of the scrollbar's RenderBoxes.
65         updateScrollbarParts(true);
66     }
67 }
68 
setEnabled(bool e)69 void RenderScrollbar::setEnabled(bool e)
70 {
71     bool wasEnabled = enabled();
72     Scrollbar::setEnabled(e);
73     if (wasEnabled != e)
74         updateScrollbarParts();
75 }
76 
styleChanged()77 void RenderScrollbar::styleChanged()
78 {
79     updateScrollbarParts();
80 }
81 
paint(GraphicsContext * context,const IntRect & damageRect)82 void RenderScrollbar::paint(GraphicsContext* context, const IntRect& damageRect)
83 {
84     if (context->updatingControlTints()) {
85         updateScrollbarParts();
86         return;
87     }
88     Scrollbar::paint(context, damageRect);
89 }
90 
setHoveredPart(ScrollbarPart part)91 void RenderScrollbar::setHoveredPart(ScrollbarPart part)
92 {
93     if (part == m_hoveredPart)
94         return;
95 
96     ScrollbarPart oldPart = m_hoveredPart;
97     m_hoveredPart = part;
98 
99     updateScrollbarPart(oldPart);
100     updateScrollbarPart(m_hoveredPart);
101 
102     updateScrollbarPart(ScrollbarBGPart);
103     updateScrollbarPart(TrackBGPart);
104 }
105 
setPressedPart(ScrollbarPart part)106 void RenderScrollbar::setPressedPart(ScrollbarPart part)
107 {
108     ScrollbarPart oldPart = m_pressedPart;
109     Scrollbar::setPressedPart(part);
110 
111     updateScrollbarPart(oldPart);
112     updateScrollbarPart(part);
113 
114     updateScrollbarPart(ScrollbarBGPart);
115     updateScrollbarPart(TrackBGPart);
116 }
117 
118 static ScrollbarPart s_styleResolvePart;
119 static RenderScrollbar* s_styleResolveScrollbar;
120 
scrollbarForStyleResolve()121 RenderScrollbar* RenderScrollbar::scrollbarForStyleResolve()
122 {
123     return s_styleResolveScrollbar;
124 }
125 
partForStyleResolve()126 ScrollbarPart RenderScrollbar::partForStyleResolve()
127 {
128     return s_styleResolvePart;
129 }
130 
getScrollbarPseudoStyle(ScrollbarPart partType,PseudoId pseudoId)131 PassRefPtr<RenderStyle> RenderScrollbar::getScrollbarPseudoStyle(ScrollbarPart partType, PseudoId pseudoId)
132 {
133     s_styleResolvePart = partType;
134     s_styleResolveScrollbar = this;
135     RefPtr<RenderStyle> result = m_owner->getUncachedPseudoStyle(pseudoId, m_owner->style());
136     s_styleResolvePart = NoPart;
137     s_styleResolveScrollbar = 0;
138     return result;
139 }
140 
updateScrollbarParts(bool destroy)141 void RenderScrollbar::updateScrollbarParts(bool destroy)
142 {
143     updateScrollbarPart(ScrollbarBGPart, destroy);
144     updateScrollbarPart(BackButtonStartPart, destroy);
145     updateScrollbarPart(ForwardButtonStartPart, destroy);
146     updateScrollbarPart(BackTrackPart, destroy);
147     updateScrollbarPart(ThumbPart, destroy);
148     updateScrollbarPart(ForwardTrackPart, destroy);
149     updateScrollbarPart(BackButtonEndPart, destroy);
150     updateScrollbarPart(ForwardButtonEndPart, destroy);
151     updateScrollbarPart(TrackBGPart, destroy);
152 
153     if (destroy)
154         return;
155 
156     // See if the scrollbar's thickness changed.  If so, we need to mark our owning object as needing a layout.
157     bool isHorizontal = orientation() == HorizontalScrollbar;
158     int oldThickness = isHorizontal ? height() : width();
159     int newThickness = 0;
160     RenderScrollbarPart* part = m_parts.get(ScrollbarBGPart);
161     if (part) {
162         part->layout();
163         newThickness = isHorizontal ? part->height() : part->width();
164     }
165 
166     if (newThickness != oldThickness) {
167         setFrameRect(IntRect(x(), y(), isHorizontal ? width() : newThickness, isHorizontal ? newThickness : height()));
168         m_owner->setChildNeedsLayout(true);
169     }
170 }
171 
pseudoForScrollbarPart(ScrollbarPart part)172 static PseudoId pseudoForScrollbarPart(ScrollbarPart part)
173 {
174     switch (part) {
175         case BackButtonStartPart:
176         case ForwardButtonStartPart:
177         case BackButtonEndPart:
178         case ForwardButtonEndPart:
179             return SCROLLBAR_BUTTON;
180         case BackTrackPart:
181         case ForwardTrackPart:
182             return SCROLLBAR_TRACK_PIECE;
183         case ThumbPart:
184             return SCROLLBAR_THUMB;
185         case TrackBGPart:
186             return SCROLLBAR_TRACK;
187         case ScrollbarBGPart:
188             return SCROLLBAR;
189         case NoPart:
190         case AllParts:
191             break;
192     }
193     ASSERT_NOT_REACHED();
194     return SCROLLBAR;
195 }
196 
updateScrollbarPart(ScrollbarPart partType,bool destroy)197 void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy)
198 {
199     if (partType == NoPart)
200         return;
201 
202     RefPtr<RenderStyle> partStyle = !destroy ? getScrollbarPseudoStyle(partType,  pseudoForScrollbarPart(partType)) : 0;
203 
204     bool needRenderer = !destroy && partStyle && partStyle->display() != NONE && partStyle->visibility() == VISIBLE;
205 
206     if (needRenderer && partStyle->display() != BLOCK) {
207         // See if we are a button that should not be visible according to OS settings.
208         ScrollbarButtonsPlacement buttonsPlacement = theme()->buttonsPlacement();
209         switch (partType) {
210             case BackButtonStartPart:
211                 needRenderer = (buttonsPlacement == ScrollbarButtonsSingle || buttonsPlacement == ScrollbarButtonsDoubleStart ||
212                                 buttonsPlacement == ScrollbarButtonsDoubleBoth);
213                 break;
214             case ForwardButtonStartPart:
215                 needRenderer = (buttonsPlacement == ScrollbarButtonsDoubleStart || buttonsPlacement == ScrollbarButtonsDoubleBoth);
216                 break;
217             case BackButtonEndPart:
218                 needRenderer = (buttonsPlacement == ScrollbarButtonsDoubleEnd || buttonsPlacement == ScrollbarButtonsDoubleBoth);
219                 break;
220             case ForwardButtonEndPart:
221                 needRenderer = (buttonsPlacement == ScrollbarButtonsSingle || buttonsPlacement == ScrollbarButtonsDoubleEnd ||
222                                 buttonsPlacement == ScrollbarButtonsDoubleBoth);
223                 break;
224             default:
225                 break;
226         }
227     }
228 
229     RenderScrollbarPart* partRenderer = m_parts.get(partType);
230     if (!partRenderer && needRenderer) {
231         partRenderer = new (m_owner->renderArena()) RenderScrollbarPart(m_owner->document(), this, partType);
232         m_parts.set(partType, partRenderer);
233     } else if (partRenderer && !needRenderer) {
234         m_parts.remove(partType);
235         partRenderer->destroy();
236         partRenderer = 0;
237     }
238 
239     if (partRenderer)
240         partRenderer->setStyle(partStyle.release());
241 }
242 
paintPart(GraphicsContext * graphicsContext,ScrollbarPart partType,const IntRect & rect)243 void RenderScrollbar::paintPart(GraphicsContext* graphicsContext, ScrollbarPart partType, const IntRect& rect)
244 {
245     RenderScrollbarPart* partRenderer = m_parts.get(partType);
246     if (!partRenderer)
247         return;
248     partRenderer->paintIntoRect(graphicsContext, x(), y(), rect);
249 }
250 
buttonRect(ScrollbarPart partType)251 IntRect RenderScrollbar::buttonRect(ScrollbarPart partType)
252 {
253     RenderScrollbarPart* partRenderer = m_parts.get(partType);
254     if (!partRenderer)
255         return IntRect();
256 
257     partRenderer->layout();
258 
259     bool isHorizontal = orientation() == HorizontalScrollbar;
260     if (partType == BackButtonStartPart)
261         return IntRect(x(), y(), isHorizontal ? partRenderer->width() : width(), isHorizontal ? height() : partRenderer->height());
262     if (partType == ForwardButtonEndPart)
263         return IntRect(isHorizontal ? x() + width() - partRenderer->width() : x(),
264 
265                        isHorizontal ? y() : y() + height() - partRenderer->height(),
266                        isHorizontal ? partRenderer->width() : width(),
267                        isHorizontal ? height() : partRenderer->height());
268 
269     if (partType == ForwardButtonStartPart) {
270         IntRect previousButton = buttonRect(BackButtonStartPart);
271         return IntRect(isHorizontal ? x() + previousButton.width() : x(),
272                        isHorizontal ? y() : y() + previousButton.height(),
273                        isHorizontal ? partRenderer->width() : width(),
274                        isHorizontal ? height() : partRenderer->height());
275     }
276 
277     IntRect followingButton = buttonRect(ForwardButtonEndPart);
278     return IntRect(isHorizontal ? x() + width() - followingButton.width() - partRenderer->width() : x(),
279                    isHorizontal ? y() : y() + height() - followingButton.height() - partRenderer->height(),
280                    isHorizontal ? partRenderer->width() : width(),
281                    isHorizontal ? height() : partRenderer->height());
282 }
283 
trackRect(int startLength,int endLength)284 IntRect RenderScrollbar::trackRect(int startLength, int endLength)
285 {
286     RenderScrollbarPart* part = m_parts.get(TrackBGPart);
287     if (part)
288         part->layout();
289 
290     if (orientation() == HorizontalScrollbar) {
291         int marginLeft = part ? part->marginLeft() : 0;
292         int marginRight = part ? part->marginRight() : 0;
293         startLength += marginLeft;
294         endLength += marginRight;
295         int totalLength = startLength + endLength;
296         return IntRect(x() + startLength, y(), width() - totalLength, height());
297     }
298 
299     int marginTop = part ? part->marginTop() : 0;
300     int marginBottom = part ? part->marginBottom() : 0;
301     startLength += marginTop;
302     endLength += marginBottom;
303     int totalLength = startLength + endLength;
304 
305     return IntRect(x(), y() + startLength, width(), height() - totalLength);
306 }
307 
trackPieceRectWithMargins(ScrollbarPart partType,const IntRect & oldRect)308 IntRect RenderScrollbar::trackPieceRectWithMargins(ScrollbarPart partType, const IntRect& oldRect)
309 {
310     RenderScrollbarPart* partRenderer = m_parts.get(partType);
311     if (!partRenderer)
312         return oldRect;
313 
314     partRenderer->layout();
315 
316     IntRect rect = oldRect;
317     if (orientation() == HorizontalScrollbar) {
318         rect.setX(rect.x() + partRenderer->marginLeft());
319         rect.setWidth(rect.width() - (partRenderer->marginLeft() + partRenderer->marginRight()));
320     } else {
321         rect.setY(rect.y() + partRenderer->marginTop());
322         rect.setHeight(rect.height() - (partRenderer->marginTop() + partRenderer->marginBottom()));
323     }
324     return rect;
325 }
326 
minimumThumbLength()327 int RenderScrollbar::minimumThumbLength()
328 {
329     RenderScrollbarPart* partRenderer = m_parts.get(ThumbPart);
330     if (!partRenderer)
331         return 0;
332     partRenderer->layout();
333     return orientation() == HorizontalScrollbar ? partRenderer->width() : partRenderer->height();
334 }
335 
336 }
337