blob: d6345988eefefa62ba8393eef16e48b8402d520e [file] [log] [blame]
/*
* Copyright (C) 2019 Apple Inc. 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 INC. AND ITS CONTRIBUTORS ``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 INC. OR ITS 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.
*/
#pragma once
#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
#include "FormattingContext.h"
#include "LayoutUnits.h"
#include <wtf/HashMap.h>
#include <wtf/IsoMalloc.h>
#include <wtf/IsoMallocInlines.h>
#include <wtf/ListHashSet.h>
#include <wtf/WeakPtr.h>
namespace WebCore {
namespace Layout {
class Box;
class ContainerBox;
class TableGrid {
WTF_MAKE_ISO_ALLOCATED(TableGrid);
public:
TableGrid();
void appendCell(const ContainerBox&);
void insertCell(const ContainerBox&, const ContainerBox& before);
void removeCell(const ContainerBox&);
void setHorizontalSpacing(LayoutUnit horizontalSpacing) { m_horizontalSpacing = horizontalSpacing; }
LayoutUnit horizontalSpacing() const { return m_horizontalSpacing; }
void setVerticalSpacing(LayoutUnit verticalSpacing) { m_verticalSpacing = verticalSpacing; }
LayoutUnit verticalSpacing() const { return m_verticalSpacing; }
void setCollapsedBorder(const Edges& collapsedBorder) { m_collapsedBorder = collapsedBorder; }
Optional<Edges> collapsedBorder() const { return m_collapsedBorder; }
void setWidthConstraints(FormattingContext::IntrinsicWidthConstraints intrinsicWidthConstraints) { m_intrinsicWidthConstraints = intrinsicWidthConstraints; }
Optional<FormattingContext::IntrinsicWidthConstraints> widthConstraints() const { return m_intrinsicWidthConstraints; }
bool isEmpty() const { return m_slotMap.isEmpty(); }
// Column represents a vertical set of slots in the grid. A column has horizontal position and width.
class Column {
public:
Column(const ContainerBox*);
void setLogicalLeft(LayoutUnit);
LayoutUnit logicalLeft() const;
LayoutUnit logicalRight() const { return logicalLeft() + logicalWidth(); }
void setLogicalWidth(LayoutUnit);
LayoutUnit logicalWidth() const;
bool isFixedWidth() const;
void setHasFixedWidthCell() { m_hasFixedWidthCell = true; }
const ContainerBox* box() const { return m_layoutBox.get(); }
private:
bool hasFixedWidthCell() const { return m_hasFixedWidthCell; }
LayoutUnit m_computedLogicalWidth;
LayoutUnit m_computedLogicalLeft;
WeakPtr<const ContainerBox> m_layoutBox;
bool m_hasFixedWidthCell { false };
#if ASSERT_ENABLED
bool m_hasComputedWidth { false };
bool m_hasComputedLeft { false };
#endif
};
class Columns {
public:
using ColumnList = Vector<Column>;
ColumnList& list() { return m_columnList; }
const ColumnList& list() const { return m_columnList; }
size_t size() const { return m_columnList.size(); }
void addColumn(const ContainerBox&);
void addAnonymousColumn();
LayoutUnit logicalWidth() const { return m_columnList.last().logicalRight() - m_columnList.first().logicalLeft(); }
bool hasFixedColumnsOnly() const;
private:
ColumnList m_columnList;
};
class Row {
public:
Row(const ContainerBox&);
void setLogicalTop(LayoutUnit logicalTop) { m_logicalTop = logicalTop; }
LayoutUnit logicalTop() const { return m_logicalTop; }
LayoutUnit logicalBottom() const { return logicalTop() + logicalHeight(); }
void setLogicalHeight(LayoutUnit logicalHeight) { m_logicalHeight = logicalHeight; }
LayoutUnit logicalHeight() const { return m_logicalHeight; }
void setBaselineOffset(InlineLayoutUnit baselineOffset) { m_baselineOffset = baselineOffset; }
InlineLayoutUnit baselineOffset() const { return m_baselineOffset; }
const ContainerBox& box() const { return *m_layoutBox.get(); }
private:
LayoutUnit m_logicalTop;
LayoutUnit m_logicalHeight;
InlineLayoutUnit m_baselineOffset;
WeakPtr<const ContainerBox> m_layoutBox;
};
class Rows {
public:
using RowList = Vector<Row>;
RowList& list() { return m_rowList; }
const RowList& list() const { return m_rowList; }
void addRow(const ContainerBox&);
size_t size() const { return m_rowList.size(); }
private:
RowList m_rowList;
};
// Cell represents a <td> or <th>. It can span multiple slots in the grid.
class Cell : public CanMakeWeakPtr<Cell> {
WTF_MAKE_ISO_ALLOCATED_INLINE(Cell);
public:
Cell(const ContainerBox&, SlotPosition, CellSpan);
size_t startColumn() const { return m_position.column; }
size_t endColumn() const { return m_position.column + m_span.column; }
size_t startRow() const { return m_position.row; }
size_t endRow() const { return m_position.row + m_span.row; }
size_t columnSpan() const { return m_span.column; }
size_t rowSpan() const { return m_span.row; }
SlotPosition position() const { return m_position; }
CellSpan span() const { return m_span; }
void setBaselineOffset(InlineLayoutUnit baselineOffset) { m_baselineOffset = baselineOffset; }
InlineLayoutUnit baselineOffset() const { return m_baselineOffset; }
bool isFixedWidth() const;
const ContainerBox& box() const { return *m_layoutBox.get(); }
private:
WeakPtr<const ContainerBox> m_layoutBox;
SlotPosition m_position;
CellSpan m_span;
InlineLayoutUnit m_baselineOffset { 0 };
};
class Slot {
public:
WTF_MAKE_STRUCT_FAST_ALLOCATED;
Slot() = default;
Slot(Cell&, bool isColumnSpanned, bool isRowSpanned);
const Cell& cell() const { return *m_cell; }
Cell& cell() { return *m_cell; }
const FormattingContext::IntrinsicWidthConstraints& widthConstraints() const { return m_widthConstraints; }
void setWidthConstraints(const FormattingContext::IntrinsicWidthConstraints& widthConstraints) { m_widthConstraints = widthConstraints; }
// Initial slot position for a spanning cell.
// <td></td><td colspan=2></td> [1, 0] slot has column span of 2.
bool hasColumnSpan() const { return m_cell->columnSpan() > 1 && !isColumnSpanned(); }
bool hasRowSpan() const { return m_cell->rowSpan() > 1 && !isRowSpanned(); }
// Non-initial spanned slot.
// <td></td><td colspan=2></td> [2, 0] slot is column spanned by [1, 0].
// <td></td><td></td><td></td>
bool isColumnSpanned() const { return m_isColumnSpanned; }
bool isRowSpanned() const { return m_isRowSpanned; }
private:
WeakPtr<Cell> m_cell;
bool m_isColumnSpanned { false };
bool m_isRowSpanned { false };
FormattingContext::IntrinsicWidthConstraints m_widthConstraints;
};
const Columns& columns() const { return m_columns; }
Columns& columns() { return m_columns; }
const Rows& rows() const { return m_rows; }
Rows& rows() { return m_rows; }
using Cells = WTF::ListHashSet<std::unique_ptr<Cell>>;
Cells& cells() { return m_cells; }
Slot* slot(SlotPosition);
const Slot* slot(SlotPosition position) const { return m_slotMap.get(position); }
bool isSpanned(SlotPosition);
private:
using SlotMap = WTF::HashMap<SlotPosition, std::unique_ptr<Slot>>;
Columns m_columns;
Rows m_rows;
Cells m_cells;
SlotMap m_slotMap;
LayoutUnit m_horizontalSpacing;
LayoutUnit m_verticalSpacing;
Optional<FormattingContext::IntrinsicWidthConstraints> m_intrinsicWidthConstraints;
Optional<Edges> m_collapsedBorder;
};
}
}
#endif