/*
 * 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 Apple Inc. 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.
 */

#ifndef LayoutBlock_h
#define LayoutBlock_h

#include "core/CoreExport.h"
#include "core/layout/LayoutBox.h"
#include "wtf/ListHashSet.h"
#include <memory>

namespace blink {

struct PaintInfo;
class LineLayoutBox;
class WordMeasurement;

typedef WTF::ListHashSet<LayoutBox*, 16> TrackedLayoutBoxListHashSet;
typedef WTF::HashMap<const LayoutBlock*,
                     std::unique_ptr<TrackedLayoutBoxListHashSet>>
    TrackedDescendantsMap;
typedef WTF::HashMap<const LayoutBox*, LayoutBlock*> TrackedContainerMap;
typedef Vector<WordMeasurement, 64> WordMeasurements;

enum ContainingBlockState { NewContainingBlock, SameContainingBlock };

// LayoutBlock is the class that is used by any LayoutObject
// that is a containing block.
// http://www.w3.org/TR/CSS2/visuren.html#containing-block
// See also LayoutObject::containingBlock() that is the function
// used to get the containing block of a LayoutObject.
//
// CSS is inconsistent and allows inline elements (LayoutInline) to be
// containing blocks, even though they are not blocks. Our
// implementation is as confused with inlines. See e.g.
// LayoutObject::containingBlock() vs LayoutObject::container().
//
// Containing blocks are a central concept for layout, in
// particular to the layout of out-of-flow positioned
// elements. They are used to determine the sizing as well
// as the positioning of the LayoutObjects.
//
// LayoutBlock is the class that handles out-of-flow positioned elements in
// Blink, in particular for layout (see layoutPositionedObjects()). That's why
// LayoutBlock keeps track of them through |gPositionedDescendantsMap| (see
// LayoutBlock.cpp).
// Note that this is a design decision made in Blink that doesn't reflect CSS:
// CSS allows relatively positioned inlines (LayoutInline) to be containing
// blocks, but they don't have the logic to handle out-of-flow positioned
// objects. This induces some complexity around choosing an enclosing
// LayoutBlock (for inserting out-of-flow objects during layout) vs the CSS
// containing block (for sizing, invalidation).
//
//
// ***** WHO LAYS OUT OUT-OF-FLOW POSITIONED OBJECTS? *****
// A positioned object gets inserted into an enclosing LayoutBlock's positioned
// map. This is determined by LayoutObject::containingBlock().
//
//
// ***** HANDLING OUT-OF-FLOW POSITIONED OBJECTS *****
// Care should be taken to handle out-of-flow positioned objects during
// certain tree walks (e.g. layout()). The rule is that anything that
// cares about containing blocks should skip the out-of-flow elements
// in the normal tree walk and do an optional follow-up pass for them
// using LayoutBlock::positionedObjects().
// Not doing so will result in passing the wrong containing
// block as tree walks will always pass the parent as the
// containing block.
//
// Sample code of how to handle positioned objects in LayoutBlock:
//
// for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
//     if (child->isOutOfFlowPositioned())
//         continue;
//
//     // Handle normal flow children.
//     ...
// }
// for (LayoutBox* positionedObject : positionedObjects()) {
//     // Handle out-of-flow positioned objects.
//     ...
// }
class CORE_EXPORT LayoutBlock : public LayoutBox {
 protected:
  explicit LayoutBlock(ContainerNode*);
  ~LayoutBlock() override;

 public:
  LayoutObject* firstChild() const {
    ASSERT(children() == virtualChildren());
    return children()->firstChild();
  }
  LayoutObject* lastChild() const {
    ASSERT(children() == virtualChildren());
    return children()->lastChild();
  }

  // If you have a LayoutBlock, use firstChild or lastChild instead.
  void slowFirstChild() const = delete;
  void slowLastChild() const = delete;

  const LayoutObjectChildList* children() const { return &m_children; }
  LayoutObjectChildList* children() { return &m_children; }

  // These two functions are overridden for inline-block.
  LayoutUnit lineHeight(
      bool firstLine,
      LineDirectionMode,
      LinePositionMode = PositionOnContainingLine) const final;
  int baselinePosition(
      FontBaseline,
      bool firstLine,
      LineDirectionMode,
      LinePositionMode = PositionOnContainingLine) const override;

