1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/base/nsFrameTraversal.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,531 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 +#include "nsCOMPtr.h" 1.9 +#include "nsGkAtoms.h" 1.10 + 1.11 +#include "nsFrameTraversal.h" 1.12 +#include "nsFrameList.h" 1.13 +#include "nsPlaceholderFrame.h" 1.14 + 1.15 + 1.16 +class nsFrameIterator : public nsIFrameEnumerator 1.17 +{ 1.18 +public: 1.19 + typedef nsIFrame::ChildListID ChildListID; 1.20 + 1.21 + NS_DECL_ISUPPORTS 1.22 + 1.23 + virtual ~nsFrameIterator() {} 1.24 + 1.25 + virtual void First() MOZ_OVERRIDE; 1.26 + virtual void Next() MOZ_OVERRIDE; 1.27 + virtual nsIFrame* CurrentItem() MOZ_OVERRIDE; 1.28 + virtual bool IsDone() MOZ_OVERRIDE; 1.29 + 1.30 + virtual void Last() MOZ_OVERRIDE; 1.31 + virtual void Prev() MOZ_OVERRIDE; 1.32 + 1.33 + nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, 1.34 + nsIteratorType aType, bool aLockScroll, bool aFollowOOFs); 1.35 + 1.36 +protected: 1.37 + void setCurrent(nsIFrame *aFrame){mCurrent = aFrame;} 1.38 + nsIFrame *getCurrent(){return mCurrent;} 1.39 + nsIFrame *getStart(){return mStart;} 1.40 + nsIFrame *getLast(){return mLast;} 1.41 + void setLast(nsIFrame *aFrame){mLast = aFrame;} 1.42 + int8_t getOffEdge(){return mOffEdge;} 1.43 + void setOffEdge(int8_t aOffEdge){mOffEdge = aOffEdge;} 1.44 + 1.45 + /* 1.46 + Our own versions of the standard frame tree navigation 1.47 + methods, which, if the iterator is following out-of-flows, 1.48 + apply the following rules for placeholder frames: 1.49 + 1.50 + - If a frame HAS a placeholder frame, getting its parent 1.51 + gets the placeholder's parent. 1.52 + 1.53 + - If a frame's first child or next/prev sibling IS a 1.54 + placeholder frame, then we instead return the real frame. 1.55 + 1.56 + - If a frame HAS a placeholder frame, getting its next/prev 1.57 + sibling gets the placeholder frame's next/prev sibling. 1.58 + 1.59 + These are all applied recursively to support multiple levels of 1.60 + placeholders. 1.61 + */ 1.62 + 1.63 + nsIFrame* GetParentFrame(nsIFrame* aFrame); 1.64 + // like GetParentFrame but returns null once a popup frame is reached 1.65 + nsIFrame* GetParentFrameNotPopup(nsIFrame* aFrame); 1.66 + 1.67 + nsIFrame* GetFirstChild(nsIFrame* aFrame); 1.68 + nsIFrame* GetLastChild(nsIFrame* aFrame); 1.69 + 1.70 + nsIFrame* GetNextSibling(nsIFrame* aFrame); 1.71 + nsIFrame* GetPrevSibling(nsIFrame* aFrame); 1.72 + 1.73 + /* 1.74 + These methods are overridden by the bidi visual iterator to have the 1.75 + semantics of "get first child in visual order", "get last child in visual 1.76 + order", "get next sibling in visual order" and "get previous sibling in visual 1.77 + order". 1.78 + */ 1.79 + 1.80 + virtual nsIFrame* GetFirstChildInner(nsIFrame* aFrame); 1.81 + virtual nsIFrame* GetLastChildInner(nsIFrame* aFrame); 1.82 + 1.83 + virtual nsIFrame* GetNextSiblingInner(nsIFrame* aFrame); 1.84 + virtual nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame); 1.85 + 1.86 + nsIFrame* GetPlaceholderFrame(nsIFrame* aFrame); 1.87 + bool IsPopupFrame(nsIFrame* aFrame); 1.88 + 1.89 + nsPresContext* const mPresContext; 1.90 + const bool mLockScroll; 1.91 + const bool mFollowOOFs; 1.92 + const nsIteratorType mType; 1.93 + 1.94 +private: 1.95 + nsIFrame* const mStart; 1.96 + nsIFrame* mCurrent; 1.97 + nsIFrame* mLast; //the last one that was in current; 1.98 + int8_t mOffEdge; //0= no -1 to far prev, 1 to far next; 1.99 +}; 1.100 + 1.101 + 1.102 + 1.103 +// Bidi visual iterator 1.104 +class nsVisualIterator: public nsFrameIterator 1.105 +{ 1.106 +public: 1.107 + nsVisualIterator(nsPresContext* aPresContext, nsIFrame *aStart, 1.108 + nsIteratorType aType, bool aLockScroll, bool aFollowOOFs) : 1.109 + nsFrameIterator(aPresContext, aStart, aType, aLockScroll, aFollowOOFs) {} 1.110 + 1.111 +protected: 1.112 + nsIFrame* GetFirstChildInner(nsIFrame* aFrame) MOZ_OVERRIDE; 1.113 + nsIFrame* GetLastChildInner(nsIFrame* aFrame) MOZ_OVERRIDE; 1.114 + 1.115 + nsIFrame* GetNextSiblingInner(nsIFrame* aFrame) MOZ_OVERRIDE; 1.116 + nsIFrame* GetPrevSiblingInner(nsIFrame* aFrame) MOZ_OVERRIDE; 1.117 +}; 1.118 + 1.119 +/************IMPLEMENTATIONS**************/ 1.120 + 1.121 +nsresult NS_CreateFrameTraversal(nsIFrameTraversal** aResult) 1.122 +{ 1.123 + NS_ENSURE_ARG_POINTER(aResult); 1.124 + *aResult = nullptr; 1.125 + 1.126 + nsCOMPtr<nsIFrameTraversal> t(new nsFrameTraversal()); 1.127 + 1.128 + *aResult = t; 1.129 + NS_ADDREF(*aResult); 1.130 + 1.131 + return NS_OK; 1.132 +} 1.133 + 1.134 +nsresult 1.135 +NS_NewFrameTraversal(nsIFrameEnumerator **aEnumerator, 1.136 + nsPresContext* aPresContext, 1.137 + nsIFrame *aStart, 1.138 + nsIteratorType aType, 1.139 + bool aVisual, 1.140 + bool aLockInScrollView, 1.141 + bool aFollowOOFs) 1.142 +{ 1.143 + if (!aEnumerator || !aStart) 1.144 + return NS_ERROR_NULL_POINTER; 1.145 + 1.146 + if (aFollowOOFs) { 1.147 + aStart = nsPlaceholderFrame::GetRealFrameFor(aStart); 1.148 + } 1.149 + 1.150 + nsCOMPtr<nsIFrameEnumerator> trav; 1.151 + if (aVisual) { 1.152 + trav = new nsVisualIterator(aPresContext, aStart, aType, 1.153 + aLockInScrollView, aFollowOOFs); 1.154 + } else { 1.155 + trav = new nsFrameIterator(aPresContext, aStart, aType, 1.156 + aLockInScrollView, aFollowOOFs); 1.157 + } 1.158 + trav.forget(aEnumerator); 1.159 + return NS_OK; 1.160 +} 1.161 + 1.162 + 1.163 +nsFrameTraversal::nsFrameTraversal() 1.164 +{ 1.165 +} 1.166 + 1.167 +nsFrameTraversal::~nsFrameTraversal() 1.168 +{ 1.169 +} 1.170 + 1.171 +NS_IMPL_ISUPPORTS(nsFrameTraversal,nsIFrameTraversal) 1.172 + 1.173 +NS_IMETHODIMP 1.174 + nsFrameTraversal::NewFrameTraversal(nsIFrameEnumerator **aEnumerator, 1.175 + nsPresContext* aPresContext, 1.176 + nsIFrame *aStart, 1.177 + int32_t aType, 1.178 + bool aVisual, 1.179 + bool aLockInScrollView, 1.180 + bool aFollowOOFs) 1.181 +{ 1.182 + return NS_NewFrameTraversal(aEnumerator, aPresContext, aStart, 1.183 + static_cast<nsIteratorType>(aType), 1.184 + aVisual, aLockInScrollView, aFollowOOFs); 1.185 +} 1.186 + 1.187 +// nsFrameIterator implementation 1.188 + 1.189 +NS_IMPL_ISUPPORTS(nsFrameIterator, nsIFrameEnumerator) 1.190 + 1.191 +nsFrameIterator::nsFrameIterator(nsPresContext* aPresContext, nsIFrame *aStart, 1.192 + nsIteratorType aType, bool aLockInScrollView, 1.193 + bool aFollowOOFs) 1.194 +: mPresContext(aPresContext), 1.195 + mLockScroll(aLockInScrollView), 1.196 + mFollowOOFs(aFollowOOFs), 1.197 + mType(aType), 1.198 + mStart(aStart), 1.199 + mCurrent(aStart), 1.200 + mLast(aStart), 1.201 + mOffEdge(0) 1.202 +{ 1.203 + MOZ_ASSERT(!aFollowOOFs || aStart->GetType() != nsGkAtoms::placeholderFrame, 1.204 + "Caller should have resolved placeholder frame"); 1.205 +} 1.206 + 1.207 + 1.208 + 1.209 +nsIFrame* 1.210 +nsFrameIterator::CurrentItem() 1.211 +{ 1.212 + if (mOffEdge) 1.213 + return nullptr; 1.214 + 1.215 + return mCurrent; 1.216 +} 1.217 + 1.218 + 1.219 + 1.220 +bool 1.221 +nsFrameIterator::IsDone() 1.222 +{ 1.223 + return mOffEdge != 0; 1.224 +} 1.225 + 1.226 +void 1.227 +nsFrameIterator::First() 1.228 +{ 1.229 + mCurrent = mStart; 1.230 +} 1.231 + 1.232 +static bool 1.233 +IsRootFrame(nsIFrame* aFrame) 1.234 +{ 1.235 + nsIAtom* atom = aFrame->GetType(); 1.236 + return (atom == nsGkAtoms::canvasFrame) || 1.237 + (atom == nsGkAtoms::rootFrame); 1.238 +} 1.239 + 1.240 +void 1.241 +nsFrameIterator::Last() 1.242 +{ 1.243 + nsIFrame* result; 1.244 + nsIFrame* parent = getCurrent(); 1.245 + // If the current frame is a popup, don't move farther up the tree. 1.246 + // Otherwise, get the nearest root frame or popup. 1.247 + if (parent->GetType() != nsGkAtoms::menuPopupFrame) { 1.248 + while (!IsRootFrame(parent) && (result = GetParentFrameNotPopup(parent))) 1.249 + parent = result; 1.250 + } 1.251 + 1.252 + while ((result = GetLastChild(parent))) { 1.253 + parent = result; 1.254 + } 1.255 + 1.256 + setCurrent(parent); 1.257 + if (!parent) 1.258 + setOffEdge(1); 1.259 +} 1.260 + 1.261 +void 1.262 +nsFrameIterator::Next() 1.263 +{ 1.264 + // recursive-oid method to get next frame 1.265 + nsIFrame *result = nullptr; 1.266 + nsIFrame *parent = getCurrent(); 1.267 + if (!parent) 1.268 + parent = getLast(); 1.269 + 1.270 + if (mType == eLeaf) { 1.271 + // Drill down to first leaf 1.272 + while ((result = GetFirstChild(parent))) { 1.273 + parent = result; 1.274 + } 1.275 + } else if (mType == ePreOrder) { 1.276 + result = GetFirstChild(parent); 1.277 + if (result) 1.278 + parent = result; 1.279 + } 1.280 + 1.281 + if (parent != getCurrent()) { 1.282 + result = parent; 1.283 + } else { 1.284 + while (parent) { 1.285 + result = GetNextSibling(parent); 1.286 + if (result) { 1.287 + if (mType != ePreOrder) { 1.288 + parent = result; 1.289 + while ((result = GetFirstChild(parent))) { 1.290 + parent = result; 1.291 + } 1.292 + result = parent; 1.293 + } 1.294 + break; 1.295 + } 1.296 + else { 1.297 + result = GetParentFrameNotPopup(parent); 1.298 + if (!result || IsRootFrame(result) || 1.299 + (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) { 1.300 + result = nullptr; 1.301 + break; 1.302 + } 1.303 + if (mType == ePostOrder) 1.304 + break; 1.305 + parent = result; 1.306 + } 1.307 + } 1.308 + } 1.309 + 1.310 + setCurrent(result); 1.311 + if (!result) { 1.312 + setOffEdge(1); 1.313 + setLast(parent); 1.314 + } 1.315 +} 1.316 + 1.317 +void 1.318 +nsFrameIterator::Prev() 1.319 +{ 1.320 + // recursive-oid method to get prev frame 1.321 + nsIFrame *result = nullptr; 1.322 + nsIFrame *parent = getCurrent(); 1.323 + if (!parent) 1.324 + parent = getLast(); 1.325 + 1.326 + if (mType == eLeaf) { 1.327 + // Drill down to last leaf 1.328 + while ((result = GetLastChild(parent))) { 1.329 + parent = result; 1.330 + } 1.331 + } else if (mType == ePostOrder) { 1.332 + result = GetLastChild(parent); 1.333 + if (result) 1.334 + parent = result; 1.335 + } 1.336 + 1.337 + if (parent != getCurrent()) { 1.338 + result = parent; 1.339 + } else { 1.340 + while (parent) { 1.341 + result = GetPrevSibling(parent); 1.342 + if (result) { 1.343 + if (mType != ePostOrder) { 1.344 + parent = result; 1.345 + while ((result = GetLastChild(parent))) { 1.346 + parent = result; 1.347 + } 1.348 + result = parent; 1.349 + } 1.350 + break; 1.351 + } else { 1.352 + result = GetParentFrameNotPopup(parent); 1.353 + if (!result || IsRootFrame(result) || 1.354 + (mLockScroll && result->GetType() == nsGkAtoms::scrollFrame)) { 1.355 + result = nullptr; 1.356 + break; 1.357 + } 1.358 + if (mType == ePreOrder) 1.359 + break; 1.360 + parent = result; 1.361 + } 1.362 + } 1.363 + } 1.364 + 1.365 + setCurrent(result); 1.366 + if (!result) { 1.367 + setOffEdge(-1); 1.368 + setLast(parent); 1.369 + } 1.370 +} 1.371 + 1.372 +nsIFrame* 1.373 +nsFrameIterator::GetParentFrame(nsIFrame* aFrame) 1.374 +{ 1.375 + if (mFollowOOFs) 1.376 + aFrame = GetPlaceholderFrame(aFrame); 1.377 + if (aFrame) 1.378 + return aFrame->GetParent(); 1.379 + 1.380 + return nullptr; 1.381 +} 1.382 + 1.383 +nsIFrame* 1.384 +nsFrameIterator::GetParentFrameNotPopup(nsIFrame* aFrame) 1.385 +{ 1.386 + if (mFollowOOFs) 1.387 + aFrame = GetPlaceholderFrame(aFrame); 1.388 + if (aFrame) { 1.389 + nsIFrame* parent = aFrame->GetParent(); 1.390 + if (!IsPopupFrame(parent)) 1.391 + return parent; 1.392 + } 1.393 + 1.394 + return nullptr; 1.395 +} 1.396 + 1.397 +nsIFrame* 1.398 +nsFrameIterator::GetFirstChild(nsIFrame* aFrame) 1.399 +{ 1.400 + nsIFrame* result = GetFirstChildInner(aFrame); 1.401 + if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame) 1.402 + return nullptr; 1.403 + if (result && mFollowOOFs) { 1.404 + result = nsPlaceholderFrame::GetRealFrameFor(result); 1.405 + 1.406 + if (IsPopupFrame(result)) 1.407 + result = GetNextSibling(result); 1.408 + } 1.409 + return result; 1.410 +} 1.411 + 1.412 +nsIFrame* 1.413 +nsFrameIterator::GetLastChild(nsIFrame* aFrame) 1.414 +{ 1.415 + nsIFrame* result = GetLastChildInner(aFrame); 1.416 + if (mLockScroll && result && result->GetType() == nsGkAtoms::scrollFrame) 1.417 + return nullptr; 1.418 + if (result && mFollowOOFs) { 1.419 + result = nsPlaceholderFrame::GetRealFrameFor(result); 1.420 + 1.421 + if (IsPopupFrame(result)) 1.422 + result = GetPrevSibling(result); 1.423 + } 1.424 + return result; 1.425 +} 1.426 + 1.427 +nsIFrame* 1.428 +nsFrameIterator::GetNextSibling(nsIFrame* aFrame) 1.429 +{ 1.430 + nsIFrame* result = nullptr; 1.431 + if (mFollowOOFs) 1.432 + aFrame = GetPlaceholderFrame(aFrame); 1.433 + if (aFrame) { 1.434 + result = GetNextSiblingInner(aFrame); 1.435 + if (result && mFollowOOFs) 1.436 + result = nsPlaceholderFrame::GetRealFrameFor(result); 1.437 + } 1.438 + 1.439 + if (mFollowOOFs && IsPopupFrame(result)) 1.440 + result = GetNextSibling(result); 1.441 + 1.442 + return result; 1.443 +} 1.444 + 1.445 +nsIFrame* 1.446 +nsFrameIterator::GetPrevSibling(nsIFrame* aFrame) 1.447 +{ 1.448 + nsIFrame* result = nullptr; 1.449 + if (mFollowOOFs) 1.450 + aFrame = GetPlaceholderFrame(aFrame); 1.451 + if (aFrame) { 1.452 + result = GetPrevSiblingInner(aFrame); 1.453 + if (result && mFollowOOFs) 1.454 + result = nsPlaceholderFrame::GetRealFrameFor(result); 1.455 + } 1.456 + 1.457 + if (mFollowOOFs && IsPopupFrame(result)) 1.458 + result = GetPrevSibling(result); 1.459 + 1.460 + return result; 1.461 +} 1.462 + 1.463 +nsIFrame* 1.464 +nsFrameIterator::GetFirstChildInner(nsIFrame* aFrame) { 1.465 + return aFrame->GetFirstPrincipalChild(); 1.466 +} 1.467 + 1.468 +nsIFrame* 1.469 +nsFrameIterator::GetLastChildInner(nsIFrame* aFrame) { 1.470 + return aFrame->PrincipalChildList().LastChild(); 1.471 +} 1.472 + 1.473 +nsIFrame* 1.474 +nsFrameIterator::GetNextSiblingInner(nsIFrame* aFrame) { 1.475 + return aFrame->GetNextSibling(); 1.476 +} 1.477 + 1.478 +nsIFrame* 1.479 +nsFrameIterator::GetPrevSiblingInner(nsIFrame* aFrame) { 1.480 + return aFrame->GetPrevSibling(); 1.481 +} 1.482 + 1.483 + 1.484 +nsIFrame* 1.485 +nsFrameIterator::GetPlaceholderFrame(nsIFrame* aFrame) 1.486 +{ 1.487 + nsIFrame* result = aFrame; 1.488 + nsIPresShell *presShell = mPresContext->GetPresShell(); 1.489 + if (presShell) { 1.490 + nsIFrame* placeholder = presShell->GetPlaceholderFrameFor(aFrame); 1.491 + if (placeholder) 1.492 + result = placeholder; 1.493 + } 1.494 + 1.495 + if (result != aFrame) 1.496 + result = GetPlaceholderFrame(result); 1.497 + 1.498 + return result; 1.499 +} 1.500 + 1.501 +bool 1.502 +nsFrameIterator::IsPopupFrame(nsIFrame* aFrame) 1.503 +{ 1.504 + return (aFrame && 1.505 + aFrame->StyleDisplay()->mDisplay == NS_STYLE_DISPLAY_POPUP); 1.506 +} 1.507 + 1.508 +// nsVisualIterator implementation 1.509 + 1.510 +nsIFrame* 1.511 +nsVisualIterator::GetFirstChildInner(nsIFrame* aFrame) { 1.512 + return aFrame->PrincipalChildList().GetNextVisualFor(nullptr); 1.513 +} 1.514 + 1.515 +nsIFrame* 1.516 +nsVisualIterator::GetLastChildInner(nsIFrame* aFrame) { 1.517 + return aFrame->PrincipalChildList().GetPrevVisualFor(nullptr); 1.518 +} 1.519 + 1.520 +nsIFrame* 1.521 +nsVisualIterator::GetNextSiblingInner(nsIFrame* aFrame) { 1.522 + nsIFrame* parent = GetParentFrame(aFrame); 1.523 + if (!parent) 1.524 + return nullptr; 1.525 + return parent->PrincipalChildList().GetNextVisualFor(aFrame); 1.526 +} 1.527 + 1.528 +nsIFrame* 1.529 +nsVisualIterator::GetPrevSiblingInner(nsIFrame* aFrame) { 1.530 + nsIFrame* parent = GetParentFrame(aFrame); 1.531 + if (!parent) 1.532 + return nullptr; 1.533 + return parent->PrincipalChildList().GetPrevVisualFor(aFrame); 1.534 +}