Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : //
7 : // Eric Vaughan
8 : // Netscape Communications
9 : //
10 : // See documentation in associated header file
11 : //
12 :
13 : #include "nsScrollbarButtonFrame.h"
14 : #include "nsPresContext.h"
15 : #include "nsIContent.h"
16 : #include "nsCOMPtr.h"
17 : #include "nsNameSpaceManager.h"
18 : #include "nsGkAtoms.h"
19 : #include "nsSliderFrame.h"
20 : #include "nsScrollbarFrame.h"
21 : #include "nsIScrollbarMediator.h"
22 : #include "nsRepeatService.h"
23 : #include "mozilla/LookAndFeel.h"
24 : #include "mozilla/MouseEvents.h"
25 : #include "mozilla/Telemetry.h"
26 : #include "mozilla/layers/ScrollInputMethods.h"
27 :
28 : using namespace mozilla;
29 : using mozilla::layers::ScrollInputMethod;
30 :
31 : //
32 : // NS_NewToolbarFrame
33 : //
34 : // Creates a new Toolbar frame and returns it
35 : //
36 : nsIFrame*
37 0 : NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
38 : {
39 0 : return new (aPresShell) nsScrollbarButtonFrame(aContext);
40 : }
41 :
42 0 : NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame)
43 :
44 : nsresult
45 0 : nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext,
46 : WidgetGUIEvent* aEvent,
47 : nsEventStatus* aEventStatus)
48 : {
49 0 : NS_ENSURE_ARG_POINTER(aEventStatus);
50 :
51 : // If a web page calls event.preventDefault() we still want to
52 : // scroll when scroll arrow is clicked. See bug 511075.
53 0 : if (!mContent->IsInNativeAnonymousSubtree() &&
54 0 : nsEventStatus_eConsumeNoDefault == *aEventStatus) {
55 0 : return NS_OK;
56 : }
57 :
58 0 : switch (aEvent->mMessage) {
59 : case eMouseDown:
60 0 : mCursorOnThis = true;
61 : // if we didn't handle the press ourselves, pass it on to the superclass
62 0 : if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) {
63 0 : return NS_OK;
64 : }
65 0 : break;
66 : case eMouseUp:
67 0 : HandleRelease(aPresContext, aEvent, aEventStatus);
68 0 : break;
69 : case eMouseOut:
70 0 : mCursorOnThis = false;
71 0 : break;
72 : case eMouseMove: {
73 : nsPoint cursor =
74 0 : nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
75 0 : nsRect frameRect(nsPoint(0, 0), GetSize());
76 0 : mCursorOnThis = frameRect.Contains(cursor);
77 0 : break;
78 : }
79 : default:
80 0 : break;
81 : }
82 :
83 0 : return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
84 : }
85 :
86 : bool
87 0 : nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext,
88 : WidgetGUIEvent* aEvent,
89 : nsEventStatus* aEventStatus)
90 : {
91 : // Get the desired action for the scrollbar button.
92 : LookAndFeel::IntID tmpAction;
93 0 : uint16_t button = aEvent->AsMouseEvent()->button;
94 0 : if (button == WidgetMouseEvent::eLeftButton) {
95 0 : tmpAction = LookAndFeel::eIntID_ScrollButtonLeftMouseButtonAction;
96 0 : } else if (button == WidgetMouseEvent::eMiddleButton) {
97 0 : tmpAction = LookAndFeel::eIntID_ScrollButtonMiddleMouseButtonAction;
98 0 : } else if (button == WidgetMouseEvent::eRightButton) {
99 0 : tmpAction = LookAndFeel::eIntID_ScrollButtonRightMouseButtonAction;
100 : } else {
101 0 : return false;
102 : }
103 :
104 : // Get the button action metric from the pres. shell.
105 : int32_t pressedButtonAction;
106 0 : if (NS_FAILED(LookAndFeel::GetInt(tmpAction, &pressedButtonAction))) {
107 0 : return false;
108 : }
109 :
110 : // get the scrollbar control
111 : nsIFrame* scrollbar;
112 0 : GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
113 :
114 0 : if (scrollbar == nullptr)
115 0 : return false;
116 :
117 : static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment,
118 : &nsGkAtoms::decrement,
119 : nullptr };
120 0 : int32_t index = mContent->FindAttrValueIn(kNameSpaceID_None,
121 : nsGkAtoms::type,
122 0 : strings, eCaseMatters);
123 : int32_t direction;
124 0 : if (index == 0)
125 0 : direction = 1;
126 0 : else if (index == 1)
127 0 : direction = -1;
128 : else
129 0 : return false;
130 :
131 0 : bool repeat = pressedButtonAction != 2;
132 : // set this attribute so we can style it later
133 0 : AutoWeakFrame weakFrame(this);
134 0 : mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
135 :
136 0 : nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
137 :
138 0 : if (!weakFrame.IsAlive()) {
139 0 : return false;
140 : }
141 :
142 0 : nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
143 0 : if (sb) {
144 0 : nsIScrollbarMediator* m = sb->GetScrollbarMediator();
145 0 : switch (pressedButtonAction) {
146 : case 0:
147 0 : sb->SetIncrementToLine(direction);
148 0 : if (m) {
149 0 : m->ScrollByLine(sb, direction, nsIScrollbarMediator::ENABLE_SNAP);
150 : }
151 0 : break;
152 : case 1:
153 0 : sb->SetIncrementToPage(direction);
154 0 : if (m) {
155 0 : m->ScrollByPage(sb, direction, nsIScrollbarMediator::ENABLE_SNAP);
156 : }
157 0 : break;
158 : case 2:
159 0 : sb->SetIncrementToWhole(direction);
160 0 : if (m) {
161 0 : m->ScrollByWhole(sb, direction, nsIScrollbarMediator::ENABLE_SNAP);
162 : }
163 0 : break;
164 : case 3:
165 : default:
166 : // We were told to ignore this click, or someone assigned a non-standard
167 : // value to the button's action.
168 0 : return false;
169 : }
170 0 : if (!weakFrame.IsAlive()) {
171 0 : return false;
172 : }
173 :
174 : mozilla::Telemetry::Accumulate(mozilla::Telemetry::SCROLL_INPUT_METHODS,
175 0 : (uint32_t) ScrollInputMethod::MainThreadScrollbarButtonClick);
176 :
177 0 : if (!m) {
178 0 : sb->MoveToNewPosition();
179 0 : if (!weakFrame.IsAlive()) {
180 0 : return false;
181 : }
182 : }
183 : }
184 0 : if (repeat) {
185 0 : StartRepeat();
186 : }
187 0 : return true;
188 : }
189 :
190 : NS_IMETHODIMP
191 0 : nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
192 : WidgetGUIEvent* aEvent,
193 : nsEventStatus* aEventStatus)
194 : {
195 0 : nsIPresShell::SetCapturingContent(nullptr, 0);
196 : // we're not active anymore
197 0 : mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
198 0 : StopRepeat();
199 : nsIFrame* scrollbar;
200 0 : GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
201 0 : nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
202 0 : if (sb) {
203 0 : nsIScrollbarMediator* m = sb->GetScrollbarMediator();
204 0 : if (m) {
205 0 : m->ScrollbarReleased(sb);
206 : }
207 : }
208 0 : return NS_OK;
209 : }
210 :
211 0 : void nsScrollbarButtonFrame::Notify()
212 : {
213 0 : if (mCursorOnThis ||
214 0 : LookAndFeel::GetInt(
215 : LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior, 0)) {
216 : // get the scrollbar control
217 : nsIFrame* scrollbar;
218 0 : GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
219 0 : nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
220 0 : if (sb) {
221 0 : nsIScrollbarMediator* m = sb->GetScrollbarMediator();
222 0 : if (m) {
223 0 : m->RepeatButtonScroll(sb);
224 : } else {
225 0 : sb->MoveToNewPosition();
226 : }
227 : }
228 : }
229 0 : }
230 :
231 : void
232 0 : nsScrollbarButtonFrame::MouseClicked(WidgetGUIEvent* aEvent)
233 : {
234 0 : nsButtonBoxFrame::MouseClicked(aEvent);
235 : //MouseClicked();
236 0 : }
237 :
238 : nsresult
239 0 : nsScrollbarButtonFrame::GetChildWithTag(nsIAtom* atom, nsIFrame* start,
240 : nsIFrame*& result)
241 : {
242 : // recursively search our children
243 0 : for (nsIFrame* childFrame : start->PrincipalChildList())
244 : {
245 : // get the content node
246 0 : nsIContent* child = childFrame->GetContent();
247 :
248 0 : if (child) {
249 : // see if it is the child
250 0 : if (child->IsXULElement(atom))
251 : {
252 0 : result = childFrame;
253 :
254 0 : return NS_OK;
255 : }
256 : }
257 :
258 : // recursive search the child
259 0 : GetChildWithTag(atom, childFrame, result);
260 0 : if (result != nullptr)
261 0 : return NS_OK;
262 : }
263 :
264 0 : result = nullptr;
265 0 : return NS_OK;
266 : }
267 :
268 : nsresult
269 92 : nsScrollbarButtonFrame::GetParentWithTag(nsIAtom* toFind, nsIFrame* start,
270 : nsIFrame*& result)
271 : {
272 92 : while (start)
273 : {
274 92 : start = start->GetParent();
275 :
276 92 : if (start) {
277 : // get the content node
278 92 : nsIContent* child = start->GetContent();
279 :
280 92 : if (child && child->IsXULElement(toFind)) {
281 92 : result = start;
282 92 : return NS_OK;
283 : }
284 : }
285 : }
286 :
287 0 : result = nullptr;
288 0 : return NS_OK;
289 : }
290 :
291 : void
292 0 : nsScrollbarButtonFrame::DestroyFrom(nsIFrame* aDestructRoot)
293 : {
294 : // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
295 : // from under you while you're in the process of scrolling.
296 0 : StopRepeat();
297 0 : nsButtonBoxFrame::DestroyFrom(aDestructRoot);
298 0 : }
|