コード例 #1
0
void InitialColumnHeightFinder::distributeImplicitBreaks() {
  // Insert a final content run to encompass all content. This will include
  // overflow if we're at the end of the multicol container.
  addContentRun(logicalBottomInFlowThread());
  unsigned columnCount = m_contentRuns.size();

  // If there is room for more breaks (to reach the used value of column-count),
  // imagine that we insert implicit breaks at suitable locations. At any given
  // time, the content run with the currently tallest columns will get another
  // implicit break "inserted", which will increase its column count by one and
  // shrink its columns' height. Repeat until we have the desired total number
  // of breaks. The largest column height among the runs will then be the
  // initial column height for the balancer to use.
  if (columnCount > columnSet().usedColumnCount()) {
    // If we exceed used column-count (which we are allowed to do if we're at
    // the initial balancing pass for a multicol that lives inside another
    // to-be-balanced outer multicol container), we only care about content that
    // could end up in the last row. We need to pad up the number of columns, so
    // that all rows will contain as many columns as used column-count dictates.
    columnCount %= columnSet().usedColumnCount();
    // If there are just enough explicit breaks to fill all rows with the right
    // amount of columns, we won't be needing any implicit breaks.
    if (!columnCount)
      return;
  }
  while (columnCount < columnSet().usedColumnCount()) {
    unsigned index = contentRunIndexWithTallestColumns();
    m_contentRuns[index].assumeAnotherImplicitBreak();
    columnCount++;
  }
}
コード例 #2
0
ファイル: ColumnBalancer.cpp プロジェクト: mirror/chromium
void InitialColumnHeightFinder::recordStrutBeforeOffset(
    LayoutUnit offsetInFlowThread,
    LayoutUnit strut) {
  ASSERT(columnSet().usedColumnCount() >= 1);
  unsigned columnCount = columnSet().usedColumnCount();
  ASSERT(m_shortestStruts.size() == columnCount);
  unsigned index = groupAtOffset(offsetInFlowThread)
                       .columnIndexAtOffset(offsetInFlowThread - strut,
                                            LayoutBox::AssociateWithLatterPage);
  if (index >= columnCount)
    return;
  m_shortestStruts[index] = std::min(m_shortestStruts[index], strut);
}
コード例 #3
0
void InitialColumnHeightFinder::addContentRun(
    LayoutUnit endOffsetInFlowThread) {
  endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread);
  if (!m_contentRuns.isEmpty() &&
      endOffsetInFlowThread <= m_contentRuns.back().breakOffset())
    return;
  // Append another item as long as we haven't exceeded used column count. What
  // ends up in the overflow area shouldn't affect column balancing. However, if
  // we're in a nested fragmentation context, we may still need to record all
  // runs, since there'll be no overflow area in the inline direction then, but
  // rather additional rows of columns in multiple outer fragmentainers.
  if (m_contentRuns.size() >= columnSet().usedColumnCount()) {
    const auto* flowThread = columnSet().multiColumnFlowThread();
    if (!flowThread->enclosingFragmentationContext() ||
        columnSet().newFragmentainerGroupsAllowed())
      return;
  }
  m_contentRuns.append(ContentRun(endOffsetInFlowThread));
}
コード例 #4
0
ファイル: ColumnBalancer.cpp プロジェクト: mirror/chromium
void InitialColumnHeightFinder::addContentRun(
    LayoutUnit endOffsetInFlowThread) {
  endOffsetInFlowThread -= spaceUsedByStrutsAt(endOffsetInFlowThread);
  if (!m_contentRuns.isEmpty() &&
      endOffsetInFlowThread <= m_contentRuns.last().breakOffset())
    return;
  // Append another item as long as we haven't exceeded used column count. What
  // ends up in the overflow area shouldn't affect column balancing.
  if (m_contentRuns.size() < columnSet().usedColumnCount())
    m_contentRuns.append(ContentRun(endOffsetInFlowThread));
}
コード例 #5
0
LayoutUnit InitialColumnHeightFinder::initialMinimalBalancedHeight() const {
  LayoutUnit rowLogicalTop;
  if (m_contentRuns.size() > columnSet().usedColumnCount()) {
    // We have not inserted additional fragmentainer groups yet (because we
    // aren't able to calculate their constraints yet), but we already know for
    // sure that there'll be more than one of them, due to the number of forced
    // breaks in a nested multicol container. We will now attempt to take all
    // the imaginary rows into account and calculate a minimal balanced logical
    // height for everything.
    unsigned stride = columnSet().usedColumnCount();
    LayoutUnit rowStartOffset = logicalTopInFlowThread();
    for (unsigned i = 0; i < firstContentRunIndexInLastRow(); i += stride) {
      LayoutUnit rowEndOffset = m_contentRuns[i + stride - 1].breakOffset();
      float rowHeight = float(rowEndOffset - rowStartOffset) / float(stride);
      rowLogicalTop += LayoutUnit::fromFloatCeil(rowHeight);
      rowStartOffset = rowEndOffset;
    }
  }
  unsigned index = contentRunIndexWithTallestColumns();
  LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset()
                                     : logicalTopInFlowThread();
  LayoutUnit height = m_contentRuns[index].columnLogicalHeight(startOffset);
  return rowLogicalTop + std::max(height, m_tallestUnbreakableLogicalHeight);
}
コード例 #6
0
LayoutUnit InitialColumnHeightFinder::spaceUsedByStrutsAt(
    LayoutUnit offsetInFlowThread) const {
  unsigned stopBeforeColumn =
      groupAtOffset(offsetInFlowThread)
          .columnIndexAtOffset(offsetInFlowThread,
                               LayoutBox::AssociateWithLatterPage) +
      1;
  stopBeforeColumn = std::min(stopBeforeColumn, columnSet().usedColumnCount());
  ASSERT(stopBeforeColumn <= m_shortestStruts.size());
  LayoutUnit totalStrutSpace;
  for (unsigned i = 0; i < stopBeforeColumn; i++) {
    if (m_shortestStruts[i] != LayoutUnit::max())
      totalStrutSpace += m_shortestStruts[i];
  }
  return totalStrutSpace;
}
コード例 #7
0
ファイル: ColumnBalancer.cpp プロジェクト: mirror/chromium
void InitialColumnHeightFinder::distributeImplicitBreaks() {
  // Insert a final content run to encompass all content. This will include
  // overflow if we're at the end of the multicol container.
  addContentRun(logicalBottomInFlowThread());
  unsigned columnCount = m_contentRuns.size();

  // If there is room for more breaks (to reach the used value of column-count),
  // imagine that we insert implicit breaks at suitable locations. At any given
  // time, the content run with the currently tallest columns will get another
  // implicit break "inserted", which will increase its column count by one and
  // shrink its columns' height. Repeat until we have the desired total number
  // of breaks. The largest column height among the runs will then be the
  // initial column height for the balancer to use.
  while (columnCount < columnSet().usedColumnCount()) {
    unsigned index = contentRunIndexWithTallestColumns();
    m_contentRuns[index].assumeAnotherImplicitBreak();
    columnCount++;
  }
}
コード例 #8
0
LayoutUnit MultiColumnFragmentainerGroup::rebalanceColumnHeightIfNeeded()
    const {
  if (actualColumnCount() <= m_columnSet.usedColumnCount()) {
    // With the current column height, the content fits without creating
    // overflowing columns. We're done.
    return m_columnHeight;
  }

  if (m_columnHeight >= m_maxColumnHeight) {
    // We cannot stretch any further. We'll just have to live with the
    // overflowing columns. This typically happens if the max column height is
    // less than the height of the tallest piece of unbreakable content (e.g.
    // lines).
    return m_columnHeight;
  }

  MinimumSpaceShortageFinder shortageFinder(
      columnSet(), logicalTopInFlowThread(), logicalBottomInFlowThread());

  if (shortageFinder.forcedBreaksCount() + 1 >= m_columnSet.usedColumnCount()) {
    // Too many forced breaks to allow any implicit breaks. Initial balancing
    // should already have set a good height. There's nothing more we should do.
    return m_columnHeight;
  }

  // If the initial guessed column height wasn't enough, stretch it now. Stretch
  // by the lowest amount of space.
  LayoutUnit minSpaceShortage = shortageFinder.minimumSpaceShortage();

  ASSERT(minSpaceShortage > 0);  // We should never _shrink_ the height!
  ASSERT(minSpaceShortage !=
         LayoutUnit::max());  // If this happens, we probably have a bug.
  if (minSpaceShortage == LayoutUnit::max())
    return m_columnHeight;  // So bail out rather than looping infinitely.

  return m_columnHeight + minSpaceShortage;
}
コード例 #9
0
void ColumnBalancer::traverse() {
  traverseSubtree(*columnSet().flowThread());
  ASSERT(!flowThreadOffset());
}
コード例 #10
0
ファイル: ColumnBalancer.cpp プロジェクト: ollie314/chromium
void ColumnBalancer::traverseSubtree(const LayoutBox& box) {
  if (box.childrenInline() && box.isLayoutBlockFlow()) {
    // Look for breaks between lines.
    for (const RootInlineBox* line = toLayoutBlockFlow(box).firstRootBox();
         line; line = line->nextRootBox()) {
      LayoutUnit lineTopInFlowThread =
          m_flowThreadOffset + line->lineTopWithLeading();
      if (lineTopInFlowThread < logicalTopInFlowThread())
        continue;
      if (lineTopInFlowThread >= logicalBottomInFlowThread())
        break;
      examineLine(*line);
    }
  }

  const LayoutFlowThread* flowThread = columnSet().flowThread();
  bool isHorizontalWritingMode = flowThread->isHorizontalWritingMode();

  // The break-after value from the previous in-flow block-level object to be
  // joined with the break-before value of the next in-flow block-level sibling.
  EBreak previousBreakAfterValue = BreakAuto;

  // Look for breaks between and inside block-level children. Even if this is a
  // block flow with inline children, there may be interesting floats to examine
  // here.
  for (const LayoutObject* child = box.slowFirstChild(); child;
       child = child->nextSibling()) {
    if (!child->isBox() || child->isInline())
      continue;
    const LayoutBox& childBox = toLayoutBox(*child);
    LayoutRect overflowRect = childBox.layoutOverflowRect();
    LayoutUnit childLogicalBottomWithOverflow =
        childBox.logicalTop() +
        (isHorizontalWritingMode ? overflowRect.maxY() : overflowRect.maxX());
    if (m_flowThreadOffset + childLogicalBottomWithOverflow <=
        logicalTopInFlowThread()) {
      // This child is fully above the flow thread portion we're examining.
      continue;
    }
    LayoutUnit childLogicalTopWithOverflow =
        childBox.logicalTop() +
        (isHorizontalWritingMode ? overflowRect.y() : overflowRect.x());
    if (m_flowThreadOffset + childLogicalTopWithOverflow >=
        logicalBottomInFlowThread()) {
      // This child is fully below the flow thread portion we're examining. We
      // cannot just stop here, though, thanks to negative margins.
      // So keep looking.
      continue;
    }
    if (childBox.isOutOfFlowPositioned() || childBox.isColumnSpanAll())
      continue;

    // Tables are wicked. Both table rows and table cells are relative to their
    // table section.
    LayoutUnit offsetForThisChild =
        childBox.isTableRow() ? LayoutUnit() : childBox.logicalTop();
    m_flowThreadOffset += offsetForThisChild;

    examineBoxAfterEntering(childBox, previousBreakAfterValue);
    // Unless the child is unsplittable, or if the child establishes an inner
    // multicol container, we descend into its subtree for further examination.
    if (childBox.getPaginationBreakability() != LayoutBox::ForbidBreaks &&
        (!childBox.isLayoutBlockFlow() ||
         !toLayoutBlockFlow(childBox).multiColumnFlowThread()))
      traverseSubtree(childBox);
    previousBreakAfterValue = childBox.breakAfter();
    examineBoxBeforeLeaving(childBox);

    m_flowThreadOffset -= offsetForThisChild;
  }
}