1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : /* rendering object to wrap rendering objects that should be scrollable */
39 :
40 : #ifndef nsGfxScrollFrame_h___
41 : #define nsGfxScrollFrame_h___
42 :
43 : #include "nsContainerFrame.h"
44 : #include "nsIAnonymousContentCreator.h"
45 : #include "nsBoxFrame.h"
46 : #include "nsDisplayList.h"
47 : #include "nsIScrollableFrame.h"
48 : #include "nsIScrollPositionListener.h"
49 : #include "nsIStatefulFrame.h"
50 : #include "nsThreadUtils.h"
51 : #include "nsIReflowCallback.h"
52 : #include "nsBoxLayoutState.h"
53 : #include "nsQueryFrame.h"
54 : #include "nsCOMArray.h"
55 : #include "nsSVGIntegrationUtils.h"
56 : #include "nsExpirationTracker.h"
57 :
58 : class nsPresContext;
59 : class nsIPresShell;
60 : class nsIContent;
61 : class nsIAtom;
62 : class nsIDocument;
63 : class nsIScrollFrameInternal;
64 : class nsPresState;
65 : struct ScrollReflowState;
66 :
67 : // When set, the next scroll operation on the scrollframe will invalidate its
68 : // entire contents. Useful for text-overflow.
69 : // This bit is cleared after each time the scrollframe is scrolled. Whoever
70 : // needs to set it should set it again on each paint.
71 : #define NS_SCROLLFRAME_INVALIDATE_CONTENTS_ON_SCROLL NS_FRAME_STATE_BIT(20)
72 :
73 : class nsGfxScrollFrameInner : public nsIReflowCallback {
74 : public:
75 : class AsyncScroll;
76 :
77 : nsGfxScrollFrameInner(nsContainerFrame* aOuter, bool aIsRoot);
78 : ~nsGfxScrollFrameInner();
79 :
80 : typedef nsIScrollableFrame::ScrollbarStyles ScrollbarStyles;
81 : ScrollbarStyles GetScrollbarStylesFromFrame() const;
82 :
83 : // If a child frame was added or removed on the scrollframe,
84 : // reload our child frame list.
85 : // We need this if a scrollbar frame is recreated.
86 : void ReloadChildFrames();
87 :
88 : nsresult CreateAnonymousContent(
89 : nsTArray<nsIAnonymousContentCreator::ContentInfo>& aElements);
90 : void AppendAnonymousContentTo(nsBaseContentList& aElements, PRUint32 aFilter);
91 : nsresult FireScrollPortEvent();
92 : void PostOverflowEvent();
93 : void Destroy();
94 :
95 : bool ShouldBuildLayer() const;
96 :
97 : nsresult BuildDisplayList(nsDisplayListBuilder* aBuilder,
98 : const nsRect& aDirtyRect,
99 : const nsDisplayListSet& aLists);
100 :
101 : void AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
102 : const nsRect& aDirtyRect,
103 : const nsDisplayListSet& aLists,
104 : bool& aCreateLayer,
105 : bool aPositioned);
106 :
107 : bool GetBorderRadii(nscoord aRadii[8]) const;
108 :
109 : // nsIReflowCallback
110 : virtual bool ReflowFinished();
111 : virtual void ReflowCallbackCanceled();
112 :
113 : // This gets called when the 'curpos' attribute on one of the scrollbars changes
114 : void CurPosAttributeChanged(nsIContent* aChild);
115 : void PostScrollEvent();
116 : void FireScrollEvent();
117 : void PostScrolledAreaEvent();
118 : void FireScrolledAreaEvent();
119 :
120 0 : class ScrollEvent : public nsRunnable {
121 : public:
122 : NS_DECL_NSIRUNNABLE
123 0 : ScrollEvent(nsGfxScrollFrameInner *inner) : mInner(inner) {}
124 0 : void Revoke() { mInner = nsnull; }
125 : private:
126 : nsGfxScrollFrameInner *mInner;
127 : };
128 :
129 0 : class AsyncScrollPortEvent : public nsRunnable {
130 : public:
131 : NS_DECL_NSIRUNNABLE
132 0 : AsyncScrollPortEvent(nsGfxScrollFrameInner *inner) : mInner(inner) {}
133 0 : void Revoke() { mInner = nsnull; }
134 : private:
135 : nsGfxScrollFrameInner *mInner;
136 : };
137 :
138 0 : class ScrolledAreaEvent : public nsRunnable {
139 : public:
140 : NS_DECL_NSIRUNNABLE
141 0 : ScrolledAreaEvent(nsGfxScrollFrameInner *inner) : mInner(inner) {}
142 0 : void Revoke() { mInner = nsnull; }
143 : private:
144 : nsGfxScrollFrameInner *mInner;
145 : };
146 :
147 : static void FinishReflowForScrollbar(nsIContent* aContent, nscoord aMinXY,
148 : nscoord aMaxXY, nscoord aCurPosXY,
149 : nscoord aPageIncrement,
150 : nscoord aIncrement);
151 : static void SetScrollbarEnabled(nsIContent* aContent, nscoord aMaxPos);
152 : static void SetCoordAttribute(nsIContent* aContent, nsIAtom* aAtom,
153 : nscoord aSize);
154 : nscoord GetCoordAttribute(nsIBox* aFrame, nsIAtom* atom, nscoord defaultValue);
155 :
156 : // Update scrollbar curpos attributes to reflect current scroll position
157 : void UpdateScrollbarPosition();
158 :
159 0 : nsRect GetScrollPortRect() const { return mScrollPort; }
160 0 : nsPoint GetScrollPosition() const {
161 0 : return mScrollPort.TopLeft() - mScrolledFrame->GetPosition();
162 : }
163 : /**
164 : * For LTR frames, the logical scroll position is the offset of the top left
165 : * corner of the frame from the top left corner of the scroll port (same as
166 : * GetScrollPosition).
167 : * For RTL frames, it is the offset of the top right corner of the frame from
168 : * the top right corner of the scroll port
169 : */
170 0 : nsPoint GetLogicalScrollPosition() const {
171 0 : nsPoint pt;
172 0 : pt.x = IsLTR() ?
173 : mScrollPort.x - mScrolledFrame->GetPosition().x :
174 0 : mScrollPort.XMost() - mScrolledFrame->GetRect().XMost();
175 0 : pt.y = mScrollPort.y - mScrolledFrame->GetPosition().y;
176 : return pt;
177 : }
178 : nsRect GetScrollRange() const;
179 :
180 : nsPoint RestrictToDevPixels(const nsPoint& aPt, nsIntPoint* aPtDevPx, bool aShouldClamp) const;
181 : nsPoint ClampScrollPosition(const nsPoint& aPt) const;
182 : static void AsyncScrollCallback(nsITimer *aTimer, void* anInstance);
183 0 : void ScrollTo(nsPoint aScrollPosition, nsIScrollableFrame::ScrollMode aMode) {
184 0 : ScrollToWithOrigin(aScrollPosition, aMode, nsGkAtoms::other);
185 0 : };
186 : void ScrollToImpl(nsPoint aScrollPosition);
187 : void ScrollVisual(nsPoint aOldScrolledFramePosition);
188 : void ScrollBy(nsIntPoint aDelta, nsIScrollableFrame::ScrollUnit aUnit,
189 : nsIScrollableFrame::ScrollMode aMode, nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull);
190 : void ScrollToRestoredPosition();
191 : nsSize GetLineScrollAmount() const;
192 : nsSize GetPageScrollAmount() const;
193 :
194 : nsPresState* SaveState(nsIStatefulFrame::SpecialStateID aStateID);
195 : void RestoreState(nsPresState* aState);
196 :
197 0 : nsIFrame* GetScrolledFrame() const { return mScrolledFrame; }
198 0 : nsIBox* GetScrollbarBox(bool aVertical) const {
199 0 : return aVertical ? mVScrollbarBox : mHScrollbarBox;
200 : }
201 :
202 0 : void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
203 0 : mListeners.AppendElement(aListener);
204 0 : }
205 0 : void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) {
206 0 : mListeners.RemoveElement(aListener);
207 0 : }
208 :
209 : static void SetScrollbarVisibility(nsIBox* aScrollbar, bool aVisible);
210 :
211 : /**
212 : * GetScrolledRect is designed to encapsulate deciding which
213 : * directions of overflow should be reachable by scrolling and which
214 : * should not. Callers should NOT depend on it having any particular
215 : * behavior (although nsXULScrollFrame currently does).
216 : *
217 : * This should only be called when the scrolled frame has been
218 : * reflowed with the scroll port size given in mScrollPort.
219 : *
220 : * Currently it allows scrolling down and to the right for
221 : * nsHTMLScrollFrames with LTR directionality and for all
222 : * nsXULScrollFrames, and allows scrolling down and to the left for
223 : * nsHTMLScrollFrames with RTL directionality.
224 : */
225 : nsRect GetScrolledRect() const;
226 :
227 : /**
228 : * GetScrolledRectInternal is designed to encapsulate deciding which
229 : * directions of overflow should be reachable by scrolling and which
230 : * should not. Callers should NOT depend on it having any particular
231 : * behavior (although nsXULScrollFrame currently does).
232 : *
233 : * Currently it allows scrolling down and to the right for
234 : * nsHTMLScrollFrames with LTR directionality and for all
235 : * nsXULScrollFrames, and allows scrolling down and to the left for
236 : * nsHTMLScrollFrames with RTL directionality.
237 : */
238 : nsRect GetScrolledRectInternal(const nsRect& aScrolledOverflowArea,
239 : const nsSize& aScrollPortSize) const;
240 :
241 0 : PRUint32 GetScrollbarVisibility() const {
242 : return (mHasVerticalScrollbar ? nsIScrollableFrame::VERTICAL : 0) |
243 0 : (mHasHorizontalScrollbar ? nsIScrollableFrame::HORIZONTAL : 0);
244 : }
245 : nsMargin GetActualScrollbarSizes() const;
246 : nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState);
247 : bool IsLTR() const;
248 : bool IsScrollbarOnRight() const;
249 0 : bool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); }
250 :
251 : bool UpdateOverflow();
252 :
253 : // adjust the scrollbar rectangle aRect to account for any visible resizer.
254 : // aHasResizer specifies if there is a content resizer, however this method
255 : // will also check if a widget resizer is present as well.
256 : void AdjustScrollbarRectForResizer(nsIFrame* aFrame, nsPresContext* aPresContext,
257 : nsRect& aRect, bool aHasResizer, bool aVertical);
258 : // returns true if a resizer should be visible
259 0 : bool HasResizer() { return mResizerBox && !mCollapsedResizer; }
260 : void LayoutScrollbars(nsBoxLayoutState& aState,
261 : const nsRect& aContentArea,
262 : const nsRect& aOldScrollArea);
263 :
264 : bool IsIgnoringViewportClipping() const;
265 :
266 : bool ShouldClampScrollPosition() const;
267 :
268 : bool IsAlwaysActive() const;
269 : void MarkActive();
270 : void MarkInactive();
271 0 : nsExpirationState* GetExpirationState() { return &mActivityExpirationState; }
272 :
273 : void ScheduleSyntheticMouseMove();
274 : static void ScrollActivityCallback(nsITimer *aTimer, void* anInstance);
275 :
276 : // owning references to the nsIAnonymousContentCreator-built content
277 : nsCOMPtr<nsIContent> mHScrollbarContent;
278 : nsCOMPtr<nsIContent> mVScrollbarContent;
279 : nsCOMPtr<nsIContent> mScrollCornerContent;
280 : nsCOMPtr<nsIContent> mResizerContent;
281 :
282 : nsRevocableEventPtr<ScrollEvent> mScrollEvent;
283 : nsRevocableEventPtr<AsyncScrollPortEvent> mAsyncScrollPortEvent;
284 : nsRevocableEventPtr<ScrolledAreaEvent> mScrolledAreaEvent;
285 : nsIBox* mHScrollbarBox;
286 : nsIBox* mVScrollbarBox;
287 : nsIFrame* mScrolledFrame;
288 : nsIBox* mScrollCornerBox;
289 : nsIBox* mResizerBox;
290 : nsContainerFrame* mOuter;
291 : AsyncScroll* mAsyncScroll;
292 : nsTArray<nsIScrollPositionListener*> mListeners;
293 : nsRect mScrollPort;
294 : // Where we're currently scrolling to, if we're scrolling asynchronously.
295 : // If we're not in the middle of an asynchronous scroll then this is
296 : // just the current scroll position. ScrollBy will choose its
297 : // destination based on this value.
298 : nsPoint mDestination;
299 : nsPoint mScrollPosAtLastPaint;
300 :
301 : nsPoint mRestorePos;
302 : nsPoint mLastPos;
303 :
304 : nsExpirationState mActivityExpirationState;
305 :
306 : nsCOMPtr<nsITimer> mScrollActivityTimer;
307 :
308 : bool mNeverHasVerticalScrollbar:1;
309 : bool mNeverHasHorizontalScrollbar:1;
310 : bool mHasVerticalScrollbar:1;
311 : bool mHasHorizontalScrollbar:1;
312 : bool mFrameIsUpdatingScrollbar:1;
313 : bool mDidHistoryRestore:1;
314 : // Is this the scrollframe for the document's viewport?
315 : bool mIsRoot:1;
316 : // If true, don't try to layout the scrollbars in Reflow(). This can be
317 : // useful if multiple passes are involved, because we don't want to place the
318 : // scrollbars at the wrong size.
319 : bool mSupppressScrollbarUpdate:1;
320 : // If true, we skipped a scrollbar layout due to mSupppressScrollbarUpdate
321 : // being set at some point. That means we should lay out scrollbars even if
322 : // it might not strictly be needed next time mSupppressScrollbarUpdate is
323 : // false.
324 : bool mSkippedScrollbarLayout:1;
325 :
326 : bool mHadNonInitialReflow:1;
327 : // State used only by PostScrollEvents so we know
328 : // which overflow states have changed.
329 : bool mHorizontalOverflow:1;
330 : bool mVerticalOverflow:1;
331 : bool mPostedReflowCallback:1;
332 : bool mMayHaveDirtyFixedChildren:1;
333 : // If true, need to actually update our scrollbar attributes in the
334 : // reflow callback.
335 : bool mUpdateScrollbarAttributes:1;
336 : // If true, we should be prepared to scroll using this scrollframe
337 : // by placing descendant content into its own layer(s)
338 : bool mScrollingActive:1;
339 : // If true, the resizer is collapsed and not displayed
340 : bool mCollapsedResizer:1;
341 :
342 : // If true, the layer should always be active because we always build a layer.
343 : // Used for asynchronous scrolling.
344 : bool mShouldBuildLayer:1;
345 :
346 : protected:
347 : void ScrollToWithOrigin(nsPoint aScrollPosition,
348 : nsIScrollableFrame::ScrollMode aMode,
349 : nsIAtom *aOrigin); // nsnull indicates "other" origin
350 : };
351 :
352 : /**
353 : * The scroll frame creates and manages the scrolling view
354 : *
355 : * It only supports having a single child frame that typically is an area
356 : * frame, but doesn't have to be. The child frame must have a view, though
357 : *
358 : * Scroll frames don't support incremental changes, i.e. you can't replace
359 : * or remove the scrolled frame
360 : */
361 : class nsHTMLScrollFrame : public nsContainerFrame,
362 : public nsIScrollableFrame,
363 : public nsIAnonymousContentCreator,
364 0 : public nsIStatefulFrame {
365 : public:
366 : friend nsIFrame* NS_NewHTMLScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
367 :
368 : NS_DECL_QUERYFRAME
369 : NS_DECL_FRAMEARENA_HELPERS
370 :
371 : // Called to set the child frames. We typically have three: the scroll area,
372 : // the vertical scrollbar, and the horizontal scrollbar.
373 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
374 : nsFrameList& aChildList);
375 :
376 0 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
377 : const nsRect& aDirtyRect,
378 : const nsDisplayListSet& aLists) {
379 0 : return mInner.BuildDisplayList(aBuilder, aDirtyRect, aLists);
380 : }
381 :
382 : bool TryLayout(ScrollReflowState* aState,
383 : nsHTMLReflowMetrics* aKidMetrics,
384 : bool aAssumeVScroll, bool aAssumeHScroll,
385 : bool aForce, nsresult* aResult);
386 : bool ScrolledContentDependsOnHeight(ScrollReflowState* aState);
387 : nsresult ReflowScrolledFrame(ScrollReflowState* aState,
388 : bool aAssumeHScroll,
389 : bool aAssumeVScroll,
390 : nsHTMLReflowMetrics* aMetrics,
391 : bool aFirstPass);
392 : nsresult ReflowContents(ScrollReflowState* aState,
393 : const nsHTMLReflowMetrics& aDesiredSize);
394 : void PlaceScrollArea(const ScrollReflowState& aState,
395 : const nsPoint& aScrollPosition);
396 : nscoord GetIntrinsicVScrollbarWidth(nsRenderingContext *aRenderingContext);
397 :
398 0 : virtual bool GetBorderRadii(nscoord aRadii[8]) const {
399 0 : return mInner.GetBorderRadii(aRadii);
400 : }
401 :
402 : virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
403 : virtual nscoord GetPrefWidth(nsRenderingContext *aRenderingContext);
404 : NS_IMETHOD GetPadding(nsMargin& aPadding);
405 : virtual bool IsCollapsed();
406 :
407 : NS_IMETHOD Reflow(nsPresContext* aPresContext,
408 : nsHTMLReflowMetrics& aDesiredSize,
409 : const nsHTMLReflowState& aReflowState,
410 : nsReflowStatus& aStatus);
411 :
412 : // Because there can be only one child frame, these two function return
413 : // NS_ERROR_FAILURE
414 : NS_IMETHOD AppendFrames(ChildListID aListID,
415 : nsFrameList& aFrameList);
416 : NS_IMETHOD InsertFrames(ChildListID aListID,
417 : nsIFrame* aPrevFrame,
418 : nsFrameList& aFrameList);
419 :
420 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
421 :
422 :
423 : NS_IMETHOD RemoveFrame(ChildListID aListID,
424 : nsIFrame* aOldFrame);
425 :
426 0 : virtual nsIScrollableFrame* GetScrollTargetFrame() {
427 0 : return this;
428 : }
429 :
430 0 : virtual nsIFrame* GetContentInsertionFrame() {
431 0 : return mInner.GetScrolledFrame()->GetContentInsertionFrame();
432 : }
433 :
434 : virtual void InvalidateInternal(const nsRect& aDamageRect,
435 : nscoord aX, nscoord aY, nsIFrame* aForChild,
436 : PRUint32 aFlags);
437 :
438 0 : virtual bool DoesClipChildren() { return true; }
439 : virtual nsSplittableType GetSplittableType() const;
440 :
441 0 : virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
442 0 : { nsPoint pt = aChild->GetPosition();
443 0 : if (aChild == mInner.GetScrolledFrame()) pt += GetScrollPosition();
444 : return pt;
445 : }
446 :
447 : // nsIAnonymousContentCreator
448 : virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements);
449 : virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
450 : PRUint32 aFilter);
451 :
452 : // nsIScrollableFrame
453 0 : virtual nsIFrame* GetScrolledFrame() const {
454 0 : return mInner.GetScrolledFrame();
455 : }
456 0 : virtual nsGfxScrollFrameInner::ScrollbarStyles GetScrollbarStyles() const {
457 0 : return mInner.GetScrollbarStylesFromFrame();
458 : }
459 0 : virtual PRUint32 GetScrollbarVisibility() const {
460 0 : return mInner.GetScrollbarVisibility();
461 : }
462 0 : virtual nsMargin GetActualScrollbarSizes() const {
463 0 : return mInner.GetActualScrollbarSizes();
464 : }
465 0 : virtual nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
466 0 : return mInner.GetDesiredScrollbarSizes(aState);
467 : }
468 0 : virtual nsMargin GetDesiredScrollbarSizes(nsPresContext* aPresContext,
469 : nsRenderingContext* aRC) {
470 0 : nsBoxLayoutState bls(aPresContext, aRC, 0);
471 0 : return GetDesiredScrollbarSizes(&bls);
472 : }
473 0 : virtual nsRect GetScrollPortRect() const {
474 0 : return mInner.GetScrollPortRect();
475 : }
476 0 : virtual nsPoint GetScrollPosition() const {
477 0 : return mInner.GetScrollPosition();
478 : }
479 0 : virtual nsRect GetScrollRange() const {
480 0 : return mInner.GetScrollRange();
481 : }
482 0 : virtual nsSize GetLineScrollAmount() const {
483 0 : return mInner.GetLineScrollAmount();
484 : }
485 0 : virtual nsSize GetPageScrollAmount() const {
486 0 : return mInner.GetPageScrollAmount();
487 : }
488 0 : virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode) {
489 0 : mInner.ScrollTo(aScrollPosition, aMode);
490 0 : }
491 0 : virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
492 : nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull) {
493 0 : mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
494 0 : }
495 0 : virtual void ScrollToRestoredPosition() {
496 0 : mInner.ScrollToRestoredPosition();
497 0 : }
498 0 : virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
499 0 : mInner.AddScrollPositionListener(aListener);
500 0 : }
501 0 : virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) {
502 0 : mInner.RemoveScrollPositionListener(aListener);
503 0 : }
504 0 : virtual nsIBox* GetScrollbarBox(bool aVertical) {
505 0 : return mInner.GetScrollbarBox(aVertical);
506 : }
507 0 : virtual void CurPosAttributeChanged(nsIContent* aChild) {
508 0 : mInner.CurPosAttributeChanged(aChild);
509 0 : }
510 0 : NS_IMETHOD PostScrolledAreaEventForCurrentArea() {
511 0 : mInner.PostScrolledAreaEvent();
512 0 : return NS_OK;
513 : }
514 0 : virtual bool IsScrollingActive() {
515 0 : return mInner.IsScrollingActive();
516 : }
517 0 : virtual bool UpdateOverflow() {
518 0 : return mInner.UpdateOverflow();
519 : }
520 :
521 : // nsIStatefulFrame
522 0 : NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState) {
523 0 : NS_ENSURE_ARG_POINTER(aState);
524 0 : *aState = mInner.SaveState(aStateID);
525 0 : return NS_OK;
526 : }
527 0 : NS_IMETHOD RestoreState(nsPresState* aState) {
528 0 : NS_ENSURE_ARG_POINTER(aState);
529 0 : mInner.RestoreState(aState);
530 0 : return NS_OK;
531 : }
532 :
533 : /**
534 : * Get the "type" of the frame
535 : *
536 : * @see nsGkAtoms::scrollFrame
537 : */
538 : virtual nsIAtom* GetType() const;
539 :
540 : #ifdef NS_DEBUG
541 : NS_IMETHOD GetFrameName(nsAString& aResult) const;
542 : #endif
543 :
544 0 : bool DidHistoryRestore() { return mInner.mDidHistoryRestore; }
545 :
546 : #ifdef ACCESSIBILITY
547 : virtual already_AddRefed<nsAccessible> CreateAccessible();
548 : #endif
549 :
550 : protected:
551 : nsHTMLScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot);
552 : virtual PRIntn GetSkipSides() const;
553 :
554 0 : void SetSuppressScrollbarUpdate(bool aSuppress) {
555 0 : mInner.mSupppressScrollbarUpdate = aSuppress;
556 0 : }
557 : bool GuessHScrollbarNeeded(const ScrollReflowState& aState);
558 : bool GuessVScrollbarNeeded(const ScrollReflowState& aState);
559 :
560 0 : bool IsScrollbarUpdateSuppressed() const {
561 0 : return mInner.mSupppressScrollbarUpdate;
562 : }
563 :
564 : // Return whether we're in an "initial" reflow. Some reflows with
565 : // NS_FRAME_FIRST_REFLOW set are NOT "initial" as far as we're concerned.
566 : bool InInitialReflow() const;
567 :
568 : /**
569 : * Override this to return false if computed height/min-height/max-height
570 : * should NOT be propagated to child content.
571 : * nsListControlFrame uses this.
572 : */
573 0 : virtual bool ShouldPropagateComputedHeightToScrolledContent() const { return true; }
574 :
575 : private:
576 : friend class nsGfxScrollFrameInner;
577 : nsGfxScrollFrameInner mInner;
578 : };
579 :
580 : /**
581 : * The scroll frame creates and manages the scrolling view
582 : *
583 : * It only supports having a single child frame that typically is an area
584 : * frame, but doesn't have to be. The child frame must have a view, though
585 : *
586 : * Scroll frames don't support incremental changes, i.e. you can't replace
587 : * or remove the scrolled frame
588 : */
589 : class nsXULScrollFrame : public nsBoxFrame,
590 : public nsIScrollableFrame,
591 : public nsIAnonymousContentCreator,
592 0 : public nsIStatefulFrame {
593 : public:
594 : NS_DECL_QUERYFRAME
595 : NS_DECL_FRAMEARENA_HELPERS
596 :
597 : friend nsIFrame* NS_NewXULScrollFrame(nsIPresShell* aPresShell, nsStyleContext* aContext, bool aIsRoot);
598 :
599 : // Called to set the child frames. We typically have three: the scroll area,
600 : // the vertical scrollbar, and the horizontal scrollbar.
601 : NS_IMETHOD SetInitialChildList(ChildListID aListID,
602 : nsFrameList& aChildList);
603 :
604 0 : NS_IMETHOD BuildDisplayList(nsDisplayListBuilder* aBuilder,
605 : const nsRect& aDirtyRect,
606 : const nsDisplayListSet& aLists) {
607 0 : return mInner.BuildDisplayList(aBuilder, aDirtyRect, aLists);
608 : }
609 :
610 : // XXXldb Is this actually used?
611 : #if 0
612 : virtual nscoord GetMinWidth(nsRenderingContext *aRenderingContext);
613 : #endif
614 :
615 : // Because there can be only one child frame, these two function return
616 : // NS_ERROR_FAILURE
617 : NS_IMETHOD AppendFrames(ChildListID aListID,
618 : nsFrameList& aFrameList);
619 : NS_IMETHOD InsertFrames(ChildListID aListID,
620 : nsIFrame* aPrevFrame,
621 : nsFrameList& aFrameList);
622 :
623 : virtual void DestroyFrom(nsIFrame* aDestructRoot);
624 :
625 : NS_IMETHOD RemoveFrame(ChildListID aListID,
626 : nsIFrame* aOldFrame);
627 :
628 0 : virtual nsIScrollableFrame* GetScrollTargetFrame() {
629 0 : return this;
630 : }
631 :
632 0 : virtual nsIFrame* GetContentInsertionFrame() {
633 0 : return mInner.GetScrolledFrame()->GetContentInsertionFrame();
634 : }
635 :
636 : virtual void InvalidateInternal(const nsRect& aDamageRect,
637 : nscoord aX, nscoord aY, nsIFrame* aForChild,
638 : PRUint32 aFlags);
639 :
640 0 : virtual bool DoesClipChildren() { return true; }
641 : virtual nsSplittableType GetSplittableType() const;
642 :
643 0 : virtual nsPoint GetPositionOfChildIgnoringScrolling(nsIFrame* aChild)
644 0 : { nsPoint pt = aChild->GetPosition();
645 0 : if (aChild == mInner.GetScrolledFrame())
646 0 : pt += mInner.GetLogicalScrollPosition();
647 : return pt;
648 : }
649 :
650 : // nsIAnonymousContentCreator
651 : virtual nsresult CreateAnonymousContent(nsTArray<ContentInfo>& aElements);
652 : virtual void AppendAnonymousContentTo(nsBaseContentList& aElements,
653 : PRUint32 aFilter);
654 :
655 : virtual nsSize GetMinSize(nsBoxLayoutState& aBoxLayoutState);
656 : virtual nsSize GetPrefSize(nsBoxLayoutState& aBoxLayoutState);
657 : virtual nsSize GetMaxSize(nsBoxLayoutState& aBoxLayoutState);
658 : virtual nscoord GetBoxAscent(nsBoxLayoutState& aBoxLayoutState);
659 :
660 : NS_IMETHOD DoLayout(nsBoxLayoutState& aBoxLayoutState);
661 : NS_IMETHOD GetPadding(nsMargin& aPadding);
662 :
663 0 : virtual bool GetBorderRadii(nscoord aRadii[8]) const {
664 0 : return mInner.GetBorderRadii(aRadii);
665 : }
666 :
667 : nsresult Layout(nsBoxLayoutState& aState);
668 : void LayoutScrollArea(nsBoxLayoutState& aState, const nsPoint& aScrollPosition);
669 :
670 : static bool AddRemoveScrollbar(bool& aHasScrollbar,
671 : nscoord& aXY,
672 : nscoord& aSize,
673 : nscoord aSbSize,
674 : bool aOnRightOrBottom,
675 : bool aAdd);
676 :
677 : bool AddRemoveScrollbar(nsBoxLayoutState& aState,
678 : bool aOnRightOrBottom,
679 : bool aHorizontal,
680 : bool aAdd);
681 :
682 : bool AddHorizontalScrollbar (nsBoxLayoutState& aState, bool aOnBottom);
683 : bool AddVerticalScrollbar (nsBoxLayoutState& aState, bool aOnRight);
684 : void RemoveHorizontalScrollbar(nsBoxLayoutState& aState, bool aOnBottom);
685 : void RemoveVerticalScrollbar (nsBoxLayoutState& aState, bool aOnRight);
686 :
687 : static void AdjustReflowStateForPrintPreview(nsBoxLayoutState& aState, bool& aSetBack);
688 : static void AdjustReflowStateBack(nsBoxLayoutState& aState, bool aSetBack);
689 :
690 : // nsIScrollableFrame
691 0 : virtual nsIFrame* GetScrolledFrame() const {
692 0 : return mInner.GetScrolledFrame();
693 : }
694 0 : virtual nsGfxScrollFrameInner::ScrollbarStyles GetScrollbarStyles() const {
695 0 : return mInner.GetScrollbarStylesFromFrame();
696 : }
697 0 : virtual PRUint32 GetScrollbarVisibility() const {
698 0 : return mInner.GetScrollbarVisibility();
699 : }
700 0 : virtual nsMargin GetActualScrollbarSizes() const {
701 0 : return mInner.GetActualScrollbarSizes();
702 : }
703 0 : virtual nsMargin GetDesiredScrollbarSizes(nsBoxLayoutState* aState) {
704 0 : return mInner.GetDesiredScrollbarSizes(aState);
705 : }
706 0 : virtual nsMargin GetDesiredScrollbarSizes(nsPresContext* aPresContext,
707 : nsRenderingContext* aRC) {
708 0 : nsBoxLayoutState bls(aPresContext, aRC, 0);
709 0 : return GetDesiredScrollbarSizes(&bls);
710 : }
711 0 : virtual nsRect GetScrollPortRect() const {
712 0 : return mInner.GetScrollPortRect();
713 : }
714 0 : virtual nsPoint GetScrollPosition() const {
715 0 : return mInner.GetScrollPosition();
716 : }
717 0 : virtual nsRect GetScrollRange() const {
718 0 : return mInner.GetScrollRange();
719 : }
720 0 : virtual nsSize GetLineScrollAmount() const {
721 0 : return mInner.GetLineScrollAmount();
722 : }
723 0 : virtual nsSize GetPageScrollAmount() const {
724 0 : return mInner.GetPageScrollAmount();
725 : }
726 0 : virtual void ScrollTo(nsPoint aScrollPosition, ScrollMode aMode) {
727 0 : mInner.ScrollTo(aScrollPosition, aMode);
728 0 : }
729 0 : virtual void ScrollBy(nsIntPoint aDelta, ScrollUnit aUnit, ScrollMode aMode,
730 : nsIntPoint* aOverflow, nsIAtom *aOrigin = nsnull) {
731 0 : mInner.ScrollBy(aDelta, aUnit, aMode, aOverflow, aOrigin);
732 0 : }
733 0 : virtual void ScrollToRestoredPosition() {
734 0 : mInner.ScrollToRestoredPosition();
735 0 : }
736 0 : virtual void AddScrollPositionListener(nsIScrollPositionListener* aListener) {
737 0 : mInner.AddScrollPositionListener(aListener);
738 0 : }
739 0 : virtual void RemoveScrollPositionListener(nsIScrollPositionListener* aListener) {
740 0 : mInner.RemoveScrollPositionListener(aListener);
741 0 : }
742 0 : virtual nsIBox* GetScrollbarBox(bool aVertical) {
743 0 : return mInner.GetScrollbarBox(aVertical);
744 : }
745 0 : virtual void CurPosAttributeChanged(nsIContent* aChild) {
746 0 : mInner.CurPosAttributeChanged(aChild);
747 0 : }
748 0 : NS_IMETHOD PostScrolledAreaEventForCurrentArea() {
749 0 : mInner.PostScrolledAreaEvent();
750 0 : return NS_OK;
751 : }
752 0 : virtual bool IsScrollingActive() {
753 0 : return mInner.IsScrollingActive();
754 : }
755 0 : virtual bool UpdateOverflow() {
756 0 : return mInner.UpdateOverflow();
757 : }
758 :
759 : // nsIStatefulFrame
760 0 : NS_IMETHOD SaveState(SpecialStateID aStateID, nsPresState** aState) {
761 0 : NS_ENSURE_ARG_POINTER(aState);
762 0 : *aState = mInner.SaveState(aStateID);
763 0 : return NS_OK;
764 : }
765 0 : NS_IMETHOD RestoreState(nsPresState* aState) {
766 0 : NS_ENSURE_ARG_POINTER(aState);
767 0 : mInner.RestoreState(aState);
768 0 : return NS_OK;
769 : }
770 :
771 : /**
772 : * Get the "type" of the frame
773 : *
774 : * @see nsGkAtoms::scrollFrame
775 : */
776 : virtual nsIAtom* GetType() const;
777 :
778 0 : virtual bool IsFrameOfType(PRUint32 aFlags) const
779 : {
780 : // Override bogus IsFrameOfType in nsBoxFrame.
781 0 : if (aFlags & (nsIFrame::eReplacedContainsBlock | nsIFrame::eReplaced))
782 0 : return false;
783 0 : return nsBoxFrame::IsFrameOfType(aFlags);
784 : }
785 :
786 : #ifdef NS_DEBUG
787 : NS_IMETHOD GetFrameName(nsAString& aResult) const;
788 : #endif
789 :
790 : protected:
791 : nsXULScrollFrame(nsIPresShell* aShell, nsStyleContext* aContext, bool aIsRoot);
792 : virtual PRIntn GetSkipSides() const;
793 :
794 0 : void ClampAndSetBounds(nsBoxLayoutState& aState,
795 : nsRect& aRect,
796 : nsPoint aScrollPosition,
797 : bool aRemoveOverflowAreas = false) {
798 : /*
799 : * For RTL frames, restore the original scrolled position of the right
800 : * edge, then subtract the current width to find the physical position.
801 : * This can break the invariant that the scroll position is a multiple of
802 : * device pixels, so round off the result to the nearest device pixel.
803 : */
804 0 : if (!mInner.IsLTR()) {
805 : aRect.x = PresContext()->RoundAppUnitsToNearestDevPixels(
806 0 : mInner.mScrollPort.XMost() - aScrollPosition.x - aRect.width);
807 : }
808 0 : mInner.mScrolledFrame->SetBounds(aState, aRect, aRemoveOverflowAreas);
809 0 : }
810 :
811 : private:
812 : friend class nsGfxScrollFrameInner;
813 : nsGfxScrollFrameInner mInner;
814 : };
815 :
816 : #endif /* nsGfxScrollFrame_h___ */
|