1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/xul/nsScrollbarButtonFrame.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,316 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +// 1.10 +// Eric Vaughan 1.11 +// Netscape Communications 1.12 +// 1.13 +// See documentation in associated header file 1.14 +// 1.15 + 1.16 +#include "nsScrollbarButtonFrame.h" 1.17 +#include "nsPresContext.h" 1.18 +#include "nsIContent.h" 1.19 +#include "nsCOMPtr.h" 1.20 +#include "nsNameSpaceManager.h" 1.21 +#include "nsGkAtoms.h" 1.22 +#include "nsSliderFrame.h" 1.23 +#include "nsScrollbarFrame.h" 1.24 +#include "nsIScrollbarMediator.h" 1.25 +#include "nsRepeatService.h" 1.26 +#include "mozilla/LookAndFeel.h" 1.27 +#include "mozilla/MouseEvents.h" 1.28 + 1.29 +using namespace mozilla; 1.30 + 1.31 +// 1.32 +// NS_NewToolbarFrame 1.33 +// 1.34 +// Creates a new Toolbar frame and returns it 1.35 +// 1.36 +nsIFrame* 1.37 +NS_NewScrollbarButtonFrame (nsIPresShell* aPresShell, nsStyleContext* aContext) 1.38 +{ 1.39 + return new (aPresShell) nsScrollbarButtonFrame(aPresShell, aContext); 1.40 +} 1.41 + 1.42 +NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarButtonFrame) 1.43 + 1.44 +nsresult 1.45 +nsScrollbarButtonFrame::HandleEvent(nsPresContext* aPresContext, 1.46 + WidgetGUIEvent* aEvent, 1.47 + nsEventStatus* aEventStatus) 1.48 +{ 1.49 + NS_ENSURE_ARG_POINTER(aEventStatus); 1.50 + 1.51 + // If a web page calls event.preventDefault() we still want to 1.52 + // scroll when scroll arrow is clicked. See bug 511075. 1.53 + if (!mContent->IsInNativeAnonymousSubtree() && 1.54 + nsEventStatus_eConsumeNoDefault == *aEventStatus) { 1.55 + return NS_OK; 1.56 + } 1.57 + 1.58 + switch (aEvent->message) { 1.59 + case NS_MOUSE_BUTTON_DOWN: 1.60 + mCursorOnThis = true; 1.61 + // if we didn't handle the press ourselves, pass it on to the superclass 1.62 + if (HandleButtonPress(aPresContext, aEvent, aEventStatus)) { 1.63 + return NS_OK; 1.64 + } 1.65 + break; 1.66 + case NS_MOUSE_BUTTON_UP: 1.67 + HandleRelease(aPresContext, aEvent, aEventStatus); 1.68 + break; 1.69 + case NS_MOUSE_EXIT_SYNTH: 1.70 + mCursorOnThis = false; 1.71 + break; 1.72 + case NS_MOUSE_MOVE: { 1.73 + nsPoint cursor = 1.74 + nsLayoutUtils::GetEventCoordinatesRelativeTo(aEvent, this); 1.75 + nsRect frameRect(nsPoint(0, 0), GetSize()); 1.76 + mCursorOnThis = frameRect.Contains(cursor); 1.77 + break; 1.78 + } 1.79 + } 1.80 + 1.81 + return nsButtonBoxFrame::HandleEvent(aPresContext, aEvent, aEventStatus); 1.82 +} 1.83 + 1.84 + 1.85 +bool 1.86 +nsScrollbarButtonFrame::HandleButtonPress(nsPresContext* aPresContext, 1.87 + WidgetGUIEvent* aEvent, 1.88 + nsEventStatus* aEventStatus) 1.89 +{ 1.90 + // Get the desired action for the scrollbar button. 1.91 + LookAndFeel::IntID tmpAction; 1.92 + uint16_t button = aEvent->AsMouseEvent()->button; 1.93 + if (button == WidgetMouseEvent::eLeftButton) { 1.94 + tmpAction = LookAndFeel::eIntID_ScrollButtonLeftMouseButtonAction; 1.95 + } else if (button == WidgetMouseEvent::eMiddleButton) { 1.96 + tmpAction = LookAndFeel::eIntID_ScrollButtonMiddleMouseButtonAction; 1.97 + } else if (button == WidgetMouseEvent::eRightButton) { 1.98 + tmpAction = LookAndFeel::eIntID_ScrollButtonRightMouseButtonAction; 1.99 + } else { 1.100 + return false; 1.101 + } 1.102 + 1.103 + // Get the button action metric from the pres. shell. 1.104 + int32_t pressedButtonAction; 1.105 + if (NS_FAILED(LookAndFeel::GetInt(tmpAction, &pressedButtonAction))) { 1.106 + return false; 1.107 + } 1.108 + 1.109 + // get the scrollbar control 1.110 + nsIFrame* scrollbar; 1.111 + GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar); 1.112 + 1.113 + if (scrollbar == nullptr) 1.114 + return false; 1.115 + 1.116 + // get the scrollbars content node 1.117 + nsIContent* content = scrollbar->GetContent(); 1.118 + 1.119 + static nsIContent::AttrValuesArray strings[] = { &nsGkAtoms::increment, 1.120 + &nsGkAtoms::decrement, 1.121 + nullptr }; 1.122 + int32_t index = mContent->FindAttrValueIn(kNameSpaceID_None, 1.123 + nsGkAtoms::type, 1.124 + strings, eCaseMatters); 1.125 + int32_t direction; 1.126 + if (index == 0) 1.127 + direction = 1; 1.128 + else if (index == 1) 1.129 + direction = -1; 1.130 + else 1.131 + return false; 1.132 + 1.133 + // Whether or not to repeat the click action. 1.134 + bool repeat = true; 1.135 + // Use smooth scrolling by default. 1.136 + bool smoothScroll = true; 1.137 + switch (pressedButtonAction) { 1.138 + case 0: 1.139 + mIncrement = direction * nsSliderFrame::GetIncrement(content); 1.140 + break; 1.141 + case 1: 1.142 + mIncrement = direction * nsSliderFrame::GetPageIncrement(content); 1.143 + break; 1.144 + case 2: 1.145 + if (direction == -1) 1.146 + mIncrement = -nsSliderFrame::GetCurrentPosition(content); 1.147 + else 1.148 + mIncrement = nsSliderFrame::GetMaxPosition(content) - 1.149 + nsSliderFrame::GetCurrentPosition(content); 1.150 + // Don't repeat or use smooth scrolling if scrolling to beginning or end 1.151 + // of a page. 1.152 + repeat = smoothScroll = false; 1.153 + break; 1.154 + case 3: 1.155 + default: 1.156 + // We were told to ignore this click, or someone assigned a non-standard 1.157 + // value to the button's action. 1.158 + return false; 1.159 + } 1.160 + // set this attribute so we can style it later 1.161 + nsWeakFrame weakFrame(this); 1.162 + mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::active, NS_LITERAL_STRING("true"), true); 1.163 + 1.164 + nsIPresShell::SetCapturingContent(mContent, CAPTURE_IGNOREALLOWED); 1.165 + 1.166 + if (weakFrame.IsAlive()) { 1.167 + DoButtonAction(smoothScroll); 1.168 + } 1.169 + if (repeat) 1.170 + StartRepeat(); 1.171 + return true; 1.172 +} 1.173 + 1.174 +NS_IMETHODIMP 1.175 +nsScrollbarButtonFrame::HandleRelease(nsPresContext* aPresContext, 1.176 + WidgetGUIEvent* aEvent, 1.177 + nsEventStatus* aEventStatus) 1.178 +{ 1.179 + nsIPresShell::SetCapturingContent(nullptr, 0); 1.180 + // we're not active anymore 1.181 + mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::active, true); 1.182 + StopRepeat(); 1.183 + return NS_OK; 1.184 +} 1.185 + 1.186 +void nsScrollbarButtonFrame::Notify() 1.187 +{ 1.188 + // Since this is only going to get called if we're scrolling a page length 1.189 + // or a line increment, we will always use smooth scrolling. 1.190 + if (mCursorOnThis || 1.191 + LookAndFeel::GetInt( 1.192 + LookAndFeel::eIntID_ScrollbarButtonAutoRepeatBehavior, 0)) { 1.193 + DoButtonAction(true); 1.194 + } 1.195 +} 1.196 + 1.197 +void 1.198 +nsScrollbarButtonFrame::MouseClicked(nsPresContext* aPresContext, 1.199 + WidgetGUIEvent* aEvent) 1.200 +{ 1.201 + nsButtonBoxFrame::MouseClicked(aPresContext, aEvent); 1.202 + //MouseClicked(); 1.203 +} 1.204 + 1.205 +void 1.206 +nsScrollbarButtonFrame::DoButtonAction(bool aSmoothScroll) 1.207 +{ 1.208 + // get the scrollbar control 1.209 + nsIFrame* scrollbar; 1.210 + GetParentWithTag(nsGkAtoms::scrollbar, this, scrollbar); 1.211 + 1.212 + if (scrollbar == nullptr) 1.213 + return; 1.214 + 1.215 + // get the scrollbars content node 1.216 + nsCOMPtr<nsIContent> content = scrollbar->GetContent(); 1.217 + 1.218 + // get the current pos 1.219 + int32_t curpos = nsSliderFrame::GetCurrentPosition(content); 1.220 + int32_t oldpos = curpos; 1.221 + 1.222 + // get the max pos 1.223 + int32_t maxpos = nsSliderFrame::GetMaxPosition(content); 1.224 + 1.225 + // increment the given amount 1.226 + if (mIncrement) 1.227 + curpos += mIncrement; 1.228 + 1.229 + // make sure the current position is between the current and max positions 1.230 + if (curpos < 0) 1.231 + curpos = 0; 1.232 + else if (curpos > maxpos) 1.233 + curpos = maxpos; 1.234 + 1.235 + nsScrollbarFrame* sb = do_QueryFrame(scrollbar); 1.236 + if (sb) { 1.237 + nsIScrollbarMediator* m = sb->GetScrollbarMediator(); 1.238 + if (m) { 1.239 + m->ScrollbarButtonPressed(sb, oldpos, curpos); 1.240 + return; 1.241 + } 1.242 + } 1.243 + 1.244 + // set the current position of the slider. 1.245 + nsAutoString curposStr; 1.246 + curposStr.AppendInt(curpos); 1.247 + 1.248 + if (aSmoothScroll) 1.249 + content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false); 1.250 + content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, true); 1.251 + if (aSmoothScroll) 1.252 + content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false); 1.253 +} 1.254 + 1.255 +nsresult 1.256 +nsScrollbarButtonFrame::GetChildWithTag(nsPresContext* aPresContext, 1.257 + nsIAtom* atom, nsIFrame* start, 1.258 + nsIFrame*& result) 1.259 +{ 1.260 + // recursively search our children 1.261 + nsIFrame* childFrame = start->GetFirstPrincipalChild(); 1.262 + while (nullptr != childFrame) 1.263 + { 1.264 + // get the content node 1.265 + nsIContent* child = childFrame->GetContent(); 1.266 + 1.267 + if (child) { 1.268 + // see if it is the child 1.269 + if (child->Tag() == atom) 1.270 + { 1.271 + result = childFrame; 1.272 + 1.273 + return NS_OK; 1.274 + } 1.275 + } 1.276 + 1.277 + // recursive search the child 1.278 + GetChildWithTag(aPresContext, atom, childFrame, result); 1.279 + if (result != nullptr) 1.280 + return NS_OK; 1.281 + 1.282 + childFrame = childFrame->GetNextSibling(); 1.283 + } 1.284 + 1.285 + result = nullptr; 1.286 + return NS_OK; 1.287 +} 1.288 + 1.289 +nsresult 1.290 +nsScrollbarButtonFrame::GetParentWithTag(nsIAtom* toFind, nsIFrame* start, 1.291 + nsIFrame*& result) 1.292 +{ 1.293 + while (start) 1.294 + { 1.295 + start = start->GetParent(); 1.296 + 1.297 + if (start) { 1.298 + // get the content node 1.299 + nsIContent* child = start->GetContent(); 1.300 + 1.301 + if (child && child->Tag() == toFind) { 1.302 + result = start; 1.303 + return NS_OK; 1.304 + } 1.305 + } 1.306 + } 1.307 + 1.308 + result = nullptr; 1.309 + return NS_OK; 1.310 +} 1.311 + 1.312 +void 1.313 +nsScrollbarButtonFrame::DestroyFrom(nsIFrame* aDestructRoot) 1.314 +{ 1.315 + // Ensure our repeat service isn't going... it's possible that a scrollbar can disappear out 1.316 + // from under you while you're in the process of scrolling. 1.317 + StopRepeat(); 1.318 + nsButtonBoxFrame::DestroyFrom(aDestructRoot); 1.319 +}