| /* |
| * Copyright (C) 2009, 2010 Apple Inc. All rights reserved. |
| * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "core/layout/LayoutObjectChildList.h" |
| |
| #include "core/dom/AXObjectCache.h" |
| #include "core/layout/LayoutCounter.h" |
| #include "core/layout/LayoutObject.h" |
| #include "core/layout/LayoutView.h" |
| #include "core/paint/ObjectPaintInvalidator.h" |
| |
| namespace blink { |
| |
| void LayoutObjectChildList::DestroyLeftoverChildren() { |
| while (FirstChild()) { |
| // List markers are owned by their enclosing list and so don't get destroyed |
| // by this container. |
| if (FirstChild()->IsListMarker()) { |
| FirstChild()->Remove(); |
| continue; |
| } |
| |
| // Destroy any anonymous children remaining in the layout tree, as well as |
| // implicit (shadow) DOM elements like those used in the engine-based text |
| // fields. |
| if (FirstChild()->GetNode()) |
| FirstChild()->GetNode()->SetLayoutObject(nullptr); |
| FirstChild()->Destroy(); |
| } |
| } |
| |
| LayoutObject* LayoutObjectChildList::RemoveChildNode( |
| LayoutObject* owner, |
| LayoutObject* old_child, |
| bool notify_layout_object) { |
| DCHECK_EQ(old_child->Parent(), owner); |
| DCHECK_EQ(this, owner->VirtualChildren()); |
| |
| if (old_child->IsFloatingOrOutOfFlowPositioned()) |
| ToLayoutBox(old_child)->RemoveFloatingOrPositionedChildFromBlockLists(); |
| |
| if (!owner->DocumentBeingDestroyed()) { |
| // So that we'll get the appropriate dirty bit set (either that a normal |
| // flow child got yanked or that a positioned child got yanked). We also |
| // issue paint invalidations, so that the area exposed when the child |
| // disappears gets paint invalidated properly. |
| if (notify_layout_object && old_child->EverHadLayout()) |
| old_child->SetNeedsLayoutAndPrefWidthsRecalc( |
| LayoutInvalidationReason::kRemovedFromLayout); |
| InvalidatePaintOnRemoval(*old_child); |
| } |
| |
| // If we have a line box wrapper, delete it. |
| if (old_child->IsBox()) |
| ToLayoutBox(old_child)->DeleteLineBoxWrapper(); |
| |
| if (!owner->DocumentBeingDestroyed()) { |
| // If oldChild is the start or end of the selection, then clear the |
| // selection to avoid problems of invalid pointers. |
| // FIXME: The FrameSelection should be responsible for this when it |
| // is notified of DOM mutations. |
| if (old_child->IsSelectionBorder() && owner->View()) |
| owner->View()->ClearSelection(); |
| |
| owner->NotifyOfSubtreeChange(); |
| |
| if (notify_layout_object) { |
| LayoutCounter::LayoutObjectSubtreeWillBeDetached(old_child); |
| old_child->WillBeRemovedFromTree(); |
| } else if (old_child->IsBox() && |
| ToLayoutBox(old_child)->IsOrthogonalWritingModeRoot()) { |
| ToLayoutBox(old_child)->UnmarkOrthogonalWritingModeRoot(); |
| } |
| } |
| |
| // WARNING: There should be no code running between willBeRemovedFromTree and |
| // the actual removal below. |
| // This is needed to avoid race conditions where willBeRemovedFromTree would |
| // dirty the tree's structure and the code running here would force an |
| // untimely rebuilding, leaving |oldChild| dangling. |
| |
| if (old_child->PreviousSibling()) |
| old_child->PreviousSibling()->SetNextSibling(old_child->NextSibling()); |
| if (old_child->NextSibling()) |
| old_child->NextSibling()->SetPreviousSibling(old_child->PreviousSibling()); |
| |
| if (FirstChild() == old_child) |
| first_child_ = old_child->NextSibling(); |
| if (LastChild() == old_child) |
| last_child_ = old_child->PreviousSibling(); |
| |
| old_child->SetPreviousSibling(nullptr); |
| old_child->SetNextSibling(nullptr); |
| old_child->SetParent(nullptr); |
| |
| old_child->RegisterSubtreeChangeListenerOnDescendants( |
| old_child->ConsumesSubtreeChangeNotification()); |
| |
| if (AXObjectCache* cache = owner->GetDocument().ExistingAXObjectCache()) |
| cache->ChildrenChanged(owner); |
| |
| return old_child; |
| } |
| |
| DISABLE_CFI_PERF |
| void LayoutObjectChildList::InsertChildNode(LayoutObject* owner, |
| LayoutObject* new_child, |
| LayoutObject* before_child, |
| bool notify_layout_object) { |
| DCHECK(!new_child->Parent()); |
| DCHECK_EQ(this, owner->VirtualChildren()); |
| DCHECK(!owner->IsLayoutBlockFlow() || |
| (!new_child->IsTableSection() && !new_child->IsTableRow() && |
| !new_child->IsTableCell())); |
| |
| while (before_child && before_child->Parent() && |
| before_child->Parent() != owner) |
| before_child = before_child->Parent(); |
| |
| // This should never happen, but if it does prevent layout tree corruption |
| // where child->parent() ends up being owner but |
| // child->nextSibling()->parent() is not owner. |
| if (before_child && before_child->Parent() != owner) { |
| NOTREACHED(); |
| return; |
| } |
| |
| new_child->SetParent(owner); |
| |
| if (FirstChild() == before_child) |
| first_child_ = new_child; |
| |
| if (before_child) { |
| LayoutObject* previous_sibling = before_child->PreviousSibling(); |
| if (previous_sibling) |
| previous_sibling->SetNextSibling(new_child); |
| new_child->SetPreviousSibling(previous_sibling); |
| new_child->SetNextSibling(before_child); |
| before_child->SetPreviousSibling(new_child); |
| } else { |
| if (LastChild()) |
| LastChild()->SetNextSibling(new_child); |
| new_child->SetPreviousSibling(LastChild()); |
| last_child_ = new_child; |
| } |
| |
| if (!owner->DocumentBeingDestroyed() && notify_layout_object) { |
| new_child->InsertedIntoTree(); |
| LayoutCounter::LayoutObjectSubtreeAttached(new_child); |
| } |
| |
| // Propagate the need to notify ancestors down into any |
| // child nodes. |
| if (owner->HasSubtreeChangeListenerRegistered()) |
| new_child->RegisterSubtreeChangeListenerOnDescendants(true); |
| |
| // If the inserted node is currently marked as needing to notify children then |
| // we have to propagate that mark up the tree. |
| if (new_child->WasNotifiedOfSubtreeChange()) |
| owner->NotifyAncestorsOfSubtreeChange(); |
| |
| new_child->SetNeedsLayoutAndPrefWidthsRecalc( |
| LayoutInvalidationReason::kAddedToLayout); |
| new_child->SetShouldDoFullPaintInvalidation( |
| PaintInvalidationReason::kAppeared); |
| new_child->SetSubtreeNeedsPaintPropertyUpdate(); |
| if (!owner->NormalChildNeedsLayout()) |
| owner->SetChildNeedsLayout(); // We may supply the static position for an |
| // absolute positioned child. |
| |
| if (!owner->DocumentBeingDestroyed()) |
| owner->NotifyOfSubtreeChange(); |
| |
| if (AXObjectCache* cache = owner->GetDocument().AxObjectCache()) |
| cache->ChildrenChanged(owner); |
| } |
| |
| void LayoutObjectChildList::InvalidatePaintOnRemoval(LayoutObject& old_child) { |
| if (!old_child.IsRooted()) |
| return; |
| if (old_child.IsBody() && old_child.View()) |
| old_child.View()->SetShouldDoFullPaintInvalidation(); |
| ObjectPaintInvalidator paint_invalidator(old_child); |
| paint_invalidator.SlowSetPaintingLayerNeedsRepaint(); |
| |
| // For SPv2 raster invalidation will be done in PaintController. |
| if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) |
| return; |
| |
| paint_invalidator.InvalidatePaintOfPreviousVisualRect( |
| old_child.ContainerForPaintInvalidation(), |
| PaintInvalidationReason::kDisappeared); |
| } |
| |
| } // namespace blink |