Backed out 4 changesets (bug 1861985, bug 1860958, bug 1865364) for causing bustage...
[gecko.git] / layout / xul / nsScrollbarButtonFrame.cpp
blobc15be52e579f406f6045f8aa4695c946713487fc
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 //
8 // Eric Vaughan
9 // Netscape Communications
11 // See documentation in associated header file
14 #include "nsScrollbarButtonFrame.h"
15 #include "nsPresContext.h"
16 #include "nsIContent.h"
17 #include "nsCOMPtr.h"
18 #include "nsNameSpaceManager.h"
19 #include "nsGkAtoms.h"
20 #include "nsLayoutUtils.h"
21 #include "nsSliderFrame.h"
22 #include "nsScrollbarFrame.h"
23 #include "nsIScrollbarMediator.h"
24 #include "nsRepeatService.h"
25 #include "mozilla/LookAndFeel.h"
26 #include "mozilla/MouseEvents.h"
27 #include "mozilla/PresShell.h"
28 #include "mozilla/Telemetry.h"
30 using namespace mozilla;
33 // NS_NewToolbarFrame
35 // Creates a new Toolbar frame and returns it
37 nsIFrame* NS_NewScrollbarButtonFrame(PresShell* aPresShell,
38 ComputedStyle* aStyle) {
39 return new (aPresShell)
40 nsScrollbarButtonFrame(aStyle, aPresShell->GetPresContext());
42 NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame)
44 nsresult nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext,
45 WidgetGUIEvent* aEvent,
46 nsEventStatus* aEventStatus) {
47 NS_ENSURE_ARG_POINTER(aEventStatus);
49 // If a web page calls event.preventDefault() we still want to
50 // scroll when scroll arrow is clicked. See bug 511075.
51 if (!mContent->IsInNativeAnonymousSubtree() &&
52 nsEventStatus_eConsumeNoDefault == *aEventStatus) {
53 return NS_OK;
56 switch (aEvent->mMessage) {
57 case eMouseDown:
58 mCursorOnThis = true;
59 // if we didn't handle the press ourselves, pass it on to the superclass
60 if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) {
61 return NS_OK;
63 break;
64 case eMouseUp:
65 HandleRelease(aPresContext, aEvent, aEventStatus);
66 break;
67 case eMouseOut:
68 mCursorOnThis = false;
69 break;
70 case eMouseMove: {
71 nsPoint cursor = nsLayoutUtils::GetEventCoordinatesRelativeTo(
72 aEvent, RelativeTo{this});
73 nsRect frameRect(nsPoint(0, 0), GetSize());
74 mCursorOnThis = frameRect.Contains(cursor);
75 break;
77 default:
78 break;
81 return SimpleXULLeafFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
84 bool nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext,
85 WidgetGUIEvent* aEvent,
86 nsEventStatus* aEventStatus) {
87 // Get the desired action for the scrollbar button.
88 LookAndFeel::IntID tmpAction;
89 uint16_t button = aEvent->AsMouseEvent()->mButton;
90 if (button == MouseButton::ePrimary) {
91 tmpAction = LookAndFeel::IntID::ScrollButtonLeftMouseButtonAction;
92 } else if (button == MouseButton::eMiddle) {
93 tmpAction = LookAndFeel::IntID::ScrollButtonMiddleMouseButtonAction;
94 } else if (button == MouseButton::eSecondary) {
95 tmpAction = LookAndFeel::IntID::ScrollButtonRightMouseButtonAction;
96 } else {
97 return false;
100 // Get the button action metric from the pres. shell.
101 int32_t pressedButtonAction;
102 if (NS_FAILED(LookAndFeel::GetInt(tmpAction, &pressedButtonAction))) {
103 return false;
106 // get the scrollbar control
107 nsIFrame* scrollbar;
108 GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
110 if (scrollbar == nullptr) return false;
112 static dom::Element::AttrValuesArray strings[] = {
113 nsGkAtoms::increment, nsGkAtoms::decrement, nullptr};
114 int32_t index = mContent->AsElement()->FindAttrValueIn(
115 kNameSpaceID_None, nsGkAtoms::type, strings, eCaseMatters);
116 int32_t direction;
117 if (index == 0)
118 direction = 1;
119 else if (index == 1)
120 direction = -1;
121 else
122 return false;
124 bool repeat = pressedButtonAction != 2;
126 PresShell::SetCapturingContent(mContent, CaptureFlags::IgnoreAllowedState);
128 AutoWeakFrame weakFrame(this);
130 if (nsScrollbarFrame* sb = do_QueryFrame(scrollbar)) {
131 nsIScrollbarMediator* m = sb->GetScrollbarMediator();
132 switch (pressedButtonAction) {
133 case 0:
134 sb->SetIncrementToLine(direction);
135 if (m) {
136 m->ScrollByLine(sb, direction, ScrollSnapFlags::IntendedDirection);
138 break;
139 case 1:
140 sb->SetIncrementToPage(direction);
141 if (m) {
142 m->ScrollByPage(sb, direction,
143 ScrollSnapFlags::IntendedDirection |
144 ScrollSnapFlags::IntendedEndPosition);
146 break;
147 case 2:
148 sb->SetIncrementToWhole(direction);
149 if (m) {
150 m->ScrollByWhole(sb, direction, ScrollSnapFlags::IntendedEndPosition);
152 break;
153 case 3:
154 default:
155 // We were told to ignore this click, or someone assigned a non-standard
156 // value to the button's action.
157 return false;
159 if (!weakFrame.IsAlive()) {
160 return false;
163 if (!m) {
164 sb->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No);
165 if (!weakFrame.IsAlive()) {
166 return false;
170 if (repeat) {
171 StartRepeat();
173 return true;
176 NS_IMETHODIMP
177 nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
178 WidgetGUIEvent* aEvent,
179 nsEventStatus* aEventStatus) {
180 PresShell::ReleaseCapturingContent();
181 StopRepeat();
182 nsIFrame* scrollbar;
183 GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
184 nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
185 if (sb) {
186 nsIScrollbarMediator* m = sb->GetScrollbarMediator();
187 if (m) {
188 m->ScrollbarReleased(sb);
191 return NS_OK;
194 void nsScrollbarButtonFrame::Notify() {
195 if (mCursorOnThis ||
196 LookAndFeel::GetInt(LookAndFeel::IntID::ScrollbarButtonAutoRepeatBehavior,
197 0)) {
198 // get the scrollbar control
199 nsIFrame* scrollbar;
200 GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
201 nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
202 if (sb) {
203 nsIScrollbarMediator* m = sb->GetScrollbarMediator();
204 if (m) {
205 m->RepeatButtonScroll(sb);
206 } else {
207 sb->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No);
213 nsresult nsScrollbarButtonFrame::GetChildWithTag(nsAtom* atom, nsIFrame* start,
214 nsIFrame*& result) {
215 // recursively search our children
216 for (nsIFrame* childFrame : start->PrincipalChildList()) {
217 // get the content node
218 nsIContent* child = childFrame->GetContent();
220 if (child) {
221 // see if it is the child
222 if (child->IsXULElement(atom)) {
223 result = childFrame;
225 return NS_OK;
229 // recursive search the child
230 GetChildWithTag(atom, childFrame, result);
231 if (result != nullptr) return NS_OK;
234 result = nullptr;
235 return NS_OK;
238 nsresult nsScrollbarButtonFrame::GetParentWithTag(nsAtom* toFind,
239 nsIFrame* start,
240 nsIFrame*& result) {
241 while (start) {
242 start = start->GetParent();
244 if (start) {
245 // get the content node
246 nsIContent* child = start->GetContent();
248 if (child && child->IsXULElement(toFind)) {
249 result = start;
250 return NS_OK;
255 result = nullptr;
256 return NS_OK;
259 void nsScrollbarButtonFrame::Destroy(DestroyContext& aContext) {
260 // Ensure our repeat service isn't going... it's possible that a scrollbar can
261 // disappear out from under you while you're in the process of scrolling.
262 StopRepeat();
263 SimpleXULLeafFrame::Destroy(aContext);