Line data Source code
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/. */
5 :
6 : //
7 : // Eric Vaughan
8 : // Netscape Communications
9 : //
10 : // See documentation in associated header file
11 : //
12 :
13 : #include "nsScrollbarFrame.h"
14 : #include "nsSliderFrame.h"
15 : #include "nsScrollbarButtonFrame.h"
16 : #include "nsGkAtoms.h"
17 : #include "nsIScrollableFrame.h"
18 : #include "nsIScrollbarMediator.h"
19 : #include "mozilla/LookAndFeel.h"
20 : #include "nsThemeConstants.h"
21 : #include "nsIContent.h"
22 : #include "nsIDOMMutationEvent.h"
23 :
24 : using namespace mozilla;
25 :
26 : //
27 : // NS_NewScrollbarFrame
28 : //
29 : // Creates a new scrollbar frame and returns it
30 : //
31 : nsIFrame*
32 4 : NS_NewScrollbarFrame(nsIPresShell* aPresShell, nsStyleContext* aContext)
33 : {
34 4 : return new (aPresShell) nsScrollbarFrame(aContext);
35 : }
36 :
37 4 : NS_IMPL_FRAMEARENA_HELPERS(nsScrollbarFrame)
38 :
39 32 : NS_QUERYFRAME_HEAD(nsScrollbarFrame)
40 14 : NS_QUERYFRAME_ENTRY(nsScrollbarFrame)
41 18 : NS_QUERYFRAME_TAIL_INHERITING(nsBoxFrame)
42 :
43 : void
44 4 : nsScrollbarFrame::Init(nsIContent* aContent,
45 : nsContainerFrame* aParent,
46 : nsIFrame* aPrevInFlow)
47 : {
48 4 : nsBoxFrame::Init(aContent, aParent, aPrevInFlow);
49 :
50 : // We want to be a reflow root since we use reflows to move the
51 : // slider. Any reflow inside the scrollbar frame will be a reflow to
52 : // move the slider and will thus not change anything outside of the
53 : // scrollbar or change the size of the scrollbar frame.
54 4 : mState |= NS_FRAME_REFLOW_ROOT;
55 4 : }
56 :
57 : void
58 4 : nsScrollbarFrame::Reflow(nsPresContext* aPresContext,
59 : ReflowOutput& aDesiredSize,
60 : const ReflowInput& aReflowInput,
61 : nsReflowStatus& aStatus)
62 : {
63 4 : nsBoxFrame::Reflow(aPresContext, aDesiredSize, aReflowInput, aStatus);
64 :
65 : // nsGfxScrollFrame may have told us to shrink to nothing. If so, make sure our
66 : // desired size agrees.
67 4 : if (aReflowInput.AvailableWidth() == 0) {
68 2 : aDesiredSize.Width() = 0;
69 : }
70 4 : if (aReflowInput.AvailableHeight() == 0) {
71 0 : aDesiredSize.Height() = 0;
72 : }
73 4 : }
74 :
75 : nsresult
76 20 : nsScrollbarFrame::AttributeChanged(int32_t aNameSpaceID,
77 : nsIAtom* aAttribute,
78 : int32_t aModType)
79 : {
80 20 : nsresult rv = nsBoxFrame::AttributeChanged(aNameSpaceID, aAttribute,
81 20 : aModType);
82 :
83 : // if the current position changes, notify any nsGfxScrollFrame
84 : // parent we may have
85 20 : if (aAttribute != nsGkAtoms::curpos)
86 16 : return rv;
87 :
88 4 : nsIScrollableFrame* scrollable = do_QueryFrame(GetParent());
89 4 : if (!scrollable)
90 0 : return rv;
91 :
92 8 : nsCOMPtr<nsIContent> content(mContent);
93 4 : scrollable->CurPosAttributeChanged(content);
94 4 : return rv;
95 : }
96 :
97 : NS_IMETHODIMP
98 0 : nsScrollbarFrame::HandlePress(nsPresContext* aPresContext,
99 : WidgetGUIEvent* aEvent,
100 : nsEventStatus* aEventStatus)
101 : {
102 0 : return NS_OK;
103 : }
104 :
105 : NS_IMETHODIMP
106 0 : nsScrollbarFrame::HandleMultiplePress(nsPresContext* aPresContext,
107 : WidgetGUIEvent* aEvent,
108 : nsEventStatus* aEventStatus,
109 : bool aControlHeld)
110 : {
111 0 : return NS_OK;
112 : }
113 :
114 : NS_IMETHODIMP
115 0 : nsScrollbarFrame::HandleDrag(nsPresContext* aPresContext,
116 : WidgetGUIEvent* aEvent,
117 : nsEventStatus* aEventStatus)
118 : {
119 0 : return NS_OK;
120 : }
121 :
122 : NS_IMETHODIMP
123 0 : nsScrollbarFrame::HandleRelease(nsPresContext* aPresContext,
124 : WidgetGUIEvent* aEvent,
125 : nsEventStatus* aEventStatus)
126 : {
127 0 : return NS_OK;
128 : }
129 :
130 : void
131 8 : nsScrollbarFrame::SetScrollbarMediatorContent(nsIContent* aMediator)
132 : {
133 8 : mScrollbarMediator = aMediator;
134 8 : }
135 :
136 : nsIScrollbarMediator*
137 12 : nsScrollbarFrame::GetScrollbarMediator()
138 : {
139 12 : if (!mScrollbarMediator) {
140 4 : return nullptr;
141 : }
142 8 : nsIFrame* f = mScrollbarMediator->GetPrimaryFrame();
143 8 : nsIScrollableFrame* scrollFrame = do_QueryFrame(f);
144 : nsIScrollbarMediator* sbm;
145 :
146 8 : if (scrollFrame) {
147 0 : nsIFrame* scrolledFrame = scrollFrame->GetScrolledFrame();
148 0 : sbm = do_QueryFrame(scrolledFrame);
149 0 : if (sbm) {
150 0 : return sbm;
151 : }
152 : }
153 8 : sbm = do_QueryFrame(f);
154 8 : if (f && !sbm) {
155 8 : f = f->PresContext()->PresShell()->GetRootScrollFrame();
156 8 : if (f && f->GetContent() == mScrollbarMediator) {
157 8 : return do_QueryFrame(f);
158 : }
159 : }
160 0 : return sbm;
161 : }
162 :
163 : nsresult
164 10 : nsScrollbarFrame::GetXULMargin(nsMargin& aMargin)
165 : {
166 10 : nsresult rv = NS_ERROR_FAILURE;
167 10 : aMargin.SizeTo(0,0,0,0);
168 :
169 10 : if (LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars) != 0) {
170 0 : nsPresContext* presContext = PresContext();
171 0 : nsITheme* theme = presContext->GetTheme();
172 0 : if (theme) {
173 0 : LayoutDeviceIntSize size;
174 : bool isOverridable;
175 0 : theme->GetMinimumWidgetSize(presContext, this, NS_THEME_SCROLLBAR, &size,
176 0 : &isOverridable);
177 0 : if (IsXULHorizontal()) {
178 0 : aMargin.top = -presContext->DevPixelsToAppUnits(size.height);
179 : }
180 : else {
181 0 : aMargin.left = -presContext->DevPixelsToAppUnits(size.width);
182 : }
183 0 : rv = NS_OK;
184 : }
185 : }
186 :
187 10 : if (NS_FAILED(rv)) {
188 10 : rv = nsBox::GetXULMargin(aMargin);
189 : }
190 :
191 10 : if (NS_SUCCEEDED(rv) && !IsXULHorizontal()) {
192 6 : nsIScrollbarMediator* scrollFrame = GetScrollbarMediator();
193 6 : if (scrollFrame && !scrollFrame->IsScrollbarOnRight()) {
194 0 : Swap(aMargin.left, aMargin.right);
195 : }
196 : }
197 :
198 10 : return rv;
199 : }
200 :
201 : void
202 0 : nsScrollbarFrame::SetIncrementToLine(int32_t aDirection)
203 : {
204 : // get the scrollbar's content node
205 0 : nsIContent* content = GetContent();
206 0 : mSmoothScroll = true;
207 0 : mIncrement = aDirection * nsSliderFrame::GetIncrement(content);
208 0 : }
209 :
210 : void
211 0 : nsScrollbarFrame::SetIncrementToPage(int32_t aDirection)
212 : {
213 : // get the scrollbar's content node
214 0 : nsIContent* content = GetContent();
215 0 : mSmoothScroll = true;
216 0 : mIncrement = aDirection * nsSliderFrame::GetPageIncrement(content);
217 0 : }
218 :
219 : void
220 0 : nsScrollbarFrame::SetIncrementToWhole(int32_t aDirection)
221 : {
222 : // get the scrollbar's content node
223 0 : nsIContent* content = GetContent();
224 0 : if (aDirection == -1)
225 0 : mIncrement = -nsSliderFrame::GetCurrentPosition(content);
226 : else
227 0 : mIncrement = nsSliderFrame::GetMaxPosition(content) -
228 0 : nsSliderFrame::GetCurrentPosition(content);
229 : // Don't repeat or use smooth scrolling if scrolling to beginning or end
230 : // of a page.
231 0 : mSmoothScroll = false;
232 0 : }
233 :
234 : int32_t
235 0 : nsScrollbarFrame::MoveToNewPosition()
236 : {
237 : // get the scrollbar's content node
238 0 : nsCOMPtr<nsIContent> content = GetContent();
239 :
240 : // get the current pos
241 0 : int32_t curpos = nsSliderFrame::GetCurrentPosition(content);
242 :
243 : // get the max pos
244 0 : int32_t maxpos = nsSliderFrame::GetMaxPosition(content);
245 :
246 : // increment the given amount
247 0 : if (mIncrement) {
248 0 : curpos += mIncrement;
249 : }
250 :
251 : // make sure the current position is between the current and max positions
252 0 : if (curpos < 0) {
253 0 : curpos = 0;
254 0 : } else if (curpos > maxpos) {
255 0 : curpos = maxpos;
256 : }
257 :
258 : // set the current position of the slider.
259 0 : nsAutoString curposStr;
260 0 : curposStr.AppendInt(curpos);
261 :
262 0 : AutoWeakFrame weakFrame(this);
263 0 : if (mSmoothScroll) {
264 0 : content->SetAttr(kNameSpaceID_None, nsGkAtoms::smooth, NS_LITERAL_STRING("true"), false);
265 : }
266 0 : content->SetAttr(kNameSpaceID_None, nsGkAtoms::curpos, curposStr, false);
267 : // notify the nsScrollbarFrame of the change
268 0 : AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION);
269 0 : if (!weakFrame.IsAlive()) {
270 0 : return curpos;
271 : }
272 : // notify all nsSliderFrames of the change
273 0 : nsIFrame::ChildListIterator childLists(this);
274 0 : for (; !childLists.IsDone(); childLists.Next()) {
275 0 : nsFrameList::Enumerator childFrames(childLists.CurrentList());
276 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
277 0 : nsIFrame* f = childFrames.get();
278 0 : nsSliderFrame* sliderFrame = do_QueryFrame(f);
279 0 : if (sliderFrame) {
280 0 : sliderFrame->AttributeChanged(kNameSpaceID_None, nsGkAtoms::curpos, nsIDOMMutationEvent::MODIFICATION);
281 0 : if (!weakFrame.IsAlive()) {
282 0 : return curpos;
283 : }
284 : }
285 : }
286 : }
287 0 : content->UnsetAttr(kNameSpaceID_None, nsGkAtoms::smooth, false);
288 0 : return curpos;
289 : }
|