blob: 708a37cfc79ac6235b9a2b5bf98799e370fcaf32 [file] [log] [blame]
/*
* 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();
// Clear NeedsCollectInlines to ensure the marking doesn't stop on
// |new_child|.
new_child->ClearNeedsCollectInlines();
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.
} else {
owner->MarkContainerNeedsCollectInlines();
}
if (!owner->DocumentBeingDestroyed())
owner->NotifyOfSubtreeChange();
if (AXObjectCache* cache = owner->GetDocument().GetOrCreateAXObjectCache())
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 SPv175 raster invalidation will be done in PaintController.
if (RuntimeEnabledFeatures::SlimmingPaintV175Enabled())
return;
paint_invalidator.InvalidatePaintOfPreviousVisualRect(
old_child.ContainerForPaintInvalidation(),
PaintInvalidationReason::kDisappeared);
}
} // namespace blink