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/. */
9 // Netscape Communications
11 // See documentation in associated header file
14 #include "nsScrollbarButtonFrame.h"
15 #include "nsPresContext.h"
16 #include "nsIContent.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
;
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
) {
56 switch (aEvent
->mMessage
) {
59 // if we didn't handle the press ourselves, pass it on to the superclass
60 if (HandleButtonPress(aPresContext
, aEvent
, aEventStatus
)) {
65 HandleRelease(aPresContext
, aEvent
, aEventStatus
);
68 mCursorOnThis
= false;
71 nsPoint cursor
= nsLayoutUtils::GetEventCoordinatesRelativeTo(
72 aEvent
, RelativeTo
{this});
73 nsRect
frameRect(nsPoint(0, 0), GetSize());
74 mCursorOnThis
= frameRect
.Contains(cursor
);
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
;
100 // Get the button action metric from the pres. shell.
101 int32_t pressedButtonAction
;
102 if (NS_FAILED(LookAndFeel::GetInt(tmpAction
, &pressedButtonAction
))) {
106 // get the scrollbar control
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
);
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
) {
134 sb
->SetIncrementToLine(direction
);
136 m
->ScrollByLine(sb
, direction
, ScrollSnapFlags::IntendedDirection
);
140 sb
->SetIncrementToPage(direction
);
142 m
->ScrollByPage(sb
, direction
,
143 ScrollSnapFlags::IntendedDirection
|
144 ScrollSnapFlags::IntendedEndPosition
);
148 sb
->SetIncrementToWhole(direction
);
150 m
->ScrollByWhole(sb
, direction
, ScrollSnapFlags::IntendedEndPosition
);
155 // We were told to ignore this click, or someone assigned a non-standard
156 // value to the button's action.
159 if (!weakFrame
.IsAlive()) {
164 sb
->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No
);
165 if (!weakFrame
.IsAlive()) {
177 nsScrollbarButtonFrame::HandleRelease(nsPresContext
* aPresContext
,
178 WidgetGUIEvent
* aEvent
,
179 nsEventStatus
* aEventStatus
) {
180 PresShell::ReleaseCapturingContent();
183 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
184 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
186 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
188 m
->ScrollbarReleased(sb
);
194 void nsScrollbarButtonFrame::Notify() {
196 LookAndFeel::GetInt(LookAndFeel::IntID::ScrollbarButtonAutoRepeatBehavior
,
198 // get the scrollbar control
200 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
201 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
203 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
205 m
->RepeatButtonScroll(sb
);
207 sb
->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No
);
213 nsresult
nsScrollbarButtonFrame::GetChildWithTag(nsAtom
* atom
, nsIFrame
* start
,
215 // recursively search our children
216 for (nsIFrame
* childFrame
: start
->PrincipalChildList()) {
217 // get the content node
218 nsIContent
* child
= childFrame
->GetContent();
221 // see if it is the child
222 if (child
->IsXULElement(atom
)) {
229 // recursive search the child
230 GetChildWithTag(atom
, childFrame
, result
);
231 if (result
!= nullptr) return NS_OK
;
238 nsresult
nsScrollbarButtonFrame::GetParentWithTag(nsAtom
* toFind
,
242 start
= start
->GetParent();
245 // get the content node
246 nsIContent
* child
= start
->GetContent();
248 if (child
&& child
->IsXULElement(toFind
)) {
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.
263 SimpleXULLeafFrame::Destroy(aContext
);