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

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

mercurial