diff options
Diffstat (limited to 'WebCore/rendering/RenderBlock.cpp')
-rw-r--r-- | WebCore/rendering/RenderBlock.cpp | 1402 |
1 files changed, 876 insertions, 526 deletions
diff --git a/WebCore/rendering/RenderBlock.cpp b/WebCore/rendering/RenderBlock.cpp index 1e378d8..d951277 100644 --- a/WebCore/rendering/RenderBlock.cpp +++ b/WebCore/rendering/RenderBlock.cpp @@ -94,7 +94,7 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding, // we're positioned, floating, a table cell. m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable() - && !block->isBlockFlowRoot(); + && !block->isWritingModeRoot(); m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE; @@ -108,8 +108,8 @@ RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding, m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD || block->style()->marginAfterCollapse() == MDISCARD; - m_posMargin = m_canCollapseMarginBeforeWithChildren ? block->maxMarginBefore(RenderBox::PositiveMargin) : 0; - m_negMargin = m_canCollapseMarginBeforeWithChildren ? block->maxMarginBefore(RenderBox::NegativeMargin) : 0; + m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0; + m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0; } // ------------------------------------------------------------------------------------------------------- @@ -1023,24 +1023,25 @@ bool RenderBlock::isSelfCollapsingBlock() const // (c) have border/padding, // (d) have a min-height // (e) have specified that one of our margins can't collapse using a CSS extension - if (height() > 0 - || isTable() || borderAndPaddingHeight() - || style()->minHeight().isPositive() + if (logicalHeight() > 0 + || isTable() || borderAndPaddingLogicalHeight() + || style()->logicalMinHeight().isPositive() || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE) return false; - bool hasAutoHeight = style()->height().isAuto(); - if (style()->height().isPercent() && !document()->inQuirksMode()) { + Length logicalHeightLength = style()->logicalHeight(); + bool hasAutoHeight = logicalHeightLength.isAuto(); + if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) { hasAutoHeight = true; for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { - if (cb->style()->height().isFixed() || cb->isTableCell()) + if (cb->style()->logicalHeight().isFixed() || cb->isTableCell()) hasAutoHeight = false; } } // If the height is 0 or auto, then whether or not we are a self-collapsing block depends // on whether we have content that is all self-collapsing or not. - if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) { + if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) { // If the block has inline children, see if we generated any line boxes. If we have any // line boxes, then we can't be self-collapsing, since we have content. if (childrenInline()) @@ -1125,7 +1126,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); - int oldWidth = width(); + int oldWidth = logicalWidth(); int oldColumnWidth = desiredColumnWidth(); computeLogicalWidth(); @@ -1145,6 +1146,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) int previousHeight = logicalHeight(); setLogicalHeight(0); bool hasSpecifiedPageHeight = false; + bool pageHeightChanged = false; ColumnInfo* colInfo = columnInfo(); if (hasColumns()) { if (!pageHeight) { @@ -1160,14 +1162,14 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) } if (colInfo->columnHeight() != pageHeight && m_everHadLayout) { colInfo->setColumnHeight(pageHeight); - markDescendantBlocksAndLinesForLayout(); // We need to dirty all descendant blocks and lines, since the column height is different now. + pageHeightChanged = true; } if (!hasSpecifiedPageHeight && !pageHeight) colInfo->clearForcedBreaks(); } - LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection(), pageHeight, colInfo); + LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection(), pageHeight, pageHeightChanged, colInfo); // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track // our current maximal positive and negative margins. These values are used when we @@ -1204,20 +1206,20 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) layer()->setHasVerticalScrollbar(true); } - int repaintTop = 0; - int repaintBottom = 0; - int maxFloatBottom = 0; + int repaintLogicalTop = 0; + int repaintLogicalBottom = 0; + int maxFloatLogicalBottom = 0; if (!firstChild() && !isAnonymousBlock()) setChildrenInline(true); if (childrenInline()) - layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); + layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom); else - layoutBlockChildren(relayoutChildren, maxFloatBottom); + layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom); // Expand our intrinsic height to encompass floats. - int toAdd = borderAfter() + paddingAfter() + horizontalScrollbarHeight(); // FIXME: https://bugs.webkit.org/show_bug.cgi?id=46645, overflow and block-flow. - if (floatBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats()) - setLogicalHeight(floatBottom() + toAdd); + int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); + if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats()) + setLogicalHeight(lowestFloatLogicalBottom() + toAdd); if (layoutColumns(hasSpecifiedPageHeight, pageHeight, statePusher)) return; @@ -1227,13 +1229,13 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) computeLogicalHeight(); int newHeight = logicalHeight(); if (oldHeight != newHeight) { - if (oldHeight > newHeight && maxFloatBottom > newHeight && !childrenInline()) { + if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) { // One of our children's floats may have become an overhanging float for us. We need to look for it. for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { RenderBlock* block = toRenderBlock(child); - if (block->floatBottom() + block->logicalTop() > newHeight) - addOverhangingFloats(block, -block->x(), -block->y(), false); + if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight) + addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false); } } } @@ -1273,10 +1275,15 @@ void RenderBlock::layoutBlock(bool relayoutChildren, int pageHeight) // Repaint with our new bounds if they are different from our old bounds. bool didFullRepaint = repainter.repaintAfterLayout(); - if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { - int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow()); - int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow()); - IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop); + if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { + int repaintLogicalLeft = min(logicalLeftVisualOverflow(), logicalLeftLayoutOverflow()); + int repaintLogicalRight = max(logicalRightVisualOverflow(), logicalRightLayoutOverflow()); + + IntRect repaintRect; + if (style()->isHorizontalWritingMode()) + repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop); + else + repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft); // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union. adjustRectForColumns(repaintRect); @@ -1318,7 +1325,7 @@ void RenderBlock::addOverflowFromFloats() DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (; (r = it.current()); ++it) { if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) - addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); + addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop())); } return; } @@ -1326,13 +1333,13 @@ void RenderBlock::addOverflowFromFloats() bool RenderBlock::expandsToEncloseOverhangingFloats() const { return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) - || hasColumns() || isTableCell() || isFieldset() || isBlockFlowRoot(); + || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot(); } void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) { if (child->style()->hasStaticX()) { - if (style()->direction() == LTR) + if (style()->isLeftToRightDirection()) child->layer()->setStaticX(borderLeft() + paddingLeft()); else child->layer()->setStaticX(borderRight() + paddingRight()); @@ -1343,8 +1350,8 @@ void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marg if (!marginInfo.canCollapseWithMarginBefore()) { child->computeBlockDirectionMargins(this); int marginTop = child->marginTop(); - int collapsedTopPos = marginInfo.posMargin(); - int collapsedTopNeg = marginInfo.negMargin(); + int collapsedTopPos = marginInfo.positiveMargin(); + int collapsedTopNeg = marginInfo.negativeMargin(); if (marginTop > 0) { if (marginTop > collapsedTopPos) collapsedTopPos = marginTop; @@ -1378,9 +1385,9 @@ void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for // an example of this scenario. int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin(); - setLogicalHeight(height() + marginOffset); + setLogicalHeight(logicalHeight() + marginOffset); positionNewFloats(); - setLogicalHeight(height() - marginOffset); + setLogicalHeight(logicalHeight() - marginOffset); } bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) @@ -1474,15 +1481,18 @@ bool RenderBlock::handleRunInChild(RenderBox* child) int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) { + // Get the four margin values for the child and cache them. + const MarginValues childMargins = marginValuesForChild(child); + // Get our max pos and neg top margins. - int posTop = child->maxMarginBefore(PositiveMargin); - int negTop = child->maxMarginBefore(NegativeMargin); + int posTop = childMargins.positiveMarginBefore(); + int negTop = childMargins.negativeMarginBefore(); // For self-collapsing blocks, collapse our bottom margins into our // top to get new posTop and negTop values. if (child->isSelfCollapsingBlock()) { - posTop = max(posTop, child->maxMarginAfter(PositiveMargin)); - negTop = max(negTop, child->maxMarginAfter(NegativeMargin)); + posTop = max(posTop, childMargins.positiveMarginAfter()); + negTop = max(negTop, childMargins.negativeMarginAfter()); } // See if the top margin is quirky. We only care if this child has @@ -1494,18 +1504,18 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) // block. If it has larger margin values, then we need to update // our own maximal values. if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk) - setMaxMarginBeforeValues(max(posTop, maxPosMarginBefore()), max(negTop, maxNegMarginBefore())); + setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore())); // The minute any of the margins involved isn't a quirk, don't // collapse it away, even if the margin is smaller (www.webreference.com // has an example of this, a <dt> with 0.8em author-specified inside // a <dl> inside a <td>. - if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop-negTop)) { + if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) { setMarginBeforeQuirk(false); marginInfo.setDeterminedMarginBeforeQuirk(true); } - if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && marginTop() == 0) + if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore()) // We have no top margin and our top child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. @@ -1517,44 +1527,44 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop)) marginInfo.setMarginBeforeQuirk(topQuirk); - int beforeCollapseY = height(); - int ypos = beforeCollapseY; + int beforeCollapseLogicalTop = logicalHeight(); + int logicalTop = beforeCollapseLogicalTop; if (child->isSelfCollapsingBlock()) { // This child has no height. We need to compute our // position before we collapse the child's margins together, // so that we can get an accurate position for the zero-height block. - int collapsedTopPos = max(marginInfo.posMargin(), child->maxMarginBefore(PositiveMargin)); - int collapsedTopNeg = max(marginInfo.negMargin(), child->maxMarginBefore(NegativeMargin)); - marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); + int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore()); + int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore()); + marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg); // Now collapse the child's margins together, which means examining our // bottom margin values as well. - marginInfo.setPosMarginIfLarger(child->maxMarginAfter(PositiveMargin)); - marginInfo.setNegMarginIfLarger(child->maxMarginAfter(NegativeMargin)); + marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter()); + marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter()); if (!marginInfo.canCollapseWithMarginBefore()) // We need to make sure that the position of the self-collapsing block // is correct, since it could have overflowing content // that needs to be positioned correctly (e.g., a block that // had a specified height of 0 but that actually had subcontent). - ypos = height() + collapsedTopPos - collapsedTopNeg; + logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg; } else { if (child->style()->marginBeforeCollapse() == MSEPARATE) { - setLogicalHeight(height() + marginInfo.margin() + child->marginTop()); - ypos = height(); + setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child)); + logicalTop = logicalHeight(); } else if (!marginInfo.atBeforeSideOfBlock() || (!marginInfo.canCollapseMarginBeforeWithChildren() && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) { // We're collapsing with a previous sibling's margins and not // with the top of the block. - setLogicalHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); - ypos = height(); + setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop)); + logicalTop = logicalHeight(); } - marginInfo.setPosMargin(child->maxMarginAfter(PositiveMargin)); - marginInfo.setNegMargin(child->maxMarginAfter(NegativeMargin)); + marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); + marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); if (marginInfo.margin()) marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD); @@ -1563,12 +1573,12 @@ int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins // collapsed into the page edge. bool paginated = view()->layoutState()->isPaginated(); - if (paginated && ypos > beforeCollapseY) { - int oldY = ypos; - ypos = min(ypos, nextPageTop(beforeCollapseY)); - setLogicalHeight(height() + (ypos - oldY)); + if (paginated && logicalTop > beforeCollapseLogicalTop) { + int oldLogicalTop = logicalTop; + logicalTop = min(logicalTop, nextPageTop(beforeCollapseLogicalTop)); + setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); } - return ypos; + return logicalTop; } int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) @@ -1590,12 +1600,14 @@ int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, i if (!curr->isFloatingOrPositioned()) atBottomOfBlock = false; } + + MarginValues childMargins = marginValuesForChild(child); if (atBottomOfBlock) { - marginInfo.setPosMargin(child->maxMarginAfter(PositiveMargin)); - marginInfo.setNegMargin(child->maxMarginAfter(NegativeMargin)); + marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); + marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); } else { - marginInfo.setPosMargin(max(child->maxMarginBefore(PositiveMargin), child->maxMarginAfter(PositiveMargin))); - marginInfo.setNegMargin(max(child->maxMarginBefore(NegativeMargin), child->maxMarginAfter(NegativeMargin))); + marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); + marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); } // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom @@ -1618,89 +1630,68 @@ int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, i return yPos + heightIncrease; } -int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) +int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo) { // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological // relayout if there are intruding floats. - int yPosEstimate = height(); + int logicalTopEstimate = logicalHeight(); if (!marginInfo.canCollapseWithMarginBefore()) { - int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginBefore(); - yPosEstimate += max(marginInfo.margin(), childMarginTop); + int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child); + logicalTopEstimate += max(marginInfo.margin(), childMarginBefore); } bool paginated = view()->layoutState()->isPaginated(); - // Adjust yPosEstimate down to the next page if the margins are so large that we don't fit on the current + // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current // page. - if (paginated && yPosEstimate > height()) - yPosEstimate = min(yPosEstimate, nextPageTop(height())); + if (paginated && logicalTopEstimate > logicalHeight()) + logicalTopEstimate = min(logicalTopEstimate, nextPageTop(logicalHeight())); - yPosEstimate += getClearDelta(child, yPosEstimate); + logicalTopEstimate += getClearDelta(child, logicalTopEstimate); if (paginated) { // If the object has a page or column break value of "before", then we should shift to the top of the next page. - yPosEstimate = applyBeforeBreak(child, yPosEstimate); + logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate); // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. - yPosEstimate = adjustForUnsplittableChild(child, yPosEstimate); + logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate); if (!child->selfNeedsLayout() && child->isRenderBlock()) - yPosEstimate += toRenderBlock(child)->paginationStrut(); + logicalTopEstimate += toRenderBlock(child)->paginationStrut(); } - return yPosEstimate; + return logicalTopEstimate; } -void RenderBlock::determineHorizontalPosition(RenderBox* child) +void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child) { - int xPos = borderLeft() + paddingLeft(); - if (style()->direction() == LTR) { - // Add in our left margin. - int chPos = xPos + child->marginLeft(); + int startPosition = borderStart() + paddingStart(); + int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); + + // Add in our start margin. + int childMarginStart = marginStartForChild(child); + int newPosition = startPosition + childMarginStart; - // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need - // to shift over as necessary to dodge any floats that might get in the way. - if (child->avoidsFloats()) { - int leftOff = logicalLeftOffsetForLine(height(), false); - if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { - if (child->marginLeft() < 0) - leftOff += child->marginLeft(); - chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit. - } - else if (leftOff != xPos) { - // The object is shifting right. The object might be centered, so we need to - // recalculate our horizontal margins. Note that the containing block content - // width computation will take into account the delta between |leftOff| and |xPos| - // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection| - // function. - child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(child->y(), false), child->width()); - chPos = leftOff + child->marginLeft(); - } - } - view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); - child->setLocation(chPos, child->y()); - } else { - xPos += availableLogicalWidth(); - int chPos = xPos - (child->width() + child->marginRight()); - if (child->avoidsFloats()) { - int rightOff = logicalRightOffsetForLine(height(), false); - if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { - if (child->marginRight() < 0) - rightOff -= child->marginRight(); - chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. - } else if (rightOff != xPos) { - // The object is shifting left. The object might be centered, so we need to - // recalculate our horizontal margins. Note that the containing block content - // width computation will take into account the delta between |rightOff| and |xPos| - // so that we can just pass the content width in directly to the |computeInlineDirectionMargins| - // function. - child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(child->y(), false), child->width()); - chPos = rightOff - child->marginRight() - child->width(); - } + // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need + // to shift over as necessary to dodge any floats that might get in the way. + if (child->avoidsFloats()) { + int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false); + if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) { + if (childMarginStart < 0) + startOff += childMarginStart; + newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit. + } else if (startOff != startPosition) { + // The object is shifting to the "end" side of the block. The object might be centered, so we need to + // recalculate our inline direction margins. Note that the containing block content + // width computation will take into account the delta between |startOff| and |startPosition| + // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection| + // function. + child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child)); + newPosition = startOff + marginStartForChild(child); } - view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); - child->setLocation(chPos, child->y()); } + + setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta); } void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) @@ -1708,12 +1699,12 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) { // Update our max pos/neg bottom margins, since we collapsed our bottom margins // with our children. - setMaxMarginAfterValues(max(maxPosMarginAfter(), marginInfo.posMargin()), max(maxNegMarginAfter(), marginInfo.negMargin())); + setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin())); if (!marginInfo.marginAfterQuirk()) setMarginAfterQuirk(false); - if (marginInfo.marginAfterQuirk() && marginBottom() == 0) + if (marginInfo.marginAfterQuirk() && marginAfter() == 0) // We have no bottom margin and our last child has a quirky margin. // We will pick up this quirky margin and pass it through. // This deals with the <td><div><p> case. @@ -1721,27 +1712,53 @@ void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) } } -void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo) +void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo) { marginInfo.setAtAfterSideOfBlock(true); // If we can't collapse with children then go ahead and add in the bottom margin. if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk())) - setLogicalHeight(height() + marginInfo.margin()); + setLogicalHeight(logicalHeight() + marginInfo.margin()); // Now add in our bottom border/padding. - setLogicalHeight(height() + bottom); + setLogicalHeight(logicalHeight() + afterSide); // Negative margins can cause our height to shrink below our minimal height (border/padding). // If this happens, ensure that the computed height is increased to the minimal height. - setLogicalHeight(max(height(), top + bottom)); + setLogicalHeight(max(logicalHeight(), beforeSide + afterSide)); // Update our bottom collapsed margin info. setCollapsedBottomMargin(marginInfo); } -void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom) +void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta) +{ + if (style()->isHorizontalWritingMode()) { + if (applyDelta == ApplyLayoutDelta) + view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0)); + child->setX(logicalLeft); + } else { + if (applyDelta == ApplyLayoutDelta) + view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft)); + child->setY(logicalLeft); + } +} + +void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta) +{ + if (style()->isHorizontalWritingMode()) { + if (applyDelta == ApplyLayoutDelta) + view()->addLayoutDelta(IntSize(0, child->y() - logicalTop)); + child->setY(logicalTop); + } else { + if (applyDelta == ApplyLayoutDelta) + view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0)); + child->setX(logicalTop); + } +} + +void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom) { if (gPercentHeightDescendantsMap) { if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { @@ -1761,20 +1778,22 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom } } - int top = borderTop() + paddingTop(); - int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); + int beforeEdge = borderBefore() + paddingBefore(); + int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); - setLogicalHeight(top); + setLogicalHeight(beforeEdge); // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, - MarginInfo marginInfo(this, top, bottom); + MarginInfo marginInfo(this, beforeEdge, afterEdge); // Fieldsets need to find their legend and position it inside the border of the object. // The legend then gets skipped during normal layout. + // FIXME: Make fieldsets work with block-flow. + // https://bugs.webkit.org/show_bug.cgi?id=46785 RenderObject* legend = layoutLegend(relayoutChildren); - int previousFloatBottom = 0; - maxFloatBottom = 0; + int previousFloatLogicalBottom = 0; + maxFloatLogicalBottom = 0; RenderBox* next = firstChildBox(); @@ -1788,11 +1807,11 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom // Make sure we layout children if they need it. // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into // an auto value. Add a method to determine this, so that we can avoid the relayout. - if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView())) + if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView())) child->setChildNeedsLayout(true, false); - // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. - if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent())) + // If relayoutChildren is set and the child has percentage padding, we also need to invalidate the child's pref widths. + if (relayoutChildren && (child->style()->paddingStart().isPercent() || child->style()->paddingEnd().isPercent())) child->setPreferredLogicalWidthsDirty(true, false); // Handle the four types of special elements first. These include positioned content, floating content, compacts and @@ -1801,63 +1820,64 @@ void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom continue; // Lay out the child. - layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom); + layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom); } // Now do the handling of the bottom of the block, adding in our bottom border/padding and // determining the correct collapsed bottom margin information. - handleBottomOfBlock(top, bottom, marginInfo); + handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo); } -void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom) +void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom) { - int oldTopPosMargin = maxPosMarginBefore(); - int oldTopNegMargin = maxNegMarginBefore(); + int oldPosMarginBefore = maxPositiveMarginBefore(); + int oldNegMarginBefore = maxNegativeMarginBefore(); - // The child is a normal flow object. Compute its vertical margins now. + // The child is a normal flow object. Compute the margins we will use for collapsing now. child->computeBlockDirectionMargins(this); - // Do not allow a collapse if the margin top collapse style is set to SEPARATE. + // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE. if (child->style()->marginBeforeCollapse() == MSEPARATE) { marginInfo.setAtBeforeSideOfBlock(false); marginInfo.clearMargin(); } - // Try to guess our correct y position. In most cases this guess will - // be correct. Only if we're wrong (when we compute the real y position) + // Try to guess our correct logical top position. In most cases this guess will + // be correct. Only if we're wrong (when we compute the real logical top position) // will we have to potentially relayout. - int yPosEstimate = estimateVerticalPosition(child, marginInfo); + int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo); // Cache our old rect so that we can dirty the proper repaint rects if the child moves. IntRect oldRect(child->x(), child->y() , child->width(), child->height()); + int oldLogicalTop = logicalTopForChild(child); + #ifndef NDEBUG IntSize oldLayoutDelta = view()->layoutDelta(); #endif // Go ahead and position the child as though it didn't collapse with the top. - view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); - child->setLocation(child->x(), yPosEstimate); + setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta); RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; bool markDescendantsWithFloats = false; - if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats()) + if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats()) markDescendantsWithFloats = true; else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { // If an element might be affected by the presence of floats, then always mark it for // layout. - int fb = max(previousFloatBottom, floatBottom()); - if (fb > yPosEstimate) + int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom()); + if (fb > logicalTopEstimate) markDescendantsWithFloats = true; } if (childRenderBlock) { if (markDescendantsWithFloats) childRenderBlock->markAllDescendantsWithFloatsForLayout(); - previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); + if (!child->isWritingModeRoot()) + previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom()); } - bool paginated = view()->layoutState()->isPaginated(); - if (!child->needsLayout() && paginated && view()->layoutState()->m_pageHeight && childRenderBlock && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY()) - childRenderBlock->markForPaginationRelayout(); + if (!child->needsLayout()) + child->markForPaginationRelayoutIfNeeded(); bool childHadLayout = child->m_everHadLayout; bool childNeededLayout = child->needsLayout(); @@ -1869,23 +1889,24 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int // Now determine the correct ypos based off examination of collapsing margin // values. - int yBeforeClear = collapseMargins(child, marginInfo); + int logicalTopBeforeClear = collapseMargins(child, marginInfo); // Now check for clear. - int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); + int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear); + bool paginated = view()->layoutState()->isPaginated(); if (paginated) { - int oldY = yAfterClear; + int oldTop = logicalTopAfterClear; // If the object has a page or column break value of "before", then we should shift to the top of the next page. - yAfterClear = applyBeforeBreak(child, yAfterClear); + logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear); // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. - int yBeforeUnsplittableAdjustment = yAfterClear; - int yAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, yAfterClear); + int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear; + int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear); int paginationStrut = 0; - int unsplittableAdjustmentDelta = yAfterUnsplittableAdjustment - yBeforeUnsplittableAdjustment; + int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; if (unsplittableAdjustmentDelta) paginationStrut = unsplittableAdjustmentDelta; else if (childRenderBlock && childRenderBlock->paginationStrut()) @@ -1894,26 +1915,25 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int if (paginationStrut) { // We are willing to propagate out to our parent block as long as we were at the top of the block prior // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination. - if (atBeforeSideOfBlock && oldY == yBeforeClear && !isPositioned() && !isTableCell()) { + if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) { // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too // and pushes to the next page anyway, so not too concerned about it. - setPaginationStrut(yAfterClear + paginationStrut); + setPaginationStrut(logicalTopAfterClear + paginationStrut); if (childRenderBlock) childRenderBlock->setPaginationStrut(0); } else - yAfterClear += paginationStrut; + logicalTopAfterClear += paginationStrut; } // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. - setLogicalHeight(height() + (yAfterClear - oldY)); + setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop)); } - view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); - child->setLocation(child->x(), yAfterClear); + setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta); - // Now we have a final y position. See if it really does end up being different from our estimate. - if (yAfterClear != yPosEstimate) { + // Now we have a final top position. See if it really does end up being different from our estimate. + if (logicalTopAfterClear != logicalTopEstimate) { if (child->shrinkToAvoidFloats()) { // The child's width depends on the line width. // When the child shifts to clear an item, its width can @@ -1924,8 +1944,8 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int if (childRenderBlock) { if (!child->avoidsFloats() && childRenderBlock->containsFloats()) childRenderBlock->markAllDescendantsWithFloatsForLayout(); - if (paginated && !child->needsLayout() && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(child->y()) != childRenderBlock->pageY()) - childRenderBlock->markForPaginationRelayout(); + if (!child->needsLayout()) + child->markForPaginationRelayoutIfNeeded(); } // Our guess was wrong. Make the child lay itself out again. @@ -1937,19 +1957,19 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock()) marginInfo.setAtBeforeSideOfBlock(false); - // Now place the child in the correct horizontal position - determineHorizontalPosition(child); + // Now place the child in the correct left position + determineLogicalLeftPositionForChild(child); // Update our height now that the child has been placed in the correct position. - setLogicalHeight(height() + child->height()); + setLogicalHeight(logicalHeight() + logicalHeightForChild(child)); if (child->style()->marginAfterCollapse() == MSEPARATE) { - setLogicalHeight(height() + child->marginBottom()); + setLogicalHeight(logicalHeight() + marginAfterForChild(child)); marginInfo.clearMargin(); } // If the child has overhanging floats that intrude into following siblings (or possibly out // of this block), then the parent gets notified of the floats now. if (childRenderBlock && childRenderBlock->containsFloats()) - maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); + maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout)); IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); if (childOffset.width() || childOffset.height()) { @@ -2014,8 +2034,6 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) if (hasColumns()) view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns. - bool paginated = view()->layoutState()->isPaginated(); - RenderBox* r; Iterator end = m_positionedObjects->end(); for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { @@ -2031,11 +2049,8 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) r->setPreferredLogicalWidthsDirty(true, false); - if (!r->needsLayout() && paginated && view()->layoutState()->m_pageHeight) { - RenderBlock* childRenderBlock = r->isRenderBlock() ? toRenderBlock(r) : 0; - if (childRenderBlock && view()->layoutState()->pageY(childRenderBlock->y()) != childRenderBlock->pageY()) - childRenderBlock->markForPaginationRelayout(); - } + if (!r->needsLayout()) + r->markForPaginationRelayoutIfNeeded(); // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. @@ -2061,6 +2076,16 @@ void RenderBlock::markPositionedObjectsForLayout() } } +void RenderBlock::markForPaginationRelayoutIfNeeded() +{ + ASSERT(!needsLayout()); + if (needsLayout()) + return; + + if (view()->layoutState()->pageHeightChanged() || (view()->layoutState()->pageHeight() && view()->layoutState()->pageY(y()) != pageY())) + setChildNeedsLayout(true, false); +} + void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) { // Repaint any overhanging floats (if we know we're the one to paint them). @@ -2081,7 +2106,7 @@ void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) // Only repaint the object if it is overhanging, is not in its own layer, and // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter // condition is replaced with being a descendant of us. - if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { + if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { r->m_renderer->repaint(); r->m_renderer->repaintOverhangingFloats(); } @@ -2134,14 +2159,14 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) // We need to do multiple passes, breaking up our child painting into strips. ColumnInfo* colInfo = columnInfo(); unsigned colCount = columnCount(colInfo); - int currXOffset = style()->direction() == LTR ? 0 : contentWidth(); + int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth(); int ruleAdd = borderLeft() + paddingLeft(); - int ruleX = style()->direction() == LTR ? 0 : contentWidth(); + int ruleX = style()->isLeftToRightDirection() ? 0 : contentWidth(); for (unsigned i = 0; i < colCount; i++) { IntRect colRect = columnRectAt(colInfo, i); // Move to the next position. - if (style()->direction() == LTR) { + if (style()->isLeftToRightDirection()) { ruleX += colRect.width() + colGap / 2; currXOffset += colRect.width() + colGap; } else { @@ -2156,7 +2181,7 @@ void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) int ruleTop = ty + borderTop() + paddingTop(); int ruleBottom = ruleTop + contentHeight(); drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, - style()->direction() == LTR ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0); + style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0); } ruleX = currXOffset; @@ -2172,7 +2197,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool unsigned colCount = columnCount(colInfo); if (!colCount) return; - int currXOffset = style()->direction() == LTR ? 0 : contentWidth() - columnRectAt(colInfo, 0).width(); + int currXOffset = style()->isLeftToRightDirection() ? 0 : contentWidth() - columnRectAt(colInfo, 0).width(); int currYOffset = 0; for (unsigned i = 0; i < colCount; i++) { // For each rect, we clip to the rect, and then we adjust our coords. @@ -2200,7 +2225,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool } // Move to the next position. - if (style()->direction() == LTR) + if (style()->isLeftToRightDirection()) currXOffset += colRect.width() + colGap; else currXOffset -= (colRect.width() + colGap); @@ -2393,8 +2418,8 @@ void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preserv if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { PaintInfo currentPaintInfo(paintInfo); currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); - int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); + int currentTX = tx + r->left() - r->m_renderer->x() + r->m_renderer->marginLeft(); + int currentTY = ty + r->top() - r->m_renderer->y() + r->m_renderer->marginTop(); r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); if (!preservePhase) { currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; @@ -2603,8 +2628,8 @@ GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int if (m_floatingObjects) { for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { FloatingObject* r = it.current(); - paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(), - ty + r->m_top + r->m_renderer->marginTop(), + paintInfo->context->clipOut(IntRect(tx + r->left() + r->m_renderer->marginLeft(), + ty + r->top() + r->m_renderer->marginTop(), r->m_renderer->width(), r->m_renderer->height())); } } @@ -2815,7 +2840,7 @@ IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int y void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) { - bool ltr = style()->direction() == LTR; + bool ltr = style()->isLeftToRightDirection(); leftGap = (state == RenderObject::SelectionInside) || (state == RenderObject::SelectionEnd && ltr) || (state == RenderObject::SelectionStart && !ltr); @@ -2933,20 +2958,21 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) // Create the special object entry & append it to the list FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight); - - newObj->m_top = -1; - newObj->m_bottom = -1; // Our location is irrelevant if we're unsplittable or no pagination is in effect. // Just go ahead and lay out the float. - bool affectedByPagination = o->isRenderBlock() && view()->layoutState()->m_pageHeight; - if (!affectedByPagination) + bool isChildRenderBlock = o->isRenderBlock(); + if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageHeightChanged()) + o->setChildNeedsLayout(true, false); + + bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageHeight; + if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root. o->layoutIfNeeded(); else { o->computeLogicalWidth(); o->computeBlockDirectionMargins(this); } - newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); + setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o)); newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. newObj->m_isDescendant = true; @@ -2964,12 +2990,14 @@ void RenderBlock::removeFloatingObject(RenderBox* o) while (it.current()) { if (it.current()->m_renderer == o) { if (childrenInline()) { - int bottom = it.current()->m_bottom; + int logicalTop = logicalTopForFloat(it.current()); + int logicalBottom = logicalBottomForFloat(it.current()); + // Special-case zero- and less-than-zero-height floats: those don't touch // the line that they're on, but it still needs to be dirtied. This is // accomplished by pretending they have a height of 1. - bottom = max(bottom, it.current()->m_top + 1); - markLinesDirtyInVerticalRange(0, bottom); + logicalBottom = max(logicalBottom, logicalTop + 1); + markLinesDirtyInBlockRange(0, logicalBottom); } m_floatingObjects->removeRef(it.current()); } @@ -2984,7 +3012,7 @@ void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int y) return; FloatingObject* curr = m_floatingObjects->last(); - while (curr != lastFloat && (curr->m_top == -1 || curr->m_top >= y)) { + while (curr != lastFloat && (!curr->isPlaced() || curr->top() >= y)) { m_floatingObjects->removeLast(); curr = m_floatingObjects->last(); } @@ -2995,111 +3023,118 @@ bool RenderBlock::positionNewFloats() if (!m_floatingObjects) return false; - FloatingObject* f = m_floatingObjects->last(); + FloatingObject* floatingObject = m_floatingObjects->last(); // If all floats have already been positioned, then we have no work to do. - if (!f || f->m_top != -1) + if (!floatingObject || floatingObject->isPlaced()) return false; // Move backwards through our floating object list until we find a float that has // already been positioned. Then we'll be able to move forward, positioning all of // the new floats that need it. FloatingObject* lastFloat = m_floatingObjects->getPrev(); - while (lastFloat && lastFloat->m_top == -1) { - f = m_floatingObjects->prev(); + while (lastFloat && !lastFloat->isPlaced()) { + floatingObject = m_floatingObjects->prev(); lastFloat = m_floatingObjects->getPrev(); } - int y = height(); + int logicalTop = logicalHeight(); - // The float cannot start above the y position of the last positioned float. + // The float cannot start above the top position of the last positioned float. if (lastFloat) - y = max(lastFloat->m_top, y); + logicalTop = max(logicalTopForFloat(lastFloat), logicalTop); // Now walk through the set of unpositioned floats and place them. - while (f) { + while (floatingObject) { // The containing block is responsible for positioning floats, so if we have floats in our // list that come from somewhere else, do not attempt to position them. - if (f->m_renderer->containingBlock() != this) { - f = m_floatingObjects->next(); + if (floatingObject->renderer()->containingBlock() != this) { + floatingObject = m_floatingObjects->next(); continue; } - RenderBox* o = f->m_renderer; + RenderBox* childBox = floatingObject->renderer(); + int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); - int ro = logicalRightOffsetForContent(); // Constant part of right offset. - int lo = logicalLeftOffsetForContent(); // Constant part of left offset. - int fwidth = f->m_width; // The width we look for. - if (ro - lo < fwidth) - fwidth = ro - lo; // Never look for more than what will be available. + int rightOffset = logicalRightOffsetForContent(); // Constant part of right offset. + int leftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. + int floatLogicalWidth = logicalWidthForFloat(floatingObject); // The width we look for. + if (rightOffset - leftOffset < floatLogicalWidth) + floatLogicalWidth = rightOffset - leftOffset; // Never look for more than what will be available. - IntRect oldRect(o->x(), o->y() , o->width(), o->height()); + IntRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height()); - if (o->style()->clear() & CLEFT) - y = max(leftBottom(), y); - if (o->style()->clear() & CRIGHT) - y = max(rightBottom(), y); + if (childBox->style()->clear() & CLEFT) + logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop); + if (childBox->style()->clear() & CRIGHT) + logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop); - if (o->style()->floating() == FLEFT) { + int floatLogicalLeft; + if (childBox->style()->floating() == FLEFT) { int heightRemainingLeft = 1; int heightRemainingRight = 1; - int fx = logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft); - while (logicalRightOffsetForLine(y, ro, false, &heightRemainingRight)-fx < fwidth) { - y += min(heightRemainingLeft, heightRemainingRight); - fx = logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft); + floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft); + while (logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { + logicalTop += min(heightRemainingLeft, heightRemainingRight); + floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft); } - fx = max(0, fx); - f->m_left = fx; - o->setLocation(fx + o->marginLeft(), y + o->marginTop()); + floatLogicalLeft = max(0, floatLogicalLeft); } else { int heightRemainingLeft = 1; int heightRemainingRight = 1; - int fx = logicalRightOffsetForLine(y, ro, false, &heightRemainingRight); - while (fx - logicalLeftOffsetForLine(y, lo, false, &heightRemainingLeft) < fwidth) { - y += min(heightRemainingLeft, heightRemainingRight); - fx = logicalRightOffsetForLine(y, ro, false, &heightRemainingRight); + floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight); + while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft) < floatLogicalWidth) { + logicalTop += min(heightRemainingLeft, heightRemainingRight); + floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight); } - f->m_left = fx - f->m_width; - o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); + floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable + // |floatLogicalWidth| was capped to the available line width. + // See fast/block/float/clamped-right-float.html. } + + setLogicalLeftForFloat(floatingObject, floatLogicalLeft); + setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin); + setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox)); if (view()->layoutState()->isPaginated()) { - RenderBlock* childBlock = o->isRenderBlock() ? toRenderBlock(o) : 0; + RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0; - if (childBlock && view()->layoutState()->m_pageHeight && view()->layoutState()->pageY(o->y()) != childBlock->pageY()) - childBlock->markForPaginationRelayout(); - o->layoutIfNeeded(); + if (!childBox->needsLayout()) + childBox->markForPaginationRelayoutIfNeeded();; + childBox->layoutIfNeeded(); // If we are unsplittable and don't fit, then we need to move down. // We include our margins as part of the unsplittable area. - int newY = adjustForUnsplittableChild(o, y, true); + int newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, true); // See if we have a pagination strut that is making us move down further. // Note that an unsplittable child can't also have a pagination strut, so this is // exclusive with the case above. if (childBlock && childBlock->paginationStrut()) { - newY += childBlock->paginationStrut(); + newLogicalTop += childBlock->paginationStrut(); childBlock->setPaginationStrut(0); } - if (newY != y) { - f->m_paginationStrut = newY - y; - y = newY; - o->setY(y + o->marginTop()); + if (newLogicalTop != logicalTop) { + floatingObject->m_paginationStrut = newLogicalTop - logicalTop; + logicalTop = newLogicalTop; + setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox)); if (childBlock) childBlock->setChildNeedsLayout(true, false); - o->layoutIfNeeded(); + childBox->layoutIfNeeded(); } } - f->m_top = y; - f->m_bottom = f->m_top + o->marginTop() + o->height() + o->marginBottom(); - + setLogicalTopForFloat(floatingObject, logicalTop); + setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox)); + + floatingObject->setIsPlaced(); + // If the child moved, we have to repaint it. - if (o->checkForRepaintDuringLayout()) - o->repaintDuringLayoutIfMoved(oldRect); + if (childBox->checkForRepaintDuringLayout()) + childBox->repaintDuringLayoutIfMoved(oldRect); - f = m_floatingObjects->next(); + floatingObject = m_floatingObjects->next(); } return true; } @@ -3110,30 +3145,29 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec if (!didPosition || !newFloat->m_paginationStrut) return didPosition; - int floatTop = newFloat->m_top; + int floatLogicalTop = logicalTopForFloat(newFloat); int paginationStrut = newFloat->m_paginationStrut; FloatingObject* f = m_floatingObjects->last(); ASSERT(f == newFloat); - if (floatTop - paginationStrut != height()) + if (floatLogicalTop - paginationStrut != logicalHeight()) return didPosition; for (f = m_floatingObjects->prev(); f && f != lastFloatFromPreviousLine; f = m_floatingObjects->prev()) { - if (f->m_top == height()) { + if (logicalTopForFloat(f) == logicalHeight()) { ASSERT(!f->m_paginationStrut); f->m_paginationStrut = paginationStrut; RenderBox* o = f->m_renderer; - o->setY(o->y() + o->marginTop() + paginationStrut); + setLogicalTopForChild(o, logicalTopForChild(o) + marginBeforeForChild(o) + paginationStrut); if (o->isRenderBlock()) toRenderBlock(o)->setChildNeedsLayout(true, false); o->layoutIfNeeded(); - f->m_top += f->m_paginationStrut; - f->m_bottom += f->m_paginationStrut; + setLogicalTopForFloat(f, logicalTopForFloat(f) + f->m_paginationStrut); } } - setLogicalHeight(height() + paginationStrut); + setLogicalHeight(logicalHeight() + paginationStrut); return didPosition; } @@ -3146,13 +3180,13 @@ void RenderBlock::newLine(EClear clear) switch (clear) { case CLEFT: - newY = leftBottom(); + newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft); break; case CRIGHT: - newY = rightBottom(); + newY = lowestFloatLogicalBottom(FloatingObject::FloatRight); break; case CBOTH: - newY = floatBottom(); + newY = lowestFloatLogicalBottom(); default: break; } @@ -3220,30 +3254,26 @@ HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; } -int RenderBlock::logicalLeftOffsetForContent() const -{ - return borderLeft() + paddingLeft(); -} - -int RenderBlock::logicalLeftOffsetForLine(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const +int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int left = fixedOffset; if (m_floatingObjects) { - if ( heightRemaining ) *heightRemaining = 1; + if (heightRemaining) + *heightRemaining = 1; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - { - if (r->m_top <= y && r->m_bottom > y && - r->type() == FloatingObject::FloatLeft && - r->m_left + r->m_width > left) { - left = r->m_left + r->m_width; - if ( heightRemaining ) *heightRemaining = r->m_bottom - y; + for ( ; (r = it.current()); ++it) { + if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop + && r->type() == FloatingObject::FloatLeft + && logicalRightForFloat(r) > left) { + left = logicalRightForFloat(r); + if (heightRemaining) + *heightRemaining = logicalBottomForFloat(r) - logicalTop; } } } - if (applyTextIndent && style()->direction() == LTR) { + if (applyTextIndent && style()->isLeftToRightDirection()) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableLogicalWidth(); @@ -3253,31 +3283,27 @@ int RenderBlock::logicalLeftOffsetForLine(int y, int fixedOffset, bool applyText return left; } -int RenderBlock::logicalRightOffsetForContent() const -{ - return borderLeft() + paddingLeft() + availableLogicalWidth(); -} - -int RenderBlock::logicalRightOffsetForLine(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const +int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const { int right = fixedOffset; if (m_floatingObjects) { - if (heightRemaining) *heightRemaining = 1; + if (heightRemaining) + *heightRemaining = 1; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - { - if (r->m_top <= y && r->m_bottom > y && - r->type() == FloatingObject::FloatRight && - r->m_left < right) { - right = r->m_left; - if ( heightRemaining ) *heightRemaining = r->m_bottom - y; + for ( ; (r = it.current()); ++it) { + if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop + && r->type() == FloatingObject::FloatRight + && logicalLeftForFloat(r) < right) { + right = logicalLeftForFloat(r); + if (heightRemaining) + *heightRemaining = logicalBottomForFloat(r) - logicalTop; } } } - if (applyTextIndent && style()->direction() == RTL) { + if (applyTextIndent && !style()->isLeftToRightDirection()) { int cw = 0; if (style()->textIndent().isPercent()) cw = containingBlock()->availableLogicalWidth(); @@ -3294,7 +3320,7 @@ RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const return (result < 0) ? 0 : result; } -int RenderBlock::nextFloatBottomBelow(int height) const +int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const { if (!m_floatingObjects) return 0; @@ -3303,36 +3329,130 @@ int RenderBlock::nextFloatBottomBelow(int height) const FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it) { - if (r->m_bottom > height) - bottom = min(r->m_bottom, bottom); + int floatBottom = logicalBottomForFloat(r); + if (floatBottom > logicalHeight) + bottom = min(floatBottom, bottom); } return bottom == INT_MAX ? 0 : bottom; } -int -RenderBlock::floatBottom() const +int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const { - if (!m_floatingObjects) return 0; - int bottom = 0; + if (!m_floatingObjects) + return 0; + int lowestFloatBottom = 0; FloatingObject* r; DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->m_bottom>bottom) - bottom = r->m_bottom; - return bottom; + for ( ; (r = it.current()); ++it) { + if (r->isPlaced() && r->type() & floatType) + lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r)); + } + return lowestFloatBottom; } -int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBlock::topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const { - int bottom = includeSelf && width() > 0 ? height() : 0; - + IntRect transformedRect = transformedFrameRect(); + int transformedTop = includeSelf && transformedRect.width() > 0 ? 0 : transformedRect.height(); + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return bottom; + return transformedTop; - if (!firstChild() && (!width() || !height())) - return bottom; + if (!firstChild() && (!transformedRect.width() || !transformedRect.height())) + return transformedTop; + + int top = includeSelf && width() > 0 ? 0 : height(); + + if (!hasColumns()) { + // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. + // For now, we have to descend into all the children, since we may have a huge abs div inside + // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to + // the abs div. + for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { + if (!c->isFloatingOrPositioned() && c->isBox()) { + RenderBox* childBox = toRenderBox(c); + top = min(top, childBox->transformedFrameRect().y() + childBox->topmostPosition(false)); + } + } + } + + if (includeSelf && isRelPositioned()) + top += relativePositionOffsetY(); + + if (!includeOverflowInterior && hasOverflowClip()) + return top; + int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0; + + if (includeSelf) + top = min(top, topLayoutOverflow() + relativeOffset); + + if (m_positionedObjects) { + RenderBox* r; + Iterator end = m_positionedObjects->end(); + for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { + r = *it; + // Fixed positioned objects do not scroll and thus should not constitute + // part of the topmost position. + if (r->style()->position() != FixedPosition) { + // FIXME: Should work for overflow sections too. + // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. + // Therefore we should not allow it to contribute to the topmost position. + IntRect transformedR = r->transformedFrameRect(); + if (!isRenderView() || transformedR.x() + transformedR.width() > 0 || transformedR.x() + r->rightmostPosition(false) > 0) { + int tp = transformedR.y() + r->topmostPosition(false); + top = min(top, tp + relativeOffset); + } + } + } + } + + if (hasColumns()) { + ColumnInfo* colInfo = columnInfo(); + for (unsigned i = 0; i < columnCount(colInfo); i++) + top = min(top, columnRectAt(colInfo, i).y() + relativeOffset); + return top; + } + + if (m_floatingObjects) { + FloatingObject* r; + DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); + for ( ; (r = it.current()); ++it) { + if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { + int tp = r->top() + r->m_renderer->marginTop() + r->m_renderer->topmostPosition(false); + top = min(top, tp + relativeOffset); + } + } + } + + if (!includeSelf && firstRootBox()) + top = min(top, firstRootBox()->selectionTop() + relativeOffset); + + if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) { + int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top)); + return transformRect.y(); + } + + return top; +} + +int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const +{ + IntRect transformedRect = transformedFrameRect(); + int transformedBottom = includeSelf && transformedRect.width() > 0 ? transformedRect.height() : 0; + + if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) + return transformedBottom; + + if (!firstChild() && (!transformedRect.width() || !transformedRect.height())) + return transformedBottom; + + int bottom = includeSelf && width() > 0 ? height() : 0; + if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. // For now, we have to descend into all the children, since we may have a huge abs div inside @@ -3343,7 +3463,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { if (!c->isFloatingOrPositioned() && c->isBox()) { RenderBox* childBox = toRenderBox(c); - bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); + bottom = max(bottom, childBox->transformedFrameRect().y() + childBox->lowestPosition(false)); } } } @@ -3369,8 +3489,9 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) // FIXME: Should work for overflow sections too. // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the lowest position. - if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { - int lp = r->y() + r->lowestPosition(false); + IntRect transformedR = r->transformedFrameRect(); + if (!isRenderView() || transformedR.x() + transformedR.width() > 0 || transformedR.x() + r->rightmostPosition(false) > 0) { + int lp = transformedR.y() + r->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } @@ -3389,7 +3510,7 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { - int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); + int lp = r->top() + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); bottom = max(bottom, lp + relativeOffset); } } @@ -3408,24 +3529,36 @@ int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) while (currBox && currBox->isFloatingOrPositioned()) currBox = currBox->previousSiblingBox(); if (currBox) { - int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginAfter(); // FIXME: "after" is wrong here for lowestPosition. + IntRect transformedCurrBox = currBox->transformedFrameRect(); + int childBottomEdge = transformedCurrBox.y() + transformedCurrBox.height() + currBox->collapsedMarginAfter(); // FIXME: "after" is wrong here for lowestPosition. bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); } } } - + + if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) { + int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top)); + return transformRect.height(); + } + return bottom; } -int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const { - int right = includeSelf && height() > 0 ? width() : 0; + IntRect transformedRect = transformedFrameRect(); + int transformedRight = includeSelf && transformedRect.height() > 0 ? transformedRect.width() : 0; if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return right; + return transformedRight; - if (!firstChild() && (!width() || !height())) - return right; + if (!firstChild() && (!transformedRect.width() || !transformedRect.height())) + return transformedRight; + + int right = includeSelf && height() > 0 ? width() : 0; if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. @@ -3435,7 +3568,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { if (!c->isFloatingOrPositioned() && c->isBox()) { RenderBox* childBox = toRenderBox(c); - right = max(right, childBox->x() + childBox->rightmostPosition(false)); + right = max(right, childBox->transformedFrameRect().x() + childBox->rightmostPosition(false)); } } } @@ -3462,8 +3595,9 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the rightmost position. - if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { - int rp = r->x() + r->rightmostPosition(false); + IntRect transformedR = r->transformedFrameRect(); + if (!isRenderView() || transformedR.y() + transformedR.height() > 0 || transformedR.y() + r->lowestPosition(false) > 0) { + int rp = transformedR.x() + r->rightmostPosition(false); right = max(right, rp + relativeOffset); } } @@ -3472,12 +3606,19 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel if (hasColumns()) { // This only matters for LTR - if (style()->direction() == LTR) { + if (style()->isLeftToRightDirection()) { ColumnInfo* colInfo = columnInfo(); unsigned count = columnCount(colInfo); if (count) right = max(columnRectAt(colInfo, count - 1).right() + relativeOffset, right); } + if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) { + int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top)); + return transformRect.width(); + } return right; } @@ -3486,7 +3627,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { - int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); + int rp = r->left() + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); right = max(right, rp + relativeOffset); } } @@ -3500,7 +3641,7 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. - if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight()) + if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection() && !paddingRight()) childRightEdge += 1; right = max(right, childRightEdge + paddingRight() + relativeOffset); } @@ -3509,24 +3650,36 @@ int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSel for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) { if (currBox->isFloatingOrPositioned()) continue; - int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight(); + IntRect transformedChild = currBox->transformedFrameRect(); + int childRightEdge = transformedChild.x() + transformedChild.width() + currBox->marginRight(); right = max(right, childRightEdge + paddingRight() + relativeOffset); } } } + + if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) { + int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top)); + return transformRect.width(); + } return right; } -int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const +int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const { - int left = includeSelf && height() > 0 ? 0 : width(); + IntRect transformedRect = transformedFrameRect(); + int transformedLeft = includeSelf && transformedRect.height() > 0 ? 0 : transformedRect.width(); if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) - return left; + return transformedLeft; - if (!firstChild() && (!width() || !height())) - return left; + if (!firstChild() && (!transformedRect.width() || !transformedRect.height())) + return transformedLeft; + + int left = includeSelf && height() > 0 ? 0 : width(); if (!hasColumns()) { // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. @@ -3536,7 +3689,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { if (!c->isFloatingOrPositioned() && c->isBox()) { RenderBox* childBox = toRenderBox(c); - left = min(left, childBox->x() + childBox->leftmostPosition(false)); + left = min(left, childBox->transformedFrameRect().x() + childBox->leftmostPosition(false)); } } } @@ -3563,8 +3716,9 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf // FIXME: Should work for overflow sections too. // If a positioned object lies completely above the root it will be unreachable via scrolling. // Therefore we should not allow it to contribute to the leftmost position. - if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { - int lp = r->x() + r->leftmostPosition(false); + IntRect transformedR = r->transformedFrameRect(); + if (!isRenderView() || transformedR.y() + transformedR.height() > 0 || transformedR.y() + r->lowestPosition(false) > 0) { + int lp = transformedR.x() + r->leftmostPosition(false); left = min(left, lp + relativeOffset); } } @@ -3573,7 +3727,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf if (hasColumns()) { // This only matters for RTL - if (style()->direction() == RTL) { + if (!style()->isLeftToRightDirection()) { ColumnInfo* colInfo = columnInfo(); unsigned count = columnCount(colInfo); if (count) @@ -3587,7 +3741,7 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for ( ; (r = it.current()); ++it ) { if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { - int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); + int lp = r->left() + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); left = min(left, lp + relativeOffset); } } @@ -3597,51 +3751,31 @@ int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf for (InlineFlowBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) left = min(left, (int)currBox->x() + relativeOffset); } + + if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) { + int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform); + IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top)); + return transformRect.x(); + } return left; } -int -RenderBlock::leftBottom() -{ - if (!m_floatingObjects) return 0; - int bottom = 0; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft) - bottom = r->m_bottom; - - return bottom; -} - -int -RenderBlock::rightBottom() -{ - if (!m_floatingObjects) return 0; - int bottom = 0; - FloatingObject* r; - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - for ( ; (r = it.current()); ++it ) - if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight) - bottom = r->m_bottom; - - return bottom; -} - -void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest) +void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest) { - if (top >= bottom) + if (logicalTop >= logicalBottom) return; RootInlineBox* lowestDirtyLine = lastRootBox(); RootInlineBox* afterLowest = lowestDirtyLine; - while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) { + while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom) { afterLowest = lowestDirtyLine; lowestDirtyLine = lowestDirtyLine->prevRootBox(); } - while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) { + while (afterLowest && afterLowest != highest && afterLowest->blockLogicalHeight() >= logicalTop) { afterLowest->markDirty(); afterLowest = afterLowest->prevRootBox(); } @@ -3678,6 +3812,7 @@ void RenderBlock::clearFloats() // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted // to avoid floats. bool parentHasFloats = false; + RenderBlock* parentBlock = toRenderBlock(parent()); RenderObject* prev = previousSibling(); while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { if (prev->isFloating()) @@ -3686,18 +3821,16 @@ void RenderBlock::clearFloats() } // First add in floats from the parent. - int offset = y(); - if (parentHasFloats) { - RenderBlock* parentBlock = toRenderBlock(parent()); - addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset); - } + int logicalTopOffset = logicalTop(); + if (parentHasFloats) + addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset); - int xoffset = 0; + int logicalLeftOffset = 0; if (prev) - offset -= toRenderBox(prev)->y(); - else if (parent()->isBox()) { - prev = parent(); - xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft(); + logicalTopOffset -= toRenderBox(prev)->logicalTop(); + else { + prev = parentBlock; + logicalLeftOffset += parentBlock->logicalLeftOffsetForContent(); } // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. @@ -3705,29 +3838,31 @@ void RenderBlock::clearFloats() return; RenderBlock* block = toRenderBlock(prev); - if (block->m_floatingObjects && block->floatBottom() > offset) - addIntrudingFloats(block, xoffset, offset); + if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset) + addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset); if (childrenInline()) { - int changeTop = numeric_limits<int>::max(); - int changeBottom = numeric_limits<int>::min(); + int changeLogicalTop = numeric_limits<int>::max(); + int changeLogicalBottom = numeric_limits<int>::min(); if (m_floatingObjects) { for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); + int logicalBottom = logicalBottomForFloat(f); if (oldFloatingObject) { - if (f->m_width != oldFloatingObject->m_width || f->m_left != oldFloatingObject->m_left) { - changeTop = 0; - changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom)); - } else if (f->m_bottom != oldFloatingObject->m_bottom) { - changeTop = min(changeTop, min(f->m_bottom, oldFloatingObject->m_bottom)); - changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom)); + int oldLogicalBottom = logicalBottomForFloat(oldFloatingObject); + if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) { + changeLogicalTop = 0; + changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); + } else if (logicalBottom != oldLogicalBottom) { + changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom)); + changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); } floatMap.remove(f->m_renderer); delete oldFloatingObject; } else { - changeTop = 0; - changeBottom = max(changeBottom, f->m_bottom); + changeLogicalTop = 0; + changeLogicalBottom = max(changeLogicalBottom, logicalBottom); } } } @@ -3736,39 +3871,37 @@ void RenderBlock::clearFloats() for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { FloatingObject* floatingObject = (*it).second; if (!floatingObject->m_isDescendant) { - changeTop = 0; - changeBottom = max(changeBottom, floatingObject->m_bottom); + changeLogicalTop = 0; + changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject)); } } deleteAllValues(floatMap); - markLinesDirtyInVerticalRange(changeTop, changeBottom); + markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); } } -int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bool makeChildPaintOtherFloats) +int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, int logicalTopOffset, bool makeChildPaintOtherFloats) { // Prevent floats from being added to the canvas by the root element, e.g., <html>. - if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isBlockFlowRoot()) + if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot()) return 0; - int lowestFloatBottom = 0; + int lowestFloatLogicalBottom = 0; // Floats that will remain the child's responsibility to paint should factor into its // overflow. DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); for (FloatingObject* r; (r = it.current()); ++it) { - int bottom = child->y() + r->m_bottom; - lowestFloatBottom = max(lowestFloatBottom, bottom); + int logicalBottom = child->logicalTop() + logicalBottomForFloat(r); + lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); - if (bottom > height()) { + if (logicalBottom > logicalHeight()) { // If the object is not in the list, we add it now. if (!containsFloat(r->m_renderer)) { - FloatingObject *floatingObj = new FloatingObject(r->type()); - floatingObj->m_top = r->m_top - yoff; - floatingObj->m_bottom = r->m_bottom - yoff; - floatingObj->m_left = r->m_left - xoff; - floatingObj->m_width = r->m_width; + int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; + int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; + FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height())); floatingObj->m_renderer = r->m_renderer; // The nearest enclosing layer always paints the float (so that zindex and stacking @@ -3797,45 +3930,48 @@ int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bo r->m_shouldPaint = true; if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) - child->addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); + child->addOverflowFromChild(r->m_renderer, IntSize(r->left() + r->m_renderer->marginLeft(), r->top() + r->m_renderer->marginTop())); } - return lowestFloatBottom; + return lowestFloatLogicalBottom; } -void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff) +void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, int logicalTopOffset) { // If the parent or previous sibling doesn't have any floats to add, don't bother. if (!prev->m_floatingObjects) return; + logicalLeftOffset += (style()->isHorizontalWritingMode() ? marginLeft() : marginTop()); + DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects); for (FloatingObject *r; (r = it.current()); ++it) { - if (r->m_bottom > yoff) { + if (logicalBottomForFloat(r) > logicalTopOffset) { // The object may already be in our list. Check for it up front to avoid // creating duplicate entries. FloatingObject* f = 0; if (m_floatingObjects) { DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); while ((f = it.current())) { - if (f->m_renderer == r->m_renderer) break; + if (f->m_renderer == r->m_renderer) + break; ++it; } } if (!f) { - FloatingObject *floatingObj = new FloatingObject(r->type()); - floatingObj->m_top = r->m_top - yoff; - floatingObj->m_bottom = r->m_bottom - yoff; - floatingObj->m_left = r->m_left - xoff; + int leftOffset = style()->isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; + int topOffset = style()->isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; + + FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->left() - leftOffset, r->top() - topOffset, r->width(), r->height())); + // Applying the child's margin makes no sense in the case where the child was passed in. - // since his own margin was added already through the subtraction of the |xoff| variable - // above. |xoff| will equal -flow->marginLeft() in this case, so it's already been taken - // into account. Only apply this code if |child| is false, since otherwise the left margin + // since this margin was added already through the modification of the |logicalLeftOffset| variable + // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken + // into account. Only apply this code if prev is the parent, since otherwise the left margin // will get applied twice. if (prev != parent()) - floatingObj->m_left += prev->marginLeft(); - floatingObj->m_left -= marginLeft(); + floatingObj->setLeft(floatingObj->left() + (style()->isHorizontalWritingMode() ? prev->marginLeft() : prev->marginTop())); + floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it. - floatingObj->m_width = r->m_width; floatingObj->m_renderer = r->m_renderer; // We create the floating object list lazily. @@ -3890,41 +4026,6 @@ void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove } } -void RenderBlock::markDescendantBlocksAndLinesForLayout(bool inLayout) -{ - if (!m_everHadLayout) - return; - - setChildNeedsLayout(true, !inLayout); - - // Iterate over our children and mark them as needed. - if (!childrenInline()) { - for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { - if (child->isFloatingOrPositioned()) - continue; - child->markDescendantBlocksAndLinesForLayout(inLayout); - } - } - - // Walk our floating objects and mark them too. - if (m_floatingObjects) { - DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); - while (it.current()) { - if (it.current()->m_renderer->isRenderBlock()) - it.current()->m_renderer->markDescendantBlocksAndLinesForLayout(inLayout); - ++it; - } - } - - if (m_positionedObjects) { - // FIXME: Technically we don't have to mark the positioned objects if we're the block - // that established the columns, but we don't really have that information here. - Iterator end = m_positionedObjects->end(); - for (Iterator it = m_positionedObjects->begin(); it != end; ++it) - (*it)->markDescendantBlocksAndLinesForLayout(); - } -} - int RenderBlock::getClearDelta(RenderBox* child, int yPos) { // There is no need to compute clearance if we have no floats. @@ -3938,13 +4039,13 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos) case CNONE: break; case CLEFT: - bottom = leftBottom(); + bottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft); break; case CRIGHT: - bottom = rightBottom(); + bottom = lowestFloatLogicalBottom(FloatingObject::FloatRight); break; case CBOTH: - bottom = floatBottom(); + bottom = lowestFloatLogicalBottom(); break; } @@ -3972,7 +4073,7 @@ int RenderBlock::getClearDelta(RenderBox* child, int yPos) if (childWidthAtY <= widthAtY) return y - yPos; - y = nextFloatBottomBelow(y); + y = nextFloatLogicalBottomBelow(y); ASSERT(y >= yPos); if (y < yPos) break; @@ -3999,7 +4100,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Check if we need to do anything at all. IntRect overflowBox = visibleOverflowRect(); overflowBox.move(tx, ty); - if (!overflowBox.intersects(result.rectFromPoint(_x, _y))) + if (!overflowBox.intersects(result.rectForPoint(_x, _y))) return false; } @@ -4013,7 +4114,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // If we have clipping, then we can't have any spillout. bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); bool useClip = (hasControlClip() || useOverflowClip); - IntRect hitTestArea(result.rectFromPoint(_x, _y)); + IntRect hitTestArea(result.rectForPoint(_x, _y)); bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty).intersects(hitTestArea)); if (checkChildren) { // Hit test descendants first. @@ -4042,7 +4143,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Now hit test our background if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { IntRect boundsRect(tx, ty, width(), height()); - if (visibleToHitTesting() && boundsRect.intersects(result.rectFromPoint(_x, _y))) { + if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(_x, _y))) { updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); if (!result.addNodeToRectBasedTestResult(node(), _x, _y, boundsRect)) return true; @@ -4066,8 +4167,8 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); for (it.toLast(); (floatingObject = it.current()); --it) { if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) { - int xOffset = tx + floatingObject->m_left + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x(); - int yOffset = ty + floatingObject->m_top + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y(); + int xOffset = tx + floatingObject->left() + floatingObject->m_renderer->marginLeft() - floatingObject->m_renderer->x(); + int yOffset = ty + floatingObject->top() + floatingObject->m_renderer->marginTop() - floatingObject->m_renderer->y(); if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), xOffset, yOffset)) { updateHitTestResult(result, IntPoint(x - xOffset, y - yOffset)); return true; @@ -4096,13 +4197,13 @@ bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& r currYOffset += colRect.height(); colRect.move(tx, ty); - if (colRect.intersects(result.rectFromPoint(x, y))) { + if (colRect.intersects(result.rectForPoint(x, y))) { // The point is inside this column. // Adjust tx and ty to change where we hit test. int finalX = tx + currXOffset; int finalY = ty + currYOffset; - if (result.isRectBasedTest() && !colRect.contains(result.rectFromPoint(x, y))) + if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(x, y))) hitTestContents(request, result, x, y, finalX, finalY, hitTestAction); else return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, x, y, finalX, finalY)); @@ -4443,7 +4544,7 @@ IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const int colHeight = colInfo->columnHeight(); int colTop = borderTop() + paddingTop(); int colGap = columnGap(); - int colLeft = style()->direction() == LTR ? + int colLeft = style()->isLeftToRightDirection() ? borderLeft() + paddingLeft() + (index * (colWidth + colGap)) : borderLeft() + paddingLeft() + contentWidth() - colWidth - (index * (colWidth + colGap)); return IntRect(colLeft, colTop, colWidth, colHeight); @@ -4485,8 +4586,8 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageHeight, int pageHeight, Lay if (columnCount(colInfo)) { IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); - int overflowLeft = style()->direction() == RTL ? min(0, lastRect.x()) : 0; - int overflowRight = style()->direction() == LTR ? max(width(), lastRect.x() + lastRect.width()) : 0; + int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0; + int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.x() + lastRect.width()) : 0; int overflowHeight = borderTop() + paddingTop() + colInfo->columnHeight(); setLogicalHeight(overflowHeight + borderBottom() + paddingBottom() + horizontalScrollbarHeight()); @@ -4607,8 +4708,8 @@ void RenderBlock::computePreferredLogicalWidths() updateFirstLetter(); - if (!isTableCell() && style()->width().isFixed() && style()->width().value() > 0) - m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->width().value()); + if (!isTableCell() && style()->logicalWidth().isFixed() && style()->logicalWidth().value() > 0) + m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->logicalWidth().value()); else { m_minPreferredLogicalWidth = 0; m_maxPreferredLogicalWidth = 0; @@ -4635,18 +4736,18 @@ void RenderBlock::computePreferredLogicalWidths() } } - if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { - m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value())); - m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->minWidth().value())); + if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) { + m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value())); + m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value())); } - if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) { - m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value())); - m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->maxWidth().value())); + if (style()->logicalMaxWidth().isFixed() && style()->logicalMaxWidth().value() != undefinedLength) { + m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value())); + m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value())); } int toAdd = 0; - toAdd = borderAndPaddingWidth(); + toAdd = borderAndPaddingLogicalWidth(); if (hasOverflowClip() && style()->overflowY() == OSCROLL) toAdd += verticalScrollbarWidth(); @@ -4732,7 +4833,7 @@ static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfI { RenderStyle* cstyle = child->style(); int result = 0; - bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline; + bool leftSide = (cstyle->isLeftToRightDirection()) ? !endOfInline : endOfInline; result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), (leftSide ? cstyle->marginLeft() : cstyle->marginRight())); @@ -5135,15 +5236,15 @@ bool RenderBlock::hasLineIfEmpty() const return false; } -int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const +int RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const { // Inline blocks are replaced elements. Otherwise, just pass off to // the base class. If we're being queried as though we're the root line // box, then the fact that we're an inline-block is irrelevant, and we behave // just like a block. - if (isReplaced() && !isRootLineBox) - return height() + marginTop() + marginBottom(); - + if (isReplaced() && linePositionMode == PositionOnContainingLine) + return RenderBox::lineHeight(firstLine, direction, linePositionMode); + if (firstLine && document()->usesFirstLineRules()) { RenderStyle* s = style(firstLine); if (s != style()) @@ -5156,16 +5257,17 @@ int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const return m_lineHeight; } -int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const +int RenderBlock::baselinePosition(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const { // Inline blocks are replaced elements. Otherwise, just pass off to // the base class. If we're being queried as though we're the root line // box, then the fact that we're an inline-block is irrelevant, and we behave // just like a block. - if (isReplaced() && !isRootLineBox) { + if (isReplaced() && linePositionMode == PositionOnContainingLine) { // For "leaf" theme objects, let the theme decide what the baseline position is. // FIXME: Might be better to have a custom CSS property instead, so that if the theme // is turned off, checkboxes/radios will still have decent baselines. + // FIXME: Need to patch form controls to deal with vertical lines. if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance())) return theme()->baselinePosition(this); @@ -5175,22 +5277,29 @@ int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside // of our content box. - int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline(); - if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight()) - return marginTop() + baselinePos; - return height() + marginTop() + marginBottom(); + bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0) + : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || isWritingModeRoot(); + int baselinePos = ignoreBaseline ? -1 : lastLineBoxBaseline(); + + int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth(); + if (baselinePos != -1 && baselinePos <= bottomOfContent) + return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos; + + return RenderBox::baselinePosition(firstLine, direction, linePositionMode); } - return RenderBox::baselinePosition(b, isRootLineBox); + + const Font& f = style(firstLine)->font(); + return f.ascent() + (lineHeight(firstLine, direction, linePositionMode) - f.height()) / 2; } int RenderBlock::firstLineBoxBaseline() const { - if (!isBlockFlow()) + if (!isBlockFlow() || isWritingModeRoot()) return -1; if (childrenInline()) { if (firstLineBox()) - return firstLineBox()->y() + style(true)->font().ascent(); + return firstLineBox()->logicalTop() + style(true)->font().ascent(); else return -1; } @@ -5199,7 +5308,7 @@ int RenderBlock::firstLineBoxBaseline() const if (!curr->isFloatingOrPositioned()) { int result = curr->firstLineBoxBaseline(); if (result != -1) - return curr->y() + result; // Translate to our coordinate space. + return curr->logicalTop() + result; // Translate to our coordinate space. } } } @@ -5209,28 +5318,33 @@ int RenderBlock::firstLineBoxBaseline() const int RenderBlock::lastLineBoxBaseline() const { - if (!isBlockFlow()) + if (!isBlockFlow() || isWritingModeRoot()) return -1; + LineDirectionMode lineDirection = style()->isHorizontalWritingMode() ? HorizontalLine : VerticalLine; + if (childrenInline()) { - if (!firstLineBox() && hasLineIfEmpty()) - return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); + if (!firstLineBox() && hasLineIfEmpty()) { + const Font& f = firstLineStyle()->font(); + return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); + } if (lastLineBox()) - return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent(); + return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->font().ascent(); return -1; - } - else { + } else { bool haveNormalFlowChild = false; for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { if (!curr->isFloatingOrPositioned()) { haveNormalFlowChild = true; int result = curr->lastLineBoxBaseline(); if (result != -1) - return curr->y() + result; // Translate to our coordinate space. + return curr->logicalTop() + result; // Translate to our coordinate space. } } - if (!haveNormalFlowChild && hasLineIfEmpty()) - return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); + if (!haveNormalFlowChild && hasLineIfEmpty()) { + const Font& f = firstLineStyle()->font(); + return f.ascent() + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - f.height()) / 2 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); + } } return -1; @@ -5279,6 +5393,24 @@ static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderOb return pseudoStyle; } +// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter +// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe), +// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included" +static inline bool isPunctuationForFirstLetter(UChar c) +{ + CharCategory charCategory = category(c); + return charCategory == Punctuation_Open + || charCategory == Punctuation_Close + || charCategory == Punctuation_InitialQuote + || charCategory == Punctuation_FinalQuote + || charCategory == Punctuation_Other; +} + +static inline bool shouldSkipForFirstLetter(UChar c) +{ + return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c); +} + void RenderBlock::updateFirstLetter() { if (!document()->usesFirstLetterRules()) @@ -5403,15 +5535,27 @@ void RenderBlock::updateFirstLetter() if (oldText && oldText->length() > 0) { unsigned length = 0; - // account for leading spaces and punctuation - while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length]))) + // Account for leading spaces and punctuation. + while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length])) length++; - // account for first letter + // Account for first letter. length++; + + // Keep looking for whitespace and allowed punctuation, but avoid + // accumulating just whitespace into the :first-letter. + for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) { + UChar c = (*oldText)[scanLength]; + + if (!shouldSkipForFirstLetter(c)) + break; - // construct text fragment for the text after the first letter - // NOTE: this might empty + if (isPunctuationForFirstLetter(c)) + length = scanLength + 1; + } + + // Construct a text fragment for the text after the first letter. + // This text fragment might be empty. RenderTextFragment* remainingText = new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); remainingText->setStyle(textObj->style()); @@ -5553,7 +5697,7 @@ void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const for (; (r = it.current()); ++it) { // Only examine the object if our m_shouldPaint flag is set. if (r->m_shouldPaint) { - int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); + int floatLeft = r->left() - r->m_renderer->x() + r->m_renderer->marginLeft(); int floatRight = floatLeft + r->m_renderer->width(); left = min(left, floatLeft); right = max(right, floatRight); @@ -5605,23 +5749,23 @@ void RenderBlock::clearTruncation() void RenderBlock::setMaxMarginBeforeValues(int pos, int neg) { if (!m_rareData) { - if (pos == RenderBlockRareData::beforePosDefault(this) && neg == RenderBlockRareData::beforeNegDefault(this)) + if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this)) return; m_rareData = new RenderBlockRareData(this); } - m_rareData->m_beforePos = pos; - m_rareData->m_beforeNeg = neg; + m_rareData->m_margins.setPositiveMarginBefore(pos); + m_rareData->m_margins.setNegativeMarginBefore(neg); } void RenderBlock::setMaxMarginAfterValues(int pos, int neg) { if (!m_rareData) { - if (pos == RenderBlockRareData::afterPosDefault(this) && neg == RenderBlockRareData::afterNegDefault(this)) + if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this)) return; m_rareData = new RenderBlockRareData(this); } - m_rareData->m_afterPos = pos; - m_rareData->m_afterNeg = neg; + m_rareData->m_margins.setPositiveMarginAfter(pos); + m_rareData->m_margins.setNegativeMarginAfter(neg); } void RenderBlock::setPaginationStrut(int strut) @@ -5745,7 +5889,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* // constructed and this kludge is not called any more. So only the caret size // of an empty :first-line'd block is wrong. I think we can live with that. RenderStyle* currentStyle = firstLineStyle(); - int height = lineHeight(true); + int height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine); enum CaretAlignment { alignLeft, alignRight, alignCenter }; @@ -5754,7 +5898,7 @@ IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* switch (currentStyle->textAlign()) { case TAAUTO: case JUSTIFY: - if (currentStyle->direction() == RTL) + if (!currentStyle->isLeftToRightDirection()) alignment = alignRight; break; case LEFT: @@ -6020,7 +6164,213 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& d } } } - + +int RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const +{ + // If the child has the same directionality as we do, then we can just return its + // collapsed margin. + if (!child->isWritingModeRoot()) + return child->collapsedMarginBefore(); + + // The child has a different directionality. If the child is parallel, then it's just + // flipped relative to us. We can use the collapsed margin for the opposite edge. + if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode()) + return child->collapsedMarginAfter(); + + // The child is perpendicular to us, which means its margins don't collapse but are on the + // "logical left/right" sides of the child box. We can just return the raw margin in this case. + return marginBeforeForChild(child); +} + +int RenderBlock::collapsedMarginAfterForChild(RenderBox* child) const +{ + // If the child has the same directionality as we do, then we can just return its + // collapsed margin. + if (!child->isWritingModeRoot()) + return child->collapsedMarginAfter(); + + // The child has a different directionality. If the child is parallel, then it's just + // flipped relative to us. We can use the collapsed margin for the opposite edge. + if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode()) + return child->collapsedMarginBefore(); + + // The child is perpendicular to us, which means its margins don't collapse but are on the + // "logical left/right" side of the child box. We can just return the raw margin in this case. + return marginAfterForChild(child); +} + +int RenderBlock::marginBeforeForChild(RenderBoxModelObject* child) const +{ + switch (style()->writingMode()) { + case TopToBottomWritingMode: + return child->marginTop(); + case BottomToTopWritingMode: + return child->marginBottom(); + case LeftToRightWritingMode: + return child->marginLeft(); + case RightToLeftWritingMode: + return child->marginRight(); + } + ASSERT_NOT_REACHED(); + return child->marginTop(); +} + +int RenderBlock::marginAfterForChild(RenderBoxModelObject* child) const +{ + switch (style()->writingMode()) { + case TopToBottomWritingMode: + return child->marginBottom(); + case BottomToTopWritingMode: + return child->marginTop(); + case LeftToRightWritingMode: + return child->marginRight(); + case RightToLeftWritingMode: + return child->marginLeft(); + } + ASSERT_NOT_REACHED(); + return child->marginBottom(); +} + +int RenderBlock::marginStartForChild(RenderBoxModelObject* child) const +{ + if (style()->isHorizontalWritingMode()) + return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight(); + return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom(); +} + +int RenderBlock::marginEndForChild(RenderBoxModelObject* child) const +{ + if (style()->isHorizontalWritingMode()) + return style()->isLeftToRightDirection() ? child->marginRight() : child->marginLeft(); + return style()->isLeftToRightDirection() ? child->marginBottom() : child->marginTop(); +} + +void RenderBlock::setMarginStartForChild(RenderBox* child, int margin) +{ + if (style()->isHorizontalWritingMode()) { + if (style()->isLeftToRightDirection()) + child->setMarginLeft(margin); + else + child->setMarginRight(margin); + } else { + if (style()->isLeftToRightDirection()) + child->setMarginTop(margin); + else + child->setMarginBottom(margin); + } +} + +void RenderBlock::setMarginEndForChild(RenderBox* child, int margin) +{ + if (style()->isHorizontalWritingMode()) { + if (style()->isLeftToRightDirection()) + child->setMarginRight(margin); + else + child->setMarginLeft(margin); + } else { + if (style()->isLeftToRightDirection()) + child->setMarginBottom(margin); + else + child->setMarginTop(margin); + } +} + +void RenderBlock::setMarginBeforeForChild(RenderBox* child, int margin) +{ + switch (style()->writingMode()) { + case TopToBottomWritingMode: + child->setMarginTop(margin); + break; + case BottomToTopWritingMode: + child->setMarginBottom(margin); + break; + case LeftToRightWritingMode: + child->setMarginLeft(margin); + break; + case RightToLeftWritingMode: + child->setMarginRight(margin); + break; + } +} + +void RenderBlock::setMarginAfterForChild(RenderBox* child, int margin) +{ + switch (style()->writingMode()) { + case TopToBottomWritingMode: + child->setMarginBottom(margin); + break; + case BottomToTopWritingMode: + child->setMarginTop(margin); + break; + case LeftToRightWritingMode: + child->setMarginRight(margin); + break; + case RightToLeftWritingMode: + child->setMarginLeft(margin); + break; + } +} + +RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) +{ + int childBeforePositive = 0; + int childBeforeNegative = 0; + int childAfterPositive = 0; + int childAfterNegative = 0; + + int beforeMargin = 0; + int afterMargin = 0; + + RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; + + // If the child has the same directionality as we do, then we can just return its + // margins in the same direction. + if (!child->isWritingModeRoot()) { + if (childRenderBlock) { + childBeforePositive = childRenderBlock->maxPositiveMarginBefore(); + childBeforeNegative = childRenderBlock->maxNegativeMarginBefore(); + childAfterPositive = childRenderBlock->maxPositiveMarginAfter(); + childAfterNegative = childRenderBlock->maxNegativeMarginAfter(); + } else { + beforeMargin = child->marginBefore(); + afterMargin = child->marginAfter(); + } + } else if (child->style()->isHorizontalWritingMode() == style()->isHorizontalWritingMode()) { + // The child has a different directionality. If the child is parallel, then it's just + // flipped relative to us. We can use the margins for the opposite edges. + if (childRenderBlock) { + childBeforePositive = childRenderBlock->maxPositiveMarginAfter(); + childBeforeNegative = childRenderBlock->maxNegativeMarginAfter(); + childAfterPositive = childRenderBlock->maxPositiveMarginBefore(); + childAfterNegative = childRenderBlock->maxNegativeMarginBefore(); + } else { + beforeMargin = child->marginAfter(); + afterMargin = child->marginBefore(); + } + } else { + // The child is perpendicular to us, which means its margins don't collapse but are on the + // "logical left/right" sides of the child box. We can just return the raw margin in this case. + beforeMargin = marginBeforeForChild(child); + afterMargin = marginAfterForChild(child); + } + + // Resolve uncollapsing margins into their positive/negative buckets. + if (beforeMargin) { + if (beforeMargin > 0) + childBeforePositive = beforeMargin; + else + childBeforeNegative = -beforeMargin; + } + if (afterMargin) { + if (afterMargin > 0) + childAfterPositive = afterMargin; + else + childAfterNegative = -afterMargin; + } + + return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative); +} + const char* RenderBlock::renderName() const { if (isBody()) |