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