#include "core/rendering/RenderCombineText.h"
#include "core/rendering/RenderDeprecatedFlexibleBox.h"
#include "core/rendering/RenderFlexibleBox.h"
+#include "core/rendering/RenderFlowThread.h"
#include "core/rendering/RenderInline.h"
#include "core/rendering/RenderLayer.h"
#include "core/rendering/RenderMarquee.h"
-#include "core/rendering/RenderNamedFlowThread.h"
#include "core/rendering/RenderRegion.h"
#include "core/rendering/RenderTableCell.h"
#include "core/rendering/RenderTextControl.h"
// Explicitly delete the child's line box tree, or the special anonymous
// block handling in willBeDestroyed will cause problems.
child->deleteLineBoxTree();
- if (childFlowThread && childFlowThread->isRenderNamedFlowThread())
- toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child);
child->destroy();
}
bool RenderBlock::isSelfCollapsingBlock() const
{
- ASSERT(!needsLayout());
+ // Placeholder elements are not laid out until the dimensions of their parent text control are known, so they
+ // don't get layout until their parent has had layout - this is unique in the layout tree and means
+ // when we call isSelfCollapsingBlock on them we find that they still need layout.
+ ASSERT(!needsLayout() || (node() && node()->isElementNode() && toElement(node())->shadowPseudoId() == "-webkit-input-placeholder"));
// We are not self-collapsing if we
// (a) have a non-zero height according to layout (an optimization to avoid wasting time)
// (c) have border/padding,
// (d) have a min-height
// (e) have specified that one of our margins can't collapse using a CSS extension
+ // (f) establish a new block formatting context.
+
+ if (createsBlockFormattingContext())
+ return false;
+
if (logicalHeight() > 0
|| isTable() || borderAndPaddingLogicalHeight()
|| style()->logicalMinHeight().isPositive()
shapeInsideInfo->dirtyShapeSize();
markShapeInsideDescendantsForLayout();
}
-
- ShapeValue* shapeOutsideValue = style()->shapeOutside();
- if (isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image)
- parent()->setNeedsLayoutAndPrefWidthsRecalc();
}
void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
if (!shapeInsideInfo)
return;
- if (isRenderNamedFlowFragment()) {
- ShapeInsideInfo* parentShapeInsideInfo = toRenderBlock(parent())->shapeInsideInfo();
- ASSERT(parentShapeInsideInfo);
- shapeInsideInfo->setShapeSize(parentShapeInsideInfo->shapeSize().width(), parentShapeInsideInfo->shapeSize().height());
- } else {
- bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
- shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
- }
+ bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
+ shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
}
void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
}
-void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
-{
- ColumnInfo* colInfo = columnInfo();
- if (hasColumns()) {
- if (!pageLogicalHeight) {
- LayoutUnit oldLogicalHeight = logicalHeight();
- setLogicalHeight(0);
- // We need to go ahead and set our explicit page height if one exists, so that we can
- // avoid doing two layout passes.
- updateLogicalHeight();
- LayoutUnit columnHeight = contentLogicalHeight();
- if (columnHeight > 0) {
- pageLogicalHeight = columnHeight;
- hasSpecifiedPageLogicalHeight = true;
- }
- setLogicalHeight(oldLogicalHeight);
- }
- if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
- colInfo->setColumnHeight(pageLogicalHeight);
- pageLogicalHeightChanged = true;
- }
-
- if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
- colInfo->clearForcedBreaks();
-
- colInfo->setPaginationUnit(paginationUnit());
- } else if (isRenderFlowThread()) {
- pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
- pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
- }
-}
-
void RenderBlock::layoutBlock(bool)
{
ASSERT_NOT_REACHED();
// Add visual overflow from theme.
addVisualOverflowFromTheme();
-
- if (isRenderNamedFlowThread())
- toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
}
void RenderBlock::addOverflowFromBlockChildren()
addVisualOverflow(inflatedRect);
}
-bool RenderBlock::expandsToEncloseOverhangingFloats() const
+bool RenderBlock::createsBlockFormattingContext() const
{
return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
- || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
+ || style()->specifiesColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot() || style()->columnSpan();
}
void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
return false;
+ FastTextAutosizer::LayoutScope fastTextAutosizerLayoutScope(document(), this);
+
// Lay out positioned descendants or objects that just need to recompute overflow.
if (needsSimplifiedNormalFlowLayout())
simplifiedNormalFlowLayout();
RenderBox* box = toRenderBox(child);
if (hasStaticInlinePosition) {
- LayoutUnit oldLeft = box->logicalLeft();
- box->updateLogicalWidth();
- if (box->logicalLeft() != oldLeft)
+ LogicalExtentComputedValues computedValues;
+ box->computeLogicalWidth(computedValues);
+ LayoutUnit newLeft = computedValues.m_position;
+ if (newLeft != box->logicalLeft())
layoutScope.setChildNeedsLayout(child);
} else if (hasStaticBlockPosition) {
LayoutUnit oldTop = box->logicalTop();
return minimumValueForLength(style()->textIndent(), cw);
}
-LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
-{
- LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
- if (!region)
- return logicalLeftOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region);
- return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
-}
-
-LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
-{
- LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
- logicalRightOffset += availableLogicalWidth();
- if (!region)
- return logicalRightOffset;
- LayoutRect boxRect = borderBoxRectInRegion(region);
- return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
-}
-
void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
{
if (logicalTop >= logicalBottom)
// If we have clipping, then we can't have any spillout.
bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
bool useClip = (hasControlClip() || useOverflowClip);
- bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize)));
+ bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize)));
if (checkChildren) {
// Hit test descendants first.
LayoutSize scrolledOffset(localOffset);
bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
{
- if (isRenderRegion())
- return toRenderRegion(this)->hitTestFlowThreadContents(request, result, locationInContainer, accumulatedOffset, hitTestAction);
-
if (childrenInline() && !isTable()) {
// We have to hit-test our line boxes.
if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction))
bool RenderBlock::requiresColumns(int desiredColumnCount) const
{
- // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
- // in the RenderView instead.
- bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody());
+ // Paged overflow is treated as multicol here, unless this element was the one that got its
+ // overflow propagated to the viewport.
+ bool isPaginated = style()->isOverflowPaged() && node() != document().viewportDefiningElement();
return firstChild()
&& (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated)
gColumnInfoMap->add(this, adoptPtr(info));
setHasColumns(true);
}
- info->setDesiredColumnCount(count);
info->setDesiredColumnWidth(width);
- info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
- info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
- }
-}
-
-void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style)
-{
- if (!hasColumns())
- return;
-
- ColumnInfo* info = gColumnInfoMap->get(this);
-
- bool needsLayout = false;
- ColumnInfo::Axis oldAxis = info->progressionAxis();
- ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis;
- if (oldAxis != newAxis) {
- info->setProgressionAxis(newAxis);
- needsLayout = true;
- }
-
- bool oldProgressionIsReversed = info->progressionIsReversed();
- bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression;
- if (oldProgressionIsReversed != newProgressionIsReversed) {
- info->setProgressionIsReversed(newProgressionIsReversed);
- needsLayout = true;
+ if (style()->isOverflowPaged()) {
+ info->setProgressionAxis(style()->hasInlinePaginationAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
+ } else {
+ info->setDesiredColumnCount(count);
+ info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
+ info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
+ }
}
-
- if (needsLayout)
- setNeedsLayoutAndPrefWidthsRecalc();
}
LayoutUnit RenderBlock::desiredColumnWidth() const
return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
}
-bool RenderBlock::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
-{
- if (!shouldBreakAtLineToAvoidWidow())
- return false;
-
- statePusher.pop();
- setEverHadLayout(true);
- layoutBlock(false);
- return true;
-}
-
void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
{
// Just bail if we have no columns.
const UChar space = ' ';
const Font& font = t->style()->font(); // FIXME: This ignores first-line.
float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style(), LTR));
- inlineMax -= spaceWidth + font.wordSpacing();
+ inlineMax -= spaceWidth + font.fontDescription().wordSpacing();
if (inlineMin > inlineMax)
inlineMin = inlineMax;
}
t->trimmedPrefWidths(inlineMax,
firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
- childMin, childMax, stripFrontSpaces);
+ childMin, childMax, stripFrontSpaces, styleToUse->direction());
// This text object will not be rendered, but it may still provide a breaking opportunity.
if (!hasBreak && childMax == 0) {
int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const
{
- if (style()->overflowY() != OVISIBLE) {
+ if (!style()->isOverflowVisible()) {
// We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us.
return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
}
LayoutUnit leftEdge = borderLeft() + paddingLeft();
LayoutUnit rightEdge = leftEdge + oldWidth;
left = min(rightEdge, max(leftEdge, left));
- right = max(leftEdge, min(rightEdge, right));
+ right = max(left, min(rightEdge, right));
LayoutUnit newContentWidth = right - left;
if (newContentWidth == oldWidth)
return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
}
-bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
-{
- ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
-
- RenderFlowThread* flowThread = flowThreadContainingBlock();
- if (!flowThread)
- return true; // Printing and multi-column both make new pages to accommodate content.
-
- // See if we're in the last region.
- LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
- RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this);
- if (!region)
- return false;
- if (region->isLastRegion())
- return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment
- || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
- return true;
-}
-
LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
{
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
return logicalOffset + remainingLogicalHeight;
}
-ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
-{
- return ColumnInfo::Column;
-}
-
LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
{
RenderView* renderView = view();
{
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
- RenderFlowThread* flowThread = flowThreadContainingBlock();
- bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
- || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
- || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
+ || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID);
if (!isUnsplittable)
return logicalOffset;
LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
- bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
updateMinimumPageHeight(logicalOffset, childLogicalHeight);
- if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
- || !hasNextPage(logicalOffset))
+ if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight)
return logicalOffset;
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
- if (remainingLogicalHeight < childLogicalHeight) {
- if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
- return logicalOffset;
+ if (remainingLogicalHeight < childLogicalHeight)
return logicalOffset + remainingLogicalHeight;
- }
return logicalOffset;
}
bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
{
- bool checkRegion = false;
- for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
- pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
- if (minimumLogicalHeight <= pageLogicalHeight)
- return true;
- if (!hasNextPage(logicalOffset + adjustment))
- return false;
- adjustment += pageLogicalHeight;
- checkRegion = true;
- }
- return !checkRegion;
+ // FIXME: multicol will need to do some work here, when we implement support for multiple rows.
+ return false;
}
void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
// If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
// still going to add a strut, so that the visible overflow fits on a single page.
- if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
- || !hasNextPage(logicalOffset))
+ if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight))
// FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
// From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
return;
}
}
-void RenderBlock::updateRegionForLine(RootInlineBox* lineBox) const
-{
- ASSERT(lineBox);
- lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
-
- RootInlineBox* prevLineBox = lineBox->prevRootBox();
- if (!prevLineBox)
- return;
-
- // This check is more accurate than the one in |adjustLinePositionForPagination| because it takes into
- // account just the container changes between lines. The before mentioned function doesn't set the flag
- // correctly if the line is positioned at the top of the last fragment container.
- if (lineBox->containingRegion() != prevLineBox->containingRegion())
- lineBox->setIsFirstAfterPageBreak(true);
-}
-
-bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
-{
- if (!flowThread)
- return false;
-
- RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
- // Just bail if the region didn't change.
- if (rootBox->containingRegion() == currentRegion)
- return false;
- return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion);
-}
-
LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
{
LayoutState* layoutState = view()->layoutState();
return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
}
-bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const
-{
- if (!flowThread || !flowThread->hasValidRegionInfo())
- return false;
-
- return flowThread->logicalWidthChangedInRegionsForBlock(this);
-}
-
-RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
-{
- RenderFlowThread* flowThread = flowThreadContainingBlock();
-
- ASSERT(isRenderView() || (region && flowThread));
- if (isRenderView())
- return region;
-
- // We need to clamp to the block, since we want any lines or blocks that overflow out of the
- // logical top or logical bottom of the block to size as though the border box in the first and
- // last regions extended infinitely. Otherwise the lines are going to size according to the regions
- // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
- RenderRegion* startRegion;
- RenderRegion* endRegion;
- flowThread->getRegionRangeForBox(this, startRegion, endRegion);
-
- if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
- return startRegion;
- if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
- return endRegion;
-
- return region;
-}
-
LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
{
// If the child has the same directionality as we do, then we can just return its