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());
43 NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame
)
45 nsresult
nsScrollbarButtonFrame::HandleEvent(nsPresContext
* aPresContext
,
46 WidgetGUIEvent
* aEvent
,
47 nsEventStatus
* aEventStatus
) {
48 NS_ENSURE_ARG_POINTER(aEventStatus
);
50 // If a web page calls event.preventDefault() we still want to
51 // scroll when scroll arrow is clicked. See bug 511075.
52 if (!mContent
->IsInNativeAnonymousSubtree() &&
53 nsEventStatus_eConsumeNoDefault
== *aEventStatus
) {
57 switch (aEvent
->mMessage
) {
60 // if we didn't handle the press ourselves, pass it on to the superclass
61 if (HandleButtonPress(aPresContext
, aEvent
, aEventStatus
)) {
66 HandleRelease(aPresContext
, aEvent
, aEventStatus
);
69 mCursorOnThis
= false;
72 nsPoint cursor
= nsLayoutUtils::GetEventCoordinatesRelativeTo(
73 aEvent
, RelativeTo
{this});
74 nsRect
frameRect(nsPoint(0, 0), GetSize());
75 mCursorOnThis
= frameRect
.Contains(cursor
);
82 return nsBoxFrame::HandleEvent(aPresContext
, aEvent
, aEventStatus
);
85 bool nsScrollbarButtonFrame::HandleButtonPress(nsPresContext
* aPresContext
,
86 WidgetGUIEvent
* aEvent
,
87 nsEventStatus
* aEventStatus
) {
88 // Get the desired action for the scrollbar button.
89 LookAndFeel::IntID tmpAction
;
90 uint16_t button
= aEvent
->AsMouseEvent()->mButton
;
91 if (button
== MouseButton::ePrimary
) {
92 tmpAction
= LookAndFeel::IntID::ScrollButtonLeftMouseButtonAction
;
93 } else if (button
== MouseButton::eMiddle
) {
94 tmpAction
= LookAndFeel::IntID::ScrollButtonMiddleMouseButtonAction
;
95 } else if (button
== MouseButton::eSecondary
) {
96 tmpAction
= LookAndFeel::IntID::ScrollButtonRightMouseButtonAction
;
101 // Get the button action metric from the pres. shell.
102 int32_t pressedButtonAction
;
103 if (NS_FAILED(LookAndFeel::GetInt(tmpAction
, &pressedButtonAction
))) {
107 // get the scrollbar control
109 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
111 if (scrollbar
== nullptr) return false;
113 static dom::Element::AttrValuesArray strings
[] = {
114 nsGkAtoms::increment
, nsGkAtoms::decrement
, nullptr};
115 int32_t index
= mContent
->AsElement()->FindAttrValueIn(
116 kNameSpaceID_None
, nsGkAtoms::type
, strings
, eCaseMatters
);
125 bool repeat
= pressedButtonAction
!= 2;
126 // set this attribute so we can style it later
127 AutoWeakFrame
weakFrame(this);
128 mContent
->AsElement()->SetAttr(kNameSpaceID_None
, nsGkAtoms::active
,
131 PresShell::SetCapturingContent(mContent
, CaptureFlags::IgnoreAllowedState
);
133 if (!weakFrame
.IsAlive()) {
137 if (nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
)) {
138 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
139 switch (pressedButtonAction
) {
141 sb
->SetIncrementToLine(direction
);
143 m
->ScrollByLine(sb
, direction
, ScrollSnapFlags::IntendedDirection
);
147 sb
->SetIncrementToPage(direction
);
149 m
->ScrollByPage(sb
, direction
,
150 ScrollSnapFlags::IntendedDirection
|
151 ScrollSnapFlags::IntendedEndPosition
);
155 sb
->SetIncrementToWhole(direction
);
157 m
->ScrollByWhole(sb
, direction
, ScrollSnapFlags::IntendedEndPosition
);
162 // We were told to ignore this click, or someone assigned a non-standard
163 // value to the button's action.
166 if (!weakFrame
.IsAlive()) {
171 sb
->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No
);
172 if (!weakFrame
.IsAlive()) {
184 nsScrollbarButtonFrame::HandleRelease(nsPresContext
* aPresContext
,
185 WidgetGUIEvent
* aEvent
,
186 nsEventStatus
* aEventStatus
) {
187 PresShell::ReleaseCapturingContent();
188 // we're not active anymore
189 mContent
->AsElement()->UnsetAttr(kNameSpaceID_None
, nsGkAtoms::active
, true);
192 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
193 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
195 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
197 m
->ScrollbarReleased(sb
);
203 void nsScrollbarButtonFrame::Notify() {
205 LookAndFeel::GetInt(LookAndFeel::IntID::ScrollbarButtonAutoRepeatBehavior
,
207 // get the scrollbar control
209 GetParentWithTag(nsGkAtoms::scrollbar
, this, scrollbar
);
210 nsScrollbarFrame
* sb
= do_QueryFrame(scrollbar
);
212 nsIScrollbarMediator
* m
= sb
->GetScrollbarMediator();
214 m
->RepeatButtonScroll(sb
);
216 sb
->MoveToNewPosition(nsScrollbarFrame::ImplementsScrollByUnit::No
);
222 nsresult
nsScrollbarButtonFrame::GetChildWithTag(nsAtom
* atom
, nsIFrame
* start
,
224 // recursively search our children
225 for (nsIFrame
* childFrame
: start
->PrincipalChildList()) {
226 // get the content node
227 nsIContent
* child
= childFrame
->GetContent();
230 // see if it is the child
231 if (child
->IsXULElement(atom
)) {
238 // recursive search the child
239 GetChildWithTag(atom
, childFrame
, result
);
240 if (result
!= nullptr) return NS_OK
;
247 nsresult
nsScrollbarButtonFrame::GetParentWithTag(nsAtom
* toFind
,
251 start
= start
->GetParent();
254 // get the content node
255 nsIContent
* child
= start
->GetContent();
257 if (child
&& child
->IsXULElement(toFind
)) {
268 void nsScrollbarButtonFrame::DestroyFrom(nsIFrame
* aDestructRoot
,
269 PostDestroyData
& aPostDestroyData
) {
270 // Ensure our repeat service isn't going... it's possible that a scrollbar can
271 // disappear out from under you while you're in the process of scrolling.
273 nsBoxFrame::DestroyFrom(aDestructRoot
, aPostDestroyData
);