/*
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2007 David Smith (catfish.man@gmail.com)
 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc.
 *               All rights reserved.
 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "third_party/blink/renderer/core/layout/layout_block.h"

#include <algorithm>
#include <memory>
#include <utility>

#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver.h"
#include "third_party/blink/renderer/core/css/style_engine.h"
#include "third_party/blink/renderer/core/display_lock/display_lock_utilities.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/dom/element.h"
#include "third_party/blink/renderer/core/editing/drag_caret.h"
#include "third_party/blink/renderer/core/editing/editing_utilities.h"
#include "third_party/blink/renderer/core/editing/frame_selection.h"
#include "third_party/blink/renderer/core/editing/ime/input_method_controller.h"
#include "third_party/blink/renderer/core/editing/text_affinity.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/html/html_marquee_element.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/layout/constraint_space.h"
#include "third_party/blink/renderer/core/layout/disable_layout_side_effects_scope.h"
#include "third_party/blink/renderer/core/layout/flex/layout_flexible_box.h"
#include "third_party/blink/renderer/core/layout/grid/layout_grid.h"
#include "third_party/blink/renderer/core/layout/grid_lanes/layout_grid_lanes.h"
#include "third_party/blink/renderer/core/layout/hit_test_location.h"
#include "third_party/blink/renderer/core/layout/hit_test_result.h"
#include "third_party/blink/renderer/core/layout/layout_block_flow.h"
#include "third_party/blink/renderer/core/layout/layout_inline.h"
#include "third_party/blink/renderer/core/layout/layout_object_inlines.h"
#include "third_party/blink/renderer/core/layout/layout_theme.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/layout/length_utils.h"
#include "third_party/blink/renderer/core/layout/mathml/layout_mathml_block.h"
#include "third_party/blink/renderer/core/layout/physical_box_fragment.h"
#include "third_party/blink/renderer/core/layout/svg/layout_svg_text.h"
#include "third_party/blink/renderer/core/page/page.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_controller.h"
#include "third_party/blink/renderer/core/paint/block_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/box_fragment_painter.h"
#include "third_party/blink/renderer/core/paint/object_paint_invalidator.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/platform/runtime_enabled_features.h"
#include "third_party/blink/renderer/platform/wtf/size_assertions.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"

namespace blink {

struct SameSizeAsLayoutBlock : public LayoutBox {
  LayoutObjectChildList children;
};

ASSERT_SIZE(LayoutBlock, SameSizeAsLayoutBlock);

LayoutBlock::LayoutBlock(ContainerNode* node) : LayoutBox(node) {
  // LayoutBlockFlow calls setChildrenInline(true).
  // By default, subclasses do not have inline children.
}

void LayoutBlock::Trace(Visitor* visitor) const {
  visitor->Trace(children_);
  LayoutBox::Trace(visitor);
}

void LayoutBlock::WillBeDestroyed(const ComputedStyle* style) {
  NOT_DESTROYED();

  if (LocalFrame* frame = GetFrame()) {
    frame->Selection().LayoutBlockWillBeDestroyed(*this);
    frame->GetPage()->GetDragCaret().LayoutBlockWillBeDestroyed(*this);
  }
  LayoutBox::WillBeDestroyed(style);
}

// Compute a local version of the "font size scale factor" used by SVG
// <text>. Squared to avoid computing the square root. See
// SVGLayoutSupport::CalculateScreenFontSizeScalingFactor().
static double ComputeSquaredLocalFontSizeScalingFactor(
    const gfx::Transform* transform) {
  if (!transform)
    return 1;
  const auto affine = AffineTransform::FromTransform(*transform);
  return affine.XScaleSquared() + affine.YScaleSquared();
}

void LayoutBlock::StyleDidChange(
    StyleDifference diff,
    const ComputedStyle* old_style,
    const ComputedStyle& new_style,
    const StyleChangeContext& style_change_context) {
  NOT_DESTROYED();
  // Computes old scaling factor before PaintLayer::UpdateTransform()
  // updates Layer()->Transform().
  double old_squared_scale = 1;
  if (Layer() && diff.transform_changed && HasSVGTextDescendants()) {
    old_squared_scale =
        ComputeSquaredLocalFontSizeScalingFactor(Layer()->Transform());
  }

  LayoutBox::StyleDidChange(diff, old_style, new_style, style_change_context);

  if (old_style && Parent()) {
    if (old_style->GetPosition() != new_style.GetPosition() &&
        new_style.GetPosition() != EPosition::kStatic) {
      // In LayoutObject::styleWillChange() we already removed ourself from our
      // old containing block's positioned descendant list, and we will be
      // inserted to the new containing block's list during layout. However the
      // positioned descendant layout logic assumes layout objects to obey
      // parent-child order in the list. Remove our descendants here so they
      // will be re-inserted after us.
      if (LayoutBlock* cb = ContainingBlock()) {
        cb->RemovePositionedObjects(this);
      }
    }
  }

  PropagateStyleToAnonymousChildren();

  if (diff.transform_changed && HasSVGTextDescendants()) {
    const double new_squared_scale = ComputeSquaredLocalFontSizeScalingFactor(
        Layer() ? Layer()->Transform() : nullptr);
    // Compare local scale before and after.
    if (old_squared_scale != new_squared_scale) {
      bool stacking_context_changed =
          old_style &&
          (IsStackingContext(*old_style) != IsStackingContext(new_style));
      for (LayoutBox* box : *View()->SvgTextDescendantsMap().at(this)) {
        To<LayoutSVGText>(box)->SetNeedsTextMetricsUpdate();
        if (GetNode() == GetDocument().documentElement() ||
            stacking_context_changed) {
          box->SetNeedsLayout(layout_invalidation_reason::kStyleChange);
        }
      }
    }
  }
}

bool LayoutBlock::RespectsCSSOverflow() const {
  NOT_DESTROYED();
  // If overflow has been propagated to the viewport, it has no effect here.
  return GetNode() != GetDocument().ViewportDefiningElement();
}

void LayoutBlock::AddChildBeforeDescendant(LayoutObject* new_child,
                                           LayoutObject* before_descendant) {
  NOT_DESTROYED();
  DCHECK(!IsLayoutBlockFlow());
  DCHECK_NE(before_descendant->Parent(), this);

  if (!new_child->IsInline() && !new_child->IsTablePart()) {
    LayoutObject* before_child =
        SplitAnonymousBoxesAroundChild(before_descendant);

    DCHECK_EQ(before_child->Parent(), this);
    AddChild(new_child, before_child);
    return;
  }

  LayoutObject* before_descendant_container = before_descendant->Parent();
  while (before_descendant_container->Parent() != this) {
    before_descendant_container = before_descendant_container->Parent();
  }
  CHECK(before_descendant_container->IsAnonymous());
  CHECK(before_descendant_container->IsLayoutBlockFlow());

  // Insert the child into the anonymous block-flow instead of here.
  before_descendant_container->AddChild(new_child, before_descendant);
}

void LayoutBlock::AddChild(LayoutObject* new_child,
                           LayoutObject* before_child) {
  NOT_DESTROYED();
  if (before_child && before_child->Parent() != this) {
    AddChildBeforeDescendant(new_child, before_child);
    return;
  }

  // Only LayoutBlockFlow should have inline children, and then we shouldn't be
  // here.
  DCHECK(!ChildrenInline());

  if (new_child->IsInline() || new_child->IsTablePart()) {
    // If we're inserting an inline child but all of our children are blocks,
    // then we have to make sure it is put into an anomyous block box. We try to
    // use an existing anonymous box if possible, otherwise a new one is created
    // and inserted into our list of children in the appropriate position.
    LayoutObject* after_child =
        before_child ? before_child->PreviousSibling() : LastChild();

    if (after_child && after_child->IsAnonymousBlockFlow()) {
      after_child->AddChild(new_child);
      return;
    }

    // No suitable existing anonymous box - create a new one.
    LayoutBlock* new_box = CreateAnonymousBlock();
    LayoutBox::AddChild(new_box, before_child);
    new_box->AddChild(new_child);
    return;
  }

  LayoutBox::AddChild(new_child, before_child);
}

void LayoutBlock::Paint(const PaintInfo& paint_info) const {
  NOT_DESTROYED();

  // When |this| is NG block fragmented, the painter should traverse fragments
  // instead of |LayoutObject|, because this function cannot handle block
  // fragmented objects. We can come here only when |this| cannot traverse
  // fragments, or the parent is legacy.
  DCHECK(IsMonolithic() || !CanTraversePhysicalFragments() ||
         !Parent()->CanTraversePhysicalFragments());
  // We may get here in multiple-fragment cases if the object is repeated
  // (inside table headers and footers, for instance).
  DCHECK(PhysicalFragmentCount() <= 1u ||
         GetPhysicalFragment(0)->GetBreakToken()->IsRepeated());

  // Avoid painting dirty objects because descendants maybe already destroyed.
  if (NeedsLayout() && !ChildLayoutBlockedByDisplayLock()) [[unlikely]] {
    DUMP_WILL_BE_NOTREACHED();
    return;
  }

  if (PhysicalFragmentCount()) {
    const PhysicalBoxFragment* fragment = GetPhysicalFragment(0);
    DCHECK(fragment);
    BoxFragmentPainter(*fragment).Paint(paint_info);
    return;
  }

  NOTREACHED();
}

void LayoutBlock::InvalidatePaint(
    const PaintInvalidatorContext& context) const {
  NOT_DESTROYED();
  BlockPaintInvalidator(*this).InvalidatePaint(context);
}

void LayoutBlock::ImageChanged(WrappedImagePtr image,
                               CanDeferInvalidation defer) {
  NOT_DESTROYED();
  LayoutBox::ImageChanged(image, defer);

  if (!StyleRef().HasPseudoElementStyle(kPseudoIdFirstLine))
    return;

  const auto* first_line_style =
      StyleRef().GetCachedPseudoElementStyle(kPseudoIdFirstLine);
  if (!first_line_style)
    return;
  if (auto* first_line_container = NearestInnerBlockWithFirstLine()) {
    for (const auto* layer = &first_line_style->BackgroundLayers(); layer;
         layer = layer->Next()) {
      if (layer->GetImage() && image == layer->GetImage()->Data()) {
        first_line_container->SetShouldDoFullPaintInvalidationForFirstLine();
        break;
      }
    }
  }
}

void LayoutBlock::RemovePositionedObjects(LayoutObject* stay_within) {
  NOT_DESTROYED();

  auto ProcessPositionedObjectRemoval = [&](LayoutObject* positioned_object) {
    if (stay_within && (!positioned_object->IsDescendantOf(stay_within) ||
                        stay_within == positioned_object)) {
      return false;
    }

    positioned_object->SetChildNeedsLayout(kMarkOnlyThis);

    // It is parent blocks job to add positioned child to positioned objects
    // list of its containing block.
    // Parent layout needs to be invalidated to ensure this happens.
    positioned_object->MarkParentForSpannerOrOutOfFlowPositionedChange();
    return true;
  };

  bool has_positioned_children_in_fragment_tree = false;

  // PositionedObjects() is populated in legacy, and in NG when inside a
  // fragmentation context root. But in other NG cases it's empty as an
  // optimization, since we can just look at the children in the fragment tree.
  for (const PhysicalBoxFragment& fragment : PhysicalFragments()) {
    if (!fragment.HasOutOfFlowFragmentChild()) {
      continue;
    }
    for (const PhysicalFragmentLink& fragment_child : fragment.Children()) {
      if (!fragment_child->IsOutOfFlowPositioned()) {
        continue;
      }
      if (LayoutObject* child = fragment_child->GetMutableLayoutObject()) {
        if (ProcessPositionedObjectRemoval(child)) {
          has_positioned_children_in_fragment_tree = true;
        }
      }
    }
  }

  // Invalidate the nearest OOF container to ensure it is marked for layout.
  // Fixed containing blocks are always absolute containing blocks too,
  // so we only need to look for absolute containing blocks.
  if (has_positioned_children_in_fragment_tree) {
    if (LayoutBlock* containing_block = ContainingBlockForAbsolutePosition())
      containing_block->SetChildNeedsLayout(kMarkContainerChain);
  }
}

void LayoutBlock::AddSvgTextDescendant(LayoutSVGText& svg_text) {
  NOT_DESTROYED();
  auto result = View()->SvgTextDescendantsMap().insert(this, nullptr);
  if (result.is_new_entry) {
    result.stored_value->value =
        MakeGarbageCollected<GCedHeapHashSet<Member<LayoutSVGText>>>();
  }
  result.stored_value->value->insert(&svg_text);
  SetHasSVGTextDescendants(true);
}

void LayoutBlock::RemoveSvgTextDescendant(LayoutSVGText& svg_text) {
  NOT_DESTROYED();
  auto& map = View()->SvgTextDescendantsMap();
  auto it = map.find(this);
  if (it == map.end())
    return;
  GCedHeapHashSet<Member<LayoutSVGText>>& descendants = *it->value;
  descendants.erase(&svg_text);
  if (descendants.empty()) {
    map.erase(this);
    SetHasSVGTextDescendants(false);
  }
}

LayoutUnit LayoutBlock::TextIndentOffset() const {
  NOT_DESTROYED();
  const ComputedStyle& style = StyleRef();
  const Length& length = style.TextIndent();
  if (length.IsZero() || style.IsTextIndentHanging()) {
    return LayoutUnit();
  }
  LayoutUnit cw;
  if (length.HasPercent()) {
    cw = ContentLogicalWidth();
  }
  return MinimumValueForLength(length, cw);
}

bool LayoutBlock::NodeAtPoint(HitTestResult& result,
                              const HitTestLocation& hit_test_location,
                              const PhysicalOffset& accumulated_offset,
                              HitTestPhase phase) {
  NOT_DESTROYED();

  // We may get here in multiple-fragment cases if the object is repeated
  // (inside table headers and footers, for instance).
  DCHECK(PhysicalFragmentCount() <= 1u ||
         GetPhysicalFragment(0)->GetBreakToken()->IsRepeated());

  if (!MayIntersect(result, hit_test_location, accumulated_offset)) {
    return false;
  }

  if (PhysicalFragmentCount()) {
    const PhysicalBoxFragment* fragment = GetPhysicalFragment(0);
    DCHECK(fragment);
    return BoxFragmentPainter(*fragment).NodeAtPoint(result, hit_test_location,
                                                     accumulated_offset, phase);
  }

  return false;
}

namespace {

// Returns true if the editability of |box| differs from that of its closest
// ancestor that has a node, i.e. |box| is an editing boundary.
bool IsEditingBoundary(const LayoutBox& box) {
  const Node* node = box.NonPseudoNode();
  if (!node) {
    return false;
  }
  const LayoutObject* parent = box.Parent();
  if (!parent) {
    return false;
  }
  const Node* parent_node = parent->GeneratingNode();
  if (!parent_node) {
    return false;
  }
  return IsEditable(*node) != IsEditable(*parent_node);
}

}  // namespace

PositionWithAffinity LayoutBlock::PositionForPointIfOutsideAtomicInlineLevel(
    const PhysicalOffset& point) const {
  NOT_DESTROYED();
  DCHECK(IsInline());
  LogicalOffset logical_offset =
      WritingModeConverter({StyleRef().GetWritingMode(), ResolvedDirection()},
                           StitchedSize())
          .ToLogical(point, PhysicalSize());

  // Which side did |point| miss on? The inline direction takes precedence over
  // the block direction.
  bool before;
  if (logical_offset.inline_offset < 0) {
    before = true;
  } else if (logical_offset.inline_offset >= LogicalWidth()) {
    before = false;
  } else if (logical_offset.block_offset < 0) {
    before = true;
  } else if (logical_offset.block_offset >= LogicalHeight()) {
    before = false;
  } else {
    // |point| is inside; let the caller resolve the position normally.
    return PositionWithAffinity();
  }

  // At an editing boundary the position must stay outside, or clicking next to
  // <div contenteditable style="display:inline-block"> pulls focus into it; the
  // LayoutObject position helpers all resolve back inside, so anchor on the
  // parent instead.
  if (IsEditingBoundary(*this) &&
      RuntimeEnabledFeatures::CaretOutsideEditableAtomicInlineEnabled()) {
    const Node* node = NonPseudoNode();
    DCHECK(node);
    const Position position =
        before ? Position::BeforeNode(*node) : Position::AfterNode(*node);
    // Re-anchor onto the parent; this box itself is the editing boundary.
    const Position position_in_parent = position.ToOffsetInAnchor();
    if (position_in_parent.IsNotNull()) {
      return PositionWithAffinity(position_in_parent);
    }
  }
  return before ? FirstPositionInOrBeforeThis() : LastPositionInOrAfterThis();
}

PositionWithAffinity LayoutBlock::PositionForPoint(
    const PhysicalOffset& point) const {
  NOT_DESTROYED();
  // NG codepath requires |kPrePaintClean|.
  // |SelectionModifier| calls this only in legacy codepath.
  DCHECK(GetDocument().Lifecycle().GetState() >=
         DocumentLifecycle::kPrePaintClean);

  if (IsInline()) {
    PositionWithAffinity position =
        PositionForPointIfOutsideAtomicInlineLevel(point);
    if (!position.IsNull())
      return position;
  }

  if (PhysicalFragmentCount()) {
    return PositionForPointInFragments(point);
  }

  return LayoutBox::PositionForPoint(point);
}

bool LayoutBlock::HasLineIfEmpty() const {
  NOT_DESTROYED();
  if (GetNode()) {
    if (IsRootEditableElement(*GetNode()))
      return true;
  }
  return FirstLineStyleRef().HasLineIfEmpty();
}

const LayoutBlock* LayoutBlock::FirstLineStyleParentBlock() const {
  NOT_DESTROYED();
  const LayoutBlock* first_line_block = this;
  // Inline blocks do not get ::first-line style from its containing blocks.
  if (IsInline()) {
    return nullptr;
  }
  // Floats and out of flow blocks do not get ::first-line style from its
  // containing blocks.
  if (IsFloatingOrOutOfFlowPositioned())
    return nullptr;

  LayoutObject* parent_block = first_line_block->Parent();
  if (!parent_block || !parent_block->BehavesLikeBlockContainer())
    return nullptr;

  const LayoutBlock* parent_layout_block = To<LayoutBlock>(parent_block);

  // If we are not the first in-flow child of our parent, we cannot get
  // ::first-line style from our ancestors.
  const LayoutObject* first_child = parent_layout_block->FirstChild();
  while (first_child->IsFloatingOrOutOfFlowPositioned() ||
         (RuntimeEnabledFeatures::FirstLineOnListItemEnabled() &&
          first_child->IsListMarker())) {
    first_child = first_child->NextSibling();
  }
  if (first_child != first_line_block)
    return nullptr;

  return parent_layout_block;
}

LayoutBlockFlow* LayoutBlock::NearestInnerBlockWithFirstLine() {
  NOT_DESTROYED();
  if (ChildrenInline())
    return To<LayoutBlockFlow>(this);
  for (LayoutObject* child = FirstChild();
       child && !child->IsFloatingOrOutOfFlowPositioned() &&
       child->IsLayoutBlockFlow();
       child = To<LayoutBlock>(child)->FirstChild()) {
    if (child->ChildrenInline())
      return To<LayoutBlockFlow>(child);
  }
  return nullptr;
}

// An inline-block uses its inlineBox as the inlineBoxWrapper,
// so the firstChild() is nullptr if the only child is an empty inline-block.
inline bool LayoutBlock::IsInlineBoxWrapperActuallyChild() const {
  NOT_DESTROYED();
  return IsInline() && !StitchedSize().IsEmpty() && GetNode() &&
         EditingIgnoresContent(*GetNode());
}

PhysicalRect LayoutBlock::LocalCaretRect(int caret_offset,
                                         CaretShape caret_shape) const {
  NOT_DESTROYED();
  // Do the normal calculation in most cases.
  if ((FirstChild() && !FirstChild()->IsPseudoElement()) ||
      IsInlineBoxWrapperActuallyChild()) {
    return LayoutBox::LocalCaretRect(caret_offset, caret_shape);
  }

  const ComputedStyle& style = StyleRef();
  const bool is_horizontal = style.IsHorizontalWritingMode();

  PhysicalSize stitched_size = StitchedSize();
  LayoutUnit inline_size =
      is_horizontal ? stitched_size.width : stitched_size.height;
  LogicalRect caret_rect = LocalCaretRectForEmptyElement(
      inline_size, TextIndentOffset(), caret_shape);
  return CreateWritingModeConverter().ToPhysical(caret_rect);
}

void LayoutBlock::AddOutlineRects(OutlineRectCollector& collector,
                                  OutlineInfo* info,
                                  const PhysicalOffset& additional_offset,
                                  OutlineType include_block_overflows) const {
  NOT_DESTROYED();
#if DCHECK_IS_ON()
  // TODO(crbug.com/987836): enable this DCHECK universally.
  Page* page = GetDocument().GetPage();
  if (page && !page->GetSettings().GetSpatialNavigationEnabled()) {
    DCHECK_GE(GetDocument().Lifecycle().GetState(),
              DocumentLifecycle::kAfterPerformLayout);
  }
#endif  // DCHECK_IS_ON()

  // For anonymous blocks, the children add outline rects.
  if (!IsAnonymous()) {
    collector.AddRect(PhysicalRect(additional_offset, StitchedSize()));
  }

  if (ShouldIncludeBlockInkOverflow(include_block_overflows) &&
      !HasNonVisibleOverflow()) {
    AddOutlineRectsForNormalChildren(collector, additional_offset,
                                     include_block_overflows);
  }
  if (info)
    *info = OutlineInfo::GetFromStyle(StyleRef());
}

LayoutBox* LayoutBlock::CreateAnonymousBoxWithSameTypeAs(
    const LayoutObject* parent) const {
  NOT_DESTROYED();
  return CreateAnonymousWithParentAndDisplay(parent, StyleRef().Display());
}

const char* LayoutBlock::GetName() const {
  NOT_DESTROYED();
  NOTREACHED();
}

LayoutBlock* LayoutBlock::CreateAnonymousWithParentAndDisplay(
    const LayoutObject* parent,
    EDisplay display) {
  // TODO(layout-dev): Do we need to convert all our inline displays to block
  // type in the anonymous logic?
  EDisplay new_display;
  switch (display) {
    case EDisplay::kFlex:
    case EDisplay::kInlineFlex:
      new_display = EDisplay::kFlex;
      break;
    case EDisplay::kGrid:
    case EDisplay::kInlineGrid:
      new_display = EDisplay::kGrid;
      break;
    case EDisplay::kGridLanes:
    case EDisplay::kInlineGridLanes:
      new_display = EDisplay::kGridLanes;
      break;
    case EDisplay::kFlowRoot:
      new_display = EDisplay::kFlowRoot;
      break;
    case EDisplay::kBlockMath:
      new_display = EDisplay::kBlockMath;
      break;
    default:
      new_display = EDisplay::kBlock;
      break;
  }
  ComputedStyleBuilder new_style_builder =
      parent->GetDocument()
          .GetStyleResolver()
          .CreateAnonymousStyleBuilderWithDisplay(parent->StyleRef(),
                                                  new_display);

  parent->UpdateAnonymousChildStyle(nullptr, new_style_builder);
  const ComputedStyle* new_style = new_style_builder.TakeStyle();

  LayoutBlock* layout_block;
  if (new_display == EDisplay::kFlex) {
    layout_block = MakeGarbageCollected<LayoutFlexibleBox>(/*element=*/nullptr);
  } else if (new_display == EDisplay::kGrid) {
    layout_block = MakeGarbageCollected<LayoutGrid>(/*element=*/nullptr);
  } else if (new_display == EDisplay::kGridLanes) {
    layout_block = MakeGarbageCollected<LayoutGridLanes>(/*element=*/nullptr);
  } else if (new_display == EDisplay::kBlockMath) {
    layout_block = MakeGarbageCollected<LayoutMathMLBlock>(/*element=*/nullptr);
  } else {
    DCHECK(new_display == EDisplay::kBlock ||
           new_display == EDisplay::kFlowRoot);
    layout_block = MakeGarbageCollected<LayoutBlockFlow>(nullptr);
  }
  layout_block->SetDocumentForAnonymous(parent->GetDocument());
  layout_block->SetStyle(new_style);
  return layout_block;
}

RecalcScrollableOverflowResult LayoutBlock::RecalcScrollableOverflow() {
  NOT_DESTROYED();
  DCHECK(!DisableLayoutSideEffectsScope::IsDisabled());
  return RecalcScrollableOverflowNG();
}

void LayoutBlock::RecalcVisualOverflow() {
  NOT_DESTROYED();
  if (!PhysicalFragmentCount()) {
    ClearVisualOverflow();
    return;
  }

  DCHECK(CanUseFragmentsForVisualOverflow());
  DCHECK(!DisplayLockUtilities::LockedAncestorPreventingPrePaint(*this));
  for (const PhysicalBoxFragment& fragment : PhysicalFragments()) {
    DCHECK(fragment.CanUseFragmentsForInkOverflow());
    fragment.GetMutableForPainting().RecalcInkOverflow();
  }
}

}  // namespace blink