  LayoutUnit minLineHeightForReplacedObject(bool isFirstLine,
                                            LayoutUnit replacedHeight) const;

  bool createsNewFormattingContext() const;

  const char* name() const override;

 protected:
  // Insert a child correctly into the tree when |beforeDescendant| isn't a direct child of
  // |this|. This happens e.g. when there's an anonymous block child of |this| and
  // |beforeDescendant| has been reparented into that one. Such things are invisible to the DOM,
  // and addChild() is typically called with the DOM tree (and not the layout tree) in mind.
  void addChildBeforeDescendant(LayoutObject* newChild,
                                LayoutObject* beforeDescendant);

 public:
  void addChild(LayoutObject* newChild,
                LayoutObject* beforeChild = nullptr) override;

  virtual void layoutBlock(bool relayoutChildren);

  void insertPositionedObject(LayoutBox*);
  static void removePositionedObject(LayoutBox*);
  void removePositionedObjects(LayoutObject*,
                               ContainingBlockState = SameContainingBlock);

  TrackedLayoutBoxListHashSet* positionedObjects() const {
    return hasPositionedObjects() ? positionedObjectsInternal() : nullptr;
  }
  bool hasPositionedObjects() const {
    ASSERT(m_hasPositionedObjects ? (positionedObjectsInternal() &&
                                     !positionedObjectsInternal()->isEmpty())
                                  : !positionedObjectsInternal());
    return m_hasPositionedObjects;
  }

  void addPercentHeightDescendant(LayoutBox*);
  void removePercentHeightDescendant(LayoutBox*);
  bool hasPercentHeightDescendant(LayoutBox* o) const {
    return hasPercentHeightDescendants() &&
           percentHeightDescendantsInternal()->contains(o);
  }

  TrackedLayoutBoxListHashSet* percentHeightDescendants() const {
    return hasPercentHeightDescendants() ? percentHeightDescendantsInternal()
                                         : nullptr;
  }
  bool hasPercentHeightDescendants() const {
    ASSERT(m_hasPercentHeightDescendants
               ? (percentHeightDescendantsInternal() &&
                  !percentHeightDescendantsInternal()->isEmpty())
               : !percentHeightDescendantsInternal());
    return m_hasPercentHeightDescendants;
  }

  void notifyScrollbarThicknessChanged() {
    m_widthAvailableToChildrenChanged = true;
  }

  void setHasMarkupTruncation(bool b) { m_hasMarkupTruncation = b; }
  bool hasMarkupTruncation() const { return m_hasMarkupTruncation; }

  void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
  void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }

  bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
  bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }

  bool hasMarginBeforeQuirk(const LayoutBox* child) const;
  bool hasMarginAfterQuirk(const LayoutBox* child) const;

  void markPositionedObjectsForLayout();

  LayoutUnit textIndentOffset() const;

  PositionWithAffinity positionForPoint(const LayoutPoint&) override;

  LayoutUnit blockDirectionOffset(const LayoutSize& offsetFromBlock) const;
  LayoutUnit inlineDirectionOffset(const LayoutSize& offsetFromBlock) const;

  LayoutBlock* blockBeforeWithinSelectionRoot(LayoutSize& offset) const;

  void setSelectionState(SelectionState) override;

  static LayoutBlock* createAnonymousWithParentAndDisplay(
      const LayoutObject*,
      EDisplay = EDisplay::Block);
  LayoutBlock* createAnonymousBlock(EDisplay display = EDisplay::Block) const {
    return createAnonymousWithParentAndDisplay(this, display);
  }

  LayoutBox* createAnonymousBoxWithSameTypeAs(
      const LayoutObject* parent) const override;

  int columnGap() const;

  // Accessors for logical width/height and margins in the containing block's block-flow direction.
  LayoutUnit logicalWidthForChild(const LayoutBox& child) const {
    return logicalWidthForChildSize(child.size());
  }
  LayoutUnit logicalWidthForChildSize(LayoutSize childSize) const {
    return isHorizontalWritingMode() ? childSize.width() : childSize.height();
  }
  LayoutUnit logicalHeightForChild(const LayoutBox& child) const {
    return isHorizontalWritingMode() ? child.size().height()
                                     : child.size().width();
  }
  LayoutSize logicalSizeForChild(const LayoutBox& child) const {
    return isHorizontalWritingMode() ? child.size()
                                     : child.size().transposedSize();
  }
  LayoutUnit logicalTopForChild(const LayoutBox& child) const {
    return isHorizontalWritingMode() ? child.location().y()
                                     : child.location().x();
  }
  DISABLE_CFI_PERF LayoutUnit
  marginBeforeForChild(const LayoutBoxModelObject& child) const {
    return child.marginBefore(style());
  }
  DISABLE_CFI_PERF LayoutUnit
  marginAfterForChild(const LayoutBoxModelObject& child) const {
    return child.marginAfter(style());
  }
  DISABLE_CFI_PERF LayoutUnit
  marginStartForChild(const LayoutBoxModelObject& child) const {
    return child.marginStart(style());
  }
  LayoutUnit marginEndForChild(const LayoutBoxModelObject& child) const {
    return child.marginEnd(style());
  }
  void setMarginStartForChild(LayoutBox& child, LayoutUnit value) const {
    child.setMarginStart(value, style());
  }
  void setMarginEndForChild(LayoutBox& child, LayoutUnit value) const {
    child.setMarginEnd(value, style());
  }
  void setMarginBeforeForChild(LayoutBox& child, LayoutUnit value) const {
    child.setMarginBefore(value, style());
  }
  void setMarginAfterForChild(LayoutBox& child, LayoutUnit value) const {
    child.setMarginAfter(value, style());
  }
  LayoutUnit collapsedMarginBeforeForChild(const LayoutBox& child) const;
  LayoutUnit collapsedMarginAfterForChild(const LayoutBox& child) const;

  virtual void scrollbarsChanged(bool /*horizontalScrollbarChanged*/,
                                 bool /*verticalScrollbarChanged*/);

  LayoutUnit availableLogicalWidthForContent() const {
    return (logicalRightOffsetForContent() - logicalLeftOffsetForContent())
        .clampNegativeToZero();
  }
  DISABLE_CFI_PERF LayoutUnit logicalLeftOffsetForContent() const {
    return isHorizontalWritingMode() ? borderLeft() + paddingLeft()
                                     : borderTop() + paddingTop();
  }
  LayoutUnit logicalRightOffsetForContent() const {
    return logicalLeftOffsetForContent() + availableLogicalWidth();
  }
  LayoutUnit startOffsetForContent() const {
    return style()->isLeftToRightDirection()
               ? logicalLeftOffsetForContent()
               : logicalWidth() - logicalRightOffsetForContent();
  }
  LayoutUnit endOffsetForContent() const {
    return !style()->isLeftToRightDirection()
               ? logicalLeftOffsetForContent()
               : logicalWidth() - logicalRightOffsetForContent();
  }

  virtual LayoutUnit logicalLeftSelectionOffset(const LayoutBlock* rootBlock,
                                                LayoutUnit position) const;
  virtual LayoutUnit logicalRightSelectionOffset(const LayoutBlock* rootBlock,
                                                 LayoutUnit position) const;

#if ENABLE(ASSERT)
  void checkPositionedObjectsNeedLayout();
