Ejemplo n.º 1
0
void TableRowPainter::paint(const PaintInfo& paintInfo,
                            const LayoutPoint& paintOffset) {
    DCHECK(m_layoutTableRow.hasSelfPaintingLayer());

    // TODO(crbug.com/577282): This painting order is inconsistent with other
    // outlines.
    if (shouldPaintSelfOutline(paintInfo.phase))
        paintOutline(paintInfo, paintOffset);
    if (paintInfo.phase == PaintPhaseSelfOutlineOnly)
        return;

    PaintInfo paintInfoForCells = paintInfo.forDescendants();
    if (shouldPaintSelfBlockBackground(paintInfo.phase)) {
        paintBoxShadow(paintInfo, paintOffset, Normal);
        if (m_layoutTableRow.styleRef().hasBackground()) {
            // Paint row background of behind the cells.
            for (LayoutTableCell* cell = m_layoutTableRow.firstCell(); cell;
                    cell = cell->nextCell())
                TableCellPainter(*cell).paintContainerBackgroundBehindCell(
                    paintInfoForCells, paintOffset, m_layoutTableRow,
                    DisplayItem::kTableCellBackgroundFromRow);
        }
        paintBoxShadow(paintInfo, paintOffset, Inset);
    }

    if (paintInfo.phase == PaintPhaseSelfBlockBackgroundOnly)
        return;

    for (LayoutTableCell* cell = m_layoutTableRow.firstCell(); cell;
            cell = cell->nextCell()) {
        if (!cell->hasSelfPaintingLayer())
            cell->paint(paintInfoForCells, paintOffset);
    }
}
Ejemplo n.º 2
0
void LayoutTableRow::layout()
{
    ASSERT(needsLayout());
    LayoutAnalyzer::Scope analyzer(*this);

    // Table rows do not add translation.
    LayoutState state(*this, LayoutSize());

    for (LayoutTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
        SubtreeLayoutScope layouter(*cell);
        if (!cell->needsLayout())
            cell->markForPaginationRelayoutIfNeeded(layouter);
        if (cell->needsLayout())
            cell->layout();
    }

    m_overflow.clear();
    addVisualEffectOverflow();
    // We do not call addOverflowFromCell here. The cell are laid out to be
    // measured above and will be sized correctly in a follow-up phase.

    // We only ever need to issue paint invalidations if our cells didn't, which means that they didn't need
    // layout, so we know that our bounds didn't change. This code is just making up for
    // the fact that we did not invalidate paints in setStyle() because we had a layout hint.
    if (selfNeedsLayout()) {
        for (LayoutTableCell* cell = firstCell(); cell; cell = cell->nextCell()) {
            // FIXME: Is this needed when issuing paint invalidations after layout?
            cell->setShouldDoFullPaintInvalidation();
        }
    }

    // LayoutTableSection::layoutRows will set our logical height and width later, so it calls updateLayerTransform().
    clearNeedsLayout();
}
Ejemplo n.º 3
0
AccessibilityRole AXTableCell::scanToDecideHeaderRole()
{
    if (!isTableHeaderCell())
        return CellRole;

    // Check scope attribute first.
    if (isRowHeaderCell())
        return RowHeaderRole;

    if (isColumnHeaderCell())
        return ColumnHeaderRole;

    // Check the previous cell and the next cell on the same row.
    LayoutTableCell* layoutCell = toLayoutTableCell(m_layoutObject);
    AccessibilityRole headerRole = CellRole;

    // if header is preceded by header cells on the same row, then it is a
    // column header. If it is preceded by other cells then it's a row header.
    if ((headerRole = decideRoleFromSibling(layoutCell->previousCell())) != CellRole)
        return headerRole;

    // if header is followed by header cells on the same row, then it is a
    // column header. If it is followed by other cells then it's a row header.
    if ((headerRole = decideRoleFromSibling(layoutCell->nextCell())) != CellRole)
        return headerRole;

    // If there are no other cells on that row, then it is a column header.
    return ColumnHeaderRole;
}
Ejemplo n.º 4
0
void TextAutosizer::inflateAutoTable(LayoutTable* table)
{
    ASSERT(table);
    ASSERT(!table->style()->isFixedTableLayout());
    ASSERT(table->containingBlock());

    Cluster* cluster = currentCluster();
    if (cluster->m_root != table)
        return;

    // Pre-inflate cells that have enough text so that their inflated preferred widths will be used
    // for column sizing.
    for (LayoutObject* section = table->firstChild(); section; section = section->nextSibling()) {
        if (!section->isTableSection())
            continue;
        for (LayoutTableRow* row = toLayoutTableSection(section)->firstRow(); row; row = row->nextRow()) {
            for (LayoutTableCell* cell = row->firstCell(); cell; cell = cell->nextCell()) {
                if (!cell->needsLayout())
                    continue;

                beginLayout(cell);
                inflate(cell, DescendToInnerBlocks);
                endLayout(cell);
            }
        }
    }
}
Ejemplo n.º 5
0
void LayoutTableCol::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle)
{
    LayoutBox::styleDidChange(diff, oldStyle);

    // If border was changed, notify table.
    if (parent()) {
        LayoutTable* table = this->table();
        if (table && !table->selfNeedsLayout() && !table->normalChildNeedsLayout() && oldStyle && oldStyle->border() != style()->border()) {
            table->invalidateCollapsedBorders();
        } else if (oldStyle && oldStyle->logicalWidth() != style()->logicalWidth()) {
            // FIXME : setPreferredLogicalWidthsDirty is done for all cells as of now.
            // Need to find a better way so that only the cells which are changed by
            // the col width should have preferred logical widths recomputed.
            for (LayoutObject* child = table->children()->firstChild(); child; child = child->nextSibling()) {
                if (!child->isTableSection())
                    continue;
                LayoutTableSection* section = toLayoutTableSection(child);
                for (LayoutTableRow* row = section->firstRow(); row; row = row->nextRow()) {
                    for (LayoutTableCell* cell = row->firstCell(); cell; cell = cell->nextCell())
                        cell->setPreferredLogicalWidthsDirty();
                }
            }
        }
    }
}
void TableLayoutAlgorithmFixed::willChangeTableLayout()
{
    // When switching table layout algorithm, we need to dirty the preferred
    // logical widths as we cleared the bits without computing them.
    // (see calcWidthArray above.) This optimization is preferred to always
    // computing the logical widths we never intended to use.
    m_table->recalcSectionsIfNeeded();
    for (LayoutTableSection* section = m_table->topNonEmptySection(); section; section = m_table->sectionBelow(section)) {
        for (unsigned i = 0; i < section->numRows(); i++) {
            LayoutTableRow* row = section->rowLayoutObjectAt(i);
            if (!row)
                continue;
            for (LayoutTableCell* cell = row->firstCell(); cell; cell = cell->nextCell())
                cell->setPreferredLogicalWidthsDirty();
        }
    }
}
Ejemplo n.º 7
0
void LayoutTableRow::computeOverflow() {
  clearAllOverflows();
  addVisualEffectOverflow();
  for (LayoutTableCell* cell = firstCell(); cell; cell = cell->nextCell())
    addOverflowFromCell(cell);
}
Ejemplo n.º 8
0
void LayoutTableRow::addChild(LayoutObject* child, LayoutObject* beforeChild) {
  if (!child->isTableCell()) {
    LayoutObject* last = beforeChild;
    if (!last)
      last = lastCell();
    if (last && last->isAnonymous() && last->isTableCell() &&
        !last->isBeforeOrAfterContent()) {
      LayoutTableCell* lastCell = toLayoutTableCell(last);
      if (beforeChild == lastCell)
        beforeChild = lastCell->firstChild();
      lastCell->addChild(child, beforeChild);
      return;
    }

    if (beforeChild && !beforeChild->isAnonymous() &&
        beforeChild->parent() == this) {
      LayoutObject* cell = beforeChild->previousSibling();
      if (cell && cell->isTableCell() && cell->isAnonymous()) {
        cell->addChild(child);
        return;
      }
    }

    // If beforeChild is inside an anonymous cell, insert into the cell.
    if (last && !last->isTableCell() && last->parent() &&
        last->parent()->isAnonymous() &&
        !last->parent()->isBeforeOrAfterContent()) {
      last->parent()->addChild(child, beforeChild);
      return;
    }

    LayoutTableCell* cell = LayoutTableCell::createAnonymousWithParent(this);
    addChild(cell, beforeChild);
    cell->addChild(child);
    return;
  }

  if (beforeChild && beforeChild->parent() != this)
    beforeChild = splitAnonymousBoxesAroundChild(beforeChild);

  LayoutTableCell* cell = toLayoutTableCell(child);

  ASSERT(!beforeChild || beforeChild->isTableCell());
  LayoutTableBoxComponent::addChild(cell, beforeChild);

  // Generated content can result in us having a null section so make sure to
  // null check our parent.
  if (parent()) {
    section()->addCell(cell, this);
    // When borders collapse, adding a cell can affect the the width of
    // neighboring cells.
    LayoutTable* enclosingTable = table();
    if (enclosingTable && enclosingTable->collapseBorders()) {
      if (LayoutTableCell* previousCell = cell->previousCell())
        previousCell->setNeedsLayoutAndPrefWidthsRecalc(
            LayoutInvalidationReason::TableChanged);
      if (LayoutTableCell* nextCell = cell->nextCell())
        nextCell->setNeedsLayoutAndPrefWidthsRecalc(
            LayoutInvalidationReason::TableChanged);
    }
  }

  if (beforeChild || nextRow())
    section()->setNeedsCellRecalc();
}
int TableLayoutAlgorithmFixed::calcWidthArray()
{
    // FIXME: We might want to wait until we have all of the first row before computing for the first time.
    int usedWidth = 0;

    // iterate over all <col> elements
    unsigned nEffCols = m_table->numEffectiveColumns();
    m_width.resize(nEffCols);
    m_width.fill(Length(Auto));

    unsigned currentEffectiveColumn = 0;
    for (LayoutTableCol* col = m_table->firstColumn(); col; col = col->nextColumn()) {
        // LayoutTableCols don't have the concept of preferred logical width, but we need to clear their dirty bits
        // so that if we call setPreferredWidthsDirty(true) on a col or one of its descendants, we'll mark it's
        // ancestors as dirty.
        col->clearPreferredLogicalWidthsDirtyBits();

        // Width specified by column-groups that have column child does not affect column width in fixed layout tables
        if (col->isTableColumnGroupWithColumnChildren())
            continue;

        Length colStyleLogicalWidth = col->style()->logicalWidth();
        int effectiveColWidth = 0;
        if (colStyleLogicalWidth.isFixed() && colStyleLogicalWidth.value() > 0)
            effectiveColWidth = colStyleLogicalWidth.value();

        unsigned span = col->span();
        while (span) {
            unsigned spanInCurrentEffectiveColumn;
            if (currentEffectiveColumn >= nEffCols) {
                m_table->appendEffectiveColumn(span);
                nEffCols++;
                m_width.append(Length());
                spanInCurrentEffectiveColumn = span;
            } else {
                if (span < m_table->spanOfEffectiveColumn(currentEffectiveColumn)) {
                    m_table->splitEffectiveColumn(currentEffectiveColumn, span);
                    nEffCols++;
                    m_width.append(Length());
                }
                spanInCurrentEffectiveColumn = m_table->spanOfEffectiveColumn(currentEffectiveColumn);
            }
            // TODO(alancutter): Make this work correctly for calc lengths.
            if ((colStyleLogicalWidth.isFixed() || colStyleLogicalWidth.hasPercent()) && colStyleLogicalWidth.isPositive()) {
                m_width[currentEffectiveColumn] = colStyleLogicalWidth;
                m_width[currentEffectiveColumn] *= spanInCurrentEffectiveColumn;
                usedWidth += effectiveColWidth * spanInCurrentEffectiveColumn;
            }
            span -= spanInCurrentEffectiveColumn;
            currentEffectiveColumn++;
        }
    }

    // Iterate over the first row in case some are unspecified.
    LayoutTableSection* section = m_table->topNonEmptySection();
    if (!section)
        return usedWidth;

    unsigned currentColumn = 0;

    LayoutTableRow* firstRow = section->firstRow();
    for (LayoutTableCell* cell = firstRow->firstCell(); cell; cell = cell->nextCell()) {
        Length logicalWidth = cell->styleOrColLogicalWidth();

        // FIXME: calc() on tables should be handled consistently with other lengths. See bug: https://crbug.com/382725
        if (logicalWidth.isCalculated())
            logicalWidth = Length(); // Make it Auto

        unsigned span = cell->colSpan();
        int fixedBorderBoxLogicalWidth = 0;
        // FIXME: Support other length types. If the width is non-auto, it should probably just use
        // LayoutBox::computeLogicalWidthUsing to compute the width.
        if (logicalWidth.isFixed() && logicalWidth.isPositive()) {
            fixedBorderBoxLogicalWidth = cell->adjustBorderBoxLogicalWidthForBoxSizing(logicalWidth.value());
            logicalWidth.setValue(fixedBorderBoxLogicalWidth);
        }

        unsigned usedSpan = 0;
        while (usedSpan < span && currentColumn < nEffCols) {
            float eSpan = m_table->spanOfEffectiveColumn(currentColumn);
            // Only set if no col element has already set it.
            if (m_width[currentColumn].isAuto() && logicalWidth.type() != Auto) {
                m_width[currentColumn] = logicalWidth;
                m_width[currentColumn] *= eSpan / span;
                usedWidth += fixedBorderBoxLogicalWidth * eSpan / span;
            }
            usedSpan += eSpan;
            ++currentColumn;
        }

        // TableLayoutAlgorithmFixed doesn't use min/maxPreferredLogicalWidths, but we need to clear the
        // dirty bit on the cell so that we'll correctly mark its ancestors dirty
        // in case we later call setPreferredLogicalWidthsDirty() on it later.
        if (cell->preferredLogicalWidthsDirty())
            cell->clearPreferredLogicalWidthsDirty();
    }

    return usedWidth;
}