layout/base/nsFrameTraversal.cpp

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/. */
     5 #include "nsCOMPtr.h"
     6 #include "nsGkAtoms.h"
     8 #include "nsFrameTraversal.h"
     9 #include "nsFrameList.h"
    10 #include "nsPlaceholderFrame.h"
    13 class nsFrameIterator : public nsIFrameEnumerator
    14 {
    15 public:
    16   typedef nsIFrame::ChildListID ChildListID;
    18   NS_DECL_ISUPPORTS
    20   virtual ~nsFrameIterator() {}
    22   virtual void First() MOZ_OVERRIDE;
    23   virtual void Next() MOZ_OVERRIDE;
    24   virtual nsIFrame* CurrentItem() MOZ_OVERRIDE;
    25   virtual bool IsDone() MOZ_OVERRIDE;
    27   virtual void Last() MOZ_OVERRIDE;
    28   virtual void Prev() MOZ_OVERRIDE;
    30   nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
    31                   nsIteratorType aType, bool aLockScroll, bool aFollowOOFs);
    33 protected:
    34   void      setCurrent(nsIFrame *aFrame){mCurrent = aFrame;}
    35   nsIFrame *getCurrent(){return mCurrent;}
    36   nsIFrame *getStart(){return mStart;}
    37   nsIFrame *getLast(){return mLast;}
    38   void      setLast(nsIFrame *aFrame){mLast = aFrame;}
    39   int8_t    getOffEdge(){return mOffEdge;}
    40   void      setOffEdge(int8_t aOffEdge){mOffEdge = aOffEdge;}
    42   /*
    43    Our own versions of the standard frame tree navigation
    44    methods, which, if the iterator is following out-of-flows,
    45    apply the following rules for placeholder frames:
    47    - If a frame HAS a placeholder frame, getting its parent
    48    gets the placeholder's parent.
    50    - If a frame's first child or next/prev sibling IS a
    51    placeholder frame, then we instead return the real frame.
    53    - If a frame HAS a placeholder frame, getting its next/prev
    54    sibling gets the placeholder frame's next/prev sibling.
    56    These are all applied recursively to support multiple levels of
    57    placeholders.
    58    */  
    60   nsIFrame* GetParentFrame(nsIFrame* aFrame);
    61   // like GetParentFrame but returns null once a popup frame is reached
    62   nsIFrame* GetParentFrameNotPopup(nsIFrame* aFrame);
    64   nsIFrame* GetFirstChild(nsIFrame* aFrame);
    65   nsIFrame* GetLastChild(nsIFrame* aFrame);
    67   nsIFrame* GetNextSibling(nsIFrame* aFrame);
    68   nsIFrame* GetPrevSibling(nsIFrame* aFrame);
    70   /*
    71    These methods are overridden by the bidi visual iterator to have the
    72    semantics of "get first child in visual order", "get last child in visual
    73    order", "get next sibling in visual order" and "get previous sibling in visual
    74    order".
    75   */
    77   virtual nsIFrame* GetFirstChildInner(nsIFrame* aFrame);
    78   virtual nsIFrame* GetLastChildInner(nsIFrame* aFrame);  
    80   virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame);
    81   virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame);
    83   nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame);
    84   bool      IsPopupFrame(nsIFrame* aFrame);
    86   nsPresContext* const mPresContext;
    87   const bool mLockScroll;
    88   const bool mFollowOOFs;
    89   const nsIteratorType mType;
    91 private:
    92   nsIFrame* const mStart;
    93   nsIFrame* mCurrent;
    94   nsIFrame* mLast; //the last one that was in current;
    95   int8_t    mOffEdge; //0= no -1 to far prev, 1 to far next;
    96 };
   100 // Bidi visual iterator
   101 class nsVisualIterator: public nsFrameIterator
   102 {
   103 public:
   104   nsVisualIterator(nsPresContext* aPresContext, nsIFrame *aStart,
   105                    nsIteratorType aType, bool aLockScroll, bool aFollowOOFs) :
   106   nsFrameIterator(aPresContext, aStart, aType, aLockScroll, aFollowOOFs) {}
   108 protected:
   109   nsIFrame* GetFirstChildInner(nsIFrame* aFrame) MOZ_OVERRIDE;
   110   nsIFrame* GetLastChildInner(nsIFrame* aFrame) MOZ_OVERRIDE;  
   112   nsIFrame* GetNextSiblingInner(nsIFrame* aFrame) MOZ_OVERRIDE;
   113   nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame) MOZ_OVERRIDE;  
   114 };
   116 /************IMPLEMENTATIONS**************/
   118 nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult)
   119 {
   120   NS_ENSURE_ARG_POINTER(aResult);
   121   *aResult = nullptr;
   123   nsCOMPtr<nsIFrameTraversal> t(new nsFrameTraversal());
   125   *aResult = t;
   126   NS_ADDREF(*aResult);
   128   return NS_OK;
   129 }
   131 nsresult
   132 NS_NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
   133                      nsPresContext* aPresContext,
   134                      nsIFrame *aStart,
   135                      nsIteratorType aType,
   136                      bool aVisual,
   137                      bool aLockInScrollView,
   138                      bool aFollowOOFs)
   139 {
   140   if (!aEnumerator || !aStart)
   141     return NS_ERROR_NULL_POINTER;
   143   if (aFollowOOFs) {
   144     aStart = nsPlaceholderFrame::GetRealFrameFor(aStart);
   145   }
   147   nsCOMPtr<nsIFrameEnumerator> trav;
   148   if (aVisual) {
   149     trav = new nsVisualIterator(aPresContext, aStart, aType,
   150                                 aLockInScrollView, aFollowOOFs);
   151   } else {
   152     trav = new nsFrameIterator(aPresContext, aStart, aType,
   153                                aLockInScrollView, aFollowOOFs);
   154   }
   155   trav.forget(aEnumerator);
   156   return NS_OK;
   157 }
   160 nsFrameTraversal::nsFrameTraversal()
   161 {
   162 }
   164 nsFrameTraversal::~nsFrameTraversal()
   165 {
   166 }
   168 NS_IMPL_ISUPPORTS(nsFrameTraversal,nsIFrameTraversal)
   170 NS_IMETHODIMP 
   171  nsFrameTraversal::NewFrameTraversal(nsIFrameEnumerator **aEnumerator,
   172                                      nsPresContext* aPresContext,
   173                                      nsIFrame *aStart,
   174                                      int32_t aType,
   175                                      bool aVisual,
   176                                      bool aLockInScrollView,
   177                                      bool aFollowOOFs)
   178 {
   179   return NS_NewFrameTraversal(aEnumerator, aPresContext, aStart,
   180                               static_cast<nsIteratorType>(aType),
   181                               aVisual, aLockInScrollView, aFollowOOFs);  
   182 }
   184 // nsFrameIterator implementation
   186 NS_IMPL_ISUPPORTS(nsFrameIterator, nsIFrameEnumerator)
   188 nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart,
   189                                  nsIteratorType aType, bool aLockInScrollView,
   190                                  bool aFollowOOFs)
   191 : mPresContext(aPresContext),
   192   mLockScroll(aLockInScrollView),
   193   mFollowOOFs(aFollowOOFs),
   194   mType(aType),
   195   mStart(aStart),
   196   mCurrent(aStart),
   197   mLast(aStart),
   198   mOffEdge(0)
   199 {
   200   MOZ_ASSERT(!aFollowOOFs || aStart->GetType() != nsGkAtoms::placeholderFrame,
   201              "Caller should have resolved placeholder frame");
   202 }
   206 nsIFrame*
   207 nsFrameIterator::CurrentItem()
   208 {
   209   if (mOffEdge)
   210     return nullptr;
   212   return mCurrent;
   213 }
   217 bool
   218 nsFrameIterator::IsDone()
   219 {
   220   return mOffEdge != 0;
   221 }
   223 void
   224 nsFrameIterator::First()
   225 {
   226   mCurrent = mStart;
   227 }
   229 static bool
   230 IsRootFrame(nsIFrame* aFrame)
   231 {
   232   nsIAtom* atom = aFrame->GetType();
   233   return (atom == nsGkAtoms::canvasFrame) ||
   234          (atom == nsGkAtoms::rootFrame);
   235 }
   237 void
   238 nsFrameIterator::Last()
   239 {
   240   nsIFrame* result;
   241   nsIFrame* parent = getCurrent();
   242   // If the current frame is a popup, don't move farther up the tree.
   243   // Otherwise, get the nearest root frame or popup.
   244   if (parent->GetType() != nsGkAtoms::menuPopupFrame) {
   245     while (!IsRootFrame(parent) && (result = GetParentFrameNotPopup(parent)))
   246       parent = result;
   247   }
   249   while ((result = GetLastChild(parent))) {
   250     parent = result;
   251   }
   253   setCurrent(parent);
   254   if (!parent)
   255     setOffEdge(1);
   256 }
   258 void
   259 nsFrameIterator::Next()
   260 {
   261   // recursive-oid method to get next frame
   262   nsIFrame *result = nullptr;
   263   nsIFrame *parent = getCurrent();
   264   if (!parent)
   265     parent = getLast();
   267   if (mType == eLeaf) {
   268     // Drill down to first leaf
   269     while ((result = GetFirstChild(parent))) {
   270       parent = result;
   271     }
   272   } else if (mType == ePreOrder) {
   273     result = GetFirstChild(parent);
   274     if (result)
   275       parent = result;
   276   }
   278   if (parent != getCurrent()) {
   279     result = parent;
   280   } else {
   281     while (parent) {
   282       result = GetNextSibling(parent);
   283       if (result) {
   284         if (mType != ePreOrder) {
   285           parent = result;
   286           while ((result = GetFirstChild(parent))) {
   287             parent = result;
   288           }
   289           result = parent;
   290         }
   291         break;
   292       }
   293       else {
   294         result = GetParentFrameNotPopup(parent);
   295         if (!result || IsRootFrame(result) ||
   296             (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) {
   297           result = nullptr;
   298           break;
   299         }
   300         if (mType == ePostOrder)
   301           break;
   302         parent = result;
   303       }
   304     }
   305   }
   307   setCurrent(result);
   308   if (!result) {
   309     setOffEdge(1);
   310     setLast(parent);
   311   }
   312 }
   314 void
   315 nsFrameIterator::Prev()
   316 {
   317   // recursive-oid method to get prev frame
   318   nsIFrame *result = nullptr;
   319   nsIFrame *parent = getCurrent();
   320   if (!parent)
   321     parent = getLast();
   323   if (mType == eLeaf) {
   324     // Drill down to last leaf
   325     while ((result = GetLastChild(parent))) {
   326       parent = result;
   327     }
   328   } else if (mType == ePostOrder) {
   329     result = GetLastChild(parent);
   330     if (result)
   331       parent = result;
   332   }
   334   if (parent != getCurrent()) {
   335     result = parent;
   336   } else {
   337     while (parent) {
   338       result = GetPrevSibling(parent);
   339       if (result) {
   340         if (mType != ePostOrder) {
   341           parent = result;
   342           while ((result = GetLastChild(parent))) {
   343             parent = result;
   344           }
   345           result = parent;
   346         }
   347         break;
   348       } else {
   349         result = GetParentFrameNotPopup(parent);
   350         if (!result || IsRootFrame(result) ||
   351             (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) {
   352           result = nullptr;
   353           break;
   354         }
   355         if (mType == ePreOrder)
   356           break;
   357         parent = result;
   358       }
   359     }
   360   }
   362   setCurrent(result);
   363   if (!result) {
   364     setOffEdge(-1);
   365     setLast(parent);
   366   }
   367 }
   369 nsIFrame*
   370 nsFrameIterator::GetParentFrame(nsIFrame* aFrame)
   371 {
   372   if (mFollowOOFs)
   373     aFrame = GetPlaceholderFrame(aFrame);
   374   if (aFrame)
   375     return aFrame->GetParent();
   377   return nullptr;
   378 }
   380 nsIFrame*
   381 nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame)
   382 {
   383   if (mFollowOOFs)
   384     aFrame = GetPlaceholderFrame(aFrame);
   385   if (aFrame) {
   386     nsIFrame* parent = aFrame->GetParent();
   387     if (!IsPopupFrame(parent))
   388       return parent;
   389   }
   391   return nullptr;
   392 }
   394 nsIFrame*
   395 nsFrameIterator::GetFirstChild(nsIFrame* aFrame)
   396 {
   397   nsIFrame* result = GetFirstChildInner(aFrame);
   398   if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame)
   399     return nullptr;
   400   if (result && mFollowOOFs) {
   401     result = nsPlaceholderFrame::GetRealFrameFor(result);
   403     if (IsPopupFrame(result))
   404       result = GetNextSibling(result);
   405   }
   406   return result;
   407 }
   409 nsIFrame*
   410 nsFrameIterator::GetLastChild(nsIFrame* aFrame)
   411 {
   412   nsIFrame* result = GetLastChildInner(aFrame);
   413   if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame)
   414     return nullptr;
   415   if (result && mFollowOOFs) {
   416     result = nsPlaceholderFrame::GetRealFrameFor(result);
   418     if (IsPopupFrame(result))
   419       result = GetPrevSibling(result);
   420   }
   421   return result;
   422 }
   424 nsIFrame*
   425 nsFrameIterator::GetNextSibling(nsIFrame* aFrame)
   426 {
   427   nsIFrame* result = nullptr;
   428   if (mFollowOOFs)
   429     aFrame = GetPlaceholderFrame(aFrame);
   430   if (aFrame) {
   431     result = GetNextSiblingInner(aFrame);
   432     if (result && mFollowOOFs)
   433       result = nsPlaceholderFrame::GetRealFrameFor(result);
   434   }
   436   if (mFollowOOFs && IsPopupFrame(result))
   437     result = GetNextSibling(result);
   439   return result;
   440 }
   442 nsIFrame*
   443 nsFrameIterator::GetPrevSibling(nsIFrame* aFrame)
   444 {
   445   nsIFrame* result = nullptr;
   446   if (mFollowOOFs)
   447     aFrame = GetPlaceholderFrame(aFrame);
   448   if (aFrame) {
   449     result = GetPrevSiblingInner(aFrame);
   450     if (result && mFollowOOFs)
   451       result = nsPlaceholderFrame::GetRealFrameFor(result);
   452   }
   454   if (mFollowOOFs && IsPopupFrame(result))
   455     result = GetPrevSibling(result);
   457   return result;
   458 }
   460 nsIFrame*
   461 nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) {
   462   return aFrame->GetFirstPrincipalChild();
   463 }
   465 nsIFrame*
   466 nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) {
   467   return aFrame->PrincipalChildList().LastChild();
   468 }
   470 nsIFrame*
   471 nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) {
   472   return aFrame->GetNextSibling();
   473 }
   475 nsIFrame*
   476 nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
   477   return aFrame->GetPrevSibling();
   478 }
   481 nsIFrame*
   482 nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame)
   483 {
   484   nsIFrame* result = aFrame;
   485   nsIPresShell *presShell = mPresContext->GetPresShell();
   486   if (presShell) {
   487     nsIFrame* placeholder = presShell->GetPlaceholderFrameFor(aFrame);
   488     if (placeholder)
   489       result = placeholder;
   490   }
   492   if (result != aFrame)
   493     result = GetPlaceholderFrame(result);
   495   return result;
   496 }
   498 bool
   499 nsFrameIterator::IsPopupFrame(nsIFrame* aFrame)
   500 {
   501   return (aFrame &&
   502           aFrame->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP);
   503 }
   505 // nsVisualIterator implementation
   507 nsIFrame*
   508 nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame) {
   509   return aFrame->PrincipalChildList().GetNextVisualFor(nullptr);
   510 }
   512 nsIFrame*
   513 nsVisualIterator::GetLastChildInner(nsIFrame* aFrame) {
   514   return aFrame->PrincipalChildList().GetPrevVisualFor(nullptr);
   515 }
   517 nsIFrame*
   518 nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame) {
   519   nsIFrame* parent = GetParentFrame(aFrame);
   520   if (!parent)
   521     return nullptr;
   522   return parent->PrincipalChildList().GetNextVisualFor(aFrame);
   523 }
   525 nsIFrame*
   526 nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame) {
   527   nsIFrame* parent = GetParentFrame(aFrame);
   528   if (!parent)
   529     return nullptr;
   530   return parent->PrincipalChildList().GetPrevVisualFor(aFrame);
   531 }

mercurial