diff --git a/content/events/src/nsEventStateManager.cpp b/content/events/src/nsEventStateManager.cpp index b2e0e1ca83f5..e3ff9d45b326 100644 --- a/content/events/src/nsEventStateManager.cpp +++ b/content/events/src/nsEventStateManager.cpp @@ -65,6 +65,7 @@ #include "nsCaret.h" #include "nsSubDocumentFrame.h" +#include "nsIFrameTraversal.h" #include "nsLayoutCID.h" #include "nsLayoutUtils.h" #include "nsIInterfaceRequestorUtils.h" @@ -113,6 +114,8 @@ using namespace mozilla::dom; static const nsIntPoint kInvalidRefPoint = nsIntPoint(-1,-1); +static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID); + static bool sLeftClickOnly = true; static bool sKeyCausesActivation = true; static uint32_t sESMInstanceCount = 0; diff --git a/dom/base/nsFocusManager.cpp b/dom/base/nsFocusManager.cpp index 29c7a497910d..a242c092a852 100644 --- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -31,7 +31,7 @@ #include "nsLayoutUtils.h" #include "nsIPresShell.h" #include "nsIContentViewer.h" -#include "nsFrameIterator.h" +#include "nsFrameTraversal.h" #include "nsObjectFrame.h" #include "nsEventDispatcher.h" #include "nsEventStateManager.h" @@ -2270,8 +2270,15 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument, if (nodeValue.Length() == (uint32_t)startOffset && !isFormControl && startContent != aDocument->GetRootElement()) { // Yes, indeed we were at the end of the last node - nsFrameIterator frameTraversal(presContext, startFrame, - eLeaf, nsFrameIterator::FLAG_FOLLOW_OUT_OF_FLOW); + nsCOMPtr frameTraversal; + nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), + presContext, startFrame, + eLeaf, + false, // aVisual + false, // aLockInScrollView + true // aFollowOOFs + ); + NS_ENSURE_SUCCESS(rv, rv); nsIFrame *newCaretFrame = nullptr; nsCOMPtr newCaretContent = startContent; @@ -2279,8 +2286,8 @@ nsFocusManager::GetSelectionLocation(nsIDocument* aDocument, do { // Continue getting the next frame until the primary content for the frame // we are on changes - we don't want to be stuck in the same place - frameTraversal.Next(); - newCaretFrame = static_cast(frameTraversal.CurrentItem()); + frameTraversal->Next(); + newCaretFrame = static_cast(frameTraversal->CurrentItem()); if (nullptr == newCaretFrame) break; newCaretContent = newCaretFrame->GetContent(); @@ -2696,14 +2703,21 @@ nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell, continue; } - nsFrameIterator frameTraversal(presContext, startFrame, - ePreOrder, nsFrameIterator::FLAG_FOLLOW_OUT_OF_FLOW); + nsCOMPtr frameTraversal; + nsresult rv = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), + presContext, startFrame, + ePreOrder, + false, // aVisual + false, // aLockInScrollView + true // aFollowOOFs + ); + NS_ENSURE_SUCCESS(rv, rv); if (iterStartContent == aRootContent) { if (!aForward) { - frameTraversal.Last(); + frameTraversal->Last(); } else if (aRootContent->IsFocusable()) { - frameTraversal.Next(); + frameTraversal->Next(); } } else if (getNextFrame && @@ -2712,13 +2726,13 @@ nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell, // Need to do special check in case we're in an imagemap which has multiple // content nodes per frame, so don't skip over the starting frame. if (aForward) - frameTraversal.Next(); + frameTraversal->Next(); else - frameTraversal.Prev(); + frameTraversal->Prev(); } // Walk frames to find something tabbable matching mCurrentTabIndex - nsIFrame* frame = static_cast(frameTraversal.CurrentItem()); + nsIFrame* frame = static_cast(frameTraversal->CurrentItem()); while (frame) { // TabIndex not set defaults to 0 for form elements, anchors and other // elements that are normally focusable. Tabindex defaults to -1 @@ -2788,10 +2802,10 @@ nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell, Element* rootElement = subdoc->GetRootElement(); nsIPresShell* subShell = subdoc->GetShell(); if (rootElement && subShell) { - nsresult rv = GetNextTabbableContent(subShell, rootElement, - aOriginalStartContent, rootElement, - aForward, (aForward ? 1 : 0), - false, aResultContent); + rv = GetNextTabbableContent(subShell, rootElement, + aOriginalStartContent, rootElement, + aForward, (aForward ? 1 : 0), + false, aResultContent); NS_ENSURE_SUCCESS(rv, rv); if (*aResultContent) return NS_OK; @@ -2835,10 +2849,10 @@ nsFocusManager::GetNextTabbableContent(nsIPresShell* aPresShell, // again. do { if (aForward) - frameTraversal.Next(); + frameTraversal->Next(); else - frameTraversal.Prev(); - frame = static_cast(frameTraversal.CurrentItem()); + frameTraversal->Prev(); + frame = static_cast(frameTraversal->CurrentItem()); } while (frame && frame->GetPrevContinuation()); } diff --git a/layout/base/Makefile.in b/layout/base/Makefile.in index ae9234bb9784..49b188385d92 100644 --- a/layout/base/Makefile.in +++ b/layout/base/Makefile.in @@ -41,7 +41,8 @@ EXPORTS = \ nsDisplayListInvalidation.h \ nsFrameManager.h \ nsFrameManagerBase.h \ - nsFrameIterator.h \ + nsFrameTraversal.h \ + nsIFrameTraversal.h \ nsILayoutDebugger.h \ nsILayoutHistoryState.h \ nsIPercentHeightObserver.h \ @@ -77,7 +78,7 @@ CPPSRCS = \ nsDisplayListInvalidation.cpp \ nsDocumentViewer.cpp \ nsFrameManager.cpp \ - nsFrameIterator.cpp \ + nsFrameTraversal.cpp \ nsGenConList.cpp \ nsLayoutDebugger.cpp \ nsLayoutHistoryState.cpp \ diff --git a/layout/base/nsFrameIterator.h b/layout/base/nsFrameIterator.h deleted file mode 100644 index 3169b8dbd007..000000000000 --- a/layout/base/nsFrameIterator.h +++ /dev/null @@ -1,107 +0,0 @@ -/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef NSFRAMEITERATOR_H -#define NSFRAMEITERATOR_H - -#include "mozilla/StandardInteger.h" - -class nsPresContext; -class nsIFrame; - -enum nsIteratorType { - eLeaf, - ePreOrder, - ePostOrder -}; - -class nsFrameIterator -{ -public: - nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, - nsIteratorType aType, uint32_t aFlags); - - ~nsFrameIterator() {} - - void First(); - void Next(); - nsIFrame* CurrentItem(); - bool IsDone(); - - void Last(); - void Prev(); - - enum FrameIteratorFlags { - FLAG_NONE = 0, - FLAG_LOCK_SCROLL = 1 << 1, - FLAG_FOLLOW_OUT_OF_FLOW = 1 << 2, - FLAG_VISUAL = 1 << 3 - }; -protected: - void setCurrent(nsIFrame *aFrame){mCurrent = aFrame;} - nsIFrame *getCurrent(){return mCurrent;} - void setStart(nsIFrame *aFrame){mStart = aFrame;} - nsIFrame *getStart(){return mStart;} - nsIFrame *getLast(){return mLast;} - void setLast(nsIFrame *aFrame){mLast = aFrame;} - int8_t getOffEdge(){return mOffEdge;} - void setOffEdge(int8_t aOffEdge){mOffEdge = aOffEdge;} - void SetLockInScrollView(bool aLockScroll){mLockScroll = aLockScroll;} - - /* - Our own versions of the standard frame tree navigation - methods, which, if the iterator is following out-of-flows, - apply the following rules for placeholder frames: - - - If a frame HAS a placeholder frame, getting its parent - gets the placeholder's parent. - - - If a frame's first child or next/prev sibling IS a - placeholder frame, then we instead return the real frame. - - - If a frame HAS a placeholder frame, getting its next/prev - sibling gets the placeholder frame's next/prev sibling. - - These are all applied recursively to support multiple levels of - placeholders. - */ - - nsIFrame* GetParentFrame(nsIFrame* aFrame); - // like GetParentFrame but returns null once a popup frame is reached - nsIFrame* GetParentFrameNotPopup(nsIFrame* aFrame); - - nsIFrame* GetFirstChild(nsIFrame* aFrame); - nsIFrame* GetLastChild(nsIFrame* aFrame); - - nsIFrame* GetNextSibling(nsIFrame* aFrame); - nsIFrame* GetPrevSibling(nsIFrame* aFrame); - - /* - These methods are different in visual mode to have the - semantics of "get first child in visual order", "get last child in visual - order", "get next sibling in visual order" and "get previous sibling in visual - order". - */ - - nsIFrame* GetFirstChildInner(nsIFrame* aFrame); - nsIFrame* GetLastChildInner(nsIFrame* aFrame); - - nsIFrame* GetNextSiblingInner(nsIFrame* aFrame); - nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame); - - nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame); - bool IsPopupFrame(nsIFrame* aFrame); - - nsPresContext* mPresContext; - nsIFrame *mStart; - nsIFrame *mCurrent; - nsIFrame *mLast; //the last one that was in current; - int8_t mOffEdge; //0= no -1 to far prev, 1 to far next; - nsIteratorType mType; - bool mLockScroll; - bool mFollowOOFs; - bool mVisual; -}; - -#endif //NSFRAMEITERATOR_H diff --git a/layout/base/nsFrameIterator.cpp b/layout/base/nsFrameTraversal.cpp similarity index 51% rename from layout/base/nsFrameIterator.cpp rename to layout/base/nsFrameTraversal.cpp index 1b84f0045804..1b38ad401170 100644 --- a/layout/base/nsFrameIterator.cpp +++ b/layout/base/nsFrameTraversal.cpp @@ -2,34 +2,215 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsFrameIterator.h" -#include "nsIFrame.h" +#include "nsCOMPtr.h" #include "nsGkAtoms.h" + +#include "nsFrameTraversal.h" +#include "nsFrameList.h" #include "nsPlaceholderFrame.h" -nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, - nsIteratorType aType, uint32_t aFlags) - : mPresContext(aPresContext) - , mOffEdge(0) - , mType(aType) + +class nsFrameIterator : public nsIFrameEnumerator { - mFollowOOFs = (aFlags & FLAG_FOLLOW_OUT_OF_FLOW) != 0; - mLockScroll = (aFlags & FLAG_LOCK_SCROLL) != 0; - mVisual = (aFlags & FLAG_VISUAL) != 0; - if (mFollowOOFs && aStart) +public: + typedef nsIFrame::ChildListID ChildListID; + + NS_DECL_ISUPPORTS + + virtual ~nsFrameIterator() {} + + virtual void First(); + virtual void Next(); + virtual nsIFrame* CurrentItem(); + virtual bool IsDone(); + + virtual void Last(); + virtual void Prev(); + + nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, + nsIteratorType aType, bool aLockScroll, bool aFollowOOFs); + +protected: + void setCurrent(nsIFrame *aFrame){mCurrent = aFrame;} + nsIFrame *getCurrent(){return mCurrent;} + void setStart(nsIFrame *aFrame){mStart = aFrame;} + nsIFrame *getStart(){return mStart;} + nsIFrame *getLast(){return mLast;} + void setLast(nsIFrame *aFrame){mLast = aFrame;} + PRInt8 getOffEdge(){return mOffEdge;} + void setOffEdge(PRInt8 aOffEdge){mOffEdge = aOffEdge;} + void SetLockInScrollView(bool aLockScroll){mLockScroll = aLockScroll;} + + /* + Our own versions of the standard frame tree navigation + methods, which, if the iterator is following out-of-flows, + apply the following rules for placeholder frames: + + - If a frame HAS a placeholder frame, getting its parent + gets the placeholder's parent. + + - If a frame's first child or next/prev sibling IS a + placeholder frame, then we instead return the real frame. + + - If a frame HAS a placeholder frame, getting its next/prev + sibling gets the placeholder frame's next/prev sibling. + + These are all applied recursively to support multiple levels of + placeholders. + */ + + nsIFrame* GetParentFrame(nsIFrame* aFrame); + // like GetParentFrame but returns null once a popup frame is reached + nsIFrame* GetParentFrameNotPopup(nsIFrame* aFrame); + + nsIFrame* GetFirstChild(nsIFrame* aFrame); + nsIFrame* GetLastChild(nsIFrame* aFrame); + + nsIFrame* GetNextSibling(nsIFrame* aFrame); + nsIFrame* GetPrevSibling(nsIFrame* aFrame); + + /* + These methods are overridden by the bidi visual iterator to have the + semantics of "get first child in visual order", "get last child in visual + order", "get next sibling in visual order" and "get previous sibling in visual + order". + */ + + virtual nsIFrame* GetFirstChildInner(nsIFrame* aFrame); + virtual nsIFrame* GetLastChildInner(nsIFrame* aFrame); + + virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame); + virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame); + + nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame); + bool IsPopupFrame(nsIFrame* aFrame); + + nsPresContext* mPresContext; + bool mLockScroll; + bool mFollowOOFs; + nsIteratorType mType; + +private: + nsIFrame *mStart; + nsIFrame *mCurrent; + nsIFrame *mLast; //the last one that was in current; + PRInt8 mOffEdge; //0= no -1 to far prev, 1 to far next; +}; + + + +// Bidi visual iterator +class nsVisualIterator: public nsFrameIterator +{ +public: + nsVisualIterator(nsPresContext* aPresContext, nsIFrame *aStart, + nsIteratorType aType, bool aLockScroll, bool aFollowOOFs) : + nsFrameIterator(aPresContext, aStart, aType, aLockScroll, aFollowOOFs) {} + +protected: + nsIFrame* GetFirstChildInner(nsIFrame* aFrame); + nsIFrame* GetLastChildInner(nsIFrame* aFrame); + + nsIFrame* GetNextSiblingInner(nsIFrame* aFrame); + nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame); +}; + +/************IMPLEMENTATIONS**************/ + +nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult) +{ + NS_ENSURE_ARG_POINTER(aResult); + *aResult = nullptr; + + nsCOMPtr t(new nsFrameTraversal()); + + *aResult = t; + NS_ADDREF(*aResult); + + return NS_OK; +} + +nsresult +NS_NewFrameTraversal(nsIFrameEnumerator **aEnumerator, + nsPresContext* aPresContext, + nsIFrame *aStart, + nsIteratorType aType, + bool aVisual, + bool aLockInScrollView, + bool aFollowOOFs) +{ + if (!aEnumerator || !aStart) + return NS_ERROR_NULL_POINTER; + nsCOMPtr trav; + if (aVisual) { + trav = new nsVisualIterator(aPresContext, aStart, aType, + aLockInScrollView, aFollowOOFs); + } else { + trav = new nsFrameIterator(aPresContext, aStart, aType, + aLockInScrollView, aFollowOOFs); + } + trav.forget(aEnumerator); + return NS_OK; +} + + +nsFrameTraversal::nsFrameTraversal() +{ +} + +nsFrameTraversal::~nsFrameTraversal() +{ +} + +NS_IMPL_ISUPPORTS1(nsFrameTraversal,nsIFrameTraversal) + +NS_IMETHODIMP + nsFrameTraversal::NewFrameTraversal(nsIFrameEnumerator **aEnumerator, + nsPresContext* aPresContext, + nsIFrame *aStart, + PRInt32 aType, + bool aVisual, + bool aLockInScrollView, + bool aFollowOOFs) +{ + return NS_NewFrameTraversal(aEnumerator, aPresContext, aStart, + static_cast(aType), + aVisual, aLockInScrollView, aFollowOOFs); +} + +// nsFrameIterator implementation + +NS_IMPL_ISUPPORTS1(nsFrameIterator, nsIFrameEnumerator) + +nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, + nsIteratorType aType, bool aLockInScrollView, + bool aFollowOOFs) +{ + mOffEdge = 0; + mPresContext = aPresContext; + if (aFollowOOFs && aStart) aStart = nsPlaceholderFrame::GetRealFrameFor(aStart); setStart(aStart); setCurrent(aStart); setLast(aStart); + mType = aType; + SetLockInScrollView(aLockInScrollView); + mFollowOOFs = aFollowOOFs; } + + nsIFrame* nsFrameIterator::CurrentItem() { - return mOffEdge ? nullptr : mCurrent; + if (mOffEdge) + return nullptr; + + return mCurrent; } + + bool nsFrameIterator::IsDone() { @@ -65,7 +246,7 @@ nsFrameIterator::Last() while ((result = GetLastChild(parent))) { parent = result; } - + setCurrent(parent); if (!parent) setOffEdge(1); @@ -146,7 +327,7 @@ nsFrameIterator::Prev() if (result) parent = result; } - + if (parent != getCurrent()) { result = parent; } else { @@ -189,7 +370,7 @@ nsFrameIterator::GetParentFrame(nsIFrame* aFrame) aFrame = GetPlaceholderFrame(aFrame); if (aFrame) return aFrame->GetParent(); - + return nullptr; } @@ -203,7 +384,7 @@ nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame) if (!IsPopupFrame(parent)) return parent; } - + return nullptr; } @@ -215,7 +396,7 @@ nsFrameIterator::GetFirstChild(nsIFrame* aFrame) return nullptr; if (result && mFollowOOFs) { result = nsPlaceholderFrame::GetRealFrameFor(result); - + if (IsPopupFrame(result)) result = GetNextSibling(result); } @@ -230,7 +411,7 @@ nsFrameIterator::GetLastChild(nsIFrame* aFrame) return nullptr; if (result && mFollowOOFs) { result = nsPlaceholderFrame::GetRealFrameFor(result); - + if (IsPopupFrame(result)) result = GetPrevSibling(result); } @@ -275,42 +456,25 @@ nsFrameIterator::GetPrevSibling(nsIFrame* aFrame) nsIFrame* nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) { - if (mVisual) { - return aFrame->PrincipalChildList().GetNextVisualFor(nullptr); - } return aFrame->GetFirstPrincipalChild(); } nsIFrame* nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) { - if (mVisual) { - return aFrame->PrincipalChildList().GetPrevVisualFor(nullptr); - } return aFrame->PrincipalChildList().LastChild(); } nsIFrame* nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) { - if (mVisual) { - nsIFrame* parent = GetParentFrame(aFrame); - if (!parent) - return nullptr; - return parent->PrincipalChildList().GetNextVisualFor(aFrame); - } return aFrame->GetNextSibling(); } nsIFrame* nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) { - if (mVisual) { - nsIFrame* parent = GetParentFrame(aFrame); - if (!parent) - return nullptr; - return parent->PrincipalChildList().GetPrevVisualFor(aFrame); - } return aFrame->GetPrevSibling(); } + nsIFrame* nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame) { @@ -335,3 +499,30 @@ nsFrameIterator::IsPopupFrame(nsIFrame* aFrame) aFrame->GetStyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP); } +// nsVisualIterator implementation + +nsIFrame* +nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame) { + return aFrame->PrincipalChildList().GetNextVisualFor(nullptr); +} + +nsIFrame* +nsVisualIterator::GetLastChildInner(nsIFrame* aFrame) { + return aFrame->PrincipalChildList().GetPrevVisualFor(nullptr); +} + +nsIFrame* +nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame) { + nsIFrame* parent = GetParentFrame(aFrame); + if (!parent) + return nullptr; + return parent->PrincipalChildList().GetNextVisualFor(aFrame); +} + +nsIFrame* +nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame) { + nsIFrame* parent = GetParentFrame(aFrame); + if (!parent) + return nullptr; + return parent->PrincipalChildList().GetPrevVisualFor(aFrame); +} diff --git a/layout/base/nsFrameTraversal.h b/layout/base/nsFrameTraversal.h new file mode 100644 index 000000000000..de7efd5d6b91 --- /dev/null +++ b/layout/base/nsFrameTraversal.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef NSFRAMETRAVERSAL_H +#define NSFRAMETRAVERSAL_H + +#include "nsIFrame.h" +#include "nsIFrameTraversal.h" + +nsresult NS_NewFrameTraversal(nsIFrameEnumerator **aEnumerator, + nsPresContext* aPresContext, + nsIFrame *aStart, + nsIteratorType aType, + bool aVisual, + bool aLockInScrollView, + bool aFollowOOFs); + +nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult); + +class nsFrameTraversal : public nsIFrameTraversal +{ +public: + nsFrameTraversal(); + virtual ~nsFrameTraversal(); + + NS_DECL_ISUPPORTS + + NS_IMETHOD NewFrameTraversal(nsIFrameEnumerator **aEnumerator, + nsPresContext* aPresContext, + nsIFrame *aStart, + PRInt32 aType, + bool aVisual, + bool aLockInScrollView, + bool aFollowOOFs); +}; + +#endif //NSFRAMETRAVERSAL_H diff --git a/layout/base/nsIFrameTraversal.h b/layout/base/nsIFrameTraversal.h new file mode 100644 index 000000000000..7853b6c0f29c --- /dev/null +++ b/layout/base/nsIFrameTraversal.h @@ -0,0 +1,72 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef NSIFRAMETRAVERSAL_H +#define NSIFRAMETRAVERSAL_H + +#include "nsISupports.h" +#include "nsIFrame.h" + +#define NS_IFRAMEENUMERATOR_IID \ +{ 0x7c633f5d, 0x91eb, 0x494e, \ + { 0xa1, 0x40, 0x17, 0x46, 0x17, 0x4c, 0x23, 0xd3 } } + +class nsIFrameEnumerator : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFRAMEENUMERATOR_IID) + + virtual void First() = 0; + virtual void Next() = 0; + virtual nsIFrame* CurrentItem() = 0; + virtual bool IsDone() = 0; + + virtual void Last() = 0; + virtual void Prev() = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsIFrameEnumerator, NS_IFRAMEENUMERATOR_IID) + +enum nsIteratorType { + eLeaf, + ePreOrder, + ePostOrder +}; + +// {9d469828-9bf2-4151-a385-05f30219221b} +#define NS_IFRAMETRAVERSAL_IID \ +{ 0x9d469828, 0x9bf2, 0x4151, { 0xa3, 0x85, 0x05, 0xf3, 0x02, 0x19, 0x22, 0x1b } } + +class nsIFrameTraversal : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFRAMETRAVERSAL_IID) + + /** + * Create a frame iterator with the specified properties. + * @param aEnumerator [out] the created iterator + * @param aPresContext [in] + * @param aStart [in] the frame to start iterating from + * @param aType [in] the type of the iterator: leaf, pre-order, or post-order + * @param aVisual [in] whether the iterator should traverse frames in visual + * bidi order + * @param aLockInScrollView [in] whether to stop iterating when exiting a + * scroll view + * @param aFollowOOFs [in] whether the iterator should follow out-of-flows. + * If true, when reaching a placeholder frame while going down will get + * the real frame. Going back up will go on past the placeholder, + * so the placeholders are logically part of the frame tree. + */ + NS_IMETHOD NewFrameTraversal(nsIFrameEnumerator **aEnumerator, + nsPresContext* aPresContext, + nsIFrame *aStart, + PRInt32 aType, + bool aVisual, + bool aLockInScrollView, + bool aFollowOOFs) = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsIFrameTraversal, NS_IFRAMETRAVERSAL_IID) + +#endif //NSIFRAMETRAVERSAL_H diff --git a/layout/build/nsLayoutCID.h b/layout/build/nsLayoutCID.h index d686ef662368..3e24d438a6ea 100644 --- a/layout/build/nsLayoutCID.h +++ b/layout/build/nsLayoutCID.h @@ -6,6 +6,10 @@ #ifndef nsLayoutCID_h__ #define nsLayoutCID_h__ +// {1691E1F4-EE41-11d4-9885-00C04FA0CF4B} +#define NS_FRAMETRAVERSAL_CID \ +{ 0x1691e1f4, 0xee41, 0x11d4, { 0x98, 0x85, 0x0, 0xc0, 0x4f, 0xa0, 0xcf, 0x4b } } + /* a6cf90f9-15b3-11d2-932e-00805f8add32 */ #define NS_LAYOUT_DEBUGGER_CID \ { 0xa6cf90f9, 0x15b3, 0x11d2,{0x93, 0x2e, 0x00, 0x80, 0x5f, 0x8a, 0xdd, 0x32}} diff --git a/layout/build/nsLayoutModule.cpp b/layout/build/nsLayoutModule.cpp index 1c680ca45c20..dd4324ac0e5e 100644 --- a/layout/build/nsLayoutModule.cpp +++ b/layout/build/nsLayoutModule.cpp @@ -45,6 +45,7 @@ #include "nsContentAreaDragDrop.h" #include "nsContentList.h" #include "nsBox.h" +#include "nsIFrameTraversal.h" #include "nsLayoutCID.h" #include "nsStyleSheetService.h" #include "nsFocusManager.h" @@ -436,6 +437,8 @@ nsresult NS_NewCanvasRenderingContext2D(nsIDOMCanvasRenderingContext2D** aResult nsresult NS_NewCanvasRenderingContext2DThebes(nsIDOMCanvasRenderingContext2D** aResult); nsresult NS_NewCanvasRenderingContextWebGL(nsIDOMWebGLRenderingContext** aResult); +nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult); + nsresult NS_NewDomSelection(nsISelection** aResult); nsresult NS_NewContentViewer(nsIContentViewer** aResult); nsresult NS_NewGenRegularIterator(nsIContentIterator** aResult); @@ -490,6 +493,7 @@ MAKE_CTOR(CreateNewFrameUtil, nsIFrameUtil, NS_NewFra MAKE_CTOR(CreateNewLayoutDebugger, nsILayoutDebugger, NS_NewLayoutDebugger) #endif +MAKE_CTOR(CreateNewFrameTraversal, nsIFrameTraversal, NS_CreateFrameTraversal) MAKE_CTOR(CreateNewPresShell, nsIPresShell, NS_NewPresShell) MAKE_CTOR(CreateNewBoxObject, nsIBoxObject, NS_NewBoxObject) @@ -685,6 +689,7 @@ Construct_nsIScriptSecurityManager(nsISupports *aOuter, REFNSIID aIID, NS_DEFINE_NAMED_CID(NS_FRAME_UTIL_CID); NS_DEFINE_NAMED_CID(NS_LAYOUT_DEBUGGER_CID); #endif +NS_DEFINE_NAMED_CID(NS_FRAMETRAVERSAL_CID); NS_DEFINE_NAMED_CID(NS_PRESSHELL_CID); NS_DEFINE_NAMED_CID(NS_BOXOBJECT_CID); #ifdef MOZ_XUL @@ -968,6 +973,7 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = { { &kNS_FRAME_UTIL_CID, false, NULL, CreateNewFrameUtil }, { &kNS_LAYOUT_DEBUGGER_CID, false, NULL, CreateNewLayoutDebugger }, #endif + { &kNS_FRAMETRAVERSAL_CID, false, NULL, CreateNewFrameTraversal }, { &kNS_PRESSHELL_CID, false, NULL, CreateNewPresShell }, { &kNS_BOXOBJECT_CID, false, NULL, CreateNewBoxObject }, #ifdef MOZ_XUL diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index f58624412b06..e165eae14e80 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -52,7 +52,7 @@ #include "nsCSSPseudoElements.h" #include "nsCSSFrameConstructor.h" -#include "nsFrameIterator.h" +#include "nsFrameTraversal.h" #include "nsStyleChangeList.h" #include "nsIDOMRange.h" #include "nsRange.h" @@ -5811,12 +5811,17 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, //resultFrame is not a block frame result = NS_ERROR_FAILURE; - uint32_t flags = nsFrameIterator::FLAG_NONE; - if (aPos->mScrollViewStop) { - flags |= nsFrameIterator::FLAG_LOCK_SCROLL; - } - nsFrameIterator frameTraversal(aPresContext, resultFrame, - ePostOrder, flags); + nsCOMPtr frameTraversal; + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), + aPresContext, resultFrame, + ePostOrder, + false, // aVisual + aPos->mScrollViewStop, + false // aFollowOOFs + ); + if (NS_FAILED(result)) + return result; + nsIFrame *storeOldResultFrame = resultFrame; while ( !found ){ nsPoint point; @@ -5830,7 +5835,7 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, return result; point.y = tempRect.height + offset.y; - //special check. if we allow non-text selection then we can allow a hit location to fall before a table. + //special check. if we allow non-text selection then we can allow a hit location to fall before a table. //otherwise there is no way to get and click signal to fall before a table (it being a line iterator itself) nsIPresShell *shell = aPresContext->GetPresShell(); if (!shell) @@ -5893,8 +5898,8 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, if (aPos->mDirection == eDirNext && (resultFrame == nearStoppingFrame)) break; //always try previous on THAT line if that fails go the other way - frameTraversal.Prev(); - resultFrame = frameTraversal.CurrentItem(); + frameTraversal->Prev(); + resultFrame = frameTraversal->CurrentItem(); if (!resultFrame) return NS_ERROR_FAILURE; } @@ -5902,12 +5907,13 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, if (!found){ resultFrame = storeOldResultFrame; - uint32_t flags = nsFrameIterator::FLAG_NONE; - if (aPos->mScrollViewStop) { - flags |= nsFrameIterator::FLAG_LOCK_SCROLL; - } - frameTraversal = nsFrameIterator(aPresContext, resultFrame, - eLeaf, flags); + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), + aPresContext, resultFrame, + eLeaf, + false, // aVisual + aPos->mScrollViewStop, + false // aFollowOOFs + ); } while ( !found ){ nsPoint point(aPos->mDesiredX, 0); @@ -5938,8 +5944,8 @@ nsFrame::GetNextPrevLineFromeBlockFrame(nsPresContext* aPresContext, if (aPos->mDirection == eDirNext && (resultFrame == farStoppingFrame)) break; //previous didnt work now we try "next" - frameTraversal.Next(); - nsIFrame *tempFrame = frameTraversal.CurrentItem(); + frameTraversal->Next(); + nsIFrame *tempFrame = frameTraversal->CurrentItem(); if (!tempFrame) break; resultFrame = tempFrame; @@ -6663,22 +6669,23 @@ nsIFrame::GetFrameFromDirection(nsDirection aDirection, bool aVisual, return NS_ERROR_FAILURE; //we are done. cannot jump lines } - uint32_t flags = nsFrameIterator::FLAG_FOLLOW_OUT_OF_FLOW; - if (aScrollViewStop) { - flags |= nsFrameIterator::FLAG_LOCK_SCROLL; - } - if (aVisual && presContext->BidiEnabled()) { - flags |= nsFrameIterator::FLAG_VISUAL; - } - nsFrameIterator frameTraversal(presContext, traversedFrame, - eLeaf, flags); + nsCOMPtr frameTraversal; + result = NS_NewFrameTraversal(getter_AddRefs(frameTraversal), + presContext, traversedFrame, + eLeaf, + aVisual && presContext->BidiEnabled(), + aScrollViewStop, + true // aFollowOOFs + ); + if (NS_FAILED(result)) + return result; if (aDirection == eDirNext) - frameTraversal.Next(); + frameTraversal->Next(); else - frameTraversal.Prev(); + frameTraversal->Prev(); - traversedFrame = frameTraversal.CurrentItem(); + traversedFrame = frameTraversal->CurrentItem(); if (!traversedFrame) return NS_ERROR_FAILURE; traversedFrame->IsSelectable(&selectable, nullptr); diff --git a/layout/generic/nsSelection.cpp b/layout/generic/nsSelection.cpp index 32b2947eb5f7..ce746b4ea16c 100644 --- a/layout/generic/nsSelection.cpp +++ b/layout/generic/nsSelection.cpp @@ -40,12 +40,14 @@ #include "nsTextFragment.h" // for IBMBIDI -#include "nsFrameIterator.h" +#include "nsFrameTraversal.h" #include "nsILineIterator.h" #include "nsGkAtoms.h" +#include "nsIFrameTraversal.h" #include "nsLayoutUtils.h" #include "nsLayoutCID.h" #include "nsBidiPresUtils.h" +static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID); #include "nsTextFrame.h" #include "nsIDOMText.h" @@ -1245,17 +1247,30 @@ nsFrameSelection::GetFrameFromLevel(nsIFrame *aFrameIn, uint8_t foundLevel = 0; nsIFrame *foundFrame = aFrameIn; - nsFrameIterator frameTraversal(mShell->GetPresContext(), aFrameIn, - eLeaf, nsFrameIterator::FLAG_NONE); + nsCOMPtr frameTraversal; + nsresult result; + nsCOMPtr trav(do_CreateInstance(kFrameTraversalCID,&result)); + if (NS_FAILED(result)) + return result; + + result = trav->NewFrameTraversal(getter_AddRefs(frameTraversal), + mShell->GetPresContext(), aFrameIn, + eLeaf, + false, // aVisual + false, // aLockInScrollView + false // aFollowOOFs + ); + if (NS_FAILED(result)) + return result; do { *aFrameOut = foundFrame; if (aDirection == eDirNext) - frameTraversal.Next(); + frameTraversal->Next(); else - frameTraversal.Prev(); + frameTraversal->Prev(); - foundFrame = frameTraversal.CurrentItem(); + foundFrame = frameTraversal->CurrentItem(); if (!foundFrame) return NS_ERROR_FAILURE; foundLevel = NS_GET_EMBEDDING_LEVEL(foundFrame); diff --git a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp index 0594ff5c3ddd..347197011df9 100644 --- a/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp +++ b/toolkit/components/typeaheadfind/nsTypeAheadFind.cpp @@ -25,7 +25,7 @@ #include "nsIDOMNode.h" #include "mozilla/dom/Element.h" #include "nsIFrame.h" -#include "nsFrameIterator.h" +#include "nsFrameTraversal.h" #include "nsIImageDocument.h" #include "nsIDOMHTMLDocument.h" #include "nsIDOMHTMLElement.h" @@ -63,6 +63,8 @@ NS_INTERFACE_MAP_END NS_IMPL_ADDREF(nsTypeAheadFind) NS_IMPL_RELEASE(nsTypeAheadFind) +static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID); + #define NS_FIND_CONTRACTID "@mozilla.org/embedcomp/rangefind;1" nsTypeAheadFind::nsTypeAheadFind(): @@ -1114,12 +1116,23 @@ nsTypeAheadFind::IsRangeVisible(nsIPresShell *aPresShell, // We know that the target range isn't usable because it's not in the // view port. Move range forward to first visible point, // this speeds us up a lot in long documents - nsFrameIterator frameTraversal(aPresContext, frame, - eLeaf, nsFrameIterator::FLAG_NONE); + nsCOMPtr frameTraversal; + nsCOMPtr trav(do_CreateInstance(kFrameTraversalCID)); + if (trav) + trav->NewFrameTraversal(getter_AddRefs(frameTraversal), + aPresContext, frame, + eLeaf, + false, // aVisual + false, // aLockInScrollView + false // aFollowOOFs + ); + + if (!frameTraversal) + return false; while (rectVisibility == nsRectVisibility_kAboveViewport) { - frameTraversal.Next(); - frame = frameTraversal.CurrentItem(); + frameTraversal->Next(); + frame = frameTraversal->CurrentItem(); if (!frame) return false;