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