1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Pierre Phaneuf <pp@ludusdesign.com>
24 : * Elika J. Etemad ("fantasai") <fantasai@inkedblade.net>
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either of the GNU General Public License Version 2 or later (the "GPL"),
28 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : /* base class #1 for rendering objects that have child lists */
41 :
42 : #include "nsContainerFrame.h"
43 :
44 : #include "nsIContent.h"
45 : #include "nsIDocument.h"
46 : #include "nsPresContext.h"
47 : #include "nsStyleContext.h"
48 : #include "nsRect.h"
49 : #include "nsPoint.h"
50 : #include "nsGUIEvent.h"
51 : #include "nsStyleConsts.h"
52 : #include "nsIView.h"
53 : #include "nsFrameManager.h"
54 : #include "nsIPresShell.h"
55 : #include "nsCOMPtr.h"
56 : #include "nsGkAtoms.h"
57 : #include "nsCSSAnonBoxes.h"
58 : #include "nsIViewManager.h"
59 : #include "nsIWidget.h"
60 : #include "nsGfxCIID.h"
61 : #include "nsIServiceManager.h"
62 : #include "nsCSSRendering.h"
63 : #include "nsTransform2D.h"
64 : #include "nsRegion.h"
65 : #include "nsLayoutErrors.h"
66 : #include "nsDisplayList.h"
67 : #include "nsContentErrors.h"
68 : #include "nsListControlFrame.h"
69 : #include "nsIBaseWindow.h"
70 : #include "nsThemeConstants.h"
71 : #include "nsCSSFrameConstructor.h"
72 : #include "mozilla/dom/Element.h"
73 :
74 : #ifdef NS_DEBUG
75 : #undef NOISY
76 : #else
77 : #undef NOISY
78 : #endif
79 :
80 : using namespace mozilla;
81 : using namespace mozilla::dom;
82 :
83 0 : NS_IMPL_FRAMEARENA_HELPERS(nsContainerFrame)
84 :
85 0 : nsContainerFrame::~nsContainerFrame()
86 : {
87 0 : }
88 :
89 0 : NS_QUERYFRAME_HEAD(nsContainerFrame)
90 0 : NS_QUERYFRAME_ENTRY(nsContainerFrame)
91 0 : NS_QUERYFRAME_TAIL_INHERITING(nsSplittableFrame)
92 :
93 : NS_IMETHODIMP
94 0 : nsContainerFrame::Init(nsIContent* aContent,
95 : nsIFrame* aParent,
96 : nsIFrame* aPrevInFlow)
97 : {
98 0 : nsresult rv = nsSplittableFrame::Init(aContent, aParent, aPrevInFlow);
99 0 : if (aPrevInFlow) {
100 : // Make sure we copy bits from our prev-in-flow that will affect
101 : // us. A continuation for a container frame needs to know if it
102 : // has a child with a view so that we'll properly reposition it.
103 0 : if (aPrevInFlow->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)
104 0 : AddStateBits(NS_FRAME_HAS_CHILD_WITH_VIEW);
105 : }
106 0 : return rv;
107 : }
108 :
109 : NS_IMETHODIMP
110 0 : nsContainerFrame::SetInitialChildList(ChildListID aListID,
111 : nsFrameList& aChildList)
112 : {
113 : nsresult result;
114 0 : if (mFrames.NotEmpty()) {
115 : // We already have child frames which means we've already been
116 : // initialized
117 0 : NS_NOTREACHED("unexpected second call to SetInitialChildList");
118 0 : result = NS_ERROR_UNEXPECTED;
119 0 : } else if (aListID != kPrincipalList) {
120 : // All we know about is the principal child list.
121 0 : NS_NOTREACHED("unknown frame list");
122 0 : result = NS_ERROR_INVALID_ARG;
123 : } else {
124 : #ifdef NS_DEBUG
125 0 : nsFrame::VerifyDirtyBitSet(aChildList);
126 : #endif
127 0 : mFrames.SetFrames(aChildList);
128 0 : result = NS_OK;
129 : }
130 0 : return result;
131 : }
132 :
133 : NS_IMETHODIMP
134 0 : nsContainerFrame::AppendFrames(ChildListID aListID,
135 : nsFrameList& aFrameList)
136 : {
137 0 : if (aListID != kPrincipalList) {
138 : #ifdef IBMBIDI
139 0 : if (aListID != kNoReflowPrincipalList)
140 : #endif
141 : {
142 0 : NS_ERROR("unexpected child list");
143 0 : return NS_ERROR_INVALID_ARG;
144 : }
145 : }
146 0 : if (aFrameList.NotEmpty()) {
147 0 : mFrames.AppendFrames(this, aFrameList);
148 :
149 : // Ask the parent frame to reflow me.
150 : #ifdef IBMBIDI
151 0 : if (aListID == kPrincipalList)
152 : #endif
153 : {
154 0 : PresContext()->PresShell()->
155 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
156 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
157 : }
158 : }
159 0 : return NS_OK;
160 : }
161 :
162 : NS_IMETHODIMP
163 0 : nsContainerFrame::InsertFrames(ChildListID aListID,
164 : nsIFrame* aPrevFrame,
165 : nsFrameList& aFrameList)
166 : {
167 0 : NS_ASSERTION(!aPrevFrame || aPrevFrame->GetParent() == this,
168 : "inserting after sibling frame with different parent");
169 :
170 0 : if (aListID != kPrincipalList) {
171 : #ifdef IBMBIDI
172 0 : if (aListID != kNoReflowPrincipalList)
173 : #endif
174 : {
175 0 : NS_ERROR("unexpected child list");
176 0 : return NS_ERROR_INVALID_ARG;
177 : }
178 : }
179 0 : if (aFrameList.NotEmpty()) {
180 : // Insert frames after aPrevFrame
181 0 : mFrames.InsertFrames(this, aPrevFrame, aFrameList);
182 :
183 : #ifdef IBMBIDI
184 0 : if (aListID == kPrincipalList)
185 : #endif
186 : {
187 0 : PresContext()->PresShell()->
188 : FrameNeedsReflow(this, nsIPresShell::eTreeChange,
189 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
190 : }
191 : }
192 0 : return NS_OK;
193 : }
194 :
195 : NS_IMETHODIMP
196 0 : nsContainerFrame::RemoveFrame(ChildListID aListID,
197 : nsIFrame* aOldFrame)
198 : {
199 0 : if (aListID != kPrincipalList) {
200 : #ifdef IBMBIDI
201 0 : if (kNoReflowPrincipalList != aListID)
202 : #endif
203 : {
204 0 : NS_ERROR("unexpected child list");
205 0 : return NS_ERROR_INVALID_ARG;
206 : }
207 : }
208 :
209 : // Loop and destroy aOldFrame and all of its continuations.
210 : // Request a reflow on the parent frames involved unless we were explicitly
211 : // told not to (kNoReflowPrincipalList).
212 0 : bool generateReflowCommand = true;
213 : #ifdef IBMBIDI
214 0 : if (kNoReflowPrincipalList == aListID) {
215 0 : generateReflowCommand = false;
216 : }
217 : #endif
218 0 : nsPresContext* pc = PresContext();
219 0 : nsContainerFrame* lastParent = nsnull;
220 0 : while (aOldFrame) {
221 : //XXXfr probably should use StealFrame here. I'm not sure if we need to
222 : // check the overflow lists atm, but we'll need a prescontext lookup
223 : // for overflow containers once we can split abspos elements with
224 : // inline containing blocks.
225 0 : nsIFrame* oldFrameNextContinuation = aOldFrame->GetNextContinuation();
226 : nsContainerFrame* parent =
227 0 : static_cast<nsContainerFrame*>(aOldFrame->GetParent());
228 0 : parent->StealFrame(pc, aOldFrame, true);
229 0 : aOldFrame->Destroy();
230 0 : aOldFrame = oldFrameNextContinuation;
231 0 : if (parent != lastParent && generateReflowCommand) {
232 0 : pc->PresShell()->
233 : FrameNeedsReflow(parent, nsIPresShell::eTreeChange,
234 0 : NS_FRAME_HAS_DIRTY_CHILDREN);
235 0 : lastParent = parent;
236 : }
237 : }
238 0 : return NS_OK;
239 : }
240 :
241 : void
242 0 : nsContainerFrame::DestroyFrom(nsIFrame* aDestructRoot)
243 : {
244 : // Prevent event dispatch during destruction
245 0 : if (HasView()) {
246 0 : GetView()->SetFrame(nsnull);
247 : }
248 :
249 : // Delete the primary child list
250 0 : mFrames.DestroyFramesFrom(aDestructRoot);
251 :
252 : // Destroy auxiliary frame lists
253 0 : nsPresContext* prescontext = PresContext();
254 :
255 0 : DestroyOverflowList(prescontext, aDestructRoot);
256 :
257 0 : if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
258 : nsFrameList* frameList =
259 0 : RemovePropTableFrames(prescontext, OverflowContainersProperty());
260 0 : if (frameList)
261 0 : frameList->DestroyFrom(aDestructRoot);
262 :
263 : frameList = RemovePropTableFrames(prescontext,
264 0 : ExcessOverflowContainersProperty());
265 0 : if (frameList)
266 0 : frameList->DestroyFrom(aDestructRoot);
267 : }
268 :
269 : // Destroy the frame and remove the flow pointers
270 0 : nsSplittableFrame::DestroyFrom(aDestructRoot);
271 0 : }
272 :
273 : /////////////////////////////////////////////////////////////////////////////
274 : // Child frame enumeration
275 :
276 : const nsFrameList&
277 0 : nsContainerFrame::GetChildList(ChildListID aListID) const
278 : {
279 : // We only know about the principal child list and the overflow lists.
280 0 : switch (aListID) {
281 : case kPrincipalList:
282 0 : return mFrames;
283 : case kOverflowList: {
284 0 : nsFrameList* list = GetOverflowFrames();
285 0 : return list ? *list : nsFrameList::EmptyList();
286 : }
287 : case kOverflowContainersList: {
288 : nsFrameList* list =
289 0 : GetPropTableFrames(PresContext(), OverflowContainersProperty());
290 0 : return list ? *list : nsFrameList::EmptyList();
291 : }
292 : case kExcessOverflowContainersList: {
293 : nsFrameList* list =
294 0 : GetPropTableFrames(PresContext(), ExcessOverflowContainersProperty());
295 0 : return list ? *list : nsFrameList::EmptyList();
296 : }
297 : default:
298 0 : return nsSplittableFrame::GetChildList(aListID);
299 : }
300 : }
301 :
302 0 : static void AppendIfNonempty(const nsIFrame* aFrame,
303 : FramePropertyTable* aPropTable,
304 : const FramePropertyDescriptor* aProperty,
305 : nsTArray<nsIFrame::ChildList>* aLists,
306 : nsIFrame::ChildListID aListID)
307 : {
308 : nsFrameList* list = static_cast<nsFrameList*>(
309 0 : aPropTable->Get(aFrame, aProperty));
310 0 : if (list) {
311 0 : list->AppendIfNonempty(aLists, aListID);
312 : }
313 0 : }
314 :
315 : void
316 0 : nsContainerFrame::GetChildLists(nsTArray<ChildList>* aLists) const
317 : {
318 0 : mFrames.AppendIfNonempty(aLists, kPrincipalList);
319 0 : FramePropertyTable* propTable = PresContext()->PropertyTable();
320 : ::AppendIfNonempty(this, propTable, OverflowProperty(),
321 0 : aLists, kOverflowList);
322 0 : if (IsFrameOfType(nsIFrame::eCanContainOverflowContainers)) {
323 : ::AppendIfNonempty(this, propTable, OverflowContainersProperty(),
324 0 : aLists, kOverflowContainersList);
325 : ::AppendIfNonempty(this, propTable, ExcessOverflowContainersProperty(),
326 0 : aLists, kExcessOverflowContainersList);
327 : }
328 0 : nsSplittableFrame::GetChildLists(aLists);
329 0 : }
330 :
331 : /////////////////////////////////////////////////////////////////////////////
332 : // Painting/Events
333 :
334 : NS_IMETHODIMP
335 0 : nsContainerFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
336 : const nsRect& aDirtyRect,
337 : const nsDisplayListSet& aLists)
338 : {
339 0 : nsresult rv = DisplayBorderBackgroundOutline(aBuilder, aLists);
340 0 : NS_ENSURE_SUCCESS(rv, rv);
341 :
342 0 : return BuildDisplayListForNonBlockChildren(aBuilder, aDirtyRect, aLists);
343 : }
344 :
345 : nsresult
346 0 : nsContainerFrame::BuildDisplayListForNonBlockChildren(nsDisplayListBuilder* aBuilder,
347 : const nsRect& aDirtyRect,
348 : const nsDisplayListSet& aLists,
349 : PRUint32 aFlags)
350 : {
351 0 : nsIFrame* kid = mFrames.FirstChild();
352 : // Put each child's background directly onto the content list
353 0 : nsDisplayListSet set(aLists, aLists.Content());
354 : // The children should be in content order
355 0 : while (kid) {
356 0 : nsresult rv = BuildDisplayListForChild(aBuilder, kid, aDirtyRect, set, aFlags);
357 0 : NS_ENSURE_SUCCESS(rv, rv);
358 0 : kid = kid->GetNextSibling();
359 : }
360 0 : return NS_OK;
361 : }
362 :
363 : /* virtual */ void
364 0 : nsContainerFrame::ChildIsDirty(nsIFrame* aChild)
365 : {
366 0 : AddStateBits(NS_FRAME_HAS_DIRTY_CHILDREN);
367 0 : }
368 :
369 : bool
370 0 : nsContainerFrame::IsLeaf() const
371 : {
372 0 : return false;
373 : }
374 :
375 : bool
376 0 : nsContainerFrame::PeekOffsetNoAmount(bool aForward, PRInt32* aOffset)
377 : {
378 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
379 : // Don't allow the caret to stay in an empty (leaf) container frame.
380 0 : return false;
381 : }
382 :
383 : bool
384 0 : nsContainerFrame::PeekOffsetCharacter(bool aForward, PRInt32* aOffset,
385 : bool aRespectClusters)
386 : {
387 0 : NS_ASSERTION (aOffset && *aOffset <= 1, "aOffset out of range");
388 : // Don't allow the caret to stay in an empty (leaf) container frame.
389 0 : return false;
390 : }
391 :
392 : /////////////////////////////////////////////////////////////////////////////
393 : // Helper member functions
394 :
395 : static nsresult
396 0 : ReparentFrameViewTo(nsIFrame* aFrame,
397 : nsIViewManager* aViewManager,
398 : nsIView* aNewParentView,
399 : nsIView* aOldParentView)
400 : {
401 :
402 : // XXX What to do about placeholder views for "position: fixed" elements?
403 : // They should be reparented too.
404 :
405 : // Does aFrame have a view?
406 0 : if (aFrame->HasView()) {
407 : #ifdef MOZ_XUL
408 0 : if (aFrame->GetType() == nsGkAtoms::menuPopupFrame) {
409 : // This view must be parented by the root view, don't reparent it.
410 0 : return NS_OK;
411 : }
412 : #endif
413 0 : nsIView* view = aFrame->GetView();
414 : // Verify that the current parent view is what we think it is
415 : //nsIView* parentView;
416 : //NS_ASSERTION(parentView == aOldParentView, "unexpected parent view");
417 :
418 0 : aViewManager->RemoveChild(view);
419 :
420 : // The view will remember the Z-order and other attributes that have been set on it.
421 0 : nsIView* insertBefore = nsLayoutUtils::FindSiblingViewFor(aNewParentView, aFrame);
422 0 : aViewManager->InsertChild(aNewParentView, view, insertBefore, insertBefore != nsnull);
423 : } else {
424 0 : nsIFrame::ChildListIterator lists(aFrame);
425 0 : for (; !lists.IsDone(); lists.Next()) {
426 : // Iterate the child frames, and check each child frame to see if it has
427 : // a view
428 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
429 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
430 : ReparentFrameViewTo(childFrames.get(), aViewManager,
431 0 : aNewParentView, aOldParentView);
432 : }
433 : }
434 : }
435 :
436 0 : return NS_OK;
437 : }
438 :
439 : nsresult
440 0 : nsContainerFrame::CreateViewForFrame(nsIFrame* aFrame,
441 : bool aForce)
442 : {
443 0 : if (aFrame->HasView()) {
444 0 : return NS_OK;
445 : }
446 :
447 : // If we don't yet have a view, see if we need a view
448 0 : if (!aForce && !aFrame->NeedsView()) {
449 : // don't need a view
450 0 : return NS_OK;
451 : }
452 :
453 0 : nsIView* parentView = aFrame->GetParent()->GetClosestView();
454 0 : NS_ASSERTION(parentView, "no parent with view");
455 :
456 0 : nsIViewManager* viewManager = parentView->GetViewManager();
457 0 : NS_ASSERTION(viewManager, "null view manager");
458 :
459 : // Create a view
460 0 : nsIView* view = viewManager->CreateView(aFrame->GetRect(), parentView);
461 0 : if (!view)
462 0 : return NS_ERROR_OUT_OF_MEMORY;
463 :
464 0 : SyncFrameViewProperties(aFrame->PresContext(), aFrame, nsnull, view);
465 :
466 0 : nsIView* insertBefore = nsLayoutUtils::FindSiblingViewFor(parentView, aFrame);
467 : // we insert this view 'above' the insertBefore view, unless insertBefore is null,
468 : // in which case we want to call with aAbove == false to insert at the beginning
469 : // in document order
470 0 : viewManager->InsertChild(parentView, view, insertBefore, insertBefore != nsnull);
471 :
472 : // REVIEW: Don't create a widget for fixed-pos elements anymore.
473 : // ComputeRepaintRegionForCopy will calculate the right area to repaint
474 : // when we scroll.
475 : // Reparent views on any child frames (or their descendants) to this
476 : // view. We can just call ReparentFrameViewTo on this frame because
477 : // we know this frame has no view, so it will crawl the children. Also,
478 : // we know that any descendants with views must have 'parentView' as their
479 : // parent view.
480 0 : ReparentFrameViewTo(aFrame, viewManager, view, parentView);
481 :
482 : // Remember our view
483 0 : aFrame->SetView(view);
484 :
485 0 : NS_FRAME_LOG(NS_FRAME_TRACE_CALLS,
486 : ("nsContainerFrame::CreateViewForFrame: frame=%p view=%p",
487 : aFrame));
488 0 : return NS_OK;
489 : }
490 :
491 : /**
492 : * Position the view associated with |aKidFrame|, if there is one. A
493 : * container frame should call this method after positioning a frame,
494 : * but before |Reflow|.
495 : */
496 : void
497 0 : nsContainerFrame::PositionFrameView(nsIFrame* aKidFrame)
498 : {
499 0 : nsIFrame* parentFrame = aKidFrame->GetParent();
500 0 : if (!aKidFrame->HasView() || !parentFrame)
501 0 : return;
502 :
503 0 : nsIView* view = aKidFrame->GetView();
504 0 : nsIViewManager* vm = view->GetViewManager();
505 0 : nsPoint pt;
506 0 : nsIView* ancestorView = parentFrame->GetClosestView(&pt);
507 :
508 0 : if (ancestorView != view->GetParent()) {
509 0 : NS_ASSERTION(ancestorView == view->GetParent()->GetParent(),
510 : "Allowed only one anonymous view between frames");
511 : // parentFrame is responsible for positioning aKidFrame's view
512 : // explicitly
513 0 : return;
514 : }
515 :
516 0 : pt += aKidFrame->GetPosition();
517 0 : vm->MoveViewTo(view, pt.x, pt.y);
518 : }
519 :
520 : nsresult
521 0 : nsContainerFrame::ReparentFrameView(nsPresContext* aPresContext,
522 : nsIFrame* aChildFrame,
523 : nsIFrame* aOldParentFrame,
524 : nsIFrame* aNewParentFrame)
525 : {
526 0 : NS_PRECONDITION(aChildFrame, "null child frame pointer");
527 0 : NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
528 0 : NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
529 0 : NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
530 :
531 : // See if either the old parent frame or the new parent frame have a view
532 0 : while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
533 : // Walk up both the old parent frame and the new parent frame nodes
534 : // stopping when we either find a common parent or views for one
535 : // or both of the frames.
536 : //
537 : // This works well in the common case where we push/pull and the old parent
538 : // frame and the new parent frame are part of the same flow. They will
539 : // typically be the same distance (height wise) from the
540 0 : aOldParentFrame = aOldParentFrame->GetParent();
541 0 : aNewParentFrame = aNewParentFrame->GetParent();
542 :
543 : // We should never walk all the way to the root frame without finding
544 : // a view
545 0 : NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
546 :
547 : // See if we reached a common ancestor
548 0 : if (aOldParentFrame == aNewParentFrame) {
549 0 : break;
550 : }
551 : }
552 :
553 : // See if we found a common parent frame
554 0 : if (aOldParentFrame == aNewParentFrame) {
555 : // We found a common parent and there are no views between the old parent
556 : // and the common parent or the new parent frame and the common parent.
557 : // Because neither the old parent frame nor the new parent frame have views,
558 : // then any child views don't need reparenting
559 0 : return NS_OK;
560 : }
561 :
562 : // We found views for one or both of the ancestor frames before we
563 : // found a common ancestor.
564 0 : nsIView* oldParentView = aOldParentFrame->GetClosestView();
565 0 : nsIView* newParentView = aNewParentFrame->GetClosestView();
566 :
567 : // See if the old parent frame and the new parent frame are in the
568 : // same view sub-hierarchy. If they are then we don't have to do
569 : // anything
570 0 : if (oldParentView != newParentView) {
571 : // They're not so we need to reparent any child views
572 : return ReparentFrameViewTo(aChildFrame, oldParentView->GetViewManager(), newParentView,
573 0 : oldParentView);
574 : }
575 :
576 0 : return NS_OK;
577 : }
578 :
579 : nsresult
580 0 : nsContainerFrame::ReparentFrameViewList(nsPresContext* aPresContext,
581 : const nsFrameList& aChildFrameList,
582 : nsIFrame* aOldParentFrame,
583 : nsIFrame* aNewParentFrame)
584 : {
585 0 : NS_PRECONDITION(aChildFrameList.NotEmpty(), "empty child frame list");
586 0 : NS_PRECONDITION(aOldParentFrame, "null old parent frame pointer");
587 0 : NS_PRECONDITION(aNewParentFrame, "null new parent frame pointer");
588 0 : NS_PRECONDITION(aOldParentFrame != aNewParentFrame, "same old and new parent frame");
589 :
590 : // See if either the old parent frame or the new parent frame have a view
591 0 : while (!aOldParentFrame->HasView() && !aNewParentFrame->HasView()) {
592 : // Walk up both the old parent frame and the new parent frame nodes
593 : // stopping when we either find a common parent or views for one
594 : // or both of the frames.
595 : //
596 : // This works well in the common case where we push/pull and the old parent
597 : // frame and the new parent frame are part of the same flow. They will
598 : // typically be the same distance (height wise) from the
599 0 : aOldParentFrame = aOldParentFrame->GetParent();
600 0 : aNewParentFrame = aNewParentFrame->GetParent();
601 :
602 : // We should never walk all the way to the root frame without finding
603 : // a view
604 0 : NS_ASSERTION(aOldParentFrame && aNewParentFrame, "didn't find view");
605 :
606 : // See if we reached a common ancestor
607 0 : if (aOldParentFrame == aNewParentFrame) {
608 0 : break;
609 : }
610 : }
611 :
612 :
613 : // See if we found a common parent frame
614 0 : if (aOldParentFrame == aNewParentFrame) {
615 : // We found a common parent and there are no views between the old parent
616 : // and the common parent or the new parent frame and the common parent.
617 : // Because neither the old parent frame nor the new parent frame have views,
618 : // then any child views don't need reparenting
619 0 : return NS_OK;
620 : }
621 :
622 : // We found views for one or both of the ancestor frames before we
623 : // found a common ancestor.
624 0 : nsIView* oldParentView = aOldParentFrame->GetClosestView();
625 0 : nsIView* newParentView = aNewParentFrame->GetClosestView();
626 :
627 : // See if the old parent frame and the new parent frame are in the
628 : // same view sub-hierarchy. If they are then we don't have to do
629 : // anything
630 0 : if (oldParentView != newParentView) {
631 0 : nsIViewManager* viewManager = oldParentView->GetViewManager();
632 :
633 : // They're not so we need to reparent any child views
634 0 : for (nsFrameList::Enumerator e(aChildFrameList); !e.AtEnd(); e.Next()) {
635 0 : ReparentFrameViewTo(e.get(), viewManager, newParentView, oldParentView);
636 : }
637 : }
638 :
639 0 : return NS_OK;
640 : }
641 :
642 : static nsIWidget*
643 0 : GetPresContextContainerWidget(nsPresContext* aPresContext)
644 : {
645 0 : nsCOMPtr<nsISupports> container = aPresContext->Document()->GetContainer();
646 0 : nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(container);
647 0 : if (!baseWindow)
648 0 : return nsnull;
649 :
650 0 : nsCOMPtr<nsIWidget> mainWidget;
651 0 : baseWindow->GetMainWidget(getter_AddRefs(mainWidget));
652 0 : return mainWidget;
653 : }
654 :
655 : static bool
656 0 : IsTopLevelWidget(nsIWidget* aWidget)
657 : {
658 : nsWindowType windowType;
659 0 : aWidget->GetWindowType(windowType);
660 : return windowType == eWindowType_toplevel ||
661 : windowType == eWindowType_dialog ||
662 0 : windowType == eWindowType_sheet;
663 : // popups aren't toplevel so they're not handled here
664 : }
665 :
666 : void
667 0 : nsContainerFrame::SyncWindowProperties(nsPresContext* aPresContext,
668 : nsIFrame* aFrame,
669 : nsIView* aView)
670 : {
671 : #ifdef MOZ_XUL
672 0 : if (!aView || !nsCSSRendering::IsCanvasFrame(aFrame) || !aView->HasWidget())
673 0 : return;
674 :
675 0 : nsIWidget* windowWidget = GetPresContextContainerWidget(aPresContext);
676 0 : if (!windowWidget || !IsTopLevelWidget(windowWidget))
677 0 : return;
678 :
679 0 : nsIViewManager* vm = aView->GetViewManager();
680 0 : nsIView* rootView = vm->GetRootView();
681 :
682 0 : if (aView != rootView)
683 0 : return;
684 :
685 0 : Element* rootElement = aPresContext->Document()->GetRootElement();
686 0 : if (!rootElement || !rootElement->IsXUL()) {
687 : // Scrollframes use native widgets which don't work well with
688 : // translucent windows, at least in Windows XP. So if the document
689 : // has a root scrollrame it's useless to try to make it transparent,
690 : // we'll just get something broken.
691 : // nsCSSFrameConstructor::ConstructRootFrame constructs root
692 : // scrollframes whenever the root element is not a XUL element, so
693 : // we test for that here. We can't just call
694 : // presShell->GetRootScrollFrame() since that might not have
695 : // been constructed yet.
696 : // We can change this to allow translucent toplevel HTML documents
697 : // (e.g. to do something like Dashboard widgets), once we
698 : // have broad support for translucent scrolled documents, but be
699 : // careful because apparently some Firefox extensions expect
700 : // openDialog("something.html") to produce an opaque window
701 : // even if the HTML doesn't have a background-color set.
702 0 : return;
703 : }
704 :
705 0 : nsIFrame *rootFrame = aPresContext->PresShell()->FrameConstructor()->GetRootElementStyleFrame();
706 0 : if (!rootFrame)
707 0 : return;
708 :
709 0 : nsTransparencyMode mode = nsLayoutUtils::GetFrameTransparency(aFrame, rootFrame);
710 0 : nsIWidget* viewWidget = aView->GetWidget();
711 0 : viewWidget->SetTransparencyMode(mode);
712 0 : windowWidget->SetWindowShadowStyle(rootFrame->GetStyleUIReset()->mWindowShadow);
713 : #endif
714 : }
715 :
716 : void
717 0 : nsContainerFrame::SyncFrameViewAfterReflow(nsPresContext* aPresContext,
718 : nsIFrame* aFrame,
719 : nsIView* aView,
720 : const nsRect& aVisualOverflowArea,
721 : PRUint32 aFlags)
722 : {
723 0 : if (!aView) {
724 0 : return;
725 : }
726 :
727 : // Make sure the view is sized and positioned correctly
728 0 : if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
729 0 : PositionFrameView(aFrame);
730 : }
731 :
732 0 : if (0 == (aFlags & NS_FRAME_NO_SIZE_VIEW)) {
733 0 : nsIViewManager* vm = aView->GetViewManager();
734 :
735 0 : vm->ResizeView(aView, aVisualOverflowArea, true);
736 : }
737 : }
738 :
739 : void
740 0 : nsContainerFrame::SyncFrameViewProperties(nsPresContext* aPresContext,
741 : nsIFrame* aFrame,
742 : nsStyleContext* aStyleContext,
743 : nsIView* aView,
744 : PRUint32 aFlags)
745 : {
746 0 : NS_ASSERTION(!aStyleContext || aFrame->GetStyleContext() == aStyleContext,
747 : "Wrong style context for frame?");
748 :
749 0 : if (!aView) {
750 0 : return;
751 : }
752 :
753 0 : nsIViewManager* vm = aView->GetViewManager();
754 :
755 0 : if (nsnull == aStyleContext) {
756 0 : aStyleContext = aFrame->GetStyleContext();
757 : }
758 :
759 : // Make sure visibility is correct. This only affects nsSubdocumentFrame.
760 0 : if (0 == (aFlags & NS_FRAME_NO_VISIBILITY) &&
761 0 : !aFrame->SupportsVisibilityHidden()) {
762 : // See if the view should be hidden or visible
763 : vm->SetViewVisibility(aView,
764 0 : aStyleContext->GetStyleVisibility()->IsVisible()
765 0 : ? nsViewVisibility_kShow : nsViewVisibility_kHide);
766 : }
767 :
768 : // See if the frame is being relatively positioned or absolutely
769 : // positioned
770 0 : bool isPositioned = aStyleContext->GetStyleDisplay()->IsPositioned();
771 :
772 0 : PRInt32 zIndex = 0;
773 0 : bool autoZIndex = false;
774 :
775 0 : if (!isPositioned) {
776 0 : autoZIndex = true;
777 : } else {
778 : // Make sure z-index is correct
779 0 : const nsStylePosition* position = aStyleContext->GetStylePosition();
780 :
781 0 : if (position->mZIndex.GetUnit() == eStyleUnit_Integer) {
782 0 : zIndex = position->mZIndex.GetIntValue();
783 0 : } else if (position->mZIndex.GetUnit() == eStyleUnit_Auto) {
784 0 : autoZIndex = true;
785 : }
786 : }
787 :
788 0 : vm->SetViewZIndex(aView, autoZIndex, zIndex, isPositioned);
789 : }
790 :
791 0 : static nscoord GetCoord(const nsStyleCoord& aCoord, nscoord aIfNotCoord)
792 : {
793 0 : if (aCoord.ConvertsToLength()) {
794 0 : return nsRuleNode::ComputeCoordPercentCalc(aCoord, 0);
795 : }
796 0 : return aIfNotCoord;
797 : }
798 :
799 : void
800 0 : nsContainerFrame::DoInlineIntrinsicWidth(nsRenderingContext *aRenderingContext,
801 : InlineIntrinsicWidthData *aData,
802 : nsLayoutUtils::IntrinsicWidthType aType)
803 : {
804 0 : if (GetPrevInFlow())
805 0 : return; // Already added.
806 :
807 0 : NS_PRECONDITION(aType == nsLayoutUtils::MIN_WIDTH ||
808 : aType == nsLayoutUtils::PREF_WIDTH, "bad type");
809 :
810 : mozilla::css::Side startSide, endSide;
811 0 : if (GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_LTR) {
812 0 : startSide = NS_SIDE_LEFT;
813 0 : endSide = NS_SIDE_RIGHT;
814 : } else {
815 0 : startSide = NS_SIDE_RIGHT;
816 0 : endSide = NS_SIDE_LEFT;
817 : }
818 :
819 0 : const nsStylePadding *stylePadding = GetStylePadding();
820 0 : const nsStyleBorder *styleBorder = GetStyleBorder();
821 0 : const nsStyleMargin *styleMargin = GetStyleMargin();
822 :
823 : // This goes at the beginning no matter how things are broken and how
824 : // messy the bidi situations are, since per CSS2.1 section 8.6
825 : // (implemented in bug 328168), the startSide border is always on the
826 : // first line.
827 : // This frame is a first-in-flow, but it might have a previous bidi
828 : // continuation, in which case that continuation should handle the startSide
829 : // border.
830 0 : if (!GetPrevContinuation()) {
831 : aData->currentLine +=
832 : // clamp negative calc() to 0
833 0 : NS_MAX(GetCoord(stylePadding->mPadding.Get(startSide), 0), 0) +
834 0 : styleBorder->GetActualBorderWidth(startSide) +
835 0 : GetCoord(styleMargin->mMargin.Get(startSide), 0);
836 : }
837 :
838 0 : const nsLineList_iterator* savedLine = aData->line;
839 0 : nsIFrame* const savedLineContainer = aData->lineContainer;
840 :
841 : nsContainerFrame *lastInFlow;
842 0 : for (nsContainerFrame *nif = this; nif;
843 0 : nif = static_cast<nsContainerFrame*>(nif->GetNextInFlow())) {
844 0 : for (nsIFrame *kid = nif->mFrames.FirstChild(); kid;
845 : kid = kid->GetNextSibling()) {
846 0 : if (aType == nsLayoutUtils::MIN_WIDTH)
847 : kid->AddInlineMinWidth(aRenderingContext,
848 0 : static_cast<InlineMinWidthData*>(aData));
849 : else
850 : kid->AddInlinePrefWidth(aRenderingContext,
851 0 : static_cast<InlinePrefWidthData*>(aData));
852 : }
853 :
854 : // After we advance to our next-in-flow, the stored line and line container
855 : // may no longer be correct. Just forget them.
856 0 : aData->line = nsnull;
857 0 : aData->lineContainer = nsnull;
858 :
859 0 : lastInFlow = nif;
860 : }
861 :
862 0 : aData->line = savedLine;
863 0 : aData->lineContainer = savedLineContainer;
864 :
865 : // This goes at the end no matter how things are broken and how
866 : // messy the bidi situations are, since per CSS2.1 section 8.6
867 : // (implemented in bug 328168), the endSide border is always on the
868 : // last line.
869 : // We reached the last-in-flow, but it might have a next bidi
870 : // continuation, in which case that continuation should handle
871 : // the endSide border.
872 0 : if (!lastInFlow->GetNextContinuation()) {
873 : aData->currentLine +=
874 : // clamp negative calc() to 0
875 0 : NS_MAX(GetCoord(stylePadding->mPadding.Get(endSide), 0), 0) +
876 0 : styleBorder->GetActualBorderWidth(endSide) +
877 0 : GetCoord(styleMargin->mMargin.Get(endSide), 0);
878 : }
879 : }
880 :
881 : /* virtual */ nsSize
882 0 : nsContainerFrame::ComputeAutoSize(nsRenderingContext *aRenderingContext,
883 : nsSize aCBSize, nscoord aAvailableWidth,
884 : nsSize aMargin, nsSize aBorder,
885 : nsSize aPadding, bool aShrinkWrap)
886 : {
887 0 : nsSize result(0xdeadbeef, NS_UNCONSTRAINEDSIZE);
888 : nscoord availBased = aAvailableWidth - aMargin.width - aBorder.width -
889 0 : aPadding.width;
890 : // replaced elements always shrink-wrap
891 0 : if (aShrinkWrap || IsFrameOfType(eReplaced)) {
892 : // don't bother setting it if the result won't be used
893 0 : if (GetStylePosition()->mWidth.GetUnit() == eStyleUnit_Auto) {
894 0 : result.width = ShrinkWidthToFit(aRenderingContext, availBased);
895 : }
896 : } else {
897 0 : result.width = availBased;
898 : }
899 : return result;
900 : }
901 :
902 : /**
903 : * Invokes the WillReflow() function, positions the frame and its view (if
904 : * requested), and then calls Reflow(). If the reflow succeeds and the child
905 : * frame is complete, deletes any next-in-flows using DeleteNextInFlowChild()
906 : */
907 : nsresult
908 0 : nsContainerFrame::ReflowChild(nsIFrame* aKidFrame,
909 : nsPresContext* aPresContext,
910 : nsHTMLReflowMetrics& aDesiredSize,
911 : const nsHTMLReflowState& aReflowState,
912 : nscoord aX,
913 : nscoord aY,
914 : PRUint32 aFlags,
915 : nsReflowStatus& aStatus,
916 : nsOverflowContinuationTracker* aTracker)
917 : {
918 0 : NS_PRECONDITION(aReflowState.frame == aKidFrame, "bad reflow state");
919 :
920 : nsresult result;
921 :
922 : // Send the WillReflow() notification, and position the child frame
923 : // and its view if requested
924 0 : aKidFrame->WillReflow(aPresContext);
925 :
926 0 : if (NS_FRAME_NO_MOVE_FRAME != (aFlags & NS_FRAME_NO_MOVE_FRAME)) {
927 0 : if ((aFlags & NS_FRAME_INVALIDATE_ON_MOVE) &&
928 0 : !(aKidFrame->GetStateBits() & NS_FRAME_FIRST_REFLOW) &&
929 0 : aKidFrame->GetPosition() != nsPoint(aX, aY)) {
930 0 : aKidFrame->InvalidateFrameSubtree();
931 : }
932 0 : aKidFrame->SetPosition(nsPoint(aX, aY));
933 : }
934 :
935 0 : if (0 == (aFlags & NS_FRAME_NO_MOVE_VIEW)) {
936 0 : PositionFrameView(aKidFrame);
937 : }
938 :
939 : // Reflow the child frame
940 : result = aKidFrame->Reflow(aPresContext, aDesiredSize, aReflowState,
941 0 : aStatus);
942 :
943 : // If the reflow was successful and the child frame is complete, delete any
944 : // next-in-flows
945 0 : if (NS_SUCCEEDED(result) && NS_FRAME_IS_FULLY_COMPLETE(aStatus)) {
946 0 : nsIFrame* kidNextInFlow = aKidFrame->GetNextInFlow();
947 0 : if (nsnull != kidNextInFlow) {
948 : // Remove all of the childs next-in-flows. Make sure that we ask
949 : // the right parent to do the removal (it's possible that the
950 : // parent is not this because we are executing pullup code)
951 0 : if (aTracker) aTracker->Finish(aKidFrame);
952 0 : static_cast<nsContainerFrame*>(kidNextInFlow->GetParent())
953 0 : ->DeleteNextInFlowChild(aPresContext, kidNextInFlow, true);
954 : }
955 : }
956 0 : return result;
957 : }
958 :
959 :
960 : /**
961 : * Position the views of |aFrame|'s descendants. A container frame
962 : * should call this method if it moves a frame after |Reflow|.
963 : */
964 : void
965 0 : nsContainerFrame::PositionChildViews(nsIFrame* aFrame)
966 : {
967 0 : if (!(aFrame->GetStateBits() & NS_FRAME_HAS_CHILD_WITH_VIEW)) {
968 0 : return;
969 : }
970 :
971 : // Recursively walk aFrame's child frames.
972 : // Process the additional child lists, but skip the popup list as the
973 : // view for popups is managed by the parent. Currently only nsMenuFrame
974 : // has a popupList and during layout will call nsMenuPopupFrame::AdjustView.
975 0 : ChildListIterator lists(aFrame);
976 0 : for (; !lists.IsDone(); lists.Next()) {
977 0 : if (lists.CurrentID() == kPopupList) {
978 0 : continue;
979 : }
980 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
981 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
982 : // Position the frame's view (if it has one) otherwise recursively
983 : // process its children
984 0 : nsIFrame* childFrame = childFrames.get();
985 0 : if (childFrame->HasView()) {
986 0 : PositionFrameView(childFrame);
987 : } else {
988 0 : PositionChildViews(childFrame);
989 : }
990 : }
991 : }
992 : }
993 :
994 : /**
995 : * The second half of frame reflow. Does the following:
996 : * - sets the frame's bounds
997 : * - sizes and positions (if requested) the frame's view. If the frame's final
998 : * position differs from the current position and the frame itself does not
999 : * have a view, then any child frames with views are positioned so they stay
1000 : * in sync
1001 : * - sets the view's visibility, opacity, content transparency, and clip
1002 : * - invoked the DidReflow() function
1003 : *
1004 : * Flags:
1005 : * NS_FRAME_NO_MOVE_FRAME - don't move the frame. aX and aY are ignored in this
1006 : * case. Also implies NS_FRAME_NO_MOVE_VIEW
1007 : * NS_FRAME_NO_MOVE_VIEW - don't position the frame's view. Set this if you
1008 : * don't want to automatically sync the frame and view
1009 : * NS_FRAME_NO_SIZE_VIEW - don't size the frame's view
1010 : */
1011 : nsresult
1012 0 : nsContainerFrame::FinishReflowChild(nsIFrame* aKidFrame,
1013 : nsPresContext* aPresContext,
1014 : const nsHTMLReflowState* aReflowState,
1015 : const nsHTMLReflowMetrics& aDesiredSize,
1016 : nscoord aX,
1017 : nscoord aY,
1018 : PRUint32 aFlags)
1019 : {
1020 0 : nsPoint curOrigin = aKidFrame->GetPosition();
1021 0 : nsRect bounds(aX, aY, aDesiredSize.width, aDesiredSize.height);
1022 :
1023 0 : aKidFrame->SetRect(bounds);
1024 :
1025 0 : if (aKidFrame->HasView()) {
1026 0 : nsIView* view = aKidFrame->GetView();
1027 : // Make sure the frame's view is properly sized and positioned and has
1028 : // things like opacity correct
1029 : SyncFrameViewAfterReflow(aPresContext, aKidFrame, view,
1030 0 : aDesiredSize.VisualOverflow(), aFlags);
1031 : }
1032 :
1033 0 : if (!(aFlags & NS_FRAME_NO_MOVE_VIEW) &&
1034 : (curOrigin.x != aX || curOrigin.y != aY)) {
1035 0 : if (!aKidFrame->HasView()) {
1036 : // If the frame has moved, then we need to make sure any child views are
1037 : // correctly positioned
1038 0 : PositionChildViews(aKidFrame);
1039 : }
1040 :
1041 : // We also need to redraw everything associated with the frame
1042 : // because if the frame's Reflow issued any invalidates, then they
1043 : // will be at the wrong offset ... note that this includes
1044 : // invalidates issued against the frame's children, so we need to
1045 : // invalidate the overflow area too.
1046 0 : aKidFrame->Invalidate(aDesiredSize.VisualOverflow());
1047 : }
1048 :
1049 0 : return aKidFrame->DidReflow(aPresContext, aReflowState, NS_FRAME_REFLOW_FINISHED);
1050 : }
1051 :
1052 : nsresult
1053 0 : nsContainerFrame::ReflowOverflowContainerChildren(nsPresContext* aPresContext,
1054 : const nsHTMLReflowState& aReflowState,
1055 : nsOverflowAreas& aOverflowRects,
1056 : PRUint32 aFlags,
1057 : nsReflowStatus& aStatus)
1058 : {
1059 0 : NS_PRECONDITION(aPresContext, "null pointer");
1060 0 : nsresult rv = NS_OK;
1061 :
1062 : nsFrameList* overflowContainers =
1063 : GetPropTableFrames(aPresContext,
1064 0 : OverflowContainersProperty());
1065 :
1066 0 : NS_ASSERTION(!(overflowContainers && GetPrevInFlow()
1067 : && static_cast<nsContainerFrame*>(GetPrevInFlow())
1068 : ->GetPropTableFrames(aPresContext,
1069 : ExcessOverflowContainersProperty())),
1070 : "conflicting overflow containers lists");
1071 :
1072 0 : if (!overflowContainers) {
1073 : // Drain excess from previnflow
1074 0 : nsContainerFrame* prev = (nsContainerFrame*) GetPrevInFlow();
1075 0 : if (prev) {
1076 : nsFrameList* excessFrames =
1077 : prev->RemovePropTableFrames(aPresContext,
1078 0 : ExcessOverflowContainersProperty());
1079 0 : if (excessFrames) {
1080 0 : excessFrames->ApplySetParent(this);
1081 : nsContainerFrame::ReparentFrameViewList(aPresContext, *excessFrames,
1082 0 : prev, this);
1083 0 : overflowContainers = excessFrames;
1084 : rv = SetPropTableFrames(aPresContext, overflowContainers,
1085 0 : OverflowContainersProperty());
1086 0 : if (NS_FAILED(rv)) {
1087 0 : excessFrames->DestroyFrames();
1088 0 : delete excessFrames;
1089 0 : return rv;
1090 : }
1091 : }
1092 : }
1093 : }
1094 :
1095 0 : if (!overflowContainers)
1096 0 : return NS_OK; // nothing to reflow
1097 :
1098 0 : nsOverflowContinuationTracker tracker(aPresContext, this, false, false);
1099 0 : bool shouldReflowAllKids = aReflowState.ShouldReflowAllKids();
1100 :
1101 0 : for (nsIFrame* frame = overflowContainers->FirstChild(); frame;
1102 : frame = frame->GetNextSibling()) {
1103 0 : if (frame->GetPrevInFlow()->GetParent() != GetPrevInFlow()) {
1104 : // frame's prevInFlow has moved, skip reflowing this frame;
1105 : // it will get reflowed once it's been placed
1106 0 : continue;
1107 : }
1108 : // If the available vertical height has changed, we need to reflow
1109 : // even if the frame isn't dirty.
1110 0 : if (shouldReflowAllKids || NS_SUBTREE_DIRTY(frame)) {
1111 : // Get prev-in-flow
1112 0 : nsIFrame* prevInFlow = frame->GetPrevInFlow();
1113 0 : NS_ASSERTION(prevInFlow,
1114 : "overflow container frame must have a prev-in-flow");
1115 0 : NS_ASSERTION(frame->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER,
1116 : "overflow container frame must have overflow container bit set");
1117 0 : nsRect prevRect = prevInFlow->GetRect();
1118 :
1119 : // Initialize reflow params
1120 0 : nsSize availSpace(prevRect.width, aReflowState.availableHeight);
1121 0 : nsHTMLReflowMetrics desiredSize;
1122 : nsHTMLReflowState frameState(aPresContext, aReflowState,
1123 0 : frame, availSpace);
1124 0 : nsReflowStatus frameStatus = NS_FRAME_COMPLETE;
1125 :
1126 : // Cache old bounds
1127 0 : nsRect oldRect = frame->GetRect();
1128 0 : nsRect oldOverflow = frame->GetVisualOverflowRect();
1129 :
1130 : // Reflow
1131 : rv = ReflowChild(frame, aPresContext, desiredSize, frameState,
1132 0 : prevRect.x, 0, aFlags, frameStatus, &tracker);
1133 0 : NS_ENSURE_SUCCESS(rv, rv);
1134 : //XXXfr Do we need to override any shrinkwrap effects here?
1135 : // e.g. desiredSize.width = prevRect.width;
1136 : rv = FinishReflowChild(frame, aPresContext, &frameState, desiredSize,
1137 0 : prevRect.x, 0, aFlags);
1138 0 : NS_ENSURE_SUCCESS(rv, rv);
1139 :
1140 : // Invalidate if there was a position or size change
1141 0 : nsRect rect = frame->GetRect();
1142 0 : if (!rect.IsEqualInterior(oldRect)) {
1143 0 : nsRect dirtyRect = oldOverflow;
1144 0 : dirtyRect.MoveBy(oldRect.x, oldRect.y);
1145 0 : Invalidate(dirtyRect);
1146 :
1147 0 : dirtyRect = frame->GetVisualOverflowRect();
1148 0 : dirtyRect.MoveBy(rect.x, rect.y);
1149 0 : Invalidate(dirtyRect);
1150 : }
1151 :
1152 : // Handle continuations
1153 0 : if (!NS_FRAME_IS_FULLY_COMPLETE(frameStatus)) {
1154 0 : if (frame->GetStateBits() & NS_FRAME_OUT_OF_FLOW) {
1155 : // Abspos frames can't cause their parent to be incomplete,
1156 : // only overflow incomplete.
1157 0 : NS_FRAME_SET_OVERFLOW_INCOMPLETE(frameStatus);
1158 : }
1159 : else {
1160 0 : NS_ASSERTION(NS_FRAME_IS_COMPLETE(frameStatus),
1161 : "overflow container frames can't be incomplete, only overflow-incomplete");
1162 : }
1163 :
1164 : // Acquire a next-in-flow, creating it if necessary
1165 0 : nsIFrame* nif = frame->GetNextInFlow();
1166 0 : if (!nif) {
1167 0 : NS_ASSERTION(frameStatus & NS_FRAME_REFLOW_NEXTINFLOW,
1168 : "Someone forgot a REFLOW_NEXTINFLOW flag");
1169 : rv = aPresContext->PresShell()->FrameConstructor()->
1170 0 : CreateContinuingFrame(aPresContext, frame, this, &nif);
1171 0 : NS_ENSURE_SUCCESS(rv, rv);
1172 : }
1173 0 : else if (!(nif->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1174 : // used to be a normal next-in-flow; steal it from the child list
1175 0 : rv = static_cast<nsContainerFrame*>(nif->GetParent())
1176 0 : ->StealFrame(aPresContext, nif);
1177 0 : NS_ENSURE_SUCCESS(rv, rv);
1178 : }
1179 :
1180 0 : tracker.Insert(nif, frameStatus);
1181 : }
1182 0 : NS_MergeReflowStatusInto(&aStatus, frameStatus);
1183 : // At this point it would be nice to assert !frame->GetOverflowRect().IsEmpty(),
1184 : // but we have some unsplittable frames that, when taller than
1185 : // availableHeight will push zero-height content into a next-in-flow.
1186 : }
1187 : else {
1188 0 : tracker.Skip(frame, aStatus);
1189 0 : if (aReflowState.mFloatManager)
1190 0 : nsBlockFrame::RecoverFloatsFor(frame, *aReflowState.mFloatManager);
1191 : }
1192 0 : ConsiderChildOverflow(aOverflowRects, frame);
1193 : }
1194 :
1195 0 : return NS_OK;
1196 : }
1197 :
1198 : void
1199 0 : nsContainerFrame::DisplayOverflowContainers(nsDisplayListBuilder* aBuilder,
1200 : const nsRect& aDirtyRect,
1201 : const nsDisplayListSet& aLists)
1202 : {
1203 : nsFrameList* overflowconts =
1204 0 : GetPropTableFrames(PresContext(), OverflowContainersProperty());
1205 0 : if (overflowconts) {
1206 0 : for (nsIFrame* frame = overflowconts->FirstChild(); frame;
1207 : frame = frame->GetNextSibling()) {
1208 0 : BuildDisplayListForChild(aBuilder, frame, aDirtyRect, aLists);
1209 : }
1210 : }
1211 0 : }
1212 :
1213 : nsresult
1214 0 : nsContainerFrame::StealFrame(nsPresContext* aPresContext,
1215 : nsIFrame* aChild,
1216 : bool aForceNormal)
1217 : {
1218 0 : bool removed = true;
1219 0 : if ((aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)
1220 0 : && !aForceNormal) {
1221 : // Try removing from the overflow container list
1222 0 : if (!RemovePropTableFrame(aPresContext, aChild,
1223 0 : OverflowContainersProperty())) {
1224 : // It must be in the excess overflow container list
1225 : removed = RemovePropTableFrame(aPresContext, aChild,
1226 0 : ExcessOverflowContainersProperty());
1227 : }
1228 : }
1229 : else {
1230 0 : if (!mFrames.RemoveFrameIfPresent(aChild)) {
1231 0 : removed = false;
1232 : // We didn't find the child in the parent's principal child list.
1233 : // Maybe it's on the overflow list?
1234 0 : nsFrameList* frameList = GetOverflowFrames();
1235 0 : if (frameList) {
1236 0 : removed = frameList->RemoveFrameIfPresent(aChild);
1237 0 : if (frameList->IsEmpty()) {
1238 0 : DestroyOverflowList(aPresContext, nsnull);
1239 : }
1240 : }
1241 : }
1242 : }
1243 :
1244 0 : NS_POSTCONDITION(removed, "StealFrame: can't find aChild");
1245 0 : return removed ? NS_OK : NS_ERROR_UNEXPECTED;
1246 : }
1247 :
1248 : nsFrameList
1249 0 : nsContainerFrame::StealFramesAfter(nsIFrame* aChild)
1250 : {
1251 0 : NS_ASSERTION(!aChild ||
1252 : !(aChild->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER),
1253 : "StealFramesAfter doesn't handle overflow containers");
1254 0 : NS_ASSERTION(GetType() != nsGkAtoms::blockFrame, "unexpected call");
1255 :
1256 0 : if (!aChild) {
1257 0 : nsFrameList copy(mFrames);
1258 0 : mFrames.Clear();
1259 0 : return copy;
1260 : }
1261 :
1262 0 : for (nsFrameList::FrameLinkEnumerator iter(mFrames); !iter.AtEnd();
1263 0 : iter.Next()) {
1264 0 : if (iter.PrevFrame() == aChild) {
1265 0 : return mFrames.ExtractTail(iter);
1266 : }
1267 : }
1268 :
1269 : // We didn't find the child in the principal child list.
1270 : // Maybe it's on the overflow list?
1271 0 : nsFrameList* overflowFrames = GetOverflowFrames();
1272 0 : if (overflowFrames) {
1273 0 : for (nsFrameList::FrameLinkEnumerator iter(*overflowFrames); !iter.AtEnd();
1274 0 : iter.Next()) {
1275 0 : if (iter.PrevFrame() == aChild) {
1276 0 : return overflowFrames->ExtractTail(iter);
1277 : }
1278 : }
1279 : }
1280 :
1281 0 : NS_ERROR("StealFramesAfter: can't find aChild");
1282 0 : return nsFrameList::EmptyList();
1283 : }
1284 :
1285 : void
1286 0 : nsContainerFrame::DestroyOverflowList(nsPresContext* aPresContext,
1287 : nsIFrame* aDestructRoot)
1288 : {
1289 : nsFrameList* list =
1290 0 : RemovePropTableFrames(aPresContext, OverflowProperty());
1291 0 : if (list) {
1292 0 : if (aDestructRoot)
1293 0 : list->DestroyFrom(aDestructRoot);
1294 : else
1295 0 : list->Destroy();
1296 : }
1297 0 : }
1298 :
1299 : /*
1300 : * Create a next-in-flow for aFrame. Will return the newly created
1301 : * frame in aNextInFlowResult <b>if and only if</b> a new frame is
1302 : * created; otherwise nsnull is returned in aNextInFlowResult.
1303 : */
1304 : nsresult
1305 0 : nsContainerFrame::CreateNextInFlow(nsPresContext* aPresContext,
1306 : nsIFrame* aFrame,
1307 : nsIFrame*& aNextInFlowResult)
1308 : {
1309 0 : NS_PRECONDITION(GetType() != nsGkAtoms::blockFrame,
1310 : "you should have called nsBlockFrame::CreateContinuationFor instead");
1311 0 : NS_PRECONDITION(mFrames.ContainsFrame(aFrame), "expected an in-flow child frame");
1312 :
1313 0 : aNextInFlowResult = nsnull;
1314 :
1315 0 : nsIFrame* nextInFlow = aFrame->GetNextInFlow();
1316 0 : if (nsnull == nextInFlow) {
1317 : // Create a continuation frame for the child frame and insert it
1318 : // into our child list.
1319 : nsresult rv = aPresContext->PresShell()->FrameConstructor()->
1320 0 : CreateContinuingFrame(aPresContext, aFrame, this, &nextInFlow);
1321 0 : if (NS_FAILED(rv)) {
1322 0 : return rv;
1323 : }
1324 0 : mFrames.InsertFrame(nsnull, aFrame, nextInFlow);
1325 :
1326 0 : NS_FRAME_LOG(NS_FRAME_TRACE_NEW_FRAMES,
1327 : ("nsContainerFrame::CreateNextInFlow: frame=%p nextInFlow=%p",
1328 : aFrame, nextInFlow));
1329 :
1330 0 : aNextInFlowResult = nextInFlow;
1331 : }
1332 0 : return NS_OK;
1333 : }
1334 :
1335 : /**
1336 : * Remove and delete aNextInFlow and its next-in-flows. Updates the sibling and flow
1337 : * pointers
1338 : */
1339 : void
1340 0 : nsContainerFrame::DeleteNextInFlowChild(nsPresContext* aPresContext,
1341 : nsIFrame* aNextInFlow,
1342 : bool aDeletingEmptyFrames)
1343 : {
1344 : #ifdef DEBUG
1345 0 : nsIFrame* prevInFlow = aNextInFlow->GetPrevInFlow();
1346 : #endif
1347 0 : NS_PRECONDITION(prevInFlow, "bad prev-in-flow");
1348 :
1349 : // If the next-in-flow has a next-in-flow then delete it, too (and
1350 : // delete it first).
1351 : // Do this in a loop so we don't overflow the stack for frames
1352 : // with very many next-in-flows
1353 0 : nsIFrame* nextNextInFlow = aNextInFlow->GetNextInFlow();
1354 0 : if (nextNextInFlow) {
1355 0 : nsAutoTArray<nsIFrame*, 8> frames;
1356 0 : for (nsIFrame* f = nextNextInFlow; f; f = f->GetNextInFlow()) {
1357 0 : frames.AppendElement(f);
1358 : }
1359 0 : for (PRInt32 i = frames.Length() - 1; i >= 0; --i) {
1360 0 : nsIFrame* delFrame = frames.ElementAt(i);
1361 0 : static_cast<nsContainerFrame*>(delFrame->GetParent())
1362 0 : ->DeleteNextInFlowChild(aPresContext, delFrame, aDeletingEmptyFrames);
1363 : }
1364 : }
1365 :
1366 0 : aNextInFlow->InvalidateFrameSubtree();
1367 :
1368 : // Take the next-in-flow out of the parent's child list
1369 : #ifdef DEBUG
1370 : nsresult rv =
1371 : #endif
1372 0 : StealFrame(aPresContext, aNextInFlow);
1373 0 : NS_ASSERTION(NS_SUCCEEDED(rv), "StealFrame failure");
1374 :
1375 : #ifdef DEBUG
1376 0 : if (aDeletingEmptyFrames) {
1377 0 : nsLayoutUtils::AssertTreeOnlyEmptyNextInFlows(aNextInFlow);
1378 : }
1379 : #endif
1380 :
1381 : // Delete the next-in-flow frame and its descendants. This will also
1382 : // remove it from its next-in-flow/prev-in-flow chain.
1383 0 : aNextInFlow->Destroy();
1384 :
1385 0 : NS_POSTCONDITION(!prevInFlow->GetNextInFlow(), "non null next-in-flow");
1386 0 : }
1387 :
1388 : /**
1389 : * Set the frames on the overflow list
1390 : */
1391 : void
1392 0 : nsContainerFrame::SetOverflowFrames(nsPresContext* aPresContext,
1393 : const nsFrameList& aOverflowFrames)
1394 : {
1395 0 : NS_PRECONDITION(aOverflowFrames.NotEmpty(), "Shouldn't be called");
1396 0 : nsFrameList* newList = new nsFrameList(aOverflowFrames);
1397 :
1398 0 : aPresContext->PropertyTable()->Set(this, OverflowProperty(), newList);
1399 0 : }
1400 :
1401 : nsFrameList*
1402 0 : nsContainerFrame::GetPropTableFrames(nsPresContext* aPresContext,
1403 : const FramePropertyDescriptor* aProperty) const
1404 : {
1405 0 : FramePropertyTable* propTable = aPresContext->PropertyTable();
1406 0 : return static_cast<nsFrameList*>(propTable->Get(this, aProperty));
1407 : }
1408 :
1409 : nsFrameList*
1410 0 : nsContainerFrame::RemovePropTableFrames(nsPresContext* aPresContext,
1411 : const FramePropertyDescriptor* aProperty)
1412 : {
1413 0 : FramePropertyTable* propTable = aPresContext->PropertyTable();
1414 0 : return static_cast<nsFrameList*>(propTable->Remove(this, aProperty));
1415 : }
1416 :
1417 : bool
1418 0 : nsContainerFrame::RemovePropTableFrame(nsPresContext* aPresContext,
1419 : nsIFrame* aFrame,
1420 : const FramePropertyDescriptor* aProperty)
1421 : {
1422 0 : nsFrameList* frameList = RemovePropTableFrames(aPresContext, aProperty);
1423 0 : if (!frameList) {
1424 : // No such list
1425 0 : return false;
1426 : }
1427 0 : if (!frameList->RemoveFrameIfPresent(aFrame)) {
1428 : // Found list, but it doesn't have the frame. Put list back.
1429 0 : SetPropTableFrames(aPresContext, frameList, aProperty);
1430 0 : return false;
1431 : }
1432 :
1433 0 : if (frameList->IsEmpty()) {
1434 : // Removed frame and now list is empty. Delete it.
1435 0 : delete frameList;
1436 : }
1437 : else {
1438 : // Removed frame, but list not empty. Put it back.
1439 0 : SetPropTableFrames(aPresContext, frameList, aProperty);
1440 : }
1441 0 : return true;
1442 : }
1443 :
1444 : nsresult
1445 0 : nsContainerFrame::SetPropTableFrames(nsPresContext* aPresContext,
1446 : nsFrameList* aFrameList,
1447 : const FramePropertyDescriptor* aProperty)
1448 : {
1449 0 : NS_PRECONDITION(aPresContext && aProperty && aFrameList, "null ptr");
1450 0 : NS_PRECONDITION(
1451 : (aProperty != nsContainerFrame::OverflowContainersProperty() &&
1452 : aProperty != nsContainerFrame::ExcessOverflowContainersProperty()) ||
1453 : IsFrameOfType(nsIFrame::eCanContainOverflowContainers),
1454 : "this type of frame can't have overflow containers");
1455 0 : aPresContext->PropertyTable()->Set(this, aProperty, aFrameList);
1456 0 : return NS_OK;
1457 : }
1458 :
1459 : /**
1460 : * Push aFromChild and its next siblings to the next-in-flow. Change the
1461 : * geometric parent of each frame that's pushed. If there is no next-in-flow
1462 : * the frames are placed on the overflow list (and the geometric parent is
1463 : * left unchanged).
1464 : *
1465 : * Updates the next-in-flow's child count. Does <b>not</b> update the
1466 : * pusher's child count.
1467 : *
1468 : * @param aFromChild the first child frame to push. It is disconnected from
1469 : * aPrevSibling
1470 : * @param aPrevSibling aFromChild's previous sibling. Must not be null. It's
1471 : * an error to push a parent's first child frame
1472 : */
1473 : void
1474 0 : nsContainerFrame::PushChildren(nsPresContext* aPresContext,
1475 : nsIFrame* aFromChild,
1476 : nsIFrame* aPrevSibling)
1477 : {
1478 0 : NS_PRECONDITION(aFromChild, "null pointer");
1479 0 : NS_PRECONDITION(aPrevSibling, "pushing first child");
1480 0 : NS_PRECONDITION(aPrevSibling->GetNextSibling() == aFromChild, "bad prev sibling");
1481 :
1482 : // Disconnect aFromChild from its previous sibling
1483 0 : nsFrameList tail = mFrames.RemoveFramesAfter(aPrevSibling);
1484 :
1485 : nsContainerFrame* nextInFlow =
1486 0 : static_cast<nsContainerFrame*>(GetNextInFlow());
1487 0 : if (nextInFlow) {
1488 : // XXX This is not a very good thing to do. If it gets removed
1489 : // then remove the copy of this routine that doesn't do this from
1490 : // nsInlineFrame.
1491 : // When pushing and pulling frames we need to check for whether any
1492 : // views need to be reparented.
1493 0 : for (nsIFrame* f = aFromChild; f; f = f->GetNextSibling()) {
1494 0 : nsContainerFrame::ReparentFrameView(aPresContext, f, this, nextInFlow);
1495 : }
1496 0 : nextInFlow->mFrames.InsertFrames(nextInFlow, nsnull, tail);
1497 : }
1498 : else {
1499 : // Add the frames to our overflow list
1500 0 : SetOverflowFrames(aPresContext, tail);
1501 : }
1502 0 : }
1503 :
1504 : /**
1505 : * Moves any frames on the overflow lists (the prev-in-flow's overflow list and
1506 : * the receiver's overflow list) to the child list.
1507 : *
1508 : * Updates this frame's child count and content mapping.
1509 : *
1510 : * @return true if any frames were moved and false otherwise
1511 : */
1512 : bool
1513 0 : nsContainerFrame::MoveOverflowToChildList(nsPresContext* aPresContext)
1514 : {
1515 0 : bool result = false;
1516 :
1517 : // Check for an overflow list with our prev-in-flow
1518 0 : nsContainerFrame* prevInFlow = (nsContainerFrame*)GetPrevInFlow();
1519 0 : if (nsnull != prevInFlow) {
1520 0 : nsAutoPtr<nsFrameList> prevOverflowFrames(prevInFlow->StealOverflowFrames());
1521 0 : if (prevOverflowFrames) {
1522 : // Tables are special; they can have repeated header/footer
1523 : // frames on mFrames at this point.
1524 0 : NS_ASSERTION(mFrames.IsEmpty() || GetType() == nsGkAtoms::tableFrame,
1525 : "bad overflow list");
1526 : // When pushing and pulling frames we need to check for whether any
1527 : // views need to be reparented.
1528 : nsContainerFrame::ReparentFrameViewList(aPresContext,
1529 0 : *prevOverflowFrames,
1530 0 : prevInFlow, this);
1531 0 : mFrames.AppendFrames(this, *prevOverflowFrames);
1532 0 : result = true;
1533 : }
1534 : }
1535 :
1536 : // It's also possible that we have an overflow list for ourselves
1537 0 : nsAutoPtr<nsFrameList> overflowFrames(StealOverflowFrames());
1538 0 : if (overflowFrames) {
1539 0 : NS_ASSERTION(mFrames.NotEmpty(), "overflow list w/o frames");
1540 0 : mFrames.AppendFrames(nsnull, *overflowFrames);
1541 0 : result = true;
1542 : }
1543 0 : return result;
1544 : }
1545 :
1546 0 : nsOverflowContinuationTracker::nsOverflowContinuationTracker(nsPresContext* aPresContext,
1547 : nsContainerFrame* aFrame,
1548 : bool aWalkOOFFrames,
1549 : bool aSkipOverflowContainerChildren)
1550 : : mOverflowContList(nsnull),
1551 : mPrevOverflowCont(nsnull),
1552 : mSentry(nsnull),
1553 : mParent(aFrame),
1554 : mSkipOverflowContainerChildren(aSkipOverflowContainerChildren),
1555 0 : mWalkOOFFrames(aWalkOOFFrames)
1556 : {
1557 0 : NS_PRECONDITION(aFrame, "null frame pointer");
1558 : nsContainerFrame* next = static_cast<nsContainerFrame*>
1559 0 : (aFrame->GetNextInFlow());
1560 0 : if (next) {
1561 : mOverflowContList = next->GetPropTableFrames(aPresContext,
1562 0 : nsContainerFrame::OverflowContainersProperty());
1563 0 : if (mOverflowContList) {
1564 0 : mParent = next;
1565 0 : SetUpListWalker();
1566 : }
1567 : }
1568 0 : if (!mOverflowContList) {
1569 : mOverflowContList = mParent->GetPropTableFrames(aPresContext,
1570 0 : nsContainerFrame::ExcessOverflowContainersProperty());
1571 0 : if (mOverflowContList) {
1572 0 : SetUpListWalker();
1573 : }
1574 : }
1575 0 : }
1576 :
1577 : /**
1578 : * Helper function to walk past overflow continuations whose prev-in-flow
1579 : * isn't a normal child and to set mSentry and mPrevOverflowCont correctly.
1580 : */
1581 : void
1582 0 : nsOverflowContinuationTracker::SetUpListWalker()
1583 : {
1584 0 : NS_ASSERTION(!mSentry && !mPrevOverflowCont,
1585 : "forgot to reset mSentry or mPrevOverflowCont");
1586 0 : if (mOverflowContList) {
1587 0 : nsIFrame* cur = mOverflowContList->FirstChild();
1588 0 : if (mSkipOverflowContainerChildren) {
1589 0 : while (cur && (cur->GetPrevInFlow()->GetStateBits()
1590 : & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1591 0 : mPrevOverflowCont = cur;
1592 0 : cur = cur->GetNextSibling();
1593 : }
1594 0 : while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1595 : == mWalkOOFFrames)) {
1596 0 : mPrevOverflowCont = cur;
1597 0 : cur = cur->GetNextSibling();
1598 : }
1599 : }
1600 0 : if (cur) {
1601 0 : mSentry = cur->GetPrevInFlow();
1602 : }
1603 : }
1604 0 : }
1605 :
1606 : /**
1607 : * Helper function to step forward through the overflow continuations list.
1608 : * Sets mSentry and mPrevOverflowCont, skipping over OOF or non-OOF frames
1609 : * as appropriate. May only be called when we have already set up an
1610 : * mOverflowContList; mOverflowContList cannot be null.
1611 : */
1612 : void
1613 0 : nsOverflowContinuationTracker::StepForward()
1614 : {
1615 0 : NS_PRECONDITION(mOverflowContList, "null list");
1616 :
1617 : // Step forward
1618 0 : if (mPrevOverflowCont) {
1619 0 : mPrevOverflowCont = mPrevOverflowCont->GetNextSibling();
1620 : }
1621 : else {
1622 0 : mPrevOverflowCont = mOverflowContList->FirstChild();
1623 : }
1624 :
1625 : // Skip over oof or non-oof frames as appropriate
1626 0 : if (mSkipOverflowContainerChildren) {
1627 0 : nsIFrame* cur = mPrevOverflowCont->GetNextSibling();
1628 0 : while (cur && (!(cur->GetStateBits() & NS_FRAME_OUT_OF_FLOW)
1629 : == mWalkOOFFrames)) {
1630 0 : mPrevOverflowCont = cur;
1631 0 : cur = cur->GetNextSibling();
1632 : }
1633 : }
1634 :
1635 : // Set up the sentry
1636 0 : mSentry = (mPrevOverflowCont->GetNextSibling())
1637 0 : ? mPrevOverflowCont->GetNextSibling()->GetPrevInFlow()
1638 0 : : nsnull;
1639 0 : }
1640 :
1641 : nsresult
1642 0 : nsOverflowContinuationTracker::Insert(nsIFrame* aOverflowCont,
1643 : nsReflowStatus& aReflowStatus)
1644 : {
1645 0 : NS_PRECONDITION(aOverflowCont, "null frame pointer");
1646 0 : NS_PRECONDITION(!mSkipOverflowContainerChildren || mWalkOOFFrames ==
1647 : !!(aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW),
1648 : "shouldn't insert frame that doesn't match walker type");
1649 0 : NS_PRECONDITION(aOverflowCont->GetPrevInFlow(),
1650 : "overflow containers must have a prev-in-flow");
1651 0 : nsresult rv = NS_OK;
1652 0 : bool convertedToOverflowContainer = false;
1653 0 : nsPresContext* presContext = aOverflowCont->PresContext();
1654 0 : if (!mSentry || aOverflowCont != mSentry->GetNextInFlow()) {
1655 : // Not in our list, so we need to add it
1656 0 : if (aOverflowCont->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER) {
1657 : // aOverflowCont is in some other overflow container list,
1658 : // steal it first
1659 0 : NS_ASSERTION(!(mOverflowContList &&
1660 : mOverflowContList->ContainsFrame(aOverflowCont)),
1661 : "overflow containers out of order");
1662 0 : rv = static_cast<nsContainerFrame*>(aOverflowCont->GetParent())
1663 0 : ->StealFrame(presContext, aOverflowCont);
1664 0 : NS_ENSURE_SUCCESS(rv, rv);
1665 : }
1666 : else {
1667 0 : aOverflowCont->AddStateBits(NS_FRAME_IS_OVERFLOW_CONTAINER);
1668 0 : convertedToOverflowContainer = true;
1669 : }
1670 0 : if (!mOverflowContList) {
1671 0 : mOverflowContList = new nsFrameList();
1672 : rv = mParent->SetPropTableFrames(presContext, mOverflowContList,
1673 0 : nsContainerFrame::ExcessOverflowContainersProperty());
1674 0 : NS_ENSURE_SUCCESS(rv, rv);
1675 0 : SetUpListWalker();
1676 : }
1677 0 : if (aOverflowCont->GetParent() != mParent) {
1678 : nsContainerFrame::ReparentFrameView(presContext, aOverflowCont,
1679 : aOverflowCont->GetParent(),
1680 0 : mParent);
1681 : }
1682 0 : mOverflowContList->InsertFrame(mParent, mPrevOverflowCont, aOverflowCont);
1683 0 : aReflowStatus |= NS_FRAME_REFLOW_NEXTINFLOW;
1684 : }
1685 :
1686 : // If we need to reflow it, mark it dirty
1687 0 : if (aReflowStatus & NS_FRAME_REFLOW_NEXTINFLOW)
1688 0 : aOverflowCont->AddStateBits(NS_FRAME_IS_DIRTY);
1689 :
1690 : // It's in our list, just step forward
1691 0 : StepForward();
1692 0 : NS_ASSERTION(mPrevOverflowCont == aOverflowCont ||
1693 : (mSkipOverflowContainerChildren &&
1694 : (mPrevOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW) !=
1695 : (aOverflowCont->GetStateBits() & NS_FRAME_OUT_OF_FLOW)),
1696 : "OverflowContTracker in unexpected state");
1697 :
1698 0 : if (convertedToOverflowContainer) {
1699 : // Convert all non-overflow-container continuations of aOverflowCont
1700 : // into overflow containers and move them to our overflow
1701 : // tracker. This preserves the invariant that the next-continuations
1702 : // of an overflow container are also overflow containers.
1703 0 : nsIFrame* f = aOverflowCont->GetNextContinuation();
1704 0 : if (f && !(f->GetStateBits() & NS_FRAME_IS_OVERFLOW_CONTAINER)) {
1705 0 : nsContainerFrame* parent = static_cast<nsContainerFrame*>(f->GetParent());
1706 0 : rv = parent->StealFrame(presContext, f);
1707 0 : NS_ENSURE_SUCCESS(rv, rv);
1708 0 : Insert(f, aReflowStatus);
1709 : }
1710 : }
1711 0 : return rv;
1712 : }
1713 :
1714 : void
1715 0 : nsOverflowContinuationTracker::Finish(nsIFrame* aChild)
1716 : {
1717 0 : NS_PRECONDITION(aChild, "null ptr");
1718 0 : NS_PRECONDITION(aChild->GetNextInFlow(),
1719 : "supposed to call Finish *before* deleting next-in-flow!");
1720 :
1721 0 : for (nsIFrame* f = aChild; f; ) {
1722 : // Make sure we drop all references if all the frames in the
1723 : // overflow containers list are about to be destroyed.
1724 0 : nsIFrame* nif = f->GetNextInFlow();
1725 0 : if (mOverflowContList &&
1726 0 : mOverflowContList->FirstChild() == nif &&
1727 0 : (!nif->GetNextSibling() ||
1728 0 : nif->GetNextSibling() == nif->GetNextInFlow())) {
1729 0 : mOverflowContList = nsnull;
1730 0 : mPrevOverflowCont = nsnull;
1731 0 : mSentry = nsnull;
1732 0 : mParent = static_cast<nsContainerFrame*>(f->GetParent());
1733 0 : break;
1734 : }
1735 0 : if (f == mSentry) {
1736 : // Step past aChild
1737 0 : nsIFrame* prevOverflowCont = mPrevOverflowCont;
1738 0 : StepForward();
1739 0 : if (mPrevOverflowCont == nif) {
1740 : // Pull mPrevOverflowChild back to aChild's prevSibling:
1741 : // aChild will be removed from our list by our caller
1742 0 : mPrevOverflowCont = prevOverflowCont;
1743 : }
1744 : }
1745 0 : f = nif;
1746 : }
1747 0 : }
1748 :
1749 : /////////////////////////////////////////////////////////////////////////////
1750 : // Debugging
1751 :
1752 : #ifdef NS_DEBUG
1753 : NS_IMETHODIMP
1754 0 : nsContainerFrame::List(FILE* out, PRInt32 aIndent) const
1755 : {
1756 0 : IndentBy(out, aIndent);
1757 0 : ListTag(out);
1758 : #ifdef DEBUG_waterson
1759 : fprintf(out, " [parent=%p]", static_cast<void*>(mParent));
1760 : #endif
1761 0 : if (HasView()) {
1762 0 : fprintf(out, " [view=%p]", static_cast<void*>(GetView()));
1763 : }
1764 0 : if (GetNextSibling()) {
1765 0 : fprintf(out, " next=%p", static_cast<void*>(GetNextSibling()));
1766 : }
1767 0 : if (nsnull != GetPrevContinuation()) {
1768 0 : fprintf(out, " prev-continuation=%p", static_cast<void*>(GetPrevContinuation()));
1769 : }
1770 0 : if (nsnull != GetNextContinuation()) {
1771 0 : fprintf(out, " next-continuation=%p", static_cast<void*>(GetNextContinuation()));
1772 : }
1773 0 : void* IBsibling = Properties().Get(IBSplitSpecialSibling());
1774 0 : if (IBsibling) {
1775 0 : fprintf(out, " IBSplitSpecialSibling=%p", IBsibling);
1776 : }
1777 0 : void* IBprevsibling = Properties().Get(IBSplitSpecialPrevSibling());
1778 0 : if (IBprevsibling) {
1779 0 : fprintf(out, " IBSplitSpecialPrevSibling=%p", IBprevsibling);
1780 : }
1781 0 : fprintf(out, " {%d,%d,%d,%d}", mRect.x, mRect.y, mRect.width, mRect.height);
1782 0 : if (0 != mState) {
1783 0 : fprintf(out, " [state=%016llx]", (unsigned long long)mState);
1784 : }
1785 0 : fprintf(out, " [content=%p]", static_cast<void*>(mContent));
1786 0 : nsContainerFrame* f = const_cast<nsContainerFrame*>(this);
1787 0 : if (f->HasOverflowAreas()) {
1788 0 : nsRect overflowArea = f->GetVisualOverflowRect();
1789 : fprintf(out, " [vis-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
1790 0 : overflowArea.width, overflowArea.height);
1791 0 : overflowArea = f->GetScrollableOverflowRect();
1792 : fprintf(out, " [scr-overflow=%d,%d,%d,%d]", overflowArea.x, overflowArea.y,
1793 0 : overflowArea.width, overflowArea.height);
1794 : }
1795 0 : fprintf(out, " [sc=%p]", static_cast<void*>(mStyleContext));
1796 0 : nsIAtom* pseudoTag = mStyleContext->GetPseudo();
1797 0 : if (pseudoTag) {
1798 0 : nsAutoString atomString;
1799 0 : pseudoTag->ToString(atomString);
1800 : fprintf(out, " pst=%s",
1801 0 : NS_LossyConvertUTF16toASCII(atomString).get());
1802 : }
1803 :
1804 : // Output the children
1805 0 : bool outputOneList = false;
1806 0 : ChildListIterator lists(this);
1807 0 : for (; !lists.IsDone(); lists.Next()) {
1808 0 : if (outputOneList) {
1809 0 : IndentBy(out, aIndent);
1810 : }
1811 0 : outputOneList = true;
1812 0 : fputs(mozilla::layout::ChildListName(lists.CurrentID()), out);
1813 0 : fputs("<\n", out);
1814 0 : nsFrameList::Enumerator childFrames(lists.CurrentList());
1815 0 : for (; !childFrames.AtEnd(); childFrames.Next()) {
1816 0 : nsIFrame* kid = childFrames.get();
1817 : // Verify the child frame's parent frame pointer is correct
1818 0 : NS_ASSERTION(kid->GetParent() == this, "bad parent frame pointer");
1819 :
1820 : // Have the child frame list
1821 0 : kid->List(out, aIndent + 1);
1822 : }
1823 0 : IndentBy(out, aIndent);
1824 0 : fputs(">\n", out);
1825 : }
1826 :
1827 0 : if (!outputOneList) {
1828 0 : fputs("<>\n", out);
1829 : }
1830 :
1831 0 : return NS_OK;
1832 : }
1833 : #endif
|