layout/generic/nsFrameList.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 #ifndef nsFrameList_h___
     7 #define nsFrameList_h___
     9 #include <stdio.h> /* for FILE* */
    10 #include "nsDebug.h"
    11 #include "nsTArrayForwardDeclare.h"
    13 #if defined(DEBUG) || defined(MOZ_DUMP_PAINTING)
    14 // DEBUG_FRAME_DUMP enables nsIFrame::List and related methods.
    15 // You can also define this in a non-DEBUG build if you need frame dumps.
    16 #define DEBUG_FRAME_DUMP 1
    17 #endif
    19 class nsIFrame;
    20 class nsIPresShell;
    21 class nsPresContext;
    23 namespace mozilla {
    24 namespace layout {
    25   class FrameChildList;
    26   enum FrameChildListID {
    27       // The individual concrete child lists.
    28       kPrincipalList                = 0x1,
    29       kPopupList                    = 0x2,
    30       kCaptionList                  = 0x4,
    31       kColGroupList                 = 0x8,
    32       kSelectPopupList              = 0x10,
    33       kAbsoluteList                 = 0x20,
    34       kFixedList                    = 0x40,
    35       kOverflowList                 = 0x80,
    36       kOverflowContainersList       = 0x100,
    37       kExcessOverflowContainersList = 0x200,
    38       kOverflowOutOfFlowList        = 0x400,
    39       kFloatList                    = 0x800,
    40       kBulletList                   = 0x1000,
    41       kPushedFloatsList             = 0x2000,
    42       // A special alias for kPrincipalList that suppress the reflow request that
    43       // is normally done when manipulating child lists.
    44       kNoReflowPrincipalList        = 0x4000
    45   };
    46 }
    47 }
    49 // Uncomment this to enable expensive frame-list integrity checking
    50 // #define DEBUG_FRAME_LIST
    52 /**
    53  * A class for managing a list of frames.
    54  */
    55 class nsFrameList {
    56 public:
    57   nsFrameList() :
    58     mFirstChild(nullptr), mLastChild(nullptr)
    59   {
    60   }
    62   nsFrameList(nsIFrame* aFirstFrame, nsIFrame* aLastFrame) :
    63     mFirstChild(aFirstFrame), mLastChild(aLastFrame)
    64   {
    65     VerifyList();
    66   }
    68   nsFrameList(const nsFrameList& aOther) :
    69     mFirstChild(aOther.mFirstChild), mLastChild(aOther.mLastChild)
    70   {
    71   }
    73   /**
    74    * Allocate a nsFrameList from the shell arena.
    75    */
    76   void* operator new(size_t sz, nsIPresShell* aPresShell) CPP_THROW_NEW;
    78   /**
    79    * Deallocate this list that was allocated from the shell arena.
    80    * The list is required to be empty.
    81    */
    82   void Delete(nsIPresShell* aPresShell);
    84   /**
    85    * For each frame in this list: remove it from the list then call
    86    * Destroy() on it.
    87    */
    88   void DestroyFrames();
    90   /**
    91    * For each frame in this list: remove it from the list then call
    92    * DestroyFrom(aDestructRoot) on it.
    93    */
    94   void DestroyFramesFrom(nsIFrame* aDestructRoot);
    96   void Clear() { mFirstChild = mLastChild = nullptr; }
    98   void SetFrames(nsIFrame* aFrameList);
   100   void SetFrames(nsFrameList& aFrameList) {
   101     NS_PRECONDITION(!mFirstChild, "Losing frames");
   103     mFirstChild = aFrameList.FirstChild();
   104     mLastChild = aFrameList.LastChild();
   105     aFrameList.Clear();
   106   }
   108   class Slice;
   110   /**
   111    * Append aFrameList to this list.  If aParent is not null,
   112    * reparents the newly added frames.  Clears out aFrameList and
   113    * returns a list slice represening the newly-appended frames.
   114    */
   115   Slice AppendFrames(nsIFrame* aParent, nsFrameList& aFrameList) {
   116     return InsertFrames(aParent, LastChild(), aFrameList);
   117   }
   120   /**
   121    * Append aFrame to this list.  If aParent is not null,
   122    * reparents the newly added frame.
   123    */
   124   void AppendFrame(nsIFrame* aParent, nsIFrame* aFrame) {
   125     nsFrameList temp(aFrame, aFrame);
   126     AppendFrames(aParent, temp);
   127   }
   129   /**
   130    * Take aFrame out of the frame list. This also disconnects aFrame
   131    * from the sibling list. The frame must be non-null and present on
   132    * this list.
   133    */
   134   void RemoveFrame(nsIFrame* aFrame);
   136   /**
   137    * Take the frames after aAfterFrame out of the frame list.  If
   138    * aAfterFrame is null, removes the entire list.
   139    * @param aAfterFrame a frame in this list, or null
   140    * @return the removed frames, if any
   141    */
   142   nsFrameList RemoveFramesAfter(nsIFrame* aAfterFrame);
   144   /**
   145    * Take the first frame (if any) out of the frame list.
   146    * @return the first child, or nullptr if the list is empty
   147    */
   148   nsIFrame* RemoveFirstChild();
   150   /**
   151    * The following two functions are intended to be used in concert for
   152    * removing a frame from its frame list when the set of possible frame
   153    * lists is known in advance, but the exact frame list is unknown.
   154    * aFrame must be non-null.
   155    * Example use:
   156    *   bool removed = frameList1.StartRemoveFrame(aFrame) ||
   157    *                  frameList2.ContinueRemoveFrame(aFrame) ||
   158    *                  frameList3.ContinueRemoveFrame(aFrame);
   159    *   MOZ_ASSERT(removed);
   160    *
   161    * @note One of the frame lists MUST contain aFrame, if it's on some other
   162    *       frame list then the example above will likely lead to crashes.
   163    * This function is O(1).
   164    * @return true iff aFrame was removed from /some/ list, not necessarily
   165    *         this one.  If it was removed from a different list then it is
   166    *         guaranteed that that list is still non-empty.
   167    * (this method is implemented in nsIFrame.h to be able to inline)
   168    */
   169   inline bool StartRemoveFrame(nsIFrame* aFrame);
   171   /**
   172    * Precondition: StartRemoveFrame MUST be called before this.
   173    * This function is O(1).
   174    * @see StartRemoveFrame
   175    * @return true iff aFrame was removed from this list
   176    * (this method is implemented in nsIFrame.h to be able to inline)
   177    */
   178   inline bool ContinueRemoveFrame(nsIFrame* aFrame);
   180   /**
   181    * Take aFrame out of the frame list and then destroy it.
   182    * The frame must be non-null and present on this list.
   183    */
   184   void DestroyFrame(nsIFrame* aFrame);
   186   /**
   187    * Insert aFrame right after aPrevSibling, or prepend it to this
   188    * list if aPrevSibling is null. If aParent is not null, also
   189    * reparents newly-added frame. Note that this method always
   190    * sets the frame's nextSibling pointer.
   191    */
   192   void InsertFrame(nsIFrame* aParent, nsIFrame* aPrevSibling,
   193                    nsIFrame* aFrame) {
   194     nsFrameList temp(aFrame, aFrame);
   195     InsertFrames(aParent, aPrevSibling, temp);
   196   }
   199   /**
   200    * Inserts aFrameList into this list after aPrevSibling (at the beginning if
   201    * aPrevSibling is null).  If aParent is not null, reparents the newly added
   202    * frames.  Clears out aFrameList and returns a list slice representing the
   203    * newly-inserted frames.
   204    */
   205   Slice InsertFrames(nsIFrame* aParent, nsIFrame* aPrevSibling,
   206                      nsFrameList& aFrameList);
   208   class FrameLinkEnumerator;
   210   /**
   211    * Split this frame list such that all the frames before the link pointed to
   212    * by aLink end up in the returned list, while the remaining frames stay in
   213    * this list.  After this call, aLink points to the beginning of this list.
   214    */
   215   nsFrameList ExtractHead(FrameLinkEnumerator& aLink);
   217   /**
   218    * Split this frame list such that all the frames coming after the link
   219    * pointed to by aLink end up in the returned list, while the frames before
   220    * that link stay in this list.  After this call, aLink is at end.
   221    */
   222   nsFrameList ExtractTail(FrameLinkEnumerator& aLink);
   224   nsIFrame* FirstChild() const {
   225     return mFirstChild;
   226   }
   228   nsIFrame* LastChild() const {
   229     return mLastChild;
   230   }
   232   nsIFrame* FrameAt(int32_t aIndex) const;
   233   int32_t IndexOf(nsIFrame* aFrame) const;
   235   bool IsEmpty() const {
   236     return nullptr == mFirstChild;
   237   }
   239   bool NotEmpty() const {
   240     return nullptr != mFirstChild;
   241   }
   243   bool ContainsFrame(const nsIFrame* aFrame) const;
   245   int32_t GetLength() const;
   247   /**
   248    * If this frame list has only one frame, return that frame.
   249    * Otherwise, return null.
   250    */
   251   nsIFrame* OnlyChild() const {
   252     if (FirstChild() == LastChild()) {
   253       return FirstChild();
   254     }
   255     return nullptr;
   256   }
   258   /**
   259    * Call SetParent(aParent) for each frame in this list.
   260    * @param aParent the new parent frame, must be non-null
   261    */
   262   void ApplySetParent(nsIFrame* aParent) const;
   264   /**
   265    * If this frame list is non-empty then append it to aLists as the
   266    * aListID child list.
   267    * (this method is implemented in FrameChildList.h for dependency reasons)
   268    */
   269   inline void AppendIfNonempty(nsTArray<mozilla::layout::FrameChildList>* aLists,
   270                                mozilla::layout::FrameChildListID aListID) const;
   272   /**
   273    * Return the frame before this frame in visual order (after Bidi reordering).
   274    * If aFrame is null, return the last frame in visual order.
   275    */
   276   nsIFrame* GetPrevVisualFor(nsIFrame* aFrame) const;
   278   /**
   279    * Return the frame after this frame in visual order (after Bidi reordering).
   280    * If aFrame is null, return the first frame in visual order.
   281    */
   282   nsIFrame* GetNextVisualFor(nsIFrame* aFrame) const;
   284 #ifdef DEBUG_FRAME_DUMP
   285   void List(FILE* out) const;
   286 #endif
   288   static inline const nsFrameList& EmptyList();
   290   class Enumerator;
   292   /**
   293    * A class representing a slice of a frame list.
   294    */
   295   class Slice {
   296     friend class Enumerator;
   298   public:
   299     // Implicit on purpose, so that we can easily create enumerators from
   300     // nsFrameList via this impicit constructor.
   301     Slice(const nsFrameList& aList) :
   302 #ifdef DEBUG
   303       mList(aList),
   304 #endif
   305       mStart(aList.FirstChild()),
   306       mEnd(nullptr)
   307     {}
   309     Slice(const nsFrameList& aList, nsIFrame* aStart, nsIFrame* aEnd) :
   310 #ifdef DEBUG
   311       mList(aList),
   312 #endif
   313       mStart(aStart),
   314       mEnd(aEnd)
   315     {}
   317     Slice(const Slice& aOther) :
   318 #ifdef DEBUG
   319       mList(aOther.mList),
   320 #endif
   321       mStart(aOther.mStart),
   322       mEnd(aOther.mEnd)
   323     {}
   325   private:
   326 #ifdef DEBUG
   327     const nsFrameList& mList;
   328 #endif
   329     nsIFrame* const mStart; // our starting frame
   330     const nsIFrame* const mEnd; // The first frame that is NOT in the slice.
   331                                 // May be null.
   332   };
   334   class Enumerator {
   335   public:
   336     Enumerator(const Slice& aSlice) :
   337 #ifdef DEBUG
   338       mSlice(aSlice),
   339 #endif
   340       mFrame(aSlice.mStart),
   341       mEnd(aSlice.mEnd)
   342     {}
   344     Enumerator(const Enumerator& aOther) :
   345 #ifdef DEBUG
   346       mSlice(aOther.mSlice),
   347 #endif
   348       mFrame(aOther.mFrame),
   349       mEnd(aOther.mEnd)
   350     {}
   352     bool AtEnd() const {
   353       // Can't just check mEnd, because some table code goes and destroys the
   354       // tail of the frame list (including mEnd!) while iterating over the
   355       // frame list.
   356       return !mFrame || mFrame == mEnd;
   357     }
   359     /* Next() needs to know about nsIFrame, and nsIFrame will need to
   360        know about nsFrameList methods, so in order to inline this put
   361        the implementation in nsIFrame.h */
   362     inline void Next();
   364     /**
   365      * Get the current frame we're pointing to.  Do not call this on an
   366      * iterator that is at end!
   367      */
   368     nsIFrame* get() const {
   369       NS_PRECONDITION(!AtEnd(), "Enumerator is at end");
   370       return mFrame;
   371     }
   373     /**
   374      * Get an enumerator that is just like this one, but not limited in terms of
   375      * the part of the list it will traverse.
   376      */
   377     Enumerator GetUnlimitedEnumerator() const {
   378       return Enumerator(*this, nullptr);
   379     }
   381 #ifdef DEBUG
   382     const nsFrameList& List() const { return mSlice.mList; }
   383 #endif
   385   protected:
   386     Enumerator(const Enumerator& aOther, const nsIFrame* const aNewEnd):
   387 #ifdef DEBUG
   388       mSlice(aOther.mSlice),
   389 #endif
   390       mFrame(aOther.mFrame),
   391       mEnd(aNewEnd)
   392     {}
   394 #ifdef DEBUG
   395     /* Has to be an object, not a reference, since the slice could
   396        well be a temporary constructed from an nsFrameList */
   397     const Slice mSlice;
   398 #endif
   399     nsIFrame* mFrame; // our current frame.
   400     const nsIFrame* const mEnd; // The first frame we should NOT enumerate.
   401                                 // May be null.
   402   };
   404   /**
   405    * A class that can be used to enumerate links between frames.  When created
   406    * from an nsFrameList, it points to the "link" immediately before the first
   407    * frame.  It can then be advanced until it points to the "link" immediately
   408    * after the last frame.  At any position, PrevFrame() and NextFrame() are
   409    * the frames before and after the given link.  This means PrevFrame() is
   410    * null when the enumerator is at the beginning of the list and NextFrame()
   411    * is null when it's AtEnd().
   412    */
   413   class FrameLinkEnumerator : private Enumerator {
   414   public:
   415     friend class nsFrameList;
   417     FrameLinkEnumerator(const nsFrameList& aList) :
   418       Enumerator(aList),
   419       mPrev(nullptr)
   420     {}
   422     FrameLinkEnumerator(const FrameLinkEnumerator& aOther) :
   423       Enumerator(aOther),
   424       mPrev(aOther.mPrev)
   425     {}
   427     /* This constructor needs to know about nsIFrame, and nsIFrame will need to
   428        know about nsFrameList methods, so in order to inline this put
   429        the implementation in nsIFrame.h */
   430     inline FrameLinkEnumerator(const nsFrameList& aList, nsIFrame* aPrevFrame);
   432     void operator=(const FrameLinkEnumerator& aOther) {
   433       NS_PRECONDITION(&List() == &aOther.List(), "Different lists?");
   434       mFrame = aOther.mFrame;
   435       mPrev = aOther.mPrev;
   436     }
   438     inline void Next();
   440     bool AtEnd() const { return Enumerator::AtEnd(); }
   442     nsIFrame* PrevFrame() const { return mPrev; }
   443     nsIFrame* NextFrame() const { return mFrame; }
   445   protected:
   446     nsIFrame* mPrev;
   447   };
   449 private:
   450   void operator delete(void*) MOZ_DELETE;
   452 #ifdef DEBUG_FRAME_LIST
   453   void VerifyList() const;
   454 #else
   455   void VerifyList() const {}
   456 #endif
   458 protected:
   459   /**
   460    * Disconnect aFrame from its siblings.  This must only be called if aFrame
   461    * is NOT the first or last sibling, because otherwise its nsFrameList will
   462    * have a stale mFirst/LastChild pointer.  This precondition is asserted.
   463    * This function is O(1).
   464    */
   465   static void UnhookFrameFromSiblings(nsIFrame* aFrame);
   467   nsIFrame* mFirstChild;
   468   nsIFrame* mLastChild;
   469 };
   471 namespace mozilla {
   472 namespace layout {
   474 /**
   475  * Simple "auto_ptr" for nsFrameLists allocated from the shell arena.
   476  * The frame list given to the constructor will be deallocated (if non-null)
   477  * in the destructor.  The frame list must then be empty.
   478  */
   479 class AutoFrameListPtr {
   480 public:
   481   AutoFrameListPtr(nsPresContext* aPresContext, nsFrameList* aFrameList)
   482     : mPresContext(aPresContext), mFrameList(aFrameList) {}
   483   ~AutoFrameListPtr();
   484   operator nsFrameList*() const { return mFrameList; }
   485   nsFrameList* operator->() const { return mFrameList; }
   486 private:
   487   nsPresContext* mPresContext;
   488   nsFrameList* mFrameList;
   489 };
   491 namespace detail {
   492 union AlignedFrameListBytes {
   493   void* ptr;
   494   char bytes[sizeof(nsFrameList)];
   495 };
   496 extern const AlignedFrameListBytes gEmptyFrameListBytes;
   497 }
   498 }
   499 }
   501 /* static */ inline const nsFrameList&
   502 nsFrameList::EmptyList()
   503 {
   504   return *reinterpret_cast<const nsFrameList*>(&mozilla::layout::detail::gEmptyFrameListBytes);
   505 }
   507 #endif /* nsFrameList_h___ */

mercurial