Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
6 //
7 // Eric Vaughan
8 // Netscape Communications
9 //
10 // See documentation in associated header file
11 //
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"
26 using namespace mozilla;
28 //
29 // NS_NewToolbarFrame
30 //
31 // Creates a new Toolbar frame and returns it
32 //
33 nsIFrame*
34 NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext)
35 {
36 return new (aPresShell) nsScrollbarButtonFrame(aPresShell, aContext);
37 }
39 NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame)
41 nsresult
42 nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext,
43 WidgetGUIEvent* aEvent,
44 nsEventStatus* aEventStatus)
45 {
46 NS_ENSURE_ARG_POINTER(aEventStatus);
48 // If a web page calls event.preventDefault() we still want to
49 // scroll when scroll arrow is clicked. See bug 511075.
50 if (!mContent->IsInNativeAnonymousSubtree() &&
51 nsEventStatus_eConsumeNoDefault == *aEventStatus) {
52 return NS_OK;
53 }
55 switch (aEvent->message) {
56 case NS_MOUSE_BUTTON_DOWN:
57 mCursorOnThis = true;
58 // if we didn't handle the press ourselves, pass it on to the superclass
59 if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) {
60 return NS_OK;
61 }
62 break;
63 case NS_MOUSE_BUTTON_UP:
64 HandleRelease(aPresContext, aEvent, aEventStatus);
65 break;
66 case NS_MOUSE_EXIT_SYNTH:
67 mCursorOnThis = false;
68 break;
69 case NS_MOUSE_MOVE: {
70 nsPoint cursor =
71 nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this);
72 nsRect frameRect(nsPoint(0, 0), GetSize());
73 mCursorOnThis = frameRect.Contains(cursor);
74 break;
75 }
76 }
78 return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus);
79 }
82 bool
83 nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext,
84 WidgetGUIEvent* aEvent,
85 nsEventStatus* aEventStatus)
86 {
87 // Get the desired action for the scrollbar button.
88 LookAndFeel::IntID tmpAction;
89 uint16_t button = aEvent->AsMouseEvent()->button;
90 if (button == WidgetMouseEvent::eLeftButton) {
91 tmpAction = LookAndFeel::eIntID_ScrollButtonLeftMouseButtonAction;
92 } else if (button == WidgetMouseEvent::eMiddleButton) {
93 tmpAction = LookAndFeel::eIntID_ScrollButtonMiddleMouseButtonAction;
94 } else if (button == WidgetMouseEvent::eRightButton) {
95 tmpAction = LookAndFeel::eIntID_ScrollButtonRightMouseButtonAction;
96 } else {
97 return false;
98 }
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;
104 }
106 // get the scrollbar control
107 nsIFrame* scrollbar;
108 GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
110 if (scrollbar == nullptr)
111 return false;
113 // get the scrollbars content node
114 nsIContent* content = scrollbar->GetContent();
116 static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment,
117 &nsGkAtoms::decrement,
118 nullptr };
119 int32_t index = mContent->FindAttrValueIn(kNameSpaceID_None,
120 nsGkAtoms::type,
121 strings, eCaseMatters);
122 int32_t direction;
123 if (index == 0)
124 direction = 1;
125 else if (index == 1)
126 direction = -1;
127 else
128 return false;
130 // Whether or not to repeat the click action.
131 bool repeat = true;
132 // Use smooth scrolling by default.
133 bool smoothScroll = true;
134 switch (pressedButtonAction) {
135 case 0:
136 mIncrement = direction * nsSliderFrame::GetIncrement(content);
137 break;
138 case 1:
139 mIncrement = direction * nsSliderFrame::GetPageIncrement(content);
140 break;
141 case 2:
142 if (direction == -1)
143 mIncrement = -nsSliderFrame::GetCurrentPosition(content);
144 else
145 mIncrement = nsSliderFrame::GetMaxPosition(content) -
146 nsSliderFrame::GetCurrentPosition(content);
147 // Don't repeat or use smooth scrolling if scrolling to beginning or end
148 // of a page.
149 repeat = smoothScroll = false;
150 break;
151 case 3:
152 default:
153 // We were told to ignore this click, or someone assigned a non-standard
154 // value to the button's action.
155 return false;
156 }
157 // set this attribute so we can style it later
158 nsWeakFrame weakFrame(this);
159 mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true);
161 nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED);
163 if (weakFrame.IsAlive()) {
164 DoButtonAction(smoothScroll);
165 }
166 if (repeat)
167 StartRepeat();
168 return true;
169 }
171 NS_IMETHODIMP
172 nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext,
173 WidgetGUIEvent* aEvent,
174 nsEventStatus* aEventStatus)
175 {
176 nsIPresShell::SetCapturingContent(nullptr, 0);
177 // we're not active anymore
178 mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true);
179 StopRepeat();
180 return NS_OK;
181 }
183 void nsScrollbarButtonFrame::Notify()
184 {
185 // Since this is only going to get called if we're scrolling a page length
186 // or a line increment, we will always use smooth scrolling.
187 if (mCursorOnThis ||
188 LookAndFeel::GetInt(
189 LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior, 0)) {
190 DoButtonAction(true);
191 }
192 }
194 void
195 nsScrollbarButtonFrame::MouseClicked(nsPresContext* aPresContext,
196 WidgetGUIEvent* aEvent)
197 {
198 nsButtonBoxFrame::MouseClicked(aPresContext, aEvent);
199 //MouseClicked();
200 }
202 void
203 nsScrollbarButtonFrame::DoButtonAction(bool aSmoothScroll)
204 {
205 // get the scrollbar control
206 nsIFrame* scrollbar;
207 GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar);
209 if (scrollbar == nullptr)
210 return;
212 // get the scrollbars content node
213 nsCOMPtr<nsIContent> content = scrollbar->GetContent();
215 // get the current pos
216 int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
217 int32_t oldpos = curpos;
219 // get the max pos
220 int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
222 // increment the given amount
223 if (mIncrement)
224 curpos += mIncrement;
226 // make sure the current position is between the current and max positions
227 if (curpos < 0)
228 curpos = 0;
229 else if (curpos > maxpos)
230 curpos = maxpos;
232 nsScrollbarFrame* sb = do_QueryFrame(scrollbar);
233 if (sb) {
234 nsIScrollbarMediator* m = sb->GetScrollbarMediator();
235 if (m) {
236 m->ScrollbarButtonPressed(sb, oldpos, curpos);
237 return;
238 }
239 }
241 // set the current position of the slider.
242 nsAutoString curposStr;
243 curposStr.AppendInt(curpos);
245 if (aSmoothScroll)
246 content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
247 content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, true);
248 if (aSmoothScroll)
249 content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
250 }
252 nsresult
253 nsScrollbarButtonFrame::GetChildWithTag(nsPresContext* aPresContext,
254 nsIAtom* atom, nsIFrame* start,
255 nsIFrame*& result)
256 {
257 // recursively search our children
258 nsIFrame* childFrame = start->GetFirstPrincipalChild();
259 while (nullptr != childFrame)
260 {
261 // get the content node
262 nsIContent* child = childFrame->GetContent();
264 if (child) {
265 // see if it is the child
266 if (child->Tag() == atom)
267 {
268 result = childFrame;
270 return NS_OK;
271 }
272 }
274 // recursive search the child
275 GetChildWithTag(aPresContext, atom, childFrame, result);
276 if (result != nullptr)
277 return NS_OK;
279 childFrame = childFrame->GetNextSibling();
280 }
282 result = nullptr;
283 return NS_OK;
284 }
286 nsresult
287 nsScrollbarButtonFrame::GetParentWithTag(nsIAtom* toFind, nsIFrame* start,
288 nsIFrame*& result)
289 {
290 while (start)
291 {
292 start = start->GetParent();
294 if (start) {
295 // get the content node
296 nsIContent* child = start->GetContent();
298 if (child && child->Tag() == toFind) {
299 result = start;
300 return NS_OK;
301 }
302 }
303 }
305 result = nullptr;
306 return NS_OK;
307 }
309 void
310 nsScrollbarButtonFrame::DestroyFrom(nsIFrame* aDestructRoot)
311 {
312 // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out
313 // from under you while you're in the process of scrolling.
314 StopRepeat();
315 nsButtonBoxFrame::DestroyFrom(aDestructRoot);
316 }