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