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 "core/rendering/RenderScrollbarPart.h"
28
29#include "core/rendering/PaintInfo.h"
30#include "core/rendering/RenderScrollbar.h"
31#include "core/rendering/RenderScrollbarTheme.h"
32#include "core/rendering/RenderView.h"
33
34using namespace std;
35
36namespace WebCore {
37
38RenderScrollbarPart::RenderScrollbarPart(RenderScrollbar* scrollbar, ScrollbarPart part)
39    : RenderBlock(0)
40    , m_scrollbar(scrollbar)
41    , m_part(part)
42{
43}
44
45RenderScrollbarPart::~RenderScrollbarPart()
46{
47}
48
49RenderScrollbarPart* RenderScrollbarPart::createAnonymous(Document* document, RenderScrollbar* scrollbar, ScrollbarPart part)
50{
51    RenderScrollbarPart* renderer = new RenderScrollbarPart(scrollbar, part);
52    renderer->setDocumentForAnonymous(document);
53    return renderer;
54}
55
56void RenderScrollbarPart::layout()
57{
58    StackStats::LayoutCheckPoint layoutCheckPoint;
59    setLocation(LayoutPoint()); // We don't worry about positioning ourselves. We're just determining our minimum width/height.
60    if (m_scrollbar->orientation() == HorizontalScrollbar)
61        layoutHorizontalPart();
62    else
63        layoutVerticalPart();
64
65    clearNeedsLayout();
66}
67
68void RenderScrollbarPart::layoutHorizontalPart()
69{
70    if (m_part == ScrollbarBGPart) {
71        setWidth(m_scrollbar->width());
72        computeScrollbarHeight();
73    } else {
74        computeScrollbarWidth();
75        setHeight(m_scrollbar->height());
76    }
77}
78
79void RenderScrollbarPart::layoutVerticalPart()
80{
81    if (m_part == ScrollbarBGPart) {
82        computeScrollbarWidth();
83        setHeight(m_scrollbar->height());
84    } else {
85        setWidth(m_scrollbar->width());
86        computeScrollbarHeight();
87    }
88}
89
90static int calcScrollbarThicknessUsing(SizeType sizeType, const Length& length, int containingLength, RenderView* renderView)
91{
92    if (!length.isIntrinsicOrAuto() || (sizeType == MinSize && length.isAuto()))
93        return minimumValueForLength(length, containingLength, renderView);
94    return ScrollbarTheme::theme()->scrollbarThickness();
95}
96
97void RenderScrollbarPart::computeScrollbarWidth()
98{
99    if (!m_scrollbar->owningRenderer())
100        return;
101    RenderView* renderView = view();
102    // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change.
103    // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders.
104    int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->style()->borderLeftWidth() - m_scrollbar->owningRenderer()->style()->borderRightWidth();
105    int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->width(), visibleSize, renderView);
106    int minWidth = calcScrollbarThicknessUsing(MinSize, style()->minWidth(), visibleSize, renderView);
107    int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style()->maxWidth(), visibleSize, renderView);
108    setWidth(max(minWidth, min(maxWidth, w)));
109
110    // Buttons and track pieces can all have margins along the axis of the scrollbar.
111    m_marginBox.setLeft(minimumValueForLength(style()->marginLeft(), visibleSize, renderView));
112    m_marginBox.setRight(minimumValueForLength(style()->marginRight(), visibleSize, renderView));
113}
114
115void RenderScrollbarPart::computeScrollbarHeight()
116{
117    if (!m_scrollbar->owningRenderer())
118        return;
119    RenderView* renderView = view();
120    // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change.
121    // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders.
122    int visibleSize = m_scrollbar->owningRenderer()->height() -  m_scrollbar->owningRenderer()->style()->borderTopWidth() - m_scrollbar->owningRenderer()->style()->borderBottomWidth();
123    int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->height(), visibleSize, renderView);
124    int minHeight = calcScrollbarThicknessUsing(MinSize, style()->minHeight(), visibleSize, renderView);
125    int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(MaxSize, style()->maxHeight(), visibleSize, renderView);
126    setHeight(max(minHeight, min(maxHeight, h)));
127
128    // Buttons and track pieces can all have margins along the axis of the scrollbar.
129    m_marginBox.setTop(minimumValueForLength(style()->marginTop(), visibleSize, renderView));
130    m_marginBox.setBottom(minimumValueForLength(style()->marginBottom(), visibleSize, renderView));
131}
132
133void RenderScrollbarPart::computePreferredLogicalWidths()
134{
135    if (!preferredLogicalWidthsDirty())
136        return;
137
138    m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = 0;
139
140    setPreferredLogicalWidthsDirty(false);
141}
142
143void RenderScrollbarPart::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
144{
145    RenderBlock::styleWillChange(diff, newStyle);
146    setInline(false);
147}
148
149void RenderScrollbarPart::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
150{
151    RenderBlock::styleDidChange(diff, oldStyle);
152    setInline(false);
153    clearPositionedState();
154    setFloating(false);
155    setHasOverflowClip(false);
156    if (oldStyle && m_scrollbar && m_part != NoPart && diff >= StyleDifferenceRepaint)
157        m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part);
158}
159
160void RenderScrollbarPart::imageChanged(WrappedImagePtr image, const IntRect* rect)
161{
162    if (m_scrollbar && m_part != NoPart)
163        m_scrollbar->theme()->invalidatePart(m_scrollbar, m_part);
164    else {
165        if (FrameView* frameView = view()->frameView()) {
166            if (frameView->isFrameViewScrollCorner(this)) {
167                frameView->invalidateScrollCorner(frameView->scrollCornerRect());
168                return;
169            }
170        }
171
172        RenderBlock::imageChanged(image, rect);
173    }
174}
175
176void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, const LayoutRect& rect)
177{
178    // Make sure our dimensions match the rect.
179    setLocation(rect.location() - toSize(paintOffset));
180    setWidth(rect.width());
181    setHeight(rect.height());
182
183    if (graphicsContext->paintingDisabled())
184        return;
185
186    // Now do the paint.
187    PaintInfo paintInfo(graphicsContext, pixelSnappedIntRect(rect), PaintPhaseBlockBackground, PaintBehaviorNormal);
188    paint(paintInfo, paintOffset);
189    paintInfo.phase = PaintPhaseChildBlockBackgrounds;
190    paint(paintInfo, paintOffset);
191    paintInfo.phase = PaintPhaseFloat;
192    paint(paintInfo, paintOffset);
193    paintInfo.phase = PaintPhaseForeground;
194    paint(paintInfo, paintOffset);
195    paintInfo.phase = PaintPhaseOutline;
196    paint(paintInfo, paintOffset);
197}
198
199RenderObject* RenderScrollbarPart::rendererOwningScrollbar() const
200{
201    if (!m_scrollbar)
202        return 0;
203    return m_scrollbar->owningRenderer();
204}
205
206}
207