/*
 * Copyright (C) 1997 Martin Jones (mjones@kde.org)
 *           (C) 1997 Torben Weis (weis@kde.org)
 *           (C) 1998 Waldo Bastian (bastian@kde.org)
 *           (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 * Copyright (C) 2003, 2004, 2005, 2006, 2009, 2013 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 LayoutTableRow_h
#define LayoutTableRow_h

#include "core/CoreExport.h"
#include "core/layout/LayoutTableSection.h"

namespace blink {

// There is a window of opportunity to read |m_rowIndex| before it is set when
// inserting the LayoutTableRow or during LayoutTableSection::recalcCells.
// This value is used to detect that case.
static const unsigned unsetRowIndex = 0x7FFFFFFF;
static const unsigned maxRowIndex = 0x7FFFFFFE; // 2,147,483,646

// LayoutTableRow is used to represent a table row (display: table-row).
//
// LayoutTableRow is a simple object. The reason is that most operations
// have to be coordinated at the LayoutTableSection level and thus are
// handled in LayoutTableSection (see e.g. layoutRows).
//
// The table model prevents any layout overflow on rows (but allow visual
// overflow). For row height, it is defined as "the maximum of the row's
// computed 'height', the computed 'height' of each cell in the row, and
// the minimum height (MIN) required by  the cells" (CSS 2.1 - section 17.5.3).
// Note that this means that rows and cells differ from other LayoutObject as
// they will ignore 'height' in some situation (when other LayoutObject just
// allow some layout overflow to occur).
//
// LayoutTableRow doesn't establish a containing block for the underlying
// LayoutTableCells. That's why it inherits from LayoutBox and not LayoutBlock.
// One oddity is that LayoutTableRow doesn't establish a new coordinate system
// for its children. LayoutTableCells are positioned with respect to the
// enclosing LayoutTableSection (this object's parent()). This particularity is
// why functions accumulating offset while walking the tree have to special case
// LayoutTableRow (see e.g. PaintInvalidationState or
// LayoutBox::positionFromPoint()).
//
// LayoutTableRow is also positioned with respect to the enclosing
// LayoutTableSection. See LayoutTableSection::layoutRows() for the placement
// logic.
class CORE_EXPORT LayoutTableRow final : public LayoutBox {
public:
    explicit LayoutTableRow(Element*);

    LayoutTableCell* firstCell() const;
    LayoutTableCell* lastCell() const;

    LayoutTableRow* previousRow() const;
    LayoutTableRow* nextRow() const;

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

    LayoutTableSection* section() const { return toLayoutTableSection(parent()); }
    LayoutTable* table() const { return toLayoutTable(parent()->parent()); }

    static LayoutTableRow* createAnonymous(Document*);
    static LayoutTableRow* createAnonymousWithParent(const LayoutObject*);
    LayoutBox* createAnonymousBoxWithSameTypeAs(const LayoutObject* parent) const override
    {
        return createAnonymousWithParent(parent);
    }

    void setRowIndex(unsigned rowIndex)
    {
        if (UNLIKELY(rowIndex > maxRowIndex))
            CRASH();

        m_rowIndex = rowIndex;
    }

    bool rowIndexWasSet() const { return m_rowIndex != unsetRowIndex; }
    unsigned rowIndex() const
    {
        ASSERT(rowIndexWasSet());
        ASSERT(!section() || !section()->needsCellRecalc()); // index may be bogus if cells need recalc.
        return m_rowIndex;
    }

    const BorderValue& borderAdjoiningTableStart() const
    {
        if (section()->hasSameDirectionAs(table()))
            return style()->borderStart();

        return style()->borderEnd();
    }

    const BorderValue& borderAdjoiningTableEnd() const
    {
        if (section()->hasSameDirectionAs(table()))
            return style()->borderEnd();

        return style()->borderStart();
    }

    const BorderValue& borderAdjoiningStartCell(const LayoutTableCell*) const;
    const BorderValue& borderAdjoiningEndCell(const LayoutTableCell*) const;

    bool nodeAtPoint(HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override;

    void addOverflowFromCell(const LayoutTableCell*);

    const char* name() const override { return "LayoutTableRow"; }

    // Whether a row has opaque background depends on many factors, e.g. border spacing,
    // border collapsing, missing cells, etc.
    // For simplicity, just conservatively assume all table rows are not opaque.
    bool foregroundIsKnownToBeOpaqueInRect(const LayoutRect&, unsigned) const override { return false; }
    bool backgroundIsKnownToBeOpaqueInRect(const LayoutRect&) const override { return false; }

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

    bool isOfType(LayoutObjectType type) const override { return type == LayoutObjectTableRow || LayoutBox::isOfType(type); }

    void willBeRemovedFromTree() override;

    void addChild(LayoutObject* child, LayoutObject* beforeChild = nullptr) override;
    void layout() override;

    PaintLayerType layerTypeRequired() const override
    {
        if (hasTransformRelatedProperty() || hasHiddenBackface() || hasClipPath() || createsGroup() || style()->shouldCompositeForCurrentAnimations() || isStickyPositioned() || style()->hasCompositorProxy())
            return NormalPaintLayer;

        if (hasOverflowClip())
            return OverflowClipPaintLayer;

        return NoPaintLayer;
    }

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

    void imageChanged(WrappedImagePtr, const IntRect* = nullptr) override;

    void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;

    void nextSibling() const = delete;
    void previousSibling() const = delete;

    LayoutObjectChildList m_children;

    // This field should never be read directly. It should be read through
    // rowIndex() above instead. This is to ensure that we never read this
    // value before it is set.
    unsigned m_rowIndex : 31;
};

DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutTableRow, isTableRow());

inline LayoutTableRow* LayoutTableRow::previousRow() const
{
    return toLayoutTableRow(LayoutObject::previousSibling());
}

inline LayoutTableRow* LayoutTableRow::nextRow() const
{
    return toLayoutTableRow(LayoutObject::nextSibling());
}

inline LayoutTableRow* LayoutTableSection::firstRow() const
{
    ASSERT(children() == virtualChildren());
    return toLayoutTableRow(children()->firstChild());
}

inline LayoutTableRow* LayoutTableSection::lastRow() const
{
    ASSERT(children() == virtualChildren());
    return toLayoutTableRow(children()->lastChild());
}

} // namespace blink

#endif // LayoutTableRow_h
