layout/generic/nsContainerFrame.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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 /* base class #1 for rendering objects that have child lists */
michael@0 7
michael@0 8 #ifndef nsContainerFrame_h___
michael@0 9 #define nsContainerFrame_h___
michael@0 10
michael@0 11 #include "mozilla/Attributes.h"
michael@0 12 #include "nsSplittableFrame.h"
michael@0 13 #include "nsFrameList.h"
michael@0 14 #include "nsLayoutUtils.h"
michael@0 15
michael@0 16 // Option flags for ReflowChild() and FinishReflowChild()
michael@0 17 // member functions
michael@0 18 #define NS_FRAME_NO_MOVE_VIEW 0x0001
michael@0 19 #define NS_FRAME_NO_MOVE_FRAME (0x0002 | NS_FRAME_NO_MOVE_VIEW)
michael@0 20 #define NS_FRAME_NO_SIZE_VIEW 0x0004
michael@0 21 #define NS_FRAME_NO_VISIBILITY 0x0008
michael@0 22 // Only applies to ReflowChild; if true, don't delete the next-in-flow, even
michael@0 23 // if the reflow is fully complete.
michael@0 24 #define NS_FRAME_NO_DELETE_NEXT_IN_FLOW_CHILD 0x0010
michael@0 25
michael@0 26 class nsOverflowContinuationTracker;
michael@0 27 namespace mozilla {
michael@0 28 class FramePropertyTable;
michael@0 29 }
michael@0 30
michael@0 31 // Some macros for container classes to do sanity checking on
michael@0 32 // width/height/x/y values computed during reflow.
michael@0 33 // NOTE: AppUnitsPerCSSPixel value hardwired here to remove the
michael@0 34 // dependency on nsDeviceContext.h. It doesn't matter if it's a
michael@0 35 // little off.
michael@0 36 #ifdef DEBUG
michael@0 37 #define CRAZY_COORD (1000000*60)
michael@0 38 #define CRAZY_SIZE(_x) (((_x) < -CRAZY_COORD) || ((_x) > CRAZY_COORD))
michael@0 39 #endif
michael@0 40
michael@0 41 /**
michael@0 42 * Implementation of a container frame.
michael@0 43 */
michael@0 44 class nsContainerFrame : public nsSplittableFrame
michael@0 45 {
michael@0 46 public:
michael@0 47 NS_DECL_FRAMEARENA_HELPERS
michael@0 48 NS_DECL_QUERYFRAME_TARGET(nsContainerFrame)
michael@0 49 NS_DECL_QUERYFRAME
michael@0 50
michael@0 51 // nsIFrame overrides
michael@0 52 virtual void Init(nsIContent* aContent,
michael@0 53 nsIFrame* aParent,
michael@0 54 nsIFrame* aPrevInFlow) MOZ_OVERRIDE;
michael@0 55 virtual nsresult SetInitialChildList(ChildListID aListID,
michael@0 56 nsFrameList& aChildList) MOZ_OVERRIDE;
michael@0 57 virtual nsresult AppendFrames(ChildListID aListID,
michael@0 58 nsFrameList& aFrameList) MOZ_OVERRIDE;
michael@0 59 virtual nsresult InsertFrames(ChildListID aListID,
michael@0 60 nsIFrame* aPrevFrame,
michael@0 61 nsFrameList& aFrameList) MOZ_OVERRIDE;
michael@0 62 virtual nsresult RemoveFrame(ChildListID aListID,
michael@0 63 nsIFrame* aOldFrame) MOZ_OVERRIDE;
michael@0 64
michael@0 65 virtual const nsFrameList& GetChildList(ChildListID aList) const MOZ_OVERRIDE;
michael@0 66 virtual void GetChildLists(nsTArray<ChildList>* aLists) const MOZ_OVERRIDE;
michael@0 67 virtual void DestroyFrom(nsIFrame* aDestructRoot) MOZ_OVERRIDE;
michael@0 68 virtual void ChildIsDirty(nsIFrame* aChild) MOZ_OVERRIDE;
michael@0 69
michael@0 70 virtual bool IsLeaf() const MOZ_OVERRIDE;
michael@0 71 virtual FrameSearchResult PeekOffsetNoAmount(bool aForward, int32_t* aOffset) MOZ_OVERRIDE;
michael@0 72 virtual FrameSearchResult PeekOffsetCharacter(bool aForward, int32_t* aOffset,
michael@0 73 bool aRespectClusters = true) MOZ_OVERRIDE;
michael@0 74
michael@0 75 #ifdef DEBUG_FRAME_DUMP
michael@0 76 void List(FILE* out = stderr, const char* aPrefix = "", uint32_t aFlags = 0) const MOZ_OVERRIDE;
michael@0 77 #endif
michael@0 78
michael@0 79 // nsContainerFrame methods
michael@0 80
michael@0 81 /**
michael@0 82 * Helper method to create next-in-flows if necessary. If aFrame
michael@0 83 * already has a next-in-flow then this method does
michael@0 84 * nothing. Otherwise, a new continuation frame is created and
michael@0 85 * linked into the flow. In addition, the new frame is inserted
michael@0 86 * into the principal child list after aFrame.
michael@0 87 * @note calling this method on a block frame is illegal. Use
michael@0 88 * nsBlockFrame::CreateContinuationFor() instead.
michael@0 89 * @param aNextInFlowResult will contain the next-in-flow
michael@0 90 * <b>if and only if</b> one is created. If a next-in-flow already
michael@0 91 * exists aNextInFlowResult is set to nullptr.
michael@0 92 * @return NS_OK if a next-in-flow already exists or is successfully created.
michael@0 93 */
michael@0 94 nsresult CreateNextInFlow(nsIFrame* aFrame, nsIFrame*& aNextInFlowResult);
michael@0 95
michael@0 96 /**
michael@0 97 * Delete aNextInFlow and its next-in-flows.
michael@0 98 * @param aDeletingEmptyFrames if set, then the reflow for aNextInFlow's
michael@0 99 * content was complete before aNextInFlow, so aNextInFlow and its
michael@0 100 * next-in-flows no longer map any real content.
michael@0 101 */
michael@0 102 virtual void DeleteNextInFlowChild(nsIFrame* aNextInFlow,
michael@0 103 bool aDeletingEmptyFrames);
michael@0 104
michael@0 105 /**
michael@0 106 * Helper method to wrap views around frames. Used by containers
michael@0 107 * under special circumstances (can be used by leaf frames as well)
michael@0 108 */
michael@0 109 static void CreateViewForFrame(nsIFrame* aFrame,
michael@0 110 bool aForce);
michael@0 111
michael@0 112 // Positions the frame's view based on the frame's origin
michael@0 113 static void PositionFrameView(nsIFrame* aKidFrame);
michael@0 114
michael@0 115 static nsresult ReparentFrameView(nsIFrame* aChildFrame,
michael@0 116 nsIFrame* aOldParentFrame,
michael@0 117 nsIFrame* aNewParentFrame);
michael@0 118
michael@0 119 static nsresult ReparentFrameViewList(const nsFrameList& aChildFrameList,
michael@0 120 nsIFrame* aOldParentFrame,
michael@0 121 nsIFrame* aNewParentFrame);
michael@0 122
michael@0 123 // Set the view's size and position after its frame has been reflowed.
michael@0 124 //
michael@0 125 // Flags:
michael@0 126 // NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
michael@0 127 // don't want to automatically sync the frame and view
michael@0 128 // NS_FRAME_NO_SIZE_VIEW - don't size the view
michael@0 129 static void SyncFrameViewAfterReflow(nsPresContext* aPresContext,
michael@0 130 nsIFrame* aFrame,
michael@0 131 nsView* aView,
michael@0 132 const nsRect& aVisualOverflowArea,
michael@0 133 uint32_t aFlags = 0);
michael@0 134
michael@0 135 // Syncs properties to the top level view and window, like transparency and
michael@0 136 // shadow.
michael@0 137 static void SyncWindowProperties(nsPresContext* aPresContext,
michael@0 138 nsIFrame* aFrame,
michael@0 139 nsView* aView,
michael@0 140 nsRenderingContext* aRC = nullptr);
michael@0 141
michael@0 142 // Sets the view's attributes from the frame style.
michael@0 143 // - visibility
michael@0 144 // - clip
michael@0 145 // Call this when one of these styles changes or when the view has just
michael@0 146 // been created.
michael@0 147 // @param aStyleContext can be null, in which case the frame's style context is used
michael@0 148 static void SyncFrameViewProperties(nsPresContext* aPresContext,
michael@0 149 nsIFrame* aFrame,
michael@0 150 nsStyleContext* aStyleContext,
michael@0 151 nsView* aView,
michael@0 152 uint32_t aFlags = 0);
michael@0 153
michael@0 154 /**
michael@0 155 * Converts the minimum and maximum sizes given in inner window app units to
michael@0 156 * outer window device pixel sizes and assigns these constraints to the widget.
michael@0 157 *
michael@0 158 * @param aPresContext pres context
michael@0 159 * @param aWidget widget for this frame
michael@0 160 * @param minimum size of the window in app units
michael@0 161 * @param maxmimum size of the window in app units
michael@0 162 */
michael@0 163 static void SetSizeConstraints(nsPresContext* aPresContext,
michael@0 164 nsIWidget* aWidget,
michael@0 165 const nsSize& aMinSize,
michael@0 166 const nsSize& aMaxSize);
michael@0 167
michael@0 168 // Used by both nsInlineFrame and nsFirstLetterFrame.
michael@0 169 void DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
michael@0 170 InlineIntrinsicWidthData *aData,
michael@0 171 nsLayoutUtils::IntrinsicWidthType aType);
michael@0 172
michael@0 173 /**
michael@0 174 * This is the CSS block concept of computing 'auto' widths, which most
michael@0 175 * classes derived from nsContainerFrame want.
michael@0 176 */
michael@0 177 virtual nsSize ComputeAutoSize(nsRenderingContext *aRenderingContext,
michael@0 178 nsSize aCBSize, nscoord aAvailableWidth,
michael@0 179 nsSize aMargin, nsSize aBorder,
michael@0 180 nsSize aPadding, bool aShrinkWrap) MOZ_OVERRIDE;
michael@0 181
michael@0 182 /**
michael@0 183 * Invokes the WillReflow() function, positions the frame and its view (if
michael@0 184 * requested), and then calls Reflow(). If the reflow succeeds and the child
michael@0 185 * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
michael@0 186 *
michael@0 187 * Flags:
michael@0 188 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
michael@0 189 * don't want to automatically sync the frame and view
michael@0 190 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
michael@0 191 * case. Also implies NS_FRAME_NO_MOVE_VIEW
michael@0 192 */
michael@0 193 nsresult ReflowChild(nsIFrame* aKidFrame,
michael@0 194 nsPresContext* aPresContext,
michael@0 195 nsHTMLReflowMetrics& aDesiredSize,
michael@0 196 const nsHTMLReflowState& aReflowState,
michael@0 197 nscoord aX,
michael@0 198 nscoord aY,
michael@0 199 uint32_t aFlags,
michael@0 200 nsReflowStatus& aStatus,
michael@0 201 nsOverflowContinuationTracker* aTracker = nullptr);
michael@0 202
michael@0 203 /**
michael@0 204 * The second half of frame reflow. Does the following:
michael@0 205 * - sets the frame's bounds
michael@0 206 * - sizes and positions (if requested) the frame's view. If the frame's final
michael@0 207 * position differs from the current position and the frame itself does not
michael@0 208 * have a view, then any child frames with views are positioned so they stay
michael@0 209 * in sync
michael@0 210 * - sets the view's visibility, opacity, content transparency, and clip
michael@0 211 * - invoked the DidReflow() function
michael@0 212 *
michael@0 213 * Flags:
michael@0 214 * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
michael@0 215 * case. Also implies NS_FRAME_NO_MOVE_VIEW
michael@0 216 * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
michael@0 217 * don't want to automatically sync the frame and view
michael@0 218 * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
michael@0 219 */
michael@0 220 static nsresult FinishReflowChild(nsIFrame* aKidFrame,
michael@0 221 nsPresContext* aPresContext,
michael@0 222 const nsHTMLReflowMetrics& aDesiredSize,
michael@0 223 const nsHTMLReflowState* aReflowState,
michael@0 224 nscoord aX,
michael@0 225 nscoord aY,
michael@0 226 uint32_t aFlags);
michael@0 227
michael@0 228
michael@0 229 static void PositionChildViews(nsIFrame* aFrame);
michael@0 230
michael@0 231 // ==========================================================================
michael@0 232 /* Overflow containers are continuation frames that hold overflow. They
michael@0 233 * are created when the frame runs out of computed height, but still has
michael@0 234 * too much content to fit in the availableHeight. The parent creates a
michael@0 235 * continuation as usual, but marks it as NS_FRAME_IS_OVERFLOW_CONTAINER
michael@0 236 * and adds it to its next-in-flow's overflow container list, either by
michael@0 237 * adding it directly or by putting it in its own excess overflow containers
michael@0 238 * list (to be drained by the next-in-flow when it calls
michael@0 239 * ReflowOverflowContainerChildren). The parent continues reflow as if
michael@0 240 * the frame was complete once it ran out of computed height, but returns
michael@0 241 * either an NS_FRAME_NOT_COMPLETE or NS_FRAME_OVERFLOW_INCOMPLETE reflow
michael@0 242 * status to request a next-in-flow. The parent's next-in-flow is then
michael@0 243 * responsible for calling ReflowOverflowContainerChildren to (drain and)
michael@0 244 * reflow these overflow continuations. Overflow containers do not affect
michael@0 245 * other frames' size or position during reflow (but do affect their
michael@0 246 * parent's overflow area).
michael@0 247 *
michael@0 248 * Overflow container continuations are different from normal continuations
michael@0 249 * in that
michael@0 250 * - more than one child of the frame can have its next-in-flow broken
michael@0 251 * off and pushed into the frame's next-in-flow
michael@0 252 * - new continuations may need to be spliced into the middle of the list
michael@0 253 * or deleted continuations slipped out
michael@0 254 * e.g. A, B, C are all fixed-size containers on one page, all have
michael@0 255 * overflow beyond availableHeight, and content is dynamically added
michael@0 256 * and removed from B
michael@0 257 * As a result, it is not possible to simply prepend the new continuations
michael@0 258 * to the old list as with the overflowProperty mechanism. To avoid
michael@0 259 * complicated list splicing, the code assumes only one overflow containers
michael@0 260 * list exists for a given frame: either its own overflowContainersProperty
michael@0 261 * or its prev-in-flow's excessOverflowContainersProperty, not both.
michael@0 262 *
michael@0 263 * The nsOverflowContinuationTracker helper class should be used for tracking
michael@0 264 * overflow containers and adding them to the appropriate list.
michael@0 265 * See nsBlockFrame::Reflow for a sample implementation.
michael@0 266 */
michael@0 267
michael@0 268 friend class nsOverflowContinuationTracker;
michael@0 269
michael@0 270 /**
michael@0 271 * Reflow overflow container children. They are invisible to normal reflow
michael@0 272 * (i.e. don't affect sizing or placement of other children) and inherit
michael@0 273 * width and horizontal position from their prev-in-flow.
michael@0 274 *
michael@0 275 * This method
michael@0 276 * 1. Pulls excess overflow containers from the prev-in-flow and adds
michael@0 277 * them to our overflow container list
michael@0 278 * 2. Reflows all our overflow container kids
michael@0 279 * 3. Expands aOverflowRect as necessary to accomodate these children.
michael@0 280 * 4. Sets aStatus's NS_FRAME_OVERFLOW_IS_INCOMPLETE flag (along with
michael@0 281 * NS_FRAME_REFLOW_NEXTINFLOW as necessary) if any overflow children
michael@0 282 * are incomplete and
michael@0 283 * 5. Prepends a list of their continuations to our excess overflow
michael@0 284 * container list, to be drained into our next-in-flow when it is
michael@0 285 * reflowed.
michael@0 286 *
michael@0 287 * The caller is responsible for tracking any new overflow container
michael@0 288 * continuations it makes, removing them from its child list, and
michael@0 289 * making sure they are stored properly in the overflow container lists.
michael@0 290 * The nsOverflowContinuationTracker helper class should be used for this.
michael@0 291 *
michael@0 292 * (aFlags just gets passed through to ReflowChild)
michael@0 293 */
michael@0 294 nsresult ReflowOverflowContainerChildren(nsPresContext* aPresContext,
michael@0 295 const nsHTMLReflowState& aReflowState,
michael@0 296 nsOverflowAreas& aOverflowRects,
michael@0 297 uint32_t aFlags,
michael@0 298 nsReflowStatus& aStatus);
michael@0 299
michael@0 300 /**
michael@0 301 * Move any frames on our overflow list to the end of our principal list.
michael@0 302 * @return true if there were any overflow frames
michael@0 303 */
michael@0 304 virtual bool DrainSelfOverflowList() MOZ_OVERRIDE;
michael@0 305
michael@0 306 /**
michael@0 307 * Removes aChild without destroying it and without requesting reflow.
michael@0 308 * Continuations are not affected. Checks the primary and overflow
michael@0 309 * or overflow containers and excess overflow containers lists, depending
michael@0 310 * on whether the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set. Does not
michael@0 311 * check any other auxiliary lists.
michael@0 312 * Returns NS_ERROR_UNEXPECTED if we failed to remove aChild.
michael@0 313 * Returns other error codes if we failed to put back a proptable list.
michael@0 314 * If aForceNormal is true, only checks the primary and overflow lists
michael@0 315 * even when the NS_FRAME_IS_OVERFLOW_CONTAINER flag is set.
michael@0 316 */
michael@0 317 virtual nsresult StealFrame(nsIFrame* aChild,
michael@0 318 bool aForceNormal = false);
michael@0 319
michael@0 320 /**
michael@0 321 * Removes the next-siblings of aChild without destroying them and without
michael@0 322 * requesting reflow. Checks the principal and overflow lists (not
michael@0 323 * overflow containers / excess overflow containers). Does not check any
michael@0 324 * other auxiliary lists.
michael@0 325 * @param aChild a child frame or nullptr
michael@0 326 * @return If aChild is non-null, the next-siblings of aChild, if any.
michael@0 327 * If aChild is null, all child frames on the principal list, if any.
michael@0 328 */
michael@0 329 nsFrameList StealFramesAfter(nsIFrame* aChild);
michael@0 330
michael@0 331 /**
michael@0 332 * Add overflow containers to the display list
michael@0 333 */
michael@0 334 void DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
michael@0 335 const nsRect& aDirtyRect,
michael@0 336 const nsDisplayListSet& aLists);
michael@0 337
michael@0 338 /**
michael@0 339 * Builds display lists for the children. The background
michael@0 340 * of each child is placed in the Content() list (suitable for inline
michael@0 341 * children and other elements that behave like inlines,
michael@0 342 * but not for in-flow block children of blocks). DOES NOT
michael@0 343 * paint the background/borders/outline of this frame. This should
michael@0 344 * probably be avoided and eventually removed. It's currently here
michael@0 345 * to emulate what nsContainerFrame::Paint did.
michael@0 346 */
michael@0 347 virtual void BuildDisplayList(nsDisplayListBuilder* aBuilder,
michael@0 348 const nsRect& aDirtyRect,
michael@0 349 const nsDisplayListSet& aLists) MOZ_OVERRIDE;
michael@0 350
michael@0 351 /**
michael@0 352 * Destructor function for the proptable-stored framelists --
michael@0 353 * it should never be called.
michael@0 354 */
michael@0 355 static void DestroyFrameList(void* aPropertyValue)
michael@0 356 {
michael@0 357 MOZ_ASSERT(false, "The owning frame should destroy its nsFrameList props");
michael@0 358 }
michael@0 359
michael@0 360 static void PlaceFrameView(nsIFrame* aFrame)
michael@0 361 {
michael@0 362 if (aFrame->HasView())
michael@0 363 nsContainerFrame::PositionFrameView(aFrame);
michael@0 364 else
michael@0 365 nsContainerFrame::PositionChildViews(aFrame);
michael@0 366 }
michael@0 367
michael@0 368 #define NS_DECLARE_FRAME_PROPERTY_FRAMELIST(prop) \
michael@0 369 NS_DECLARE_FRAME_PROPERTY(prop, nsContainerFrame::DestroyFrameList)
michael@0 370
michael@0 371 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowProperty)
michael@0 372 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(OverflowContainersProperty)
michael@0 373 NS_DECLARE_FRAME_PROPERTY_FRAMELIST(ExcessOverflowContainersProperty)
michael@0 374
michael@0 375 protected:
michael@0 376 nsContainerFrame(nsStyleContext* aContext) : nsSplittableFrame(aContext) {}
michael@0 377 ~nsContainerFrame();
michael@0 378
michael@0 379 /**
michael@0 380 * Helper for DestroyFrom. DestroyAbsoluteFrames is called before
michael@0 381 * destroying frames on lists that can contain placeholders.
michael@0 382 * Derived classes must do that too, if they destroy such frame lists.
michael@0 383 * See nsBlockFrame::DestroyFrom for an example.
michael@0 384 */
michael@0 385 void DestroyAbsoluteFrames(nsIFrame* aDestructRoot);
michael@0 386
michael@0 387 /**
michael@0 388 * Builds a display list for non-block children that behave like
michael@0 389 * inlines. This puts the background of each child into the
michael@0 390 * Content() list (suitable for inline children but not for
michael@0 391 * in-flow block children of blocks).
michael@0 392 * @param aForcePseudoStack forces each child into a pseudo-stacking-context
michael@0 393 * so its background and all other display items (except for positioned
michael@0 394 * display items) go into the Content() list.
michael@0 395 */
michael@0 396 void BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
michael@0 397 const nsRect& aDirtyRect,
michael@0 398 const nsDisplayListSet& aLists,
michael@0 399 uint32_t aFlags = 0);
michael@0 400
michael@0 401 /**
michael@0 402 * A version of BuildDisplayList that use DISPLAY_CHILD_INLINE.
michael@0 403 * Intended as a convenience for derived classes.
michael@0 404 */
michael@0 405 void BuildDisplayListForInline(nsDisplayListBuilder* aBuilder,
michael@0 406 const nsRect& aDirtyRect,
michael@0 407 const nsDisplayListSet& aLists) {
michael@0 408 DisplayBorderBackgroundOutline(aBuilder, aLists);
michael@0 409 BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists,
michael@0 410 DISPLAY_CHILD_INLINE);
michael@0 411 }
michael@0 412
michael@0 413
michael@0 414 // ==========================================================================
michael@0 415 /* Overflow Frames are frames that did not fit and must be pulled by
michael@0 416 * our next-in-flow during its reflow. (The same concept for overflow
michael@0 417 * containers is called "excess frames". We should probably make the
michael@0 418 * names match.)
michael@0 419 */
michael@0 420
michael@0 421 /**
michael@0 422 * Get the frames on the overflow list. Can return null if there are no
michael@0 423 * overflow frames. The caller does NOT take ownership of the list; it's
michael@0 424 * still owned by this frame. A non-null return value indicates that the
michael@0 425 * list is nonempty.
michael@0 426 */
michael@0 427 inline nsFrameList* GetOverflowFrames() const;
michael@0 428
michael@0 429 /**
michael@0 430 * As GetOverflowFrames, but removes the overflow frames property. The
michael@0 431 * caller is responsible for deleting nsFrameList and either passing
michael@0 432 * ownership of the frames to someone else or destroying the frames.
michael@0 433 * A non-null return value indicates that the list is nonempty. The
michael@0 434 * recommended way to use this function it to assign its return value
michael@0 435 * into an AutoFrameListPtr.
michael@0 436 */
michael@0 437 inline nsFrameList* StealOverflowFrames();
michael@0 438
michael@0 439 /**
michael@0 440 * Set the overflow list. aOverflowFrames must not be an empty list.
michael@0 441 */
michael@0 442 void SetOverflowFrames(const nsFrameList& aOverflowFrames);
michael@0 443
michael@0 444 /**
michael@0 445 * Destroy the overflow list, which must be empty.
michael@0 446 */
michael@0 447 inline void DestroyOverflowList();
michael@0 448
michael@0 449 /**
michael@0 450 * Moves any frames on both the prev-in-flow's overflow list and the
michael@0 451 * receiver's overflow to the receiver's child list.
michael@0 452 *
michael@0 453 * Resets the overlist pointers to nullptr, and updates the receiver's child
michael@0 454 * count and content mapping.
michael@0 455 *
michael@0 456 * @return true if any frames were moved and false otherwise
michael@0 457 */
michael@0 458 bool MoveOverflowToChildList();
michael@0 459
michael@0 460 /**
michael@0 461 * Push aFromChild and its next siblings to the next-in-flow. Change
michael@0 462 * the geometric parent of each frame that's pushed. If there is no
michael@0 463 * next-in-flow the frames are placed on the overflow list (and the
michael@0 464 * geometric parent is left unchanged).
michael@0 465 *
michael@0 466 * Updates the next-in-flow's child count. Does <b>not</b> update the
michael@0 467 * pusher's child count.
michael@0 468 *
michael@0 469 * @param aFromChild the first child frame to push. It is disconnected from
michael@0 470 * aPrevSibling
michael@0 471 * @param aPrevSibling aFromChild's previous sibling. Must not be null.
michael@0 472 * It's an error to push a parent's first child frame
michael@0 473 */
michael@0 474 void PushChildren(nsIFrame* aFromChild, nsIFrame* aPrevSibling);
michael@0 475
michael@0 476 // ==========================================================================
michael@0 477 /*
michael@0 478 * Convenience methods for nsFrameLists stored in the
michael@0 479 * PresContext's proptable
michael@0 480 */
michael@0 481
michael@0 482 /**
michael@0 483 * Get the PresContext-stored nsFrameList named aPropID for this frame.
michael@0 484 * May return null.
michael@0 485 */
michael@0 486 nsFrameList* GetPropTableFrames(const FramePropertyDescriptor* aProperty) const;
michael@0 487
michael@0 488 /**
michael@0 489 * Remove and return the PresContext-stored nsFrameList named aPropID for
michael@0 490 * this frame. May return null.
michael@0 491 */
michael@0 492 nsFrameList* RemovePropTableFrames(const FramePropertyDescriptor* aProperty);
michael@0 493
michael@0 494 /**
michael@0 495 * Set the PresContext-stored nsFrameList named aPropID for this frame
michael@0 496 * to the given aFrameList, which must not be null.
michael@0 497 */
michael@0 498 void SetPropTableFrames(nsFrameList* aFrameList,
michael@0 499 const FramePropertyDescriptor* aProperty);
michael@0 500
michael@0 501 /**
michael@0 502 * Safely destroy the frames on the nsFrameList stored on aProp for this
michael@0 503 * frame then remove the property and delete the frame list.
michael@0 504 * Nothing happens if the property doesn't exist.
michael@0 505 */
michael@0 506 void SafelyDestroyFrameListProp(nsIFrame* aDestructRoot,
michael@0 507 nsIPresShell* aPresShell,
michael@0 508 mozilla::FramePropertyTable* aPropTable,
michael@0 509 const FramePropertyDescriptor* aProp);
michael@0 510
michael@0 511 // ==========================================================================
michael@0 512
michael@0 513 nsFrameList mFrames;
michael@0 514 };
michael@0 515
michael@0 516 // ==========================================================================
michael@0 517 /* The out-of-flow-related code below is for a hacky way of splitting
michael@0 518 * absolutely-positioned frames. Basically what we do is split the frame
michael@0 519 * in nsAbsoluteContainingBlock and pretend the continuation is an overflow
michael@0 520 * container. This isn't an ideal solution, but it lets us print the content
michael@0 521 * at least. See bug 154892.
michael@0 522 */
michael@0 523
michael@0 524 #define IS_TRUE_OVERFLOW_CONTAINER(frame) \
michael@0 525 ( (frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) \
michael@0 526 && !( (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) && \
michael@0 527 frame->IsAbsolutelyPositioned() ) )
michael@0 528 //XXXfr This check isn't quite correct, because it doesn't handle cases
michael@0 529 // where the out-of-flow has overflow.. but that's rare.
michael@0 530 // We'll need to revisit the way abspos continuations are handled later
michael@0 531 // for various reasons, this detail is one of them. See bug 154892
michael@0 532
michael@0 533 /**
michael@0 534 * Helper class for tracking overflow container continuations during reflow.
michael@0 535 *
michael@0 536 * A frame is related to two sets of overflow containers: those that /are/
michael@0 537 * its own children, and those that are /continuations/ of its children.
michael@0 538 * This tracker walks through those continuations (the frame's NIF's children)
michael@0 539 * and their prev-in-flows (a subset of the frame's normal and overflow
michael@0 540 * container children) in parallel. It allows the reflower to synchronously
michael@0 541 * walk its overflow continuations while it loops through and reflows its
michael@0 542 * children. This makes it possible to insert new continuations at the correct
michael@0 543 * place in the overflow containers list.
michael@0 544 *
michael@0 545 * The reflower is expected to loop through its children in the same order it
michael@0 546 * looped through them the last time (if there was a last time).
michael@0 547 * For each child, the reflower should either
michael@0 548 * - call Skip for the child if was not reflowed in this pass
michael@0 549 * - call Insert for the overflow continuation if the child was reflowed
michael@0 550 * but has incomplete overflow
michael@0 551 * - call Finished for the child if it was reflowed in this pass but
michael@0 552 * is either complete or has a normal next-in-flow. This call can
michael@0 553 * be skipped if the child did not previously have an overflow
michael@0 554 * continuation.
michael@0 555 */
michael@0 556 class nsOverflowContinuationTracker {
michael@0 557 public:
michael@0 558 /**
michael@0 559 * Initializes an nsOverflowContinuationTracker to help track overflow
michael@0 560 * continuations of aFrame's children. Typically invoked on 'this'.
michael@0 561 *
michael@0 562 * aWalkOOFFrames determines whether the walker skips out-of-flow frames
michael@0 563 * or skips non-out-of-flow frames.
michael@0 564 *
michael@0 565 * Don't set aSkipOverflowContainerChildren to false unless you plan
michael@0 566 * to walk your own overflow container children. (Usually they are handled
michael@0 567 * by calling ReflowOverflowContainerChildren.) aWalkOOFFrames is ignored
michael@0 568 * if aSkipOverflowContainerChildren is false.
michael@0 569 */
michael@0 570 nsOverflowContinuationTracker(nsContainerFrame* aFrame,
michael@0 571 bool aWalkOOFFrames,
michael@0 572 bool aSkipOverflowContainerChildren = true);
michael@0 573 /**
michael@0 574 * This function adds an overflow continuation to our running list and
michael@0 575 * sets its NS_FRAME_IS_OVERFLOW_CONTAINER flag.
michael@0 576 *
michael@0 577 * aReflowStatus should preferably be specific to the recently-reflowed
michael@0 578 * child and not influenced by any of its siblings' statuses. This
michael@0 579 * function sets the NS_FRAME_IS_DIRTY bit on aOverflowCont if it needs
michael@0 580 * to be reflowed. (Its need for reflow depends on changes to its
michael@0 581 * prev-in-flow, not to its parent--for whom it is invisible, reflow-wise.)
michael@0 582 *
michael@0 583 * The caller MUST disconnect the frame from its parent's child list
michael@0 584 * if it was not previously an NS_FRAME_IS_OVERFLOW_CONTAINER (because
michael@0 585 * StealFrame is much more inefficient than disconnecting in place
michael@0 586 * during Reflow, which the caller is able to do but we are not).
michael@0 587 *
michael@0 588 * The caller MUST NOT disconnect the frame from its parent's
michael@0 589 * child list if it is already an NS_FRAME_IS_OVERFLOW_CONTAINER.
michael@0 590 * (In this case we will disconnect and reconnect it ourselves.)
michael@0 591 */
michael@0 592 nsresult Insert(nsIFrame* aOverflowCont,
michael@0 593 nsReflowStatus& aReflowStatus);
michael@0 594 /**
michael@0 595 * Begin/EndFinish() must be called for each child that is reflowed
michael@0 596 * but no longer has an overflow continuation. (It may be called for
michael@0 597 * other children, but in that case has no effect.) It increments our
michael@0 598 * walker and makes sure we drop any dangling pointers to its
michael@0 599 * next-in-flow. This function MUST be called before stealing or
michael@0 600 * deleting aChild's next-in-flow.
michael@0 601 * The AutoFinish helper object does that for you. Use it like so:
michael@0 602 * if (kidNextInFlow) {
michael@0 603 * nsOverflowContinuationTracker::AutoFinish fini(tracker, kid);
michael@0 604 * ... DeleteNextInFlowChild/StealFrame(kidNextInFlow) here ...
michael@0 605 * }
michael@0 606 */
michael@0 607 class MOZ_STACK_CLASS AutoFinish {
michael@0 608 public:
michael@0 609 AutoFinish(nsOverflowContinuationTracker* aTracker, nsIFrame* aChild)
michael@0 610 : mTracker(aTracker), mChild(aChild)
michael@0 611 {
michael@0 612 if (mTracker) mTracker->BeginFinish(mChild);
michael@0 613 }
michael@0 614 ~AutoFinish()
michael@0 615 {
michael@0 616 if (mTracker) mTracker->EndFinish(mChild);
michael@0 617 }
michael@0 618 private:
michael@0 619 nsOverflowContinuationTracker* mTracker;
michael@0 620 nsIFrame* mChild;
michael@0 621 };
michael@0 622
michael@0 623 /**
michael@0 624 * This function should be called for each child that isn't reflowed.
michael@0 625 * It increments our walker and sets the NS_FRAME_OVERFLOW_INCOMPLETE
michael@0 626 * reflow flag if it encounters an overflow continuation so that our
michael@0 627 * next-in-flow doesn't get prematurely deleted. It MUST be called on
michael@0 628 * each unreflowed child that has an overflow container continuation;
michael@0 629 * it MAY be called on other children, but it isn't necessary (doesn't
michael@0 630 * do anything).
michael@0 631 */
michael@0 632 void Skip(nsIFrame* aChild, nsReflowStatus& aReflowStatus)
michael@0 633 {
michael@0 634 NS_PRECONDITION(aChild, "null ptr");
michael@0 635 if (aChild == mSentry) {
michael@0 636 StepForward();
michael@0 637 NS_MergeReflowStatusInto(&aReflowStatus, NS_FRAME_OVERFLOW_INCOMPLETE);
michael@0 638 }
michael@0 639 }
michael@0 640
michael@0 641 private:
michael@0 642
michael@0 643 /**
michael@0 644 * @see class AutoFinish
michael@0 645 */
michael@0 646 void BeginFinish(nsIFrame* aChild);
michael@0 647 void EndFinish(nsIFrame* aChild);
michael@0 648
michael@0 649 void SetupOverflowContList();
michael@0 650 void SetUpListWalker();
michael@0 651 void StepForward();
michael@0 652
michael@0 653 /* We hold a pointer to either the next-in-flow's overflow containers list
michael@0 654 or, if that doesn't exist, our frame's excess overflow containers list.
michael@0 655 We need to make sure that we drop that pointer if the list becomes
michael@0 656 empty and is deleted elsewhere. */
michael@0 657 nsFrameList* mOverflowContList;
michael@0 658 /* We hold a pointer to the most recently-reflowed child that has an
michael@0 659 overflow container next-in-flow. We do this because it's a known
michael@0 660 good point; this pointer won't be deleted on us. We can use it to
michael@0 661 recover our place in the list. */
michael@0 662 nsIFrame* mPrevOverflowCont;
michael@0 663 /* This is a pointer to the next overflow container's prev-in-flow, which
michael@0 664 is (or should be) a child of our frame. When we hit this, we will need
michael@0 665 to increment this walker to the next overflow container. */
michael@0 666 nsIFrame* mSentry;
michael@0 667 /* Parent of all frames in mOverflowContList. If our mOverflowContList
michael@0 668 is an excessOverflowContainersProperty, or null, then this is our frame
michael@0 669 (the frame that was passed in to our constructor). Otherwise this is
michael@0 670 that frame's next-in-flow, and our mOverflowContList is mParent's
michael@0 671 overflowContainersProperty */
michael@0 672 nsContainerFrame* mParent;
michael@0 673 /* Tells SetUpListWalker whether or not to walk us past any continuations
michael@0 674 of overflow containers. aWalkOOFFrames is ignored when this is false. */
michael@0 675 bool mSkipOverflowContainerChildren;
michael@0 676 /* Tells us whether to pay attention to OOF frames or non-OOF frames */
michael@0 677 bool mWalkOOFFrames;
michael@0 678 };
michael@0 679
michael@0 680 inline
michael@0 681 nsFrameList*
michael@0 682 nsContainerFrame::GetOverflowFrames() const
michael@0 683 {
michael@0 684 nsFrameList* list =
michael@0 685 static_cast<nsFrameList*>(Properties().Get(OverflowProperty()));
michael@0 686 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
michael@0 687 return list;
michael@0 688 }
michael@0 689
michael@0 690 inline
michael@0 691 nsFrameList*
michael@0 692 nsContainerFrame::StealOverflowFrames()
michael@0 693 {
michael@0 694 nsFrameList* list =
michael@0 695 static_cast<nsFrameList*>(Properties().Remove(OverflowProperty()));
michael@0 696 NS_ASSERTION(!list || !list->IsEmpty(), "Unexpected empty overflow list");
michael@0 697 return list;
michael@0 698 }
michael@0 699
michael@0 700 inline void
michael@0 701 nsContainerFrame::DestroyOverflowList()
michael@0 702 {
michael@0 703 nsFrameList* list = RemovePropTableFrames(OverflowProperty());
michael@0 704 MOZ_ASSERT(list && list->IsEmpty());
michael@0 705 list->Delete(PresContext()->PresShell());
michael@0 706 }
michael@0 707
michael@0 708 #endif /* nsContainerFrame_h___ */

mercurial