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