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