#endif

  LayoutUnit availableLogicalHeightForPercentageComputation() const;
  bool hasDefiniteLogicalHeight() const;

 protected:
  bool recalcNormalFlowChildOverflowIfNeeded(LayoutObject*);
  bool recalcPositionedDescendantsOverflowAfterStyleChange();

 public:
  virtual bool recalcChildOverflowAfterStyleChange();
  bool recalcOverflowAfterStyleChange();

  // An example explaining layout tree structure about first-line style:
  // <style>
  //   #enclosingFirstLineStyleBlock::first-line { ... }
  // </style>
  // <div id="enclosingFirstLineStyleBlock">
  //   <div>
  //     <div id="nearestInnerBlockWithFirstLine">
  //       [<span>]first line text[</span>]
  //     </div>
  //   </div>
  // </div>

  // Returns the nearest enclosing block (including this block) that contributes a first-line style to our first line.
  const LayoutBlock* enclosingFirstLineStyleBlock() const;
  // Returns this block or the nearest inner block containing the actual first line.
  LayoutBlockFlow* nearestInnerBlockWithFirstLine();

 protected:
  void willBeDestroyed() override;

  void dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope&);

  void layout() override;

  enum PositionedLayoutBehavior {
    DefaultLayout,
    LayoutOnlyFixedPositionedObjects,
    ForcedLayoutAfterContainingBlockMoved
  };

  void layoutPositionedObjects(bool relayoutChildren,
                               PositionedLayoutBehavior = DefaultLayout);
  void markFixedPositionObjectForLayoutIfNeeded(LayoutObject* child,
                                                SubtreeLayoutScope&);

  LayoutUnit marginIntrinsicLogicalWidthForChild(const LayoutBox& child) const;

  int beforeMarginInLineDirection(LineDirectionMode) const;

  void paint(const PaintInfo&, const LayoutPoint&) const override;

 public:
  virtual void paintObject(const PaintInfo&, const LayoutPoint&) const;
  virtual void paintChildren(const PaintInfo&, const LayoutPoint&) const;

 protected:
  virtual void adjustInlineDirectionLineBounds(
      unsigned /* expansionOpportunityCount */,
      LayoutUnit& /* logicalLeft */,
      LayoutUnit& /* logicalWidth */) const {}

  void computeIntrinsicLogicalWidths(
      LayoutUnit& minLogicalWidth,
      LayoutUnit& maxLogicalWidth) const override;
  void computePreferredLogicalWidths() override;
  void computeChildPreferredLogicalWidths(
      LayoutObject& child,
      LayoutUnit& minPreferredLogicalWidth,
      LayoutUnit& maxPreferredLogicalWidth) const;

  int firstLineBoxBaseline() const override;
  int inlineBlockBaseline(LineDirectionMode) const override;

  // This function disables the 'overflow' check in inlineBlockBaseline.
  // For 'inline-block', CSS says that the baseline is the bottom margin edge
  // if 'overflow' is not visible. But some descendant classes want to ignore
  // this condition.
  virtual bool shouldIgnoreOverflowPropertyForInlineBlockBaseline() const {
    return false;
  }

  bool hitTestOverflowControl(HitTestResult&,
                              const HitTestLocation&,
                              const LayoutPoint& adjustedLocation) override;
  bool hitTestChildren(HitTestResult&,
                       const HitTestLocation& locationInContainer,
                       const LayoutPoint& accumulatedOffset,
                       HitTestAction) override;
  void updateHitTestResult(HitTestResult&, const LayoutPoint&) override;

  void updateAfterLayout();

  void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override;
  void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
  void updateFromStyle() override;

  // Returns true if non-visible overflow should be respected. Otherwise hasOverflowClip() will be
  // false and we won't create scrollable area for this object even if overflow is non-visible.
  virtual bool allowsOverflowClip() const;

  virtual bool hasLineIfEmpty() const;

  bool simplifiedLayout();
  virtual void simplifiedNormalFlowLayout();

 public:
  virtual void computeOverflow(LayoutUnit oldClientAfterEdge, bool = false);

 protected:
  virtual void addOverflowFromChildren();
  void addOverflowFromPositionedObjects();
  void addOverflowFromBlockChildren();
  void addVisualOverflowFromTheme();

  void addOutlineRects(Vector<LayoutRect>&,
                       const LayoutPoint& additionalOffset,
                       IncludeBlockVisualOverflowOrNot) const override;

  void updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, LayoutBox&);

  // TODO(jchaffraix): We should rename this function as inline-flex and inline-grid as also covered.
  // Alternatively it should be removed as we clarify the meaning of isAtomicInlineLevel to imply
  // isInline.
  bool isInlineBlockOrInlineTable() const final {
    return isInline() && isAtomicInlineLevel();
  }

 private:
  LayoutObjectChildList* virtualChildren() final { return children(); }
  const LayoutObjectChildList* virtualChildren() const final {
    return children();
  }

  bool isLayoutBlock() const final { return true; }

  virtual void removeLeftoverAnonymousBlock(LayoutBlock* child);

  TrackedLayoutBoxListHashSet* positionedObjectsInternal() const;
  TrackedLayoutBoxListHashSet* percentHeightDescendantsInternal() const;

  // Returns true if the positioned movement-only layout succeeded.
  bool tryLayoutDoingPositionedMovementOnly();

  bool avoidsFloats() const override { return true; }

  bool isInSelfHitTestingPhase(HitTestAction hitTestAction) const final {
    return hitTestAction == HitTestBlockBackground ||
           hitTestAction == HitTestChildBlockBackground;
  }

  bool isPointInOverflowControl(HitTestResult&,
                                const LayoutPoint& locationInContainer,
                                const LayoutPoint& accumulatedOffset) const;

  void computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth,
                                          LayoutUnit& maxLogicalWidth) const;

  bool isSelectionRoot() const;

 public:
  bool hasCursorCaret() const;
  bool hasDragCaret() const;
  bool hasCaret() const { return hasCursorCaret() || hasDragCaret(); }

 protected:
  PaintInvalidationReason invalidatePaintIfNeeded(
      const PaintInvalidationState&) override;
  PaintInvalidationReason invalidatePaintIfNeeded(
      const PaintInvalidatorContext&) const override;

 private:
  LayoutRect localCaretRect(InlineBox*,
                            int caretOffset,
                            LayoutUnit* extraWidthToEndOfLine = nullptr) final;
  bool isInlineBoxWrapperActuallyChild() const;

  Position positionForBox(InlineBox*, bool start = true) const;

  // End helper functions and structs used by layoutBlockChildren.

  void removeFromGlobalMaps();
  bool widthAvailableToChildrenHasChanged();

 protected:
  bool isPageLogicalHeightKnown(LayoutUnit logicalOffset) const {
    return pageLogicalHeightForOffset(logicalOffset);
  }

  // Returns the logical offset at the top of the next page, for a given offset.
  LayoutUnit nextPageLogicalTop(LayoutUnit logicalOffset) const;

  // Paginated content inside this block was laid out.
  // |logicalBottomOffsetAfterPagination| is the logical bottom offset of the child content after
  // applying any forced or unforced breaks as needed.
  void paginatedContentWasLaidOut(
      LayoutUnit logicalBottomOffsetAfterPagination);

  // Adjust from painting offsets to the local coords of this layoutObject
  void offsetForContents(LayoutPoint&) const;

  PositionWithAffinity positionForPointRespectingEditingBoundaries(
      LineLayoutBox child,
      const LayoutPoint& pointInParentCoordinates);
  PositionWithAffinity positionForPointIfOutsideAtomicInlineLevel(
      const LayoutPoint&);

  virtual bool updateLogicalWidthAndColumnWidth();

  LayoutObjectChildList m_children;

  unsigned
      m_hasMarginBeforeQuirk : 1;  // Note these quirk values can't be put in LayoutBlockRareData since they are set too frequently.
  unsigned m_hasMarginAfterQuirk : 1;
  unsigned m_beingDestroyed : 1;
  unsigned m_hasMarkupTruncation : 1;
  unsigned m_widthAvailableToChildrenChanged : 1;
  unsigned m_heightAvailableToChildrenChanged : 1;
  unsigned
      m_isSelfCollapsing : 1;  // True if margin-before and margin-after are adjoining.
  unsigned m_descendantsWithFloatsMarkedForLayout : 1;

  unsigned m_hasPositionedObjects : 1;
  unsigned m_hasPercentHeightDescendants : 1;

  // FIXME: This is temporary as we move code that accesses block flow
  // member variables out of LayoutBlock and into LayoutBlockFlow.
  friend class LayoutBlockFlow;

  // This is necessary for now for interoperability between the old and new
  // layout code. Primarily for calling layoutPositionedObjects at the moment.
  friend class NGBox;

 public:
  // TODO(lunalu): Temporary in order to ensure compatibility with existing layout test
  // results.
  virtual void adjustChildDebugRect(LayoutRect&) const {}
};

DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutBlock, isLayoutBlock());

}  // namespace blink

#endif  // LayoutBlock_h
