diff options
Diffstat (limited to 'Source/WebCore/rendering/InlineFlowBox.cpp')
-rw-r--r-- | Source/WebCore/rendering/InlineFlowBox.cpp | 702 |
1 files changed, 393 insertions, 309 deletions
diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index 6a0634c63..5a00f9ece 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -23,13 +23,14 @@ #include "CSSPropertyNames.h" #include "Document.h" #include "EllipsisBox.h" -#include "Font.h" +#include "FontCascade.h" #include "GraphicsContext.h" #include "InlineTextBox.h" #include "HitTestResult.h" #include "RenderBlock.h" #include "RenderInline.h" #include "RenderLayer.h" +#include "RenderLineBreak.h" #include "RenderListMarker.h" #include "RenderRubyBase.h" #include "RenderRubyRun.h" @@ -50,35 +51,43 @@ struct SameSizeAsInlineFlowBox : public InlineBox { COMPILE_ASSERT(sizeof(InlineFlowBox) == sizeof(SameSizeAsInlineFlowBox), InlineFlowBox_should_stay_small); #if !ASSERT_WITH_SECURITY_IMPLICATION_DISABLED + InlineFlowBox::~InlineFlowBox() { - if (!m_hasBadChildList) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) - child->setHasBadParent(); - } + setHasBadChildList(); +} + +void InlineFlowBox::setHasBadChildList() +{ + assertNotDeleted(); + if (m_hasBadChildList) + return; + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->setHasBadParent(); + m_hasBadChildList = true; } + #endif -LayoutUnit InlineFlowBox::getFlowSpacingLogicalWidth() +RenderBlockFlow* InlineFlowBox::anonymousInlineBlock() const { - LayoutUnit totWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight(); - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->isInlineFlowBox()) - totWidth += toInlineFlowBox(curr)->getFlowSpacingLogicalWidth(); - } - return totWidth; + if (!m_hasAnonymousInlineBlock || !firstChild()) + return nullptr; + if (is<InlineFlowBox>(*firstChild())) + return downcast<InlineFlowBox>(*firstChild()).anonymousInlineBlock(); + if (firstChild()->renderer().isAnonymousInlineBlock()) + return &downcast<RenderBlockFlow>(firstChild()->renderer()); + return nullptr; } -IntRect InlineFlowBox::roundedFrameRect() const +LayoutUnit InlineFlowBox::getFlowSpacingLogicalWidth() { - // Begin by snapping the x and y coordinates to the nearest pixel. - int snappedX = lroundf(x()); - int snappedY = lroundf(y()); - - int snappedMaxX = lroundf(x() + width()); - int snappedMaxY = lroundf(y() + height()); - - return IntRect(snappedX, snappedY, snappedMaxX - snappedX, snappedMaxY - snappedY); + LayoutUnit totalWidth = marginBorderPaddingLogicalLeft() + marginBorderPaddingLogicalRight(); + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (is<InlineFlowBox>(*child)) + totalWidth += downcast<InlineFlowBox>(*child).getFlowSpacingLogicalWidth(); + } + return totalWidth; } static void setHasTextDescendantsOnAncestors(InlineFlowBox* box) @@ -111,10 +120,14 @@ void InlineFlowBox::addToLine(InlineBox* child) if (child->renderer().parent() == &renderer()) m_hasTextChildren = true; setHasTextDescendantsOnAncestors(this); - } else if (child->isInlineFlowBox()) { - if (toInlineFlowBox(child)->hasTextDescendants()) + } else if (is<InlineFlowBox>(*child)) { + if (downcast<InlineFlowBox>(*child).hasTextDescendants()) setHasTextDescendantsOnAncestors(this); + if (downcast<InlineFlowBox>(*child).hasAnonymousInlineBlock()) + setHasAnonymousInlineBlock(true); } + if (child->renderer().isAnonymousInlineBlock()) + setHasAnonymousInlineBlock(true); if (descendantsHaveSameLineHeightAndBaseline() && !child->renderer().isOutOfFlowPositioned()) { const RenderStyle& parentStyle = lineStyle(); @@ -124,7 +137,7 @@ void InlineFlowBox::addToLine(InlineBox* child) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; else if (child->behavesLikeText()) { if (child->renderer().isLineBreak() || child->renderer().parent() != &renderer()) { - if (!parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.font().fontMetrics()) + if (!parentStyle.fontCascade().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.fontCascade().fontMetrics()) || parentStyle.lineHeight() != childStyle.lineHeight() || (parentStyle.verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle.verticalAlign() != BASELINE) shouldClearDescendantsHaveSameLineHeightAndBaseline = true; @@ -137,11 +150,10 @@ void InlineFlowBox::addToLine(InlineBox* child) // Other than making a zillion tests have to regenerate results, there's no reason to ditch the optimization here. shouldClearDescendantsHaveSameLineHeightAndBaseline = child->renderer().isBR(); } else { - ASSERT(isInlineFlowBox()); - InlineFlowBox* childFlowBox = toInlineFlowBox(child); + auto& childFlowBox = downcast<InlineFlowBox>(*child); // Check the child's bit, and then also check for differences in font, line-height, vertical-align - if (!childFlowBox->descendantsHaveSameLineHeightAndBaseline() - || !parentStyle.font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.font().fontMetrics()) + if (!childFlowBox.descendantsHaveSameLineHeightAndBaseline() + || !parentStyle.fontCascade().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.fontCascade().fontMetrics()) || parentStyle.lineHeight() != childStyle.lineHeight() || (parentStyle.verticalAlign() != BASELINE && !isRootInlineBox()) || childStyle.verticalAlign() != BASELINE || childStyle.hasBorder() || childStyle.hasPadding() || childStyle.hasTextCombine()) @@ -160,15 +172,17 @@ void InlineFlowBox::addToLine(InlineBox* child) if (childStyle->letterSpacing() < 0 || childStyle->textShadow() || childStyle->textEmphasisMark() != TextEmphasisMarkNone || childStyle->textStrokeWidth()) child->clearKnownToHaveNoOverflow(); } else if (child->renderer().isReplaced()) { - const RenderBox& box = toRenderBox(child->renderer()); + const RenderBox& box = downcast<RenderBox>(child->renderer()); if (box.hasRenderOverflow() || box.hasSelfPaintingLayer()) child->clearKnownToHaveNoOverflow(); } else if (!child->renderer().isLineBreak() && (childStyle.boxShadow() || child->boxModelObject()->hasSelfPaintingLayer() - || (child->renderer().isListMarker() && !toRenderListMarker(child->renderer()).isInside()) + || (is<RenderListMarker>(child->renderer()) && !downcast<RenderListMarker>(child->renderer()).isInside()) || childStyle.hasBorderImageOutsets())) child->clearKnownToHaveNoOverflow(); + else if (childStyle.hasOutlineInVisualOverflow()) + child->clearKnownToHaveNoOverflow(); - if (knownToHaveNoOverflow() && child->isInlineFlowBox() && !toInlineFlowBox(child)->knownToHaveNoOverflow()) + if (knownToHaveNoOverflow() && is<InlineFlowBox>(*child) && !downcast<InlineFlowBox>(*child).knownToHaveNoOverflow()) clearKnownToHaveNoOverflow(); } @@ -193,7 +207,7 @@ void InlineFlowBox::removeChild(InlineBox* child) if (child->prevOnLine()) child->prevOnLine()->setNextOnLine(child->nextOnLine()); - child->setParent(0); + child->setParent(nullptr); checkConsistency(); } @@ -201,19 +215,19 @@ void InlineFlowBox::removeChild(InlineBox* child) void InlineFlowBox::deleteLine() { InlineBox* child = firstChild(); - InlineBox* next = 0; + InlineBox* next = nullptr; while (child) { ASSERT(this == child->parent()); next = child->nextOnLine(); #ifndef NDEBUG - child->setParent(0); + child->setParent(nullptr); #endif child->deleteLine(); child = next; } #ifndef NDEBUG - m_firstChild = 0; - m_lastChild = 0; + m_firstChild = nullptr; + m_lastChild = nullptr; #endif removeLineBoxFromRenderObject(); @@ -222,7 +236,7 @@ void InlineFlowBox::deleteLine() void InlineFlowBox::removeLineBoxFromRenderObject() { - toRenderInline(renderer()).lineBoxes().removeLineBox(this); + downcast<RenderInline>(renderer()).lineBoxes().removeLineBox(this); } void InlineFlowBox::extractLine() @@ -235,7 +249,7 @@ void InlineFlowBox::extractLine() void InlineFlowBox::extractLineBoxFromRenderObject() { - toRenderInline(renderer()).lineBoxes().extractLineBox(this); + downcast<RenderInline>(renderer()).lineBoxes().extractLineBox(this); } void InlineFlowBox::attachLine() @@ -248,7 +262,7 @@ void InlineFlowBox::attachLine() void InlineFlowBox::attachLineBoxToRenderObject() { - toRenderInline(renderer()).lineBoxes().attachLineBox(this); + downcast<RenderInline>(renderer()).lineBoxes().attachLineBox(this); } void InlineFlowBox::adjustPosition(float dx, float dy) @@ -303,7 +317,7 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically // The root inline box never has borders/margins/padding. if (parent()) { - const auto& inlineFlow = toRenderInline(renderer()); + const auto& inlineFlow = downcast<RenderInline>(renderer()); bool ltr = renderer().style().isLeftToRightDirection(); @@ -350,15 +364,13 @@ void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, bool isLogically setEdges(includeLeftEdge, includeRightEdge); // Recur into our children. - for (InlineBox* currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) { - if (currChild->isInlineFlowBox()) { - InlineFlowBox* currFlow = toInlineFlowBox(currChild); - currFlow->determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (is<InlineFlowBox>(*child)) + downcast<InlineFlowBox>(*child).determineSpacingForFlowBoxes(lastLine, isLogicallyLastRunWrapped, logicallyLastRunRenderer); } } -float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) +float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsWordSpacing) { // Set our x position. beginPlacingBoxRangesInInlineDirection(logicalLeft); @@ -369,61 +381,64 @@ float InlineFlowBox::placeBoxesInInlineDirection(float logicalLeft, bool& needsW float minLogicalLeft = startLogicalLeft; float maxLogicalRight = logicalLeft; - placeBoxRangeInInlineDirection(firstChild(), 0, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing, textBoxDataMap); + placeBoxRangeInInlineDirection(firstChild(), nullptr, logicalLeft, minLogicalLeft, maxLogicalRight, needsWordSpacing); logicalLeft += borderLogicalRight() + paddingLogicalRight(); endPlacingBoxRangesInInlineDirection(startLogicalLeft, logicalLeft, minLogicalLeft, maxLogicalRight); return logicalLeft; } -float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing, GlyphOverflowAndFallbackFontsMap& textBoxDataMap) +float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, InlineBox* lastChild, float& logicalLeft, float& minLogicalLeft, float& maxLogicalRight, bool& needsWordSpacing) { - for (InlineBox* curr = firstChild; curr && curr != lastChild; curr = curr->nextOnLine()) { - if (curr->renderer().isText()) { - InlineTextBox* text = toInlineTextBox(curr); - RenderText& rt = text->renderer(); - if (rt.textLength()) { - if (needsWordSpacing && isSpaceOrNewline(rt.characterAt(text->start()))) - logicalLeft += text->lineStyle().font().wordSpacing(); - needsWordSpacing = !isSpaceOrNewline(rt.characterAt(text->end())); + float totalExpansion = 0; + for (InlineBox* child = firstChild; child && child != lastChild; child = child->nextOnLine()) { + if (is<RenderText>(child->renderer())) { + auto& textBox = downcast<InlineTextBox>(*child); + RenderText& renderText = textBox.renderer(); + if (renderText.textLength()) { + if (needsWordSpacing && isSpaceOrNewline(renderText.characterAt(textBox.start()))) + logicalLeft += textBox.lineStyle().fontCascade().wordSpacing(); + needsWordSpacing = !isSpaceOrNewline(renderText.characterAt(textBox.end())); } - text->setLogicalLeft(logicalLeft); + textBox.setLogicalLeft(logicalLeft); if (knownToHaveNoOverflow()) minLogicalLeft = std::min(logicalLeft, minLogicalLeft); - logicalLeft += text->logicalWidth(); + logicalLeft += textBox.logicalWidth(); + totalExpansion += textBox.expansion(); if (knownToHaveNoOverflow()) maxLogicalRight = std::max(logicalLeft, maxLogicalRight); } else { - if (curr->renderer().isOutOfFlowPositioned()) { - if (curr->renderer().parent()->style().isLeftToRightDirection()) - curr->setLogicalLeft(logicalLeft); + if (child->renderer().isOutOfFlowPositioned()) { + if (child->renderer().parent()->style().isLeftToRightDirection()) + child->setLogicalLeft(logicalLeft); else // Our offset that we cache needs to be from the edge of the right border box and // not the left border box. We have to subtract |x| from the width of the block // (which can be obtained from the root line box). - curr->setLogicalLeft(root().blockFlow().logicalWidth() - logicalLeft); + child->setLogicalLeft(root().blockFlow().logicalWidth() - logicalLeft); continue; // The positioned object has no effect on the width. } - if (curr->renderer().isRenderInline()) { - InlineFlowBox* flow = toInlineFlowBox(curr); - logicalLeft += flow->marginLogicalLeft(); + if (is<RenderInline>(child->renderer())) { + auto& flow = downcast<InlineFlowBox>(*child); + logicalLeft += flow.marginLogicalLeft(); if (knownToHaveNoOverflow()) minLogicalLeft = std::min(logicalLeft, minLogicalLeft); - logicalLeft = flow->placeBoxesInInlineDirection(logicalLeft, needsWordSpacing, textBoxDataMap); + logicalLeft = flow.placeBoxesInInlineDirection(logicalLeft, needsWordSpacing); + totalExpansion += flow.expansion(); if (knownToHaveNoOverflow()) maxLogicalRight = std::max(logicalLeft, maxLogicalRight); - logicalLeft += flow->marginLogicalRight(); - } else if (!curr->renderer().isListMarker() || toRenderListMarker(curr->renderer()).isInside()) { + logicalLeft += flow.marginLogicalRight(); + } else if (!is<RenderListMarker>(child->renderer()) || downcast<RenderListMarker>(child->renderer()).isInside()) { // The box can have a different writing-mode than the overall line, so this is a bit complicated. // Just get all the physical margin and overflow values by hand based off |isVertical|. - LayoutUnit logicalLeftMargin = isHorizontal() ? curr->boxModelObject()->marginLeft() : curr->boxModelObject()->marginTop(); - LayoutUnit logicalRightMargin = isHorizontal() ? curr->boxModelObject()->marginRight() : curr->boxModelObject()->marginBottom(); + LayoutUnit logicalLeftMargin = isHorizontal() ? child->boxModelObject()->marginLeft() : child->boxModelObject()->marginTop(); + LayoutUnit logicalRightMargin = isHorizontal() ? child->boxModelObject()->marginRight() : child->boxModelObject()->marginBottom(); logicalLeft += logicalLeftMargin; - curr->setLogicalLeft(logicalLeft); + child->setLogicalLeft(logicalLeft); if (knownToHaveNoOverflow()) minLogicalLeft = std::min(logicalLeft, minLogicalLeft); - logicalLeft += curr->logicalWidth(); + logicalLeft += child->logicalWidth(); if (knownToHaveNoOverflow()) maxLogicalRight = std::max(logicalLeft, maxLogicalRight); logicalLeft += logicalRightMargin; @@ -432,6 +447,7 @@ float InlineFlowBox::placeBoxRangeInInlineDirection(InlineBox* firstChild, Inlin } } } + setExpansionWithoutGrowing(totalExpansion); return logicalLeft; } @@ -441,30 +457,30 @@ bool InlineFlowBox::requiresIdeographicBaseline(const GlyphOverflowAndFallbackFo return false; const RenderStyle& lineStyle = this->lineStyle(); - if (lineStyle.fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientationUpright - || lineStyle.font().primaryFont()->hasVerticalGlyphs()) + if (lineStyle.fontDescription().nonCJKGlyphOrientation() == NonCJKGlyphOrientation::Upright + || lineStyle.fontCascade().primaryFont().hasVerticalGlyphs()) return true; - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->isInlineFlowBox()) { - if (toInlineFlowBox(curr)->requiresIdeographicBaseline(textBoxDataMap)) + if (is<InlineFlowBox>(*child)) { + if (downcast<InlineFlowBox>(*child).requiresIdeographicBaseline(textBoxDataMap)) return true; } else { - if (curr->lineStyle().font().primaryFont()->hasVerticalGlyphs()) + if (child->lineStyle().fontCascade().primaryFont().hasVerticalGlyphs()) return true; - const Vector<const SimpleFontData*>* usedFonts = 0; - if (curr->isInlineTextBox()) { - GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(toInlineTextBox(curr)); - usedFonts = it == textBoxDataMap.end() ? 0 : &it->value.first; + const Vector<const Font*>* usedFonts = nullptr; + if (is<InlineTextBox>(*child)) { + GlyphOverflowAndFallbackFontsMap::const_iterator it = textBoxDataMap.find(downcast<InlineTextBox>(child)); + usedFonts = it == textBoxDataMap.end() ? nullptr : &it->value.first; } if (usedFonts) { - for (size_t i = 0; i < usedFonts->size(); ++i) { - if (usedFonts->at(i)->hasVerticalGlyphs()) + for (const Font* font : *usedFonts) { + if (font->hasVerticalGlyphs()) return true; } } @@ -483,15 +499,15 @@ static bool verticalAlignApplies(const RenderObject& renderer) void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, int maxPositionTop, int maxPositionBottom) { - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { // The computed lineheight needs to be extended for the // positioned elements - if (curr->renderer().isOutOfFlowPositioned()) + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if ((curr->verticalAlign() == TOP || curr->verticalAlign() == BOTTOM) && verticalAlignApplies(curr->renderer())) { - int lineHeight = curr->lineHeight(); - if (curr->verticalAlign() == TOP) { + if ((child->verticalAlign() == TOP || child->verticalAlign() == BOTTOM) && verticalAlignApplies(child->renderer())) { + int lineHeight = child->lineHeight(); + if (child->verticalAlign() == TOP) { if (maxAscent + maxDescent < lineHeight) maxDescent = lineHeight - maxAscent; } @@ -504,15 +520,15 @@ void InlineFlowBox::adjustMaxAscentAndDescent(int& maxAscent, int& maxDescent, i break; } - if (curr->isInlineFlowBox()) - toInlineFlowBox(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); + if (is<InlineFlowBox>(*child)) + downcast<InlineFlowBox>(*child).adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom); } } -void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, - int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, - bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, - FontBaseline baselineType, VerticalPositionCache& verticalPositionCache) +void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox& rootBox, LayoutUnit& maxPositionTop, LayoutUnit& maxPositionBottom, + int& maxAscent, int& maxDescent, bool& setMaxAscent, bool& setMaxDescent, + bool strictMode, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, + FontBaseline baselineType, VerticalPositionCache& verticalPositionCache) { // The primary purpose of this function is to compute the maximal ascent and descent values for // a line. These values are computed based off the block's line-box-contain property, which indicates @@ -537,7 +553,7 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& // Examine our root box. int ascent = 0; int descent = 0; - rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); + rootBox.ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) { if (maxAscent < ascent || !setMaxAscent) { maxAscent = ascent; @@ -553,11 +569,11 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& if (!checkChildren) return; - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; + InlineFlowBox* inlineFlowBox = is<InlineFlowBox>(*child) ? downcast<InlineFlowBox>(child) : nullptr; bool affectsAscent = false; bool affectsDescent = false; @@ -565,17 +581,17 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& // The verticalPositionForBox function returns the distance between the child box's baseline // and the root box's baseline. The value is negative if the child box's baseline is above the // root box's baseline, and it is positive if the child box's baseline is below the root box's baseline. - curr->setLogicalTop(rootBox->verticalPositionForBox(curr, verticalPositionCache)); + child->setLogicalTop(rootBox.verticalPositionForBox(child, verticalPositionCache)); int ascent = 0; int descent = 0; - rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); + rootBox.ascentAndDescentForBox(*child, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); LayoutUnit boxHeight = ascent + descent; - if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer())) { + if (child->verticalAlign() == TOP && verticalAlignApplies(child->renderer())) { if (maxPositionTop < boxHeight) maxPositionTop = boxHeight; - } else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer())) { + } else if (child->verticalAlign() == BOTTOM && verticalAlignApplies(child->renderer())) { if (maxPositionBottom < boxHeight) maxPositionBottom = boxHeight; } else if (!inlineFlowBox || strictMode || inlineFlowBox->hasTextChildren() || (inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants()) @@ -586,8 +602,8 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& // means is that ascent and descent (including leading), can end up being negative. The setMaxAscent and // setMaxDescent booleans are used to ensure that we're willing to initially set maxAscent/Descent to negative // values. - ascent -= curr->logicalTop(); - descent += curr->logicalTop(); + ascent -= child->logicalTop(); + descent += child->logicalTop(); if (affectsAscent && (maxAscent < ascent || !setMaxAscent)) { maxAscent = ascent; setMaxAscent = true; @@ -607,7 +623,7 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& } void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHeight, int maxAscent, bool strictMode, LayoutUnit& lineTop, LayoutUnit& lineBottom, bool& setLineTop, - LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType) + LayoutUnit& lineTopIncludingMargins, LayoutUnit& lineBottomIncludingMargins, bool& hasAnnotationsBefore, bool& hasAnnotationsAfter, FontBaseline baselineType) { bool isRootBox = isRootInlineBox(); if (isRootBox) { @@ -624,78 +640,83 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei adjustmentForChildrenWithSameLineHeightAndBaseline += renderer().borderAndPaddingBefore(); } - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. if (descendantsHaveSameLineHeightAndBaseline()) { - curr->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline); + child->adjustBlockDirectionPosition(adjustmentForChildrenWithSameLineHeightAndBaseline); continue; } - InlineFlowBox* inlineFlowBox = curr->isInlineFlowBox() ? toInlineFlowBox(curr) : 0; + InlineFlowBox* inlineFlowBox = is<InlineFlowBox>(*child) ? downcast<InlineFlowBox>(child) : nullptr; bool childAffectsTopBottomPos = true; - if (curr->verticalAlign() == TOP && verticalAlignApplies(curr->renderer())) - curr->setLogicalTop(top); - else if (curr->verticalAlign() == BOTTOM && verticalAlignApplies(curr->renderer())) - curr->setLogicalTop(top + maxHeight - curr->lineHeight()); + if (child->verticalAlign() == TOP && verticalAlignApplies(child->renderer())) + child->setLogicalTop(top); + else if (child->verticalAlign() == BOTTOM && verticalAlignApplies(child->renderer())) + child->setLogicalTop(top + maxHeight - child->lineHeight()); else { if (!strictMode && inlineFlowBox && !inlineFlowBox->hasTextChildren() && !inlineFlowBox->renderer().hasInlineDirectionBordersOrPadding() && !(inlineFlowBox->descendantsHaveSameLineHeightAndBaseline() && inlineFlowBox->hasTextDescendants())) childAffectsTopBottomPos = false; - LayoutUnit posAdjust = maxAscent - curr->baselinePosition(baselineType); - curr->setLogicalTop(curr->logicalTop() + top + posAdjust); + LayoutUnit posAdjust = maxAscent - child->baselinePosition(baselineType); + child->setLogicalTop(child->logicalTop() + top + posAdjust); } - LayoutUnit newLogicalTop = curr->logicalTop(); + if (child->renderer().isAnonymousInlineBlock()) { + const auto& box = downcast<RenderBox>(child->renderer()); + child->setLogicalTop(box.logicalTop()); + } + + LayoutUnit newLogicalTop = child->logicalTop(); LayoutUnit newLogicalTopIncludingMargins = newLogicalTop; - LayoutUnit boxHeight = curr->logicalHeight(); + LayoutUnit boxHeight = child->logicalHeight(); LayoutUnit boxHeightIncludingMargins = boxHeight; - const RenderStyle& childLineStyle = curr->lineStyle(); - if (curr->behavesLikeText() || curr->isInlineFlowBox()) { + const RenderStyle& childLineStyle = child->lineStyle(); + if (child->behavesLikeText() || is<InlineFlowBox>(*child)) { const FontMetrics& fontMetrics = childLineStyle.fontMetrics(); - newLogicalTop += curr->baselinePosition(baselineType) - fontMetrics.ascent(baselineType); - if (curr->isInlineFlowBox()) { - RenderBoxModelObject& boxObject = toRenderBoxModelObject(curr->renderer()); + newLogicalTop += child->baselinePosition(baselineType) - fontMetrics.ascent(baselineType); + if (is<InlineFlowBox>(*child)) { + RenderBoxModelObject& boxObject = downcast<InlineFlowBox>(*child).renderer(); newLogicalTop -= childLineStyle.isHorizontalWritingMode() ? boxObject.borderTop() + boxObject.paddingTop() : boxObject.borderRight() + boxObject.paddingRight(); } newLogicalTopIncludingMargins = newLogicalTop; - } else if (!curr->renderer().isBR()) { - const RenderBox& box = toRenderBox(curr->renderer()); + } else if (!child->renderer().isBR() && !child->renderer().isAnonymousInlineBlock()) { + const auto& box = downcast<RenderBox>(child->renderer()); newLogicalTopIncludingMargins = newLogicalTop; - LayoutUnit overSideMargin = curr->isHorizontal() ? box.marginTop() : box.marginRight(); - LayoutUnit underSideMargin = curr->isHorizontal() ? box.marginBottom() : box.marginLeft(); + LayoutUnit overSideMargin = child->isHorizontal() ? box.marginTop() : box.marginRight(); + LayoutUnit underSideMargin = child->isHorizontal() ? box.marginBottom() : box.marginLeft(); newLogicalTop += overSideMargin; boxHeightIncludingMargins += overSideMargin + underSideMargin; } - curr->setLogicalTop(newLogicalTop); + child->setLogicalTop(newLogicalTop); if (childAffectsTopBottomPos) { - if (curr->renderer().isRubyRun()) { + if (is<RenderRubyRun>(child->renderer())) { // Treat the leading on the first and last lines of ruby runs as not being part of the overall lineTop/lineBottom. // Really this is a workaround hack for the fact that ruby should have been done as line layout and not done using // inline-block. - if (renderer().style().isFlippedLinesWritingMode() == (curr->renderer().style().rubyPosition() == RubyPositionAfter)) + if (renderer().style().isFlippedLinesWritingMode() == (child->renderer().style().rubyPosition() == RubyPositionAfter)) hasAnnotationsBefore = true; else hasAnnotationsAfter = true; - RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + auto& rubyRun = downcast<RenderRubyRun>(child->renderer()); if (RenderRubyBase* rubyBase = rubyRun.rubyBase()) { - LayoutUnit bottomRubyBaseLeading = (curr->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit()); + LayoutUnit bottomRubyBaseLeading = (child->logicalHeight() - rubyBase->logicalBottom()) + rubyBase->logicalHeight() - (rubyBase->lastRootBox() ? rubyBase->lastRootBox()->lineBottom() : LayoutUnit()); LayoutUnit topRubyBaseLeading = rubyBase->logicalTop() + (rubyBase->firstRootBox() ? rubyBase->firstRootBox()->lineTop() : LayoutUnit()); newLogicalTop += !renderer().style().isFlippedLinesWritingMode() ? topRubyBaseLeading : bottomRubyBaseLeading; boxHeight -= (topRubyBaseLeading + bottomRubyBaseLeading); } } - if (curr->isInlineTextBox()) { + if (is<InlineTextBox>(*child)) { bool emphasisMarkIsOver; - if (toInlineTextBox(curr)->emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsOver)) { + if (downcast<InlineTextBox>(*child).emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsOver)) { if (emphasisMarkIsOver != childLineStyle.isFlippedLinesWritingMode()) hasAnnotationsBefore = true; else @@ -723,16 +744,16 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei } if (isRootBox) { - if (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { + if (!hasAnonymousInlineBlock() && (strictMode || hasTextChildren() || (descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants()))) { if (!setLineTop) { setLineTop = true; - lineTop = pixelSnappedLogicalTop(); + lineTop = logicalTop(); lineTopIncludingMargins = lineTop; } else { - lineTop = std::min<LayoutUnit>(lineTop, pixelSnappedLogicalTop()); + lineTop = std::min<LayoutUnit>(lineTop, logicalTop()); lineTopIncludingMargins = std::min(lineTop, lineTopIncludingMargins); } - lineBottom = std::max<LayoutUnit>(lineBottom, pixelSnappedLogicalBottom()); + lineBottom = std::max<LayoutUnit>(lineBottom, logicalBottom()); lineBottomIncludingMargins = std::max(lineBottom, lineBottomIncludingMargins); } @@ -741,20 +762,45 @@ void InlineFlowBox::placeBoxesInBlockDirection(LayoutUnit top, LayoutUnit maxHei } } -void InlineFlowBox::computeMaxLogicalTop(float& maxLogicalTop) const +void InlineFlowBox::maxLogicalBottomForTextDecorationLine(float& maxLogicalBottom, const RenderElement* decorationRenderer, TextDecoration textDecoration) const { - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - - if (descendantsHaveSameLineHeightAndBaseline()) + + if (!(child->lineStyle().textDecorationsInEffect() & textDecoration)) + continue; // If the text decoration isn't in effect on the child, then it must be outside of |decorationRenderer|'s hierarchy. + + if (decorationRenderer && decorationRenderer->isRenderInline() && !isAncestorAndWithinBlock(downcast<RenderInline>(*decorationRenderer), &child->renderer())) continue; + + if (is<InlineFlowBox>(*child)) + downcast<InlineFlowBox>(*child).maxLogicalBottomForTextDecorationLine(maxLogicalBottom, decorationRenderer, textDecoration); + else { + if (child->isInlineTextBox() || child->lineStyle().textDecorationSkip() == TextDecorationSkipNone) + maxLogicalBottom = std::max<float>(maxLogicalBottom, child->logicalBottom()); + } + } +} - maxLogicalTop = std::max<float>(maxLogicalTop, curr->y()); - float localMaxLogicalTop = 0; - if (curr->isInlineFlowBox()) - toInlineFlowBox(curr)->computeMaxLogicalTop(localMaxLogicalTop); - maxLogicalTop = std::max<float>(maxLogicalTop, localMaxLogicalTop); +void InlineFlowBox::minLogicalTopForTextDecorationLine(float& minLogicalTop, const RenderElement* decorationRenderer, TextDecoration textDecoration) const +{ + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) + continue; // Positioned placeholders don't affect calculations. + + if (!(child->lineStyle().textDecorationsInEffect() & textDecoration)) + continue; // If the text decoration isn't in effect on the child, then it must be outside of |decorationRenderer|'s hierarchy. + + if (decorationRenderer && decorationRenderer->isRenderInline() && !isAncestorAndWithinBlock(downcast<RenderInline>(*decorationRenderer), &child->renderer())) + continue; + + if (is<InlineFlowBox>(*child)) + downcast<InlineFlowBox>(*child).minLogicalTopForTextDecorationLine(minLogicalTop, decorationRenderer, textDecoration); + else { + if (child->isInlineTextBox() || child->lineStyle().textDecorationSkip() == TextDecorationSkipNone) + minLogicalTop = std::min<float>(minLogicalTop, child->logicalTop()); + } } } @@ -763,14 +809,14 @@ void InlineFlowBox::flipLinesInBlockDirection(LayoutUnit lineTop, LayoutUnit lin // Flip the box on the line such that the top is now relative to the lineBottom instead of the lineTop. setLogicalTop(lineBottom - (logicalTop() - lineTop) - logicalHeight()); - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders aren't affected here. - if (curr->isInlineFlowBox()) - toInlineFlowBox(curr)->flipLinesInBlockDirection(lineTop, lineBottom); + if (is<InlineFlowBox>(*child)) + downcast<InlineFlowBox>(*child).flipLinesInBlockDirection(lineTop, lineBottom); else - curr->setLogicalTop(lineBottom - (curr->logicalTop() - lineTop) - curr->logicalHeight()); + child->setLogicalTop(lineBottom - (child->logicalTop() - lineTop) - child->logicalHeight()); } } @@ -793,15 +839,15 @@ inline void InlineFlowBox::addBoxShadowVisualOverflow(LayoutRect& logicalVisualO LayoutUnit shadowLogicalTop = lineStyle.isFlippedLinesWritingMode() ? -boxShadowLogicalBottom : boxShadowLogicalTop; LayoutUnit shadowLogicalBottom = lineStyle.isFlippedLinesWritingMode() ? -boxShadowLogicalTop : boxShadowLogicalBottom; - LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() + shadowLogicalTop, logicalVisualOverflow.y()); - LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + shadowLogicalBottom, logicalVisualOverflow.maxY()); + LayoutUnit logicalTopVisualOverflow = std::min<LayoutUnit>(logicalTop() + shadowLogicalTop, logicalVisualOverflow.y()); + LayoutUnit logicalBottomVisualOverflow = std::max<LayoutUnit>(logicalBottom() + shadowLogicalBottom, logicalVisualOverflow.maxY()); LayoutUnit boxShadowLogicalLeft; LayoutUnit boxShadowLogicalRight; lineStyle.getBoxShadowInlineDirectionExtent(boxShadowLogicalLeft, boxShadowLogicalRight); - LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); - LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); + LayoutUnit logicalLeftVisualOverflow = std::min<LayoutUnit>(logicalLeft() + boxShadowLogicalLeft, logicalVisualOverflow.x()); + LayoutUnit logicalRightVisualOverflow = std::max<LayoutUnit>(logicalRight() + boxShadowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); @@ -819,38 +865,38 @@ inline void InlineFlowBox::addBorderOutsetVisualOverflow(LayoutRect& logicalVisu LayoutBoxExtent borderOutsets = lineStyle.borderImageOutsets(); - LayoutUnit borderOutsetLogicalTop = borderOutsets.logicalTop(lineStyle.writingMode()); - LayoutUnit borderOutsetLogicalBottom = borderOutsets.logicalBottom(lineStyle.writingMode()); - LayoutUnit borderOutsetLogicalLeft = borderOutsets.logicalLeft(lineStyle.writingMode()); - LayoutUnit borderOutsetLogicalRight = borderOutsets.logicalRight(lineStyle.writingMode()); + LayoutUnit borderOutsetLogicalTop = borderOutsets.before(lineStyle.writingMode()); + LayoutUnit borderOutsetLogicalBottom = borderOutsets.after(lineStyle.writingMode()); + LayoutUnit borderOutsetLogicalLeft = borderOutsets.start(lineStyle.writingMode()); + LayoutUnit borderOutsetLogicalRight = borderOutsets.end(lineStyle.writingMode()); // Similar to how glyph overflow works, if our lines are flipped, then it's actually the opposite border that applies, since // the line is "upside down" in terms of block coordinates. vertical-rl and horizontal-bt are the flipped line modes. LayoutUnit outsetLogicalTop = lineStyle.isFlippedLinesWritingMode() ? borderOutsetLogicalBottom : borderOutsetLogicalTop; LayoutUnit outsetLogicalBottom = lineStyle.isFlippedLinesWritingMode() ? borderOutsetLogicalTop : borderOutsetLogicalBottom; - LayoutUnit logicalTopVisualOverflow = std::min(pixelSnappedLogicalTop() - outsetLogicalTop, logicalVisualOverflow.y()); - LayoutUnit logicalBottomVisualOverflow = std::max(pixelSnappedLogicalBottom() + outsetLogicalBottom, logicalVisualOverflow.maxY()); + LayoutUnit logicalTopVisualOverflow = std::min<LayoutUnit>(logicalTop() - outsetLogicalTop, logicalVisualOverflow.y()); + LayoutUnit logicalBottomVisualOverflow = std::max<LayoutUnit>(logicalBottom() + outsetLogicalBottom, logicalVisualOverflow.maxY()); LayoutUnit outsetLogicalLeft = includeLogicalLeftEdge() ? borderOutsetLogicalLeft : LayoutUnit(); LayoutUnit outsetLogicalRight = includeLogicalRightEdge() ? borderOutsetLogicalRight : LayoutUnit(); - LayoutUnit logicalLeftVisualOverflow = std::min(pixelSnappedLogicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x()); - LayoutUnit logicalRightVisualOverflow = std::max(pixelSnappedLogicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX()); + LayoutUnit logicalLeftVisualOverflow = std::min<LayoutUnit>(logicalLeft() - outsetLogicalLeft, logicalVisualOverflow.x()); + LayoutUnit logicalRightVisualOverflow = std::max<LayoutUnit>(logicalRight() + outsetLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); } -inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow) +inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox& textBox, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutRect& logicalVisualOverflow) { - if (textBox->knownToHaveNoOverflow()) + if (textBox.knownToHaveNoOverflow()) return; const RenderStyle& lineStyle = this->lineStyle(); - GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(textBox); - GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? 0 : &it->value.second; + GlyphOverflowAndFallbackFontsMap::iterator it = textBoxDataMap.find(&textBox); + GlyphOverflow* glyphOverflow = it == textBoxDataMap.end() ? nullptr : &it->value.second; bool isFlippedLine = lineStyle.isFlippedLinesWritingMode(); int topGlyphEdge = glyphOverflow ? (isFlippedLine ? glyphOverflow->bottom : glyphOverflow->top) : 0; @@ -865,8 +911,8 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp int rightGlyphOverflow = strokeOverflow + rightGlyphEdge; bool emphasisMarkIsAbove; - if (lineStyle.textEmphasisMark() != TextEmphasisMarkNone && textBox->emphasisMarkExistsAndIsAbove(lineStyle, emphasisMarkIsAbove)) { - int emphasisMarkHeight = lineStyle.font().emphasisMarkHeight(lineStyle.textEmphasisMarkString()); + if (lineStyle.textEmphasisMark() != TextEmphasisMarkNone && textBox.emphasisMarkExistsAndIsAbove(lineStyle, emphasisMarkIsAbove)) { + int emphasisMarkHeight = lineStyle.fontCascade().emphasisMarkHeight(lineStyle.textEmphasisMarkString()); if (emphasisMarkIsAbove == !lineStyle.isFlippedLinesWritingMode()) topGlyphOverflow = std::min(topGlyphOverflow, -emphasisMarkHeight); else @@ -875,7 +921,7 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp // If letter-spacing is negative, we should factor that into right layout overflow. (Even in RTL, letter-spacing is // applied to the right, so this is not an issue with left overflow. - rightGlyphOverflow -= std::min(0, (int)lineStyle.font().letterSpacing()); + rightGlyphOverflow -= std::min(0, (int)lineStyle.fontCascade().letterSpacing()); LayoutUnit textShadowLogicalTop; LayoutUnit textShadowLogicalBottom; @@ -891,20 +937,34 @@ inline void InlineFlowBox::addTextBoxVisualOverflow(InlineTextBox* textBox, Glyp LayoutUnit childOverflowLogicalLeft = std::min<LayoutUnit>(textShadowLogicalLeft + leftGlyphOverflow, leftGlyphOverflow); LayoutUnit childOverflowLogicalRight = std::max<LayoutUnit>(textShadowLogicalRight + rightGlyphOverflow, rightGlyphOverflow); - LayoutUnit logicalTopVisualOverflow = std::min(textBox->pixelSnappedLogicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); - LayoutUnit logicalBottomVisualOverflow = std::max(textBox->pixelSnappedLogicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); - LayoutUnit logicalLeftVisualOverflow = std::min(textBox->pixelSnappedLogicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); - LayoutUnit logicalRightVisualOverflow = std::max(textBox->pixelSnappedLogicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); + LayoutUnit logicalTopVisualOverflow = std::min<LayoutUnit>(textBox.logicalTop() + childOverflowLogicalTop, logicalVisualOverflow.y()); + LayoutUnit logicalBottomVisualOverflow = std::max<LayoutUnit>(textBox.logicalBottom() + childOverflowLogicalBottom, logicalVisualOverflow.maxY()); + LayoutUnit logicalLeftVisualOverflow = std::min<LayoutUnit>(textBox.logicalLeft() + childOverflowLogicalLeft, logicalVisualOverflow.x()); + LayoutUnit logicalRightVisualOverflow = std::max<LayoutUnit>(textBox.logicalRight() + childOverflowLogicalRight, logicalVisualOverflow.maxX()); logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); - textBox->setLogicalOverflowRect(logicalVisualOverflow); + textBox.setLogicalOverflowRect(logicalVisualOverflow); +} + +inline void InlineFlowBox::addOutlineVisualOverflow(LayoutRect& logicalVisualOverflow) +{ + const auto& lineStyle = this->lineStyle(); + if (!lineStyle.hasOutlineInVisualOverflow()) + return; + LayoutUnit outlineSize = lineStyle.outlineSize(); + LayoutUnit logicalTopVisualOverflow = std::min(LayoutUnit(logicalTop() - outlineSize), logicalVisualOverflow.y()); + LayoutUnit logicalBottomVisualOverflow = std::max(LayoutUnit(logicalBottom() + outlineSize), logicalVisualOverflow.maxY()); + LayoutUnit logicalLeftVisualOverflow = std::min(LayoutUnit(logicalLeft() - outlineSize), logicalVisualOverflow.x()); + LayoutUnit logicalRightVisualOverflow = std::max(LayoutUnit(logicalRight() + outlineSize), logicalVisualOverflow.maxX()); + logicalVisualOverflow = LayoutRect(logicalLeftVisualOverflow, logicalTopVisualOverflow, + logicalRightVisualOverflow - logicalLeftVisualOverflow, logicalBottomVisualOverflow - logicalTopVisualOverflow); } inline void InlineFlowBox::addReplacedChildOverflow(const InlineBox* inlineBox, LayoutRect& logicalLayoutOverflow, LayoutRect& logicalVisualOverflow) { - const RenderBox& box = toRenderBox(inlineBox->renderer()); + const RenderBox& box = downcast<RenderBox>(inlineBox->renderer()); // Visual overflow only propagates if the box doesn't have a self-painting layer. This rectangle does not include // transforms or relative positioning (since those objects always have self-painting layers), but it does need to be adjusted @@ -929,6 +989,9 @@ void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, G if (knownToHaveNoOverflow()) return; + if (m_overflow) + m_overflow = nullptr; + // Visual overflow just includes overflow for stuff we need to repaint ourselves. Self-painting layers are ignored. // Layout overflow is used to determine scrolling extent, so it still includes child layers and also factors in // transforms, relative positioning, etc. @@ -936,29 +999,30 @@ void InlineFlowBox::computeOverflow(LayoutUnit lineTop, LayoutUnit lineBottom, G LayoutRect logicalVisualOverflow(logicalLayoutOverflow); addBoxShadowVisualOverflow(logicalVisualOverflow); + addOutlineVisualOverflow(logicalVisualOverflow); addBorderOutsetVisualOverflow(logicalVisualOverflow); - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->renderer().isLineBreak()) + if (is<RenderLineBreak>(child->renderer())) continue; - if (curr->renderer().isText()) { - InlineTextBox* text = toInlineTextBox(curr); - LayoutRect textBoxOverflow(enclosingLayoutRect(text->logicalFrameRect())); - addTextBoxVisualOverflow(text, textBoxDataMap, textBoxOverflow); + if (is<RenderText>(child->renderer())) { + auto& textBox = downcast<InlineTextBox>(*child); + LayoutRect textBoxOverflow(enclosingLayoutRect(textBox.logicalFrameRect())); + addTextBoxVisualOverflow(textBox, textBoxDataMap, textBoxOverflow); logicalVisualOverflow.unite(textBoxOverflow); - } else if (curr->renderer().isRenderInline()) { - InlineFlowBox* flow = toInlineFlowBox(curr); - flow->computeOverflow(lineTop, lineBottom, textBoxDataMap); - if (!flow->renderer().hasSelfPaintingLayer()) - logicalVisualOverflow.unite(flow->logicalVisualOverflowRect(lineTop, lineBottom)); - LayoutRect childLayoutOverflow = flow->logicalLayoutOverflowRect(lineTop, lineBottom); - childLayoutOverflow.move(flow->renderer().relativePositionLogicalOffset()); + } else if (is<RenderInline>(child->renderer())) { + auto& flow = downcast<InlineFlowBox>(*child); + flow.computeOverflow(lineTop, lineBottom, textBoxDataMap); + if (!flow.renderer().hasSelfPaintingLayer()) + logicalVisualOverflow.unite(flow.logicalVisualOverflowRect(lineTop, lineBottom)); + LayoutRect childLayoutOverflow = flow.logicalLayoutOverflowRect(lineTop, lineBottom); + childLayoutOverflow.move(flow.renderer().relativePositionLogicalOffset()); logicalLayoutOverflow.unite(childLayoutOverflow); } else - addReplacedChildOverflow(curr, logicalLayoutOverflow, logicalVisualOverflow); + addReplacedChildOverflow(child, logicalLayoutOverflow, logicalVisualOverflow); } setOverflowFromLogicalRects(logicalLayoutOverflow, logicalVisualOverflow, lineTop, lineBottom); @@ -997,8 +1061,12 @@ void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutO setVisualOverflow(visualOverflow, lineTop, lineBottom); } -bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) +bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction hitTestAction) { + // As long as we don't have an anonymous inline block on our line, we restrict our hit testing only to the foreground phase. + if (!hasAnonymousInlineBlock() && hitTestAction != HitTestForeground) + return false; + LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom)); flipForWritingMode(overflowRect); overflowRect.moveBy(accumulatedOffset); @@ -1007,29 +1075,29 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // Check children first. // We need to account for culled inline parents of the hit-tested nodes, so that they may also get included in area-based hit-tests. - RenderElement* culledParent = 0; - for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if (curr->renderer().isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) { - RenderElement* newParent = 0; + RenderElement* culledParent = nullptr; + for (InlineBox* child = lastChild(); child; child = child->prevOnLine()) { + if (is<RenderText>(child->renderer()) || !child->boxModelObject()->hasSelfPaintingLayer()) { + RenderElement* newParent = nullptr; // Culled parents are only relevant for area-based hit-tests, so ignore it in point-based ones. if (locationInContainer.isRectBasedTest()) { - newParent = curr->renderer().parent(); + newParent = child->renderer().parent(); if (newParent == &renderer()) - newParent = 0; + newParent = nullptr; } // Check the culled parent after all its children have been checked, to do this we wait until // we are about to test an element with a different parent. if (newParent != culledParent) { if (!newParent || !newParent->isDescendantOf(culledParent)) { while (culledParent && culledParent != &renderer() && culledParent != newParent) { - if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) + if (is<RenderInline>(*culledParent) && downcast<RenderInline>(*culledParent).hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) return true; culledParent = culledParent->parent(); } } culledParent = newParent; } - if (curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { + if (child->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom, hitTestAction)) { renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } @@ -1037,7 +1105,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } // Check any culled ancestor of the final children tested. while (culledParent && culledParent != &renderer()) { - if (culledParent->isRenderInline() && toRenderInline(culledParent)->hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) + if (is<RenderInline>(*culledParent) && downcast<RenderInline>(*culledParent).hitTestCulledInline(request, result, locationInContainer, accumulatedOffset)) return true; culledParent = culledParent->parent(); } @@ -1049,7 +1117,7 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // Do not hittest content beyond the ellipsis box. if (isRootInlineBox() && hasEllipsisBox()) { const EllipsisBox* ellipsisBox = root().ellipsisBox(); - LayoutRect boundsRect(roundedFrameRect()); + FloatRect boundsRect(frameRect()); if (isHorizontal()) renderer().style().isLeftToRightDirection() ? boundsRect.shiftXEdgeTo(ellipsisBox->right()) : boundsRect.setWidth(ellipsisBox->left() - left()); @@ -1063,25 +1131,19 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re return false; } - LayoutRect frameRect = roundedFrameRect(); - LayoutUnit minX = frameRect.x(); - LayoutUnit minY = frameRect.y(); - LayoutUnit width = frameRect.width(); - LayoutUnit height = frameRect.height(); - // Constrain our hit testing to the line top and bottom if necessary. bool noQuirksMode = renderer().document().inNoQuirksMode(); if (!noQuirksMode && !hasTextChildren() && !(descendantsHaveSameLineHeightAndBaseline() && hasTextDescendants())) { RootInlineBox& rootBox = root(); - LayoutUnit& top = isHorizontal() ? minY : minX; - LayoutUnit& logicalHeight = isHorizontal() ? height : width; + LayoutUnit top = isHorizontal() ? y() : x(); + LayoutUnit logicalHeight = isHorizontal() ? height() : width(); LayoutUnit bottom = std::min(rootBox.lineBottom(), top + logicalHeight); top = std::max(rootBox.lineTop(), top); logicalHeight = bottom - top; } // Move x/y to our coordinates. - LayoutRect rect(minX, minY, width, height); + FloatRect rect(frameRect()); flipForWritingMode(rect); rect.moveBy(accumulatedOffset); @@ -1096,12 +1158,15 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { + // As long as we don't have an anonymous inline block on our line, we restrict our painting only to a few phases. + if (!hasAnonymousInlineBlock() && (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection && paintInfo.phase != PaintPhaseOutline && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseChildOutlines && paintInfo.phase != PaintPhaseTextClip && paintInfo.phase != PaintPhaseMask)) + return; + LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom)); - overflowRect.inflate(renderer().maximalOutlineSize(paintInfo.phase)); flipForWritingMode(overflowRect); overflowRect.moveBy(paintOffset); - if (!paintInfo.rect.intersects(pixelSnappedIntRect(overflowRect))) + if (!paintInfo.rect.intersects(snappedIntRect(overflowRect))) return; if (paintInfo.phase != PaintPhaseChildOutlines) { @@ -1109,9 +1174,9 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, // Add ourselves to the paint info struct's list of inlines that need to paint their // outlines. if (renderer().style().visibility() == VISIBLE && renderer().hasOutline() && !isRootInlineBox()) { - RenderInline& inlineFlow = toRenderInline(renderer()); + RenderInline& inlineFlow = downcast<RenderInline>(renderer()); - RenderBlock* cb = 0; + RenderBlock* containingBlock = nullptr; bool containingBlockPaintsContinuationOutline = inlineFlow.continuation() || inlineFlow.isInlineElementContinuation(); if (containingBlockPaintsContinuationOutline) { // FIXME: See https://bugs.webkit.org/show_bug.cgi?id=54690. We currently don't reconnect inline continuations @@ -1121,8 +1186,8 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (!enclosingAnonymousBlock->isAnonymousBlock()) containingBlockPaintsContinuationOutline = false; else { - cb = enclosingAnonymousBlock->containingBlock(); - for (auto box = &renderer(); box != cb; box = box->parent()->enclosingBoxModelObject()) { + containingBlock = enclosingAnonymousBlock->containingBlock(); + for (auto* box = &renderer(); box != containingBlock; box = &box->parent()->enclosingBoxModelObject()) { if (box->hasSelfPaintingLayer()) { containingBlockPaintsContinuationOutline = false; break; @@ -1134,16 +1199,18 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, if (containingBlockPaintsContinuationOutline) { // Add ourselves to the containing block of the entire continuation so that it can // paint us atomically. - cb->addContinuationWithOutline(toRenderInline(renderer().element()->renderer())); + containingBlock->addContinuationWithOutline(downcast<RenderInline>(renderer().element()->renderer())); } else if (!inlineFlow.isInlineElementContinuation()) paintInfo.outlineObjects->add(&inlineFlow); } } else if (paintInfo.phase == PaintPhaseMask) { - paintMask(paintInfo, paintOffset); + if (!hasAnonymousInlineBlock()) + paintMask(paintInfo, paintOffset); return; } else { // Paint our background, border and box-shadow. - paintBoxDecorations(paintInfo, paintOffset); + if (!hasAnonymousInlineBlock()) + paintBoxDecorations(paintInfo, paintOffset); } } @@ -1164,12 +1231,14 @@ void InlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, } } -void InlineFlowBox::paintFillLayers(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, CompositeOperator op) +void InlineFlowBox::paintFillLayers(const PaintInfo& paintInfo, const Color& color, const FillLayer& fillLayer, const LayoutRect& rect, CompositeOperator op) { - if (!fillLayer) - return; - paintFillLayers(paintInfo, c, fillLayer->next(), rect, op); - paintFillLayer(paintInfo, c, fillLayer, rect, op); + Vector<const FillLayer*, 8> layers; + for (auto* layer = &fillLayer; layer; layer = layer->next()) + layers.append(layer); + layers.reverse(); + for (auto* layer : layers) + paintFillLayer(paintInfo, color, *layer, rect, op); } bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackgroundLayer) const @@ -1181,17 +1250,17 @@ bool InlineFlowBox::boxShadowCanBeAppliedToBackground(const FillLayer& lastBackg return (!hasFillImage && !renderer().style().hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent(); } -void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer* fillLayer, const LayoutRect& rect, CompositeOperator op) +void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& color, const FillLayer& fillLayer, const LayoutRect& rect, CompositeOperator op) { - StyleImage* img = fillLayer->image(); - bool hasFillImage = img && img->canRender(&renderer(), renderer().style().effectiveZoom()); + auto* image = fillLayer.image(); + bool hasFillImage = image && image->canRender(&renderer(), renderer().style().effectiveZoom()); if ((!hasFillImage && !renderer().style().hasBorderRadius()) || (!prevLineBox() && !nextLineBox()) || !parent()) - renderer().paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); + renderer().paintFillLayerExtended(paintInfo, color, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); #if ENABLE(CSS_BOX_DECORATION_BREAK) else if (renderer().style().boxDecorationBreak() == DCLONE) { - GraphicsContextStateSaver stateSaver(*paintInfo.context); - paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), width(), height())); - renderer().paintFillLayerExtended(paintInfo, c, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); + GraphicsContextStateSaver stateSaver(paintInfo.context()); + paintInfo.context().clip(LayoutRect(rect.x(), rect.y(), width(), height())); + renderer().paintFillLayerExtended(paintInfo, color, fillLayer, rect, BackgroundBleedNone, this, rect.size(), op); } #endif else { @@ -1218,23 +1287,23 @@ void InlineFlowBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, c } LayoutUnit stripX = rect.x() - (isHorizontal() ? logicalOffsetOnLine : LayoutUnit()); LayoutUnit stripY = rect.y() - (isHorizontal() ? LayoutUnit() : logicalOffsetOnLine); - LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : static_cast<LayoutUnit>(width()); - LayoutUnit stripHeight = isHorizontal() ? static_cast<LayoutUnit>(height()) : totalLogicalWidth; + LayoutUnit stripWidth = isHorizontal() ? totalLogicalWidth : LayoutUnit(width()); + LayoutUnit stripHeight = isHorizontal() ? LayoutUnit(height()) : totalLogicalWidth; - GraphicsContextStateSaver stateSaver(*paintInfo.context); - paintInfo.context->clip(LayoutRect(rect.x(), rect.y(), width(), height())); - renderer().paintFillLayerExtended(paintInfo, c, fillLayer, LayoutRect(stripX, stripY, stripWidth, stripHeight), BackgroundBleedNone, this, rect.size(), op); + GraphicsContextStateSaver stateSaver(paintInfo.context()); + paintInfo.context().clip(LayoutRect(rect.x(), rect.y(), width(), height())); + renderer().paintFillLayerExtended(paintInfo, color, fillLayer, LayoutRect(stripX, stripY, stripWidth, stripHeight), BackgroundBleedNone, this, rect.size(), op); } } void InlineFlowBox::paintBoxShadow(const PaintInfo& info, const RenderStyle& style, ShadowStyle shadowStyle, const LayoutRect& paintRect) { if ((!prevLineBox() && !nextLineBox()) || !parent()) - renderer().paintBoxShadow(info, paintRect, &style, shadowStyle); + renderer().paintBoxShadow(info, paintRect, style, shadowStyle); else { // FIXME: We can do better here in the multi-line case. We want to push a clip so that the shadow doesn't // protrude incorrectly at the edges, and we want to possibly include shadows cast from the previous/following lines - renderer().paintBoxShadow(info, paintRect, &style, shadowStyle, includeLogicalLeftEdge(), includeLogicalRightEdge()); + renderer().paintBoxShadow(info, paintRect, style, shadowStyle, includeLogicalLeftEdge(), includeLogicalRightEdge()); } } @@ -1261,7 +1330,7 @@ void InlineFlowBox::constrainToLineTopAndBottomIfNeeded(LayoutRect& rect) const static LayoutRect clipRectForNinePieceImageStrip(InlineFlowBox* box, const NinePieceImage& image, const LayoutRect& paintRect) { LayoutRect clipRect(paintRect); - RenderStyle& style = box->renderer().style(); + auto& style = box->renderer().style(); LayoutBoxExtent outsets = style.imageOutsets(image); if (box->isHorizontal()) { clipRect.setY(paintRect.y() - outsets.top()); @@ -1290,9 +1359,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer().style().visibility() != VISIBLE || paintInfo.phase != PaintPhaseForeground) return; - // Pixel snap background/border painting. - LayoutRect frameRect = roundedFrameRect(); - + LayoutRect frameRect(this->frameRect()); constrainToLineTopAndBottomIfNeeded(frameRect); // Move x/y to our coordinates. @@ -1301,26 +1368,26 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& // You can use p::first-line to specify a background. If so, the root line boxes for // a line may actually have to paint a background. - if (parent() && !renderer().hasBoxDecorations()) + if (parent() && !renderer().hasVisibleBoxDecorations()) return; const RenderStyle& lineStyle = this->lineStyle(); if (!parent() && (!isFirstLine() || &lineStyle == &renderer().style())) return; LayoutPoint adjustedPaintoffset = paintOffset + localRect.location(); - GraphicsContext* context = paintInfo.context; + GraphicsContext& context = paintInfo.context(); LayoutRect paintRect = LayoutRect(adjustedPaintoffset, frameRect.size()); // Shadow comes first and is behind the background and border. - if (!renderer().boxShadowShouldBeAppliedToBackground(BackgroundBleedNone, this)) + if (!renderer().boxShadowShouldBeAppliedToBackground(adjustedPaintoffset, BackgroundBleedNone, this)) paintBoxShadow(paintInfo, lineStyle, Normal, paintRect); - Color c = lineStyle.visitedDependentColor(CSSPropertyBackgroundColor); - paintFillLayers(paintInfo, c, lineStyle.backgroundLayers(), paintRect); + const Color& color = lineStyle.visitedDependentColor(CSSPropertyBackgroundColor); + paintFillLayers(paintInfo, color, lineStyle.backgroundLayers(), paintRect); paintBoxShadow(paintInfo, lineStyle, Inset, paintRect); // :first-line cannot be used to put borders on a line. Always paint borders with our // non-first-line style. - if (!parent() || !renderer().style().hasBorder()) + if (!parent() || !renderer().style().hasVisibleBorderDecoration()) return; const NinePieceImage& borderImage = renderer().style().borderImage(); StyleImage* borderImageSource = borderImage.image(); @@ -1331,7 +1398,7 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& // The simple case is where we either have no border image or we are the only box for this object. In those // cases only a single call to draw is required. if (!hasBorderImage || (!prevLineBox() && !nextLineBox())) - renderer().paintBorder(paintInfo, paintRect, &lineStyle, BackgroundBleedNone, includeLogicalLeftEdge(), includeLogicalRightEdge()); + renderer().paintBorder(paintInfo, paintRect, lineStyle, BackgroundBleedNone, includeLogicalLeftEdge(), includeLogicalRightEdge()); else { // We have a border image that spans multiple lines. // We need to adjust tx and ty by the width of all previous lines. @@ -1353,9 +1420,9 @@ void InlineFlowBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth; LayoutRect clipRect = clipRectForNinePieceImageStrip(this, borderImage, paintRect); - GraphicsContextStateSaver stateSaver(*context); - context->clip(clipRect); - renderer().paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), &lineStyle); + GraphicsContextStateSaver stateSaver(context); + context.clip(clipRect); + renderer().paintBorder(paintInfo, LayoutRect(stripX, stripY, stripWidth, stripHeight), lineStyle); } } @@ -1364,9 +1431,7 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs if (!paintInfo.shouldPaintWithinRoot(renderer()) || renderer().style().visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask) return; - // Pixel snap mask painting. - LayoutRect frameRect = roundedFrameRect(); - + LayoutRect frameRect(this->frameRect()); constrainToLineTopAndBottomIfNeeded(frameRect); // Move x/y to our coordinates. @@ -1383,13 +1448,13 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs bool flattenCompositingLayers = renderer().view().frameView().paintBehavior() & PaintBehaviorFlattenCompositingLayers; CompositeOperator compositeOp = CompositeSourceOver; if (!compositedMask || flattenCompositingLayers) { - if ((maskBoxImage && renderer().style().maskLayers()->hasImage()) || renderer().style().maskLayers()->next()) + if ((maskBoxImage && renderer().style().maskLayers().hasImage()) || renderer().style().maskLayers().next()) pushTransparencyLayer = true; compositeOp = CompositeDestinationIn; if (pushTransparencyLayer) { - paintInfo.context->setCompositeOperation(CompositeDestinationIn); - paintInfo.context->beginTransparencyLayer(1.0f); + paintInfo.context().setCompositeOperation(CompositeDestinationIn); + paintInfo.context().beginTransparencyLayer(1.0f); compositeOp = CompositeSourceOver; } } @@ -1400,14 +1465,14 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs bool hasBoxImage = maskBoxImage && maskBoxImage->canRender(&renderer(), renderer().style().effectiveZoom()); if (!hasBoxImage || !maskBoxImage->isLoaded()) { if (pushTransparencyLayer) - paintInfo.context->endTransparencyLayer(); + paintInfo.context().endTransparencyLayer(); return; // Don't paint anything while we wait for the image to load. } // The simple case is where we are the only box for this object. In those // cases only a single call to draw is required. if (!prevLineBox() && !nextLineBox()) { - renderer().paintNinePieceImage(paintInfo.context, LayoutRect(adjustedPaintOffset, frameRect.size()), &renderer().style(), maskNinePieceImage, compositeOp); + renderer().paintNinePieceImage(paintInfo.context(), LayoutRect(adjustedPaintOffset, frameRect.size()), renderer().style(), maskNinePieceImage, compositeOp); } else { // We have a mask image that spans multiple lines. // We need to adjust _tx and _ty by the width of all previous lines. @@ -1423,28 +1488,28 @@ void InlineFlowBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffs LayoutUnit stripHeight = isHorizontal() ? frameRect.height() : totalLogicalWidth; LayoutRect clipRect = clipRectForNinePieceImageStrip(this, maskNinePieceImage, paintRect); - GraphicsContextStateSaver stateSaver(*paintInfo.context); - paintInfo.context->clip(clipRect); - renderer().paintNinePieceImage(paintInfo.context, LayoutRect(stripX, stripY, stripWidth, stripHeight), &renderer().style(), maskNinePieceImage, compositeOp); + GraphicsContextStateSaver stateSaver(paintInfo.context()); + paintInfo.context().clip(clipRect); + renderer().paintNinePieceImage(paintInfo.context(), LayoutRect(stripX, stripY, stripWidth, stripHeight), renderer().style(), maskNinePieceImage, compositeOp); } if (pushTransparencyLayer) - paintInfo.context->endTransparencyLayer(); + paintInfo.context().endTransparencyLayer(); } InlineBox* InlineFlowBox::firstLeafChild() const { - InlineBox* leaf = 0; + InlineBox* leaf = nullptr; for (InlineBox* child = firstChild(); child && !leaf; child = child->nextOnLine()) - leaf = child->isLeaf() ? child : toInlineFlowBox(child)->firstLeafChild(); + leaf = child->isLeaf() ? child : downcast<InlineFlowBox>(*child).firstLeafChild(); return leaf; } InlineBox* InlineFlowBox::lastLeafChild() const { - InlineBox* leaf = 0; + InlineBox* leaf = nullptr; for (InlineBox* child = lastChild(); child && !leaf; child = child->prevOnLine()) - leaf = child->isLeaf() ? child : toInlineFlowBox(child)->lastLeafChild(); + leaf = child->isLeaf() ? child : downcast<InlineFlowBox>(*child).lastLeafChild(); return leaf; } @@ -1501,15 +1566,15 @@ void InlineFlowBox::clearTruncation() LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosition) const { LayoutUnit result = 0; - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->isInlineFlowBox()) - result = std::max(result, toInlineFlowBox(curr)->computeOverAnnotationAdjustment(allowedPosition)); + if (is<InlineFlowBox>(*child)) + result = std::max(result, downcast<InlineFlowBox>(*child).computeOverAnnotationAdjustment(allowedPosition)); - if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style().rubyPosition() == RubyPositionBefore) { - RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + if (child->renderer().isReplaced() && is<RenderRubyRun>(child->renderer()) && child->renderer().style().rubyPosition() == RubyPositionBefore) { + auto& rubyRun = downcast<RenderRubyRun>(child->renderer()); RenderRubyText* rubyText = rubyRun.rubyText(); if (!rubyText) continue; @@ -1518,26 +1583,26 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); if (topOfFirstRubyTextLine >= 0) continue; - topOfFirstRubyTextLine += curr->logicalTop(); + topOfFirstRubyTextLine += child->logicalTop(); result = std::max(result, allowedPosition - topOfFirstRubyTextLine); } else { LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight()); - if (bottomOfLastRubyTextLine <= curr->logicalHeight()) + if (bottomOfLastRubyTextLine <= child->logicalHeight()) continue; - bottomOfLastRubyTextLine += curr->logicalTop(); + bottomOfLastRubyTextLine += child->logicalTop(); result = std::max(result, bottomOfLastRubyTextLine - allowedPosition); } } - if (curr->isInlineTextBox()) { - const RenderStyle& childLineStyle = curr->lineStyle(); + if (is<InlineTextBox>(*child)) { + const RenderStyle& childLineStyle = child->lineStyle(); bool emphasisMarkIsAbove; - if (childLineStyle.textEmphasisMark() != TextEmphasisMarkNone && toInlineTextBox(curr)->emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsAbove) && emphasisMarkIsAbove) { + if (childLineStyle.textEmphasisMark() != TextEmphasisMarkNone && downcast<InlineTextBox>(*child).emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsAbove) && emphasisMarkIsAbove) { if (!childLineStyle.isFlippedLinesWritingMode()) { - int topOfEmphasisMark = curr->logicalTop() - childLineStyle.font().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); + int topOfEmphasisMark = child->logicalTop() - childLineStyle.fontCascade().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); result = std::max(result, allowedPosition - topOfEmphasisMark); } else { - int bottomOfEmphasisMark = curr->logicalBottom() + childLineStyle.font().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); + int bottomOfEmphasisMark = child->logicalBottom() + childLineStyle.fontCascade().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); result = std::max(result, bottomOfEmphasisMark - allowedPosition); } } @@ -1549,15 +1614,15 @@ LayoutUnit InlineFlowBox::computeOverAnnotationAdjustment(LayoutUnit allowedPosi LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPosition) const { LayoutUnit result = 0; - for (InlineBox* curr = firstChild(); curr; curr = curr->nextOnLine()) { - if (curr->renderer().isOutOfFlowPositioned()) + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { + if (child->renderer().isOutOfFlowPositioned()) continue; // Positioned placeholders don't affect calculations. - if (curr->isInlineFlowBox()) - result = std::max(result, toInlineFlowBox(curr)->computeUnderAnnotationAdjustment(allowedPosition)); + if (is<InlineFlowBox>(*child)) + result = std::max(result, downcast<InlineFlowBox>(*child).computeUnderAnnotationAdjustment(allowedPosition)); - if (curr->renderer().isReplaced() && curr->renderer().isRubyRun() && curr->renderer().style().rubyPosition() == RubyPositionAfter) { - RenderRubyRun& rubyRun = toRenderRubyRun(curr->renderer()); + if (child->renderer().isReplaced() && is<RenderRubyRun>(child->renderer()) && child->renderer().style().rubyPosition() == RubyPositionAfter) { + auto& rubyRun = downcast<RenderRubyRun>(child->renderer()); RenderRubyText* rubyText = rubyRun.rubyText(); if (!rubyText) continue; @@ -1566,27 +1631,27 @@ LayoutUnit InlineFlowBox::computeUnderAnnotationAdjustment(LayoutUnit allowedPos LayoutUnit topOfFirstRubyTextLine = rubyText->logicalTop() + (rubyText->firstRootBox() ? rubyText->firstRootBox()->lineTop() : LayoutUnit()); if (topOfFirstRubyTextLine >= 0) continue; - topOfFirstRubyTextLine += curr->logicalTop(); + topOfFirstRubyTextLine += child->logicalTop(); result = std::max(result, allowedPosition - topOfFirstRubyTextLine); } else { LayoutUnit bottomOfLastRubyTextLine = rubyText->logicalTop() + (rubyText->lastRootBox() ? rubyText->lastRootBox()->lineBottom() : rubyText->logicalHeight()); - if (bottomOfLastRubyTextLine <= curr->logicalHeight()) + if (bottomOfLastRubyTextLine <= child->logicalHeight()) continue; - bottomOfLastRubyTextLine += curr->logicalTop(); + bottomOfLastRubyTextLine += child->logicalTop(); result = std::max(result, bottomOfLastRubyTextLine - allowedPosition); } } - if (curr->isInlineTextBox()) { - const RenderStyle& childLineStyle = curr->lineStyle(); + if (is<InlineTextBox>(*child)) { + const RenderStyle& childLineStyle = child->lineStyle(); bool emphasisMarkIsAbove; - toInlineTextBox(curr)->emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsAbove); + downcast<InlineTextBox>(*child).emphasisMarkExistsAndIsAbove(childLineStyle, emphasisMarkIsAbove); if (childLineStyle.textEmphasisMark() != TextEmphasisMarkNone && !emphasisMarkIsAbove) { if (!childLineStyle.isFlippedLinesWritingMode()) { - LayoutUnit bottomOfEmphasisMark = curr->logicalBottom() + childLineStyle.font().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); + LayoutUnit bottomOfEmphasisMark = child->logicalBottom() + childLineStyle.fontCascade().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); result = std::max(result, bottomOfEmphasisMark - allowedPosition); } else { - LayoutUnit topOfEmphasisMark = curr->logicalTop() - childLineStyle.font().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); + LayoutUnit topOfEmphasisMark = child->logicalTop() - childLineStyle.fontCascade().emphasisMarkHeight(childLineStyle.textEmphasisMarkString()); result = std::max(result, allowedPosition - topOfEmphasisMark); } } @@ -1648,31 +1713,50 @@ void InlineFlowBox::collectLeafBoxesInLogicalOrder(Vector<InlineBox*>& leafBoxes } } -#ifndef NDEBUG +void InlineFlowBox::computeReplacedAndTextLineTopAndBottom(LayoutUnit& lineTop, LayoutUnit& lineBottom) const +{ + for (const auto* box = firstChild(); box; box = box->nextOnLine()) { + if (is<InlineFlowBox>(*box)) + downcast<InlineFlowBox>(*box).computeReplacedAndTextLineTopAndBottom(lineTop, lineBottom); + else { + if (box->logicalTop() < lineTop) + lineTop = box->logicalTop(); + if (box->logicalBottom() > lineBottom) + lineBottom = box->logicalBottom(); + } + } +} + +#if ENABLE(TREE_DEBUGGING) const char* InlineFlowBox::boxName() const { return "InlineFlowBox"; } -void InlineFlowBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj, int depth) const +void InlineFlowBox::showLineTreeAndMark(const InlineBox* markedBox, int depth) const { - InlineBox::showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth); + InlineBox::showLineTreeAndMark(markedBox, depth); for (const InlineBox* box = firstChild(); box; box = box->nextOnLine()) - box->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, depth + 1); + box->showLineTreeAndMark(markedBox, depth + 1); } +#endif + +#ifndef NDEBUG + void InlineFlowBox::checkConsistency() const { + assertNotDeleted(); ASSERT_WITH_SECURITY_IMPLICATION(!m_hasBadChildList); #ifdef CHECK_CONSISTENCY - const InlineBox* prev = 0; - for (const InlineBox* child = m_firstChild; child; child = child->nextOnLine()) { + const InlineBox* previousChild = nullptr; + for (const InlineBox* child = firstChild(); child; child = child->nextOnLine()) { ASSERT(child->parent() == this); - ASSERT(child->prevOnLine() == prev); - prev = child; + ASSERT(child->prevOnLine() == previousChild); + previousChild = child; } - ASSERT(prev == m_lastChild); + ASSERT(previousChild == m_lastChild); #endif } |