1/*
2 * This file is part of the select element renderer in WebCore.
3 *
4 * Copyright (C) 2006, 2007, 2009, 2014 Apple Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#pragma once
32
33#include "RenderBlockFlow.h"
34#include "ScrollableArea.h"
35#include <wtf/Optional.h>
36
37namespace WebCore {
38
39class HTMLSelectElement;
40
41class RenderListBox final : public RenderBlockFlow, public ScrollableArea {
42 WTF_MAKE_ISO_ALLOCATED(RenderListBox);
43public:
44 RenderListBox(HTMLSelectElement&, RenderStyle&&);
45 virtual ~RenderListBox();
46
47 HTMLSelectElement& selectElement() const;
48
49 void selectionChanged();
50
51 void setOptionsChanged(bool changed) { m_optionsChanged = changed; }
52
53 int listIndexAtOffset(const LayoutSize&);
54 LayoutRect itemBoundingBoxRect(const LayoutPoint&, int index);
55
56 bool scrollToRevealElementAtListIndex(int index);
57 bool listIndexIsVisible(int index);
58
59 int scrollToward(const IntPoint&); // Returns the new index or -1 if no scroll occurred
60
61 int size() const;
62
63 bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Element** stopElement = nullptr, RenderBox* startBox = nullptr, const IntPoint& wheelEventAbsolutePoint = IntPoint()) override;
64
65 bool scrolledToTop() const override;
66 bool scrolledToBottom() const override;
67 bool scrolledToLeft() const override;
68 bool scrolledToRight() const override;
69
70private:
71 void willBeDestroyed() override;
72
73 void element() const = delete;
74
75 const char* renderName() const override { return "RenderListBox"; }
76
77 bool isListBox() const override { return true; }
78
79 void updateFromElement() override;
80 bool hasControlClip() const override { return true; }
81 void paintObject(PaintInfo&, const LayoutPoint&) override;
82 LayoutRect controlClipRect(const LayoutPoint&) const override;
83
84 bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) override;
85
86 bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Element** stopElement = nullptr) override;
87
88 void computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const override;
89 void computePreferredLogicalWidths() override;
90 int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const override;
91 LogicalExtentComputedValues computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const override;
92
93 void layout() override;
94
95 void addFocusRingRects(Vector<LayoutRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = nullptr) override;
96
97 bool canBeProgramaticallyScrolled() const override { return true; }
98 void autoscroll(const IntPoint&) override;
99 void stopAutoscroll() override;
100
101 virtual bool shouldPanScroll() const { return true; }
102 void panScroll(const IntPoint&) override;
103
104 int verticalScrollbarWidth() const override;
105 int scrollLeft() const override;
106 int scrollTop() const override;
107 int scrollWidth() const override;
108 int scrollHeight() const override;
109 void setScrollLeft(int, ScrollType, ScrollClamping) override;
110 void setScrollTop(int, ScrollType, ScrollClamping) override;
111
112 bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;
113
114 // ScrollableArea interface.
115 int scrollSize(ScrollbarOrientation) const override;
116 int scrollOffset(ScrollbarOrientation) const override;
117 void setScrollOffset(const ScrollOffset&) override;
118 ScrollPosition minimumScrollPosition() const override;
119 ScrollPosition maximumScrollPosition() const override;
120 void invalidateScrollbarRect(Scrollbar&, const IntRect&) override;
121 bool isActive() const override;
122 bool isScrollCornerVisible() const override { return false; } // We don't support resize on list boxes yet. If we did these would have to change.
123 IntRect scrollCornerRect() const override { return IntRect(); }
124 void invalidateScrollCornerRect(const IntRect&) override { }
125 IntRect convertFromScrollbarToContainingView(const Scrollbar&, const IntRect&) const override;
126 IntRect convertFromContainingViewToScrollbar(const Scrollbar&, const IntRect&) const override;
127 IntPoint convertFromScrollbarToContainingView(const Scrollbar&, const IntPoint&) const override;
128 IntPoint convertFromContainingViewToScrollbar(const Scrollbar&, const IntPoint&) const override;
129 Scrollbar* verticalScrollbar() const override { return m_vBar.get(); }
130 IntSize contentsSize() const override;
131 IntSize visibleSize() const override { return IntSize(width(), height()); }
132 IntPoint lastKnownMousePosition() const override;
133 bool isHandlingWheelEvent() const override;
134 bool shouldSuspendScrollAnimations() const override;
135 bool forceUpdateScrollbarsOnMainThreadForPerformanceTesting() const override;
136
137 ScrollableArea* enclosingScrollableArea() const override;
138 bool isScrollableOrRubberbandable() override;
139 bool hasScrollableOrRubberbandableAncestor() override;
140 IntRect scrollableAreaBoundingBox(bool* = nullptr) const override;
141 bool usesMockScrollAnimator() const override;
142 void logMockScrollAnimatorMessage(const String&) const override;
143
144 // NOTE: This should only be called by the overridden setScrollOffset from ScrollableArea.
145 void scrollTo(int newOffset);
146
147 using PaintFunction = WTF::Function<void(PaintInfo&, const LayoutPoint&, int listItemIndex)>;
148 void paintItem(PaintInfo&, const LayoutPoint&, const PaintFunction&);
149
150 void setHasVerticalScrollbar(bool hasScrollbar);
151 Ref<Scrollbar> createScrollbar();
152 void destroyScrollbar();
153
154 int maximumNumberOfItemsThatFitInPaddingBottomArea() const;
155
156 int numberOfVisibleItemsInPaddingTop() const;
157 int numberOfVisibleItemsInPaddingBottom() const;
158
159 void computeFirstIndexesVisibleInPaddingTopBottomAreas();
160
161 LayoutUnit itemHeight() const;
162 void valueChanged(unsigned listIndex);
163
164 enum class ConsiderPadding { Yes, No };
165 int numVisibleItems(ConsiderPadding = ConsiderPadding::No) const;
166 int numItems() const;
167 LayoutUnit listHeight() const;
168 void paintScrollbar(PaintInfo&, const LayoutPoint&);
169 void paintItemForeground(PaintInfo&, const LayoutPoint&, int listIndex);
170 void paintItemBackground(PaintInfo&, const LayoutPoint&, int listIndex);
171 void scrollToRevealSelection();
172
173 bool shouldPlaceBlockDirectionScrollbarOnLeft() const final { return RenderBlockFlow::shouldPlaceBlockDirectionScrollbarOnLeft(); }
174
175 bool m_optionsChanged;
176 bool m_scrollToRevealSelectionAfterLayout;
177 bool m_inAutoscroll;
178 int m_optionsWidth;
179 int m_indexOffset;
180
181 Optional<int> m_indexOfFirstVisibleItemInsidePaddingTopArea;
182 Optional<int> m_indexOfFirstVisibleItemInsidePaddingBottomArea;
183
184 RefPtr<Scrollbar> m_vBar;
185};
186
187} // namepace WebCore
188
189SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderListBox, isListBox())
190