diff options
Diffstat (limited to 'Source/WebCore/rendering/RenderInline.cpp')
-rw-r--r-- | Source/WebCore/rendering/RenderInline.cpp | 1090 |
1 files changed, 608 insertions, 482 deletions
diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 89b8ca407..8b529030b 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -25,20 +25,24 @@ #include "Chrome.h" #include "FloatQuad.h" +#include "FrameSelection.h" #include "GraphicsContext.h" #include "HitTestResult.h" #include "InlineElementBox.h" #include "InlineTextBox.h" -#include "Page.h" #include "RenderBlock.h" +#include "RenderChildIterator.h" #include "RenderFullScreen.h" #include "RenderGeometryMap.h" #include "RenderIterator.h" #include "RenderLayer.h" #include "RenderLineBreak.h" +#include "RenderListMarker.h" #include "RenderNamedFlowThread.h" +#include "RenderTable.h" #include "RenderTheme.h" #include "RenderView.h" +#include "Settings.h" #include "StyleInheritedData.h" #include "TransformState.h" #include "VisiblePosition.h" @@ -49,14 +53,14 @@ namespace WebCore { -RenderInline::RenderInline(Element& element, PassRef<RenderStyle> style) - : RenderBoxModelObject(element, std::move(style), RenderInlineFlag) +RenderInline::RenderInline(Element& element, RenderStyle&& style) + : RenderBoxModelObject(element, WTFMove(style), RenderInlineFlag) { setChildrenInline(true); } -RenderInline::RenderInline(Document& document, PassRef<RenderStyle> style) - : RenderBoxModelObject(document, std::move(style), RenderInlineFlag) +RenderInline::RenderInline(Document& document, RenderStyle&& style) + : RenderBoxModelObject(document, WTFMove(style), RenderInlineFlag) { setChildrenInline(true); } @@ -79,24 +83,13 @@ void RenderInline::willBeDestroyed() // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. destroyLeftoverChildren(); - - // Destroy our continuation before anything other than anonymous children. - // The reason we don't destroy it before anonymous children is that they may - // have continuations of their own that are anonymous children of our continuation. - RenderBoxModelObject* continuation = this->continuation(); - if (continuation) { - continuation->destroy(); - setContinuation(0); - } - if (!documentBeingDestroyed()) { + if (!renderTreeBeingDestroyed()) { if (firstLineBox()) { // We can't wait for RenderBoxModelObject::destroy to clear the selection, // because by then we will have nuked the line boxes. - // FIXME: The FrameSelection should be responsible for this when it - // is notified of DOM mutations. if (isSelectionBorder()) - view().clearSelection(); + frame().selection().setNeedsSelectionUpdate(); // If line boxes are contained inside a root, that means we're an inline. // In that case, we need to remove all the line boxes so that the parent @@ -104,11 +97,11 @@ void RenderInline::willBeDestroyed() // not have a parent that means they are either already disconnected or // root lines that can just be destroyed without disconnecting. if (firstLineBox()->parent()) { - for (auto box = firstLineBox(); box; box = box->nextLineBox()) + for (auto* box = firstLineBox(); box; box = box->nextLineBox()) box->removeFromParent(); } - } else if (parent()) - parent()->dirtyLinesFromChangedChild(this); + } else if (parent()) + parent()->dirtyLinesFromChangedChild(*this); } m_lineBoxes.deleteLineBoxes(); @@ -122,20 +115,18 @@ RenderInline* RenderInline::inlineElementContinuation() const if (!continuation) return nullptr; - if (continuation->isRenderInline()) - return toRenderInline(continuation); + if (is<RenderInline>(*continuation)) + return downcast<RenderInline>(continuation); - return continuation->isRenderBlock() ? toRenderBlock(continuation)->inlineElementContinuation() : nullptr; + return is<RenderBlock>(*continuation) ? downcast<RenderBlock>(*continuation).inlineElementContinuation() : nullptr; } void RenderInline::updateFromStyle() { RenderBoxModelObject::updateFromStyle(); - setInline(true); // Needed for run-ins, since run-in is considered a block display type. - // FIXME: Support transforms and reflections on inline flows someday. - setHasTransform(false); + setHasTransformRelatedProperty(false); setHasReflection(false); } @@ -146,30 +137,43 @@ static RenderElement* inFlowPositionedInlineAncestor(RenderElement* p) return p; p = p->parent(); } - return 0; + return nullptr; } -static void updateStyleOfAnonymousBlockContinuations(RenderBlock& block, const RenderStyle* newStyle, const RenderStyle* oldStyle) +static void updateStyleOfAnonymousBlockContinuations(const RenderBlock& block, const RenderStyle* newStyle, const RenderStyle* oldStyle) { - for (RenderBox* box = █ box && box->isAnonymousBlock(); box = box->nextSiblingBox()) { + // If any descendant blocks exist then they will be in the next anonymous block and its siblings. + for (RenderBox* box = block.nextSiblingBox(); box && box->isAnonymousBlock(); box = box->nextSiblingBox()) { if (box->style().position() == newStyle->position()) continue; - if (!box->isRenderBlock()) - break; // We're done if we ever encounter something other than a RenderBlock. + if (!is<RenderBlock>(*box)) + continue; - RenderBlock* block = toRenderBlock(box); - if (!block->isAnonymousBlockContinuation()) - break; // We're done if we ever encounter something other than a continuation RenderBlock. + RenderBlock& block = downcast<RenderBlock>(*box); + if (!block.isAnonymousBlockContinuation()) + continue; // If we are no longer in-flow positioned but our descendant block(s) still have an in-flow positioned ancestor then // their containing anonymous block should keep its in-flow positioning. - RenderInline* cont = block->inlineElementContinuation(); - if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(cont)) + RenderInline* continuation = block.inlineElementContinuation(); + if (oldStyle->hasInFlowPosition() && inFlowPositionedInlineAncestor(continuation)) continue; - auto blockStyle = RenderStyle::createAnonymousStyleWithDisplay(&block->style(), BLOCK); - blockStyle.get().setPosition(newStyle->position()); - block->setStyle(std::move(blockStyle)); + auto blockStyle = RenderStyle::createAnonymousStyleWithDisplay(block.style(), BLOCK); + blockStyle.setPosition(newStyle->position()); + block.setStyle(WTFMove(blockStyle)); + } +} + +void RenderInline::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) +{ + RenderBoxModelObject::styleWillChange(diff, newStyle); + // RenderInlines forward their absolute positioned descendants to their (non-anonymous) containing block. + // Check if this non-anonymous containing block can hold the absolute positioned elements when the inline is no longer positioned. + if (canContainAbsolutelyPositionedObjects() && newStyle.position() == StaticPosition) { + auto* container = containingBlockForAbsolutePosition(); + if (container && !container->canContainAbsolutelyPositionedObjects()) + container->removePositionedObjects(nullptr, NewContainingBlock); } } @@ -183,29 +187,24 @@ void RenderInline::styleDidChange(StyleDifference diff, const RenderStyle* oldSt // e.g., <font>foo <h4>goo</h4> moo</font>. The <font> inlines before // and after the block share the same style, but the block doesn't // need to pass its style on to anyone else. - RenderStyle& newStyle = style(); + auto& newStyle = style(); RenderInline* continuation = inlineElementContinuation(); if (continuation) { for (RenderInline* currCont = continuation; currCont; currCont = currCont->inlineElementContinuation()) { RenderBoxModelObject* nextCont = currCont->continuation(); currCont->setContinuation(nullptr); - currCont->setStyle(newStyle); + currCont->setStyle(RenderStyle::clone(newStyle)); currCont->setContinuation(nextCont); } // If an inline's in-flow positioning has changed and it is part of an active continuation as a descendant of an anonymous containing block, // then any descendant blocks will need to change their in-flow positioning accordingly. // Do this by updating the position of the descendant blocks' containing anonymous blocks - there may be more than one. - if (containingBlock()->isAnonymousBlock() && oldStyle && newStyle.position() != oldStyle->position() && (newStyle.hasInFlowPosition() || oldStyle->hasInFlowPosition())) { - // If any descendant blocks exist then they will be in the next anonymous block and its siblings. - ASSERT(containingBlock()->nextSibling()); - RenderBlock& block = *toRenderBlock(containingBlock()->nextSibling()); - ASSERT(block.isAnonymousBlock()); - updateStyleOfAnonymousBlockContinuations(block, &newStyle, oldStyle); - } + if (containingBlock()->isAnonymousBlock() && oldStyle && newStyle.position() != oldStyle->position() && (newStyle.hasInFlowPosition() || oldStyle->hasInFlowPosition())) + updateStyleOfAnonymousBlockContinuations(*containingBlock(), &newStyle, oldStyle); } if (!alwaysCreateLineBoxes()) { - bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasBoxDecorations() || newStyle.hasPadding() || newStyle.hasMargin() || hasOutline(); + bool alwaysCreateLineBoxes = hasSelfPaintingLayer() || hasVisibleBoxDecorations() || newStyle.hasBorder() || newStyle.hasPadding() || newStyle.hasMargin() || hasOutline(); if (oldStyle && alwaysCreateLineBoxes) { dirtyLineBoxes(false); setNeedsLayout(); @@ -221,23 +220,23 @@ void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout) if (alwaysCreateLineBoxes()) return; - RenderStyle* parentStyle = &parent()->style(); - RenderInline* parentRenderInline = parent()->isRenderInline() ? toRenderInline(parent()) : 0; + auto* parentStyle = &parent()->style(); + RenderInline* parentRenderInline = is<RenderInline>(*parent()) ? downcast<RenderInline>(parent()) : nullptr; bool checkFonts = document().inNoQuirksMode(); RenderFlowThread* flowThread = flowThreadContainingBlock(); bool alwaysCreateLineBoxes = (parentRenderInline && parentRenderInline->alwaysCreateLineBoxes()) || (parentRenderInline && parentStyle->verticalAlign() != BASELINE) || style().verticalAlign() != BASELINE || style().textEmphasisMark() != TextEmphasisMarkNone - || (checkFonts && (!parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(style().font().fontMetrics()) + || (checkFonts && (!parentStyle->fontCascade().fontMetrics().hasIdenticalAscentDescentAndLineGap(style().fontCascade().fontMetrics()) || parentStyle->lineHeight() != style().lineHeight())) || (flowThread && flowThread->isRenderNamedFlowThread()); // FIXME: Enable the optimization once we make overflow computation for culled inlines in regions. - if (!alwaysCreateLineBoxes && checkFonts && document().styleSheetCollection().usesFirstLineRules()) { + if (!alwaysCreateLineBoxes && checkFonts && view().usesFirstLineRules()) { // Have to check the first line style as well. parentStyle = &parent()->firstLineStyle(); - RenderStyle& childStyle = firstLineStyle(); - alwaysCreateLineBoxes = !parentStyle->font().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.font().fontMetrics()) + auto& childStyle = firstLineStyle(); + alwaysCreateLineBoxes = !parentStyle->fontCascade().fontMetrics().hasIdenticalAscentDescentAndLineGap(childStyle.fontCascade().fontMetrics()) || childStyle.verticalAlign() != BASELINE || parentStyle->lineHeight() != childStyle.lineHeight(); } @@ -249,7 +248,7 @@ void RenderInline::updateAlwaysCreateLineBoxes(bool fullLayout) } } -LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* extraWidthToEndOfLine) +LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, unsigned, LayoutUnit* extraWidthToEndOfLine) { if (firstChild()) { // This condition is possible if the RenderInline is at an editing boundary, @@ -265,26 +264,29 @@ LayoutRect RenderInline::localCaretRect(InlineBox* inlineBox, int, LayoutUnit* e if (extraWidthToEndOfLine) *extraWidthToEndOfLine = 0; - LayoutRect caretRect = localCaretRectForEmptyElement(borderAndPaddingWidth(), 0); + LayoutRect caretRect = localCaretRectForEmptyElement(horizontalBorderAndPaddingExtent(), 0); if (InlineBox* firstBox = firstLineBox()) - caretRect.moveBy(roundedLayoutPoint(firstBox->topLeft())); + caretRect.moveBy(LayoutPoint(firstBox->topLeft())); return caretRect; } void RenderInline::addChild(RenderObject* newChild, RenderObject* beforeChild) { + auto* beforeChildOrPlaceholder = beforeChild; + if (auto* flowThread = flowThreadContainingBlock()) + beforeChildOrPlaceholder = flowThread->resolveMovedChild(beforeChild); if (continuation()) - return addChildToContinuation(newChild, beforeChild); - return addChildIgnoringContinuation(newChild, beforeChild); + return addChildToContinuation(newChild, beforeChildOrPlaceholder); + return addChildIgnoringContinuation(newChild, beforeChildOrPlaceholder); } static RenderBoxModelObject* nextContinuation(RenderObject* renderer) { - if (renderer->isInline() && !renderer->isReplaced()) - return toRenderInline(renderer)->continuation(); - return toRenderBlock(renderer)->inlineElementContinuation(); + if (is<RenderInline>(*renderer) && !renderer->isReplaced()) + return downcast<RenderInline>(*renderer).continuation(); + return downcast<RenderBlock>(*renderer).inlineElementContinuation(); } RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild) @@ -312,25 +314,34 @@ RenderBoxModelObject* RenderInline::continuationBefore(RenderObject* beforeChild return last; } +static bool newChildIsInline(const RenderObject& newChild, const RenderInline& parent) +{ + // inline parent generates inline-table. + return newChild.isInline() | (parent.childRequiresTable(newChild) && parent.style().display() == INLINE); +} + void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) { // Make sure we don't append things after :after-generated content if we have it. if (!beforeChild && isAfterContent(lastChild())) beforeChild = lastChild(); - - if (!newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) { + + bool useNewBlockInsideInlineModel = settings().newBlockInsideInlineModelEnabled(); + bool childInline = newChildIsInline(*newChild, *this); + // This code is for the old block-inside-inline model that uses continuations. + if (!useNewBlockInsideInlineModel && !childInline && !newChild->isFloatingOrOutOfFlowPositioned()) { // We are placing a block inside an inline. We have to perform a split of this // inline into continuations. This involves creating an anonymous block box to hold // |newChild|. We then make that block box a continuation of this inline. We take all of // the children after |beforeChild| and put them in a clone of this object. - auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(&style(), BLOCK); + auto newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK); // If inside an inline affected by in-flow positioning the block needs to be affected by it too. // Giving the block a layer like this allows it to collect the x/y offsets from inline parents later. if (auto positionedAncestor = inFlowPositionedInlineAncestor(this)) - newStyle.get().setPosition(positionedAncestor->style().position()); + newStyle.setPosition(positionedAncestor->style().position()); - RenderBlock* newBox = new RenderBlockFlow(document(), std::move(newStyle)); + RenderBlock* newBox = new RenderBlockFlow(document(), WTFMove(newStyle)); newBox->initializeStyle(); RenderBoxModelObject* oldContinuation = continuation(); setContinuation(newBox); @@ -338,6 +349,65 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb splitFlow(beforeChild, newBox, newChild, oldContinuation); return; } + + if (!useNewBlockInsideInlineModel) { + RenderBoxModelObject::addChild(newChild, beforeChild); + newChild->setNeedsLayoutAndPrefWidthsRecalc(); + return; + } + + // This code is for the new block-inside-inline model that uses anonymous inline blocks. + // If the requested beforeChild is not one of our children, then this is most likely because + // there is an anonymous inline-block box within this object that contains the beforeChild. + // Insert the child into the anonymous inline-block box instead of here. + // A second possibility is that the beforeChild is an anonymous block inside the anonymous inline block. + // This can happen if inlines are inserted in between two of the anonymous inline block's block-level + // children after it has been created. + if (beforeChild && beforeChild->parent() != this) { + ASSERT(beforeChild->parent()); + ASSERT(beforeChild->parent()->isAnonymousInlineBlock() || beforeChild->parent()->isAnonymousBlock()); + if (beforeChild->parent()->isAnonymousInlineBlock()) { + if (!childInline || (childInline && beforeChild->parent()->firstChild() != beforeChild)) + beforeChild->parent()->addChild(newChild, beforeChild); + else + addChild(newChild, beforeChild->parent()); + } else if (beforeChild->parent()->isAnonymousBlock()) { + ASSERT(!beforeChild->parent()->parent() || beforeChild->parent()->parent()->isAnonymousInlineBlock()); + ASSERT(childInline); + if (childInline || (!childInline && beforeChild->parent()->firstChild() != beforeChild)) + beforeChild->parent()->addChild(newChild, beforeChild); + else + addChild(newChild, beforeChild->parent()); + } + return; + } + + if (!childInline) { + // We are placing a block inside an inline. We have to place the block inside an anonymous inline-block. + // This inline-block can house a sequence of contiguous block-level children, and they will all sit on the + // same "line" together. We try to reuse an existing inline-block if possible. + if (beforeChild) { + if (beforeChild->previousSibling() && beforeChild->previousSibling()->isAnonymousInlineBlock()) { + downcast<RenderBlockFlow>(beforeChild->previousSibling())->addChild(newChild); + return; + } + } else { + if (lastChild() && lastChild()->isAnonymousInlineBlock()) { + downcast<RenderBlockFlow>(lastChild())->addChild(newChild); + return; + } + } + + if (!newChild->isFloatingOrOutOfFlowPositioned()) { + // There was no suitable existing anonymous inline-block. Create a new one. + RenderBlockFlow* anonymousInlineBlock = new RenderBlockFlow(document(), RenderStyle::createAnonymousStyleWithDisplay(style(), INLINE_BLOCK)); + anonymousInlineBlock->initializeStyle(); + + RenderBoxModelObject::addChild(anonymousInlineBlock, beforeChild); + anonymousInlineBlock->addChild(newChild); + return; + } + } RenderBoxModelObject::addChild(newChild, beforeChild); @@ -346,9 +416,10 @@ void RenderInline::addChildIgnoringContinuation(RenderObject* newChild, RenderOb RenderPtr<RenderInline> RenderInline::clone() const { - RenderPtr<RenderInline> cloneInline = createRenderer<RenderInline>(*element(), style()); + RenderPtr<RenderInline> cloneInline = createRenderer<RenderInline>(*element(), RenderStyle::clone(style())); cloneInline->initializeStyle(); cloneInline->setFlowThreadState(flowThreadState()); + cloneInline->setHasOutlineAutoAncestor(hasOutlineAutoAncestor()); return cloneInline; } @@ -358,8 +429,6 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, { // Create a clone of this inline. RenderPtr<RenderInline> cloneInline = clone(); - cloneInline->setContinuation(oldCont); - #if ENABLE(FULLSCREEN_API) // If we're splitting the inline containing the fullscreened element, // |beforeChild| may be the renderer for the fullscreened element. However, @@ -370,26 +439,51 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, if (fullScreenElement && beforeChild && beforeChild->node() == fullScreenElement) beforeChild = document().fullScreenRenderer(); #endif - // Now take all of the children from beforeChild to the end and remove // them from |this| and place them in the clone. - RenderObject* o = beforeChild; - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - removeChildInternal(*tmp, NotifyChildren); - cloneInline->addChildIgnoringContinuation(tmp, 0); - tmp->setNeedsLayoutAndPrefWidthsRecalc(); + for (RenderObject* rendererToMove = beforeChild; rendererToMove;) { + RenderObject* nextSibling = rendererToMove->nextSibling(); + // When anonymous wrapper is present, we might need to move the whole subtree instead. + if (rendererToMove->parent() != this) { + auto* anonymousParent = rendererToMove->parent(); + while (anonymousParent && anonymousParent->parent() != this) { + ASSERT(anonymousParent->isAnonymous()); + anonymousParent = anonymousParent->parent(); + } + if (!anonymousParent) { + ASSERT_NOT_REACHED(); + break; + } + // If beforeChild is the first child in the subtree, we could just move the whole subtree. + if (!rendererToMove->previousSibling()) { + // Reparent the whole anonymous wrapper tree. + rendererToMove = anonymousParent; + // Skip to the next sibling that is not in this subtree. + nextSibling = anonymousParent->nextSibling(); + } else if (!rendererToMove->nextSibling()) { + // This is the last renderer in the subtree. We need to jump out of the wrapper subtree, so that + // the siblings are getting reparented too. + nextSibling = anonymousParent->nextSibling(); + } + // Otherwise just move the renderer to the inline clone. Should the renderer need an anon + // wrapper, the addChild() will generate one for it. + // FIXME: When the anonymous wrapper has multiple children, we end up traversing up to the topmost wrapper + // every time, which is a bit wasteful. + } + rendererToMove->parent()->removeChildInternal(*rendererToMove, NotifyChildren); + cloneInline->addChildIgnoringContinuation(rendererToMove); + rendererToMove->setNeedsLayoutAndPrefWidthsRecalc(); + rendererToMove = nextSibling; } - + cloneInline->setContinuation(oldCont); // Hook |clone| up as the continuation of the middle block. middleBlock->setContinuation(cloneInline.get()); // We have been reparented and are now under the fromBlock. We need // to walk up our inline parent chain until we hit the containing block. // Once we hit the containing block we're done. - RenderBoxModelObject* curr = toRenderBoxModelObject(parent()); - RenderBoxModelObject* currChild = this; + RenderBoxModelObject* current = downcast<RenderBoxModelObject>(parent()); + RenderBoxModelObject* currentChild = this; // FIXME: Because splitting is O(n^2) as tags nest pathologically, we cap the depth at which we're willing to clone. // There will eventually be a better approach to this problem that will let us nest to a much @@ -397,58 +491,59 @@ void RenderInline::splitInlines(RenderBlock* fromBlock, RenderBlock* toBlock, // incorrect rendering, but the alternative is to hang forever. unsigned splitDepth = 1; const unsigned cMaxSplitDepth = 200; - while (curr && curr != fromBlock) { - ASSERT(curr->isRenderInline()); + while (current && current != fromBlock) { if (splitDepth < cMaxSplitDepth) { // Create a new clone. - RenderPtr<RenderInline> cloneChild = std::move(cloneInline); - cloneInline = toRenderInline(curr)->clone(); + RenderPtr<RenderInline> cloneChild = WTFMove(cloneInline); + cloneInline = downcast<RenderInline>(*current).clone(); // Insert our child clone as the first child. - cloneInline->addChildIgnoringContinuation(cloneChild.leakPtr(), 0); + cloneInline->addChildIgnoringContinuation(cloneChild.leakPtr()); // Hook the clone up as a continuation of |curr|. - RenderInline* inlineCurr = toRenderInline(curr); - oldCont = inlineCurr->continuation(); - inlineCurr->setContinuation(cloneInline.get()); + RenderInline& currentInline = downcast<RenderInline>(*current); + oldCont = currentInline.continuation(); + currentInline.setContinuation(cloneInline.get()); cloneInline->setContinuation(oldCont); // Now we need to take all of the children starting from the first child - // *after* currChild and append them all to the clone. - o = currChild->nextSibling(); - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - inlineCurr->removeChildInternal(*tmp, NotifyChildren); - cloneInline->addChildIgnoringContinuation(tmp, 0); - tmp->setNeedsLayoutAndPrefWidthsRecalc(); + // *after* currentChild and append them all to the clone. + for (auto* current = currentChild->nextSibling(); current;) { + auto* next = current->nextSibling(); + currentInline.removeChildInternal(*current, NotifyChildren); + cloneInline->addChildIgnoringContinuation(current); + current->setNeedsLayoutAndPrefWidthsRecalc(); + current = next; } } // Keep walking up the chain. - currChild = curr; - curr = toRenderBoxModelObject(curr->parent()); - splitDepth++; + currentChild = current; + current = downcast<RenderBoxModelObject>(current->parent()); + ++splitDepth; } + // Clear the flow thread containing blocks cached during the detached state insertions. + for (auto& cloneBlockChild : childrenOfType<RenderBlock>(*cloneInline)) + cloneBlockChild.resetFlowThreadContainingBlockAndChildInfoIncludingDescendants(); + // Now we are at the block level. We need to put the clone into the toBlock. toBlock->insertChildInternal(cloneInline.leakPtr(), nullptr, NotifyChildren); - // Now take all the children after currChild and remove them from the fromBlock + // Now take all the children after currentChild and remove them from the fromBlock // and put them in the toBlock. - o = currChild->nextSibling(); - while (o) { - RenderObject* tmp = o; - o = tmp->nextSibling(); - fromBlock->removeChildInternal(*tmp, NotifyChildren); - toBlock->insertChildInternal(tmp, nullptr, NotifyChildren); + for (auto* current = currentChild->nextSibling(); current;) { + auto* next = current->nextSibling(); + fromBlock->removeChildInternal(*current, NotifyChildren); + toBlock->insertChildInternal(current, nullptr, NotifyChildren); + current = next; } } void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild, RenderBoxModelObject* oldCont) { - RenderBlock* pre = 0; + RenderBlock* pre = nullptr; RenderBlock* block = containingBlock(); // Delete our line boxes before we do the inline split into continuations. @@ -458,12 +553,12 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox if (block->isAnonymousBlock() && (!block->parent() || !block->parent()->createsAnonymousWrapper())) { // We can reuse this block and make it the preBlock of the next continuation. pre = block; - pre->removePositionedObjects(0); + pre->removePositionedObjects(nullptr); // FIXME-BLOCKFLOW: The enclosing method should likely be switched over // to only work on RenderBlockFlow, in which case this conversion can be // removed. - if (pre->isRenderBlockFlow()) - toRenderBlockFlow(pre)->removeFloatingObjects(); + if (is<RenderBlockFlow>(*pre)) + downcast<RenderBlockFlow>(*pre).removeFloatingObjects(); block = block->containingBlock(); } else { // No anonymous block available for use. Make one. @@ -471,13 +566,13 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox madeNewBeforeBlock = true; } - RenderBlock* post = toRenderBlock(pre->createAnonymousBoxWithSameTypeAs(block)); + auto& post = downcast<RenderBlock>(*pre->createAnonymousBoxWithSameTypeAs(*block).release()); RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); if (madeNewBeforeBlock) block->insertChildInternal(pre, boxFirst, NotifyChildren); block->insertChildInternal(newBlockBox, boxFirst, NotifyChildren); - block->insertChildInternal(post, boxFirst, NotifyChildren); + block->insertChildInternal(&post, boxFirst, NotifyChildren); block->setChildrenInline(false); if (madeNewBeforeBlock) { @@ -491,7 +586,7 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox } } - splitInlines(pre, post, newBlockBox, beforeChild, oldCont); + splitInlines(pre, &post, newBlockBox, beforeChild, oldCont); // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting // time in makeChildrenNonInline by just setting this explicitly up front. @@ -507,45 +602,59 @@ void RenderInline::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox // make new line boxes instead of leaving the old line boxes around. pre->setNeedsLayoutAndPrefWidthsRecalc(); block->setNeedsLayoutAndPrefWidthsRecalc(); - post->setNeedsLayoutAndPrefWidthsRecalc(); + post.setNeedsLayoutAndPrefWidthsRecalc(); +} + +static bool canUseAsParentForContinuation(const RenderObject* renderer) +{ + if (!renderer) + return false; + if (!is<RenderBlock>(renderer) && renderer->isAnonymous()) + return false; + if (is<RenderTable>(renderer)) + return false; + return true; } void RenderInline::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild) { - RenderBoxModelObject* flow = continuationBefore(beforeChild); - ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() || beforeChild->parent()->isRenderInline()); - RenderBoxModelObject* beforeChildParent = 0; - if (beforeChild) - beforeChildParent = toRenderBoxModelObject(beforeChild->parent()); - else { - RenderBoxModelObject* cont = nextContinuation(flow); - if (cont) - beforeChildParent = cont; - else - beforeChildParent = flow; - } + auto* flow = continuationBefore(beforeChild); + // It may or may not be the direct parent of the beforeChild. + RenderBoxModelObject* beforeChildAncestor = nullptr; + if (!beforeChild) { + auto* continuation = nextContinuation(flow); + beforeChildAncestor = continuation ? continuation : flow; + } else if (canUseAsParentForContinuation(beforeChild->parent())) + beforeChildAncestor = downcast<RenderBoxModelObject>(beforeChild->parent()); + else if (beforeChild->parent()) { + // In case of anonymous wrappers, the parent of the beforeChild is mostly irrelevant. What we need is the topmost wrapper. + auto* parent = beforeChild->parent(); + while (parent && parent->parent() && parent->parent()->isAnonymous()) { + // The ancestor candidate needs to be inside the continuation. + if (parent->hasContinuation()) + break; + parent = parent->parent(); + } + ASSERT(parent && parent->parent()); + beforeChildAncestor = downcast<RenderBoxModelObject>(parent->parent()); + } else + ASSERT_NOT_REACHED(); if (newChild->isFloatingOrOutOfFlowPositioned()) - return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); + return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); + if (flow == beforeChildAncestor) + return flow->addChildIgnoringContinuation(newChild, beforeChild); // A continuation always consists of two potential candidates: an inline or an anonymous // block box holding block children. - bool childInline = newChild->isInline(); - bool bcpInline = beforeChildParent->isInline(); - bool flowInline = flow->isInline(); - - if (flow == beforeChildParent) - return flow->addChildIgnoringContinuation(newChild, beforeChild); - else { - // The goal here is to match up if we can, so that we can coalesce and create the - // minimal # of continuations needed for the inline. - if (childInline == bcpInline) - return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); - else if (flowInline == childInline) - return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append. - else - return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); - } + bool childInline = newChildIsInline(*newChild, *this); + // The goal here is to match up if we can, so that we can coalesce and create the + // minimal # of continuations needed for the inline. + if (childInline == beforeChildAncestor->isInline()) + return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); + if (flow->isInline() == childInline) + return flow->addChildIgnoringContinuation(newChild); // Just treat like an append. + return beforeChildAncestor->addChildIgnoringContinuation(newChild, beforeChild); } void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) @@ -554,91 +663,92 @@ void RenderInline::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) } template<typename GeneratorContext> -void RenderInline::generateLineBoxRects(GeneratorContext& yield) const +void RenderInline::generateLineBoxRects(GeneratorContext& context) const { if (!alwaysCreateLineBoxes()) - generateCulledLineBoxRects(yield, this); + generateCulledLineBoxRects(context, this); else if (InlineFlowBox* curr = firstLineBox()) { for (; curr; curr = curr->nextLineBox()) - yield(FloatRect(curr->topLeft(), curr->size())); + context.addRect(FloatRect(curr->topLeft(), curr->size())); } else - yield(FloatRect()); + context.addRect(FloatRect()); } template<typename GeneratorContext> -void RenderInline::generateCulledLineBoxRects(GeneratorContext& yield, const RenderInline* container) const +void RenderInline::generateCulledLineBoxRects(GeneratorContext& context, const RenderInline* container) const { if (!culledInlineFirstLineBox()) { - yield(FloatRect()); + context.addRect(FloatRect()); return; } bool isHorizontal = style().isHorizontalWritingMode(); - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isFloatingOrOutOfFlowPositioned()) + for (auto& current : childrenOfType<RenderObject>(*this)) { + if (current.isFloatingOrOutOfFlowPositioned()) continue; - + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block // direction (aligned to the root box's baseline). - if (curr->isBox()) { - RenderBox* currBox = toRenderBox(curr); - if (currBox->inlineBoxWrapper()) { - const RootInlineBox& rootBox = currBox->inlineBoxWrapper()->root(); + if (is<RenderBox>(current)) { + auto& renderBox = downcast<RenderBox>(current); + if (renderBox.inlineBoxWrapper()) { + const RootInlineBox& rootBox = renderBox.inlineBoxWrapper()->root(); const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style(); - int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent()); - int logicalHeight = containerStyle.font().fontMetrics().height(); + int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent()); + int logicalHeight = containerStyle.fontCascade().fontMetrics().height(); if (isHorizontal) - yield(FloatRect(currBox->inlineBoxWrapper()->x() - currBox->marginLeft(), logicalTop, currBox->width() + currBox->marginWidth(), logicalHeight)); + context.addRect(FloatRect(renderBox.inlineBoxWrapper()->x() - renderBox.marginLeft(), logicalTop, renderBox.width() + renderBox.horizontalMarginExtent(), logicalHeight)); else - yield(FloatRect(logicalTop, currBox->inlineBoxWrapper()->y() - currBox->marginTop(), logicalHeight, currBox->height() + currBox->marginHeight())); + context.addRect(FloatRect(logicalTop, renderBox.inlineBoxWrapper()->y() - renderBox.marginTop(), logicalHeight, renderBox.height() + renderBox.verticalMarginExtent())); } - } else if (curr->isRenderInline()) { + } else if (is<RenderInline>(current)) { // If the child doesn't need line boxes either, then we can recur. - RenderInline* currInline = toRenderInline(curr); - if (!currInline->alwaysCreateLineBoxes()) - currInline->generateCulledLineBoxRects(yield, container); + auto& renderInline = downcast<RenderInline>(current); + if (!renderInline.alwaysCreateLineBoxes()) + renderInline.generateCulledLineBoxRects(context, container); else { - for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) { + for (InlineFlowBox* childLine = renderInline.firstLineBox(); childLine; childLine = childLine->nextLineBox()) { const RootInlineBox& rootBox = childLine->root(); const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style(); - int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent()); + int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent()); int logicalHeight = containerStyle.fontMetrics().height(); - if (isHorizontal) - yield(FloatRect(childLine->x() - childLine->marginLogicalLeft(), + if (isHorizontal) { + context.addRect(FloatRect(childLine->x() - childLine->marginLogicalLeft(), logicalTop, childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight(), logicalHeight)); - else - yield(FloatRect(logicalTop, + } else { + context.addRect(FloatRect(logicalTop, childLine->y() - childLine->marginLogicalLeft(), logicalHeight, childLine->logicalWidth() + childLine->marginLogicalLeft() + childLine->marginLogicalRight())); + } } } - } else if (curr->isText()) { - RenderText* currText = toRenderText(curr); - for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) { + } else if (is<RenderText>(current)) { + auto& currText = downcast<RenderText>(current); + for (InlineTextBox* childText = currText.firstTextBox(); childText; childText = childText->nextTextBox()) { const RootInlineBox& rootBox = childText->root(); const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style(); - int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent()); - int logicalHeight = containerStyle.font().fontMetrics().height(); + int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent()); + int logicalHeight = containerStyle.fontCascade().fontMetrics().height(); if (isHorizontal) - yield(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight)); + context.addRect(FloatRect(childText->x(), logicalTop, childText->logicalWidth(), logicalHeight)); else - yield(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth())); + context.addRect(FloatRect(logicalTop, childText->y(), logicalHeight, childText->logicalWidth())); } - } else if (curr->isLineBreak()) { - if (InlineBox* inlineBox = toRenderLineBreak(curr)->inlineBoxWrapper()) { + } else if (is<RenderLineBreak>(current)) { + if (auto* inlineBox = downcast<RenderLineBreak>(current).inlineBoxWrapper()) { // FIXME: This could use a helper to share these with text path. const RootInlineBox& rootBox = inlineBox->root(); const RenderStyle& containerStyle = rootBox.isFirstLine() ? container->firstLineStyle() : container->style(); - int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().font().fontMetrics().ascent() - containerStyle.font().fontMetrics().ascent()); + int logicalTop = rootBox.logicalTop() + (rootBox.lineStyle().fontCascade().fontMetrics().ascent() - containerStyle.fontCascade().fontMetrics().ascent()); int logicalHeight = containerStyle.fontMetrics().height(); if (isHorizontal) - yield(FloatRect(inlineBox->x(), logicalTop, inlineBox->logicalWidth(), logicalHeight)); + context.addRect(FloatRect(inlineBox->x(), logicalTop, inlineBox->logicalWidth(), logicalHeight)); else - yield(FloatRect(logicalTop, inlineBox->y(), logicalHeight, inlineBox->logicalWidth())); + context.addRect(FloatRect(logicalTop, inlineBox->y(), logicalHeight, inlineBox->logicalWidth())); } } } @@ -648,18 +758,18 @@ namespace { class AbsoluteRectsGeneratorContext { public: - AbsoluteRectsGeneratorContext(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) + AbsoluteRectsGeneratorContext(Vector<LayoutRect>& rects, const LayoutPoint& accumulatedOffset) : m_rects(rects) , m_accumulatedOffset(accumulatedOffset) { } - void operator()(const FloatRect& rect) + void addRect(const FloatRect& rect) { - IntRect intRect = enclosingIntRect(rect); - intRect.move(m_accumulatedOffset.x(), m_accumulatedOffset.y()); - m_rects.append(intRect); + LayoutRect adjustedRect = LayoutRect(rect); + adjustedRect.moveBy(m_accumulatedOffset); + m_rects.append(adjustedRect); } private: - Vector<IntRect>& m_rects; + Vector<LayoutRect>& m_rects; const LayoutPoint& m_accumulatedOffset; }; @@ -667,13 +777,16 @@ private: void RenderInline::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const { - AbsoluteRectsGeneratorContext context(rects, accumulatedOffset); + Vector<LayoutRect> lineboxRects; + AbsoluteRectsGeneratorContext context(lineboxRects, accumulatedOffset); generateLineBoxRects(context); + for (const auto& rect : lineboxRects) + rects.append(snappedIntRect(rect)); if (RenderBoxModelObject* continuation = this->continuation()) { - if (continuation->isBox()) { - RenderBox* box = toRenderBox(continuation); - continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box->locationOffset())); + if (is<RenderBox>(*continuation)) { + auto& box = downcast<RenderBox>(*continuation); + continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location() + box.locationOffset())); } else continuation->absoluteRects(rects, toLayoutPoint(accumulatedOffset - containingBlock()->location())); } @@ -688,10 +801,10 @@ public: : m_quads(quads) , m_geometryMap() { - m_geometryMap.pushMappingsToAncestor(renderer, 0); + m_geometryMap.pushMappingsToAncestor(renderer, nullptr); } - void operator()(const FloatRect& rect) + void addRect(const FloatRect& rect) { m_quads.append(m_geometryMap.absoluteRect(rect)); } @@ -741,10 +854,8 @@ static LayoutUnit computeMargin(const RenderInline* renderer, const Length& marg return 0; if (margin.isFixed()) return margin.value(); - if (margin.isPercent()) + if (margin.isPercentOrCalculated()) return minimumValueForLength(margin, std::max<LayoutUnit>(0, renderer->containingBlock()->availableLogicalWidth())); - if (margin.isViewportPercentage()) - return valueForLength(margin, 0, &renderer->view()); return 0; } @@ -799,8 +910,6 @@ const char* RenderInline::renderName() const return "RenderInline (generated)"; if (isAnonymous()) return "RenderInline (generated)"; - if (isRunIn()) - return "RenderInline (run-in)"; return "RenderInline"; } @@ -814,13 +923,20 @@ namespace { class HitTestCulledInlinesGeneratorContext { public: - HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) : m_intersected(false), m_region(region), m_location(location) { } - void operator()(const FloatRect& rect) + HitTestCulledInlinesGeneratorContext(Region& region, const HitTestLocation& location) + : m_intersected(false) + , m_region(region) + , m_location(location) + { } + + void addRect(const FloatRect& rect) { m_intersected = m_intersected || m_location.intersects(rect); m_region.unite(enclosingIntRect(rect)); } + bool intersected() const { return m_intersected; } + private: bool m_intersected; Region& m_region; @@ -851,27 +967,27 @@ bool RenderInline::hitTestCulledInline(const HitTestRequest& request, HitTestRes return false; } -VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point) +VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point, const RenderRegion* region) { // FIXME: Does not deal with relative or sticky positioned inlines (should it?) - RenderBlock* cb = containingBlock(); + RenderBlock& containingBlock = *this->containingBlock(); if (firstLineBox()) { // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We // should try to find a result by asking our containing block. - return cb->positionForPoint(point); + return containingBlock.positionForPoint(point, region); } // Translate the coords from the pre-anonymous block to the post-anonymous block. - LayoutPoint parentBlockPoint = cb->location() + point; - RenderBoxModelObject* c = continuation(); - while (c) { - RenderBox* contBlock = c->isInline() ? c->containingBlock() : toRenderBlock(c); - if (c->isInline() || c->firstChild()) - return c->positionForPoint(parentBlockPoint - contBlock->locationOffset()); - c = toRenderBlock(c)->inlineElementContinuation(); + LayoutPoint parentBlockPoint = containingBlock.location() + point; + RenderBoxModelObject* continuation = this->continuation(); + while (continuation) { + RenderBlock* currentBlock = continuation->isInline() ? continuation->containingBlock() : downcast<RenderBlock>(continuation); + if (continuation->isInline() || continuation->firstChild()) + return continuation->positionForPoint(parentBlockPoint - currentBlock->locationOffset(), region); + continuation = downcast<RenderBlock>(*continuation).inlineElementContinuation(); } - return RenderBoxModelObject::positionForPoint(point); + return RenderBoxModelObject::positionForPoint(point, region); } namespace { @@ -879,7 +995,8 @@ namespace { class LinesBoundingBoxGeneratorContext { public: LinesBoundingBoxGeneratorContext(FloatRect& rect) : m_rect(rect) { } - void operator()(const FloatRect& rect) + + void addRect(const FloatRect& rect) { m_rect.uniteIfNonZero(rect); } @@ -930,62 +1047,60 @@ IntRect RenderInline::linesBoundingBox() const InlineBox* RenderInline::culledInlineFirstLineBox() const { - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isFloatingOrOutOfFlowPositioned()) + for (auto& current : childrenOfType<RenderObject>(*this)) { + if (current.isFloatingOrOutOfFlowPositioned()) continue; - + // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block // direction (aligned to the root box's baseline). - if (curr->isBox()) { - const auto& renderBox = *toRenderBox(curr); + if (is<RenderBox>(current)) { + auto& renderBox = downcast<RenderBox>(current); if (renderBox.inlineBoxWrapper()) return renderBox.inlineBoxWrapper(); - } else if (curr->isLineBreak()) { - RenderLineBreak* renderBR = toRenderLineBreak(curr); - if (renderBR->inlineBoxWrapper()) - return renderBR->inlineBoxWrapper(); - } else if (curr->isRenderInline()) { - RenderInline* currInline = toRenderInline(curr); - InlineBox* result = currInline->firstLineBoxIncludingCulling(); - if (result) + } else if (is<RenderLineBreak>(current)) { + auto& renderBR = downcast<RenderLineBreak>(current); + if (renderBR.inlineBoxWrapper()) + return renderBR.inlineBoxWrapper(); + } else if (is<RenderInline>(current)) { + auto& renderInline = downcast<RenderInline>(current); + if (InlineBox* result = renderInline.firstLineBoxIncludingCulling()) return result; - } else if (curr->isText()) { - RenderText* currText = toRenderText(curr); - if (currText->firstTextBox()) - return currText->firstTextBox(); + } else if (is<RenderText>(current)) { + auto& renderText = downcast<RenderText>(current); + if (renderText.firstTextBox()) + return renderText.firstTextBox(); } } - return 0; + return nullptr; } InlineBox* RenderInline::culledInlineLastLineBox() const { - for (RenderObject* curr = lastChild(); curr; curr = curr->previousSibling()) { - if (curr->isFloatingOrOutOfFlowPositioned()) + for (RenderObject* current = lastChild(); current; current = current->previousSibling()) { + if (current->isFloatingOrOutOfFlowPositioned()) continue; // We want to get the margin box in the inline direction, and then use our font ascent/descent in the block // direction (aligned to the root box's baseline). - if (curr->isBox()) { - const auto& renderBox = *toRenderBox(curr); + if (is<RenderBox>(*current)) { + const auto& renderBox = downcast<RenderBox>(*current); if (renderBox.inlineBoxWrapper()) return renderBox.inlineBoxWrapper(); - } else if (curr->isLineBreak()) { - RenderLineBreak* renderBR = toRenderLineBreak(curr); - if (renderBR->inlineBoxWrapper()) - return renderBR->inlineBoxWrapper(); - } else if (curr->isRenderInline()) { - RenderInline* currInline = toRenderInline(curr); - InlineBox* result = currInline->lastLineBoxIncludingCulling(); - if (result) + } else if (is<RenderLineBreak>(*current)) { + RenderLineBreak& renderBR = downcast<RenderLineBreak>(*current); + if (renderBR.inlineBoxWrapper()) + return renderBR.inlineBoxWrapper(); + } else if (is<RenderInline>(*current)) { + RenderInline& renderInline = downcast<RenderInline>(*current); + if (InlineBox* result = renderInline.lastLineBoxIncludingCulling()) return result; - } else if (curr->isText()) { - RenderText* currText = toRenderText(curr); - if (currText->lastTextBox()) - return currText->lastTextBox(); + } else if (is<RenderText>(*current)) { + RenderText& renderText = downcast<RenderText>(*current); + if (renderText.lastTextBox()) + return renderText.lastTextBox(); } } - return 0; + return nullptr; } LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const @@ -995,35 +1110,35 @@ LayoutRect RenderInline::culledInlineVisualOverflowBoundingBox() const generateCulledLineBoxRects(context, this); LayoutRect result(enclosingLayoutRect(floatResult)); bool isHorizontal = style().isHorizontalWritingMode(); - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isFloatingOrOutOfFlowPositioned()) + for (auto& current : childrenOfType<RenderObject>(*this)) { + if (current.isFloatingOrOutOfFlowPositioned()) continue; - + // For overflow we just have to propagate by hand and recompute it all. - if (curr->isBox()) { - RenderBox* currBox = toRenderBox(curr); - if (!currBox->hasSelfPaintingLayer() && currBox->inlineBoxWrapper()) { - LayoutRect logicalRect = currBox->logicalVisualOverflowRectForPropagation(&style()); + if (is<RenderBox>(current)) { + auto& renderBox = downcast<RenderBox>(current); + if (!renderBox.hasSelfPaintingLayer() && renderBox.inlineBoxWrapper()) { + LayoutRect logicalRect = renderBox.logicalVisualOverflowRectForPropagation(&style()); if (isHorizontal) { - logicalRect.moveBy(currBox->location()); + logicalRect.moveBy(renderBox.location()); result.uniteIfNonZero(logicalRect); } else { - logicalRect.moveBy(currBox->location()); + logicalRect.moveBy(renderBox.location()); result.uniteIfNonZero(logicalRect.transposedRect()); } } - } else if (curr->isRenderInline()) { + } else if (is<RenderInline>(current)) { // If the child doesn't need line boxes either, then we can recur. - RenderInline* currInline = toRenderInline(curr); - if (!currInline->alwaysCreateLineBoxes()) - result.uniteIfNonZero(currInline->culledInlineVisualOverflowBoundingBox()); - else if (!currInline->hasSelfPaintingLayer()) - result.uniteIfNonZero(currInline->linesVisualOverflowBoundingBox()); - } else if (curr->isText()) { + auto& renderInline = downcast<RenderInline>(current); + if (!renderInline.alwaysCreateLineBoxes()) + result.uniteIfNonZero(renderInline.culledInlineVisualOverflowBoundingBox()); + else if (!renderInline.hasSelfPaintingLayer()) + result.uniteIfNonZero(renderInline.linesVisualOverflowBoundingBox()); + } else if (is<RenderText>(current)) { // FIXME; Overflow from text boxes is lost. We will need to cache this information in // InlineTextBoxes. - RenderText* currText = toRenderText(curr); - result.uniteIfNonZero(currText->linesVisualOverflowBoundingBox()); + auto& renderText = downcast<RenderText>(current); + result.uniteIfNonZero(renderText.linesVisualOverflowBoundingBox()); } } return result; @@ -1104,8 +1219,8 @@ LayoutRect RenderInline::linesVisualOverflowBoundingBoxInRegion(const RenderRegi LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { - // Only run-ins and first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints. - ASSERT(!view().layoutStateEnabled() || isRunIn() || style().styleType() == FIRST_LETTER); + // Only first-letter renderers are allowed in here during layout. They mutate the tree triggering repaints. + ASSERT(!view().layoutStateEnabled() || style().styleType() == FIRST_LETTER || hasSelfPaintingLayer()); if (!firstLineBoxIncludingCulling() && !continuation()) return LayoutRect(); @@ -1115,30 +1230,27 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(const RenderLayerModelObj // We need to add in the in-flow position offsets of any inlines (including us) up to our // containing block. - RenderBlock* cb = containingBlock(); - for (const RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isRenderInline() && inlineFlow != cb; + RenderBlock* containingBlock = this->containingBlock(); + for (const RenderElement* inlineFlow = this; is<RenderInline>(inlineFlow) && inlineFlow != containingBlock; inlineFlow = inlineFlow->parent()) { if (inlineFlow == repaintContainer) { hitRepaintContainer = true; break; } if (inlineFlow->style().hasInFlowPosition() && inlineFlow->hasLayer()) - repaintRect.move(toRenderInline(inlineFlow)->layer()->offsetForInFlowPosition()); + repaintRect.move(downcast<RenderInline>(*inlineFlow).layer()->offsetForInFlowPosition()); } LayoutUnit outlineSize = style().outlineSize(); repaintRect.inflate(outlineSize); - if (hitRepaintContainer || !cb) + if (hitRepaintContainer || !containingBlock) return repaintRect; - if (cb->hasColumns()) - cb->adjustRectForColumns(repaintRect); - - if (cb->hasOverflowClip()) - cb->applyCachedClipAndScrollOffsetForRepaint(repaintRect); + if (containingBlock->hasOverflowClip() && containingBlock->shouldApplyClipAndScrollPositionForRepaint(repaintContainer)) + containingBlock->applyCachedClipAndScrollPositionForRepaint(repaintRect); - cb->computeRectForRepaint(repaintContainer, repaintRect); + repaintRect = containingBlock->computeRectForRepaint(repaintRect, repaintContainer); if (outlineSize) { for (auto& child : childrenOfType<RenderElement>(*this)) @@ -1161,38 +1273,29 @@ LayoutRect RenderInline::rectWithOutlineForRepaint(const RenderLayerModelObject* return r; } -void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +LayoutRect RenderInline::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, RepaintContext context) const { // LayoutState is only valid for root-relative repainting + LayoutRect adjustedRect = rect; if (view().layoutStateEnabled() && !repaintContainer) { LayoutState* layoutState = view().layoutState(); if (style().hasInFlowPosition() && layer()) - rect.move(layer()->offsetForInFlowPosition()); - rect.move(layoutState->m_paintOffset); + adjustedRect.move(layer()->offsetForInFlowPosition()); + adjustedRect.move(layoutState->m_paintOffset); if (layoutState->m_clipped) - rect.intersect(layoutState->m_clipRect); - return; + adjustedRect.intersect(layoutState->m_clipRect); + return adjustedRect; } if (repaintContainer == this) - return; + return adjustedRect; bool containerSkipped; - RenderElement* o = container(repaintContainer, &containerSkipped); - if (!o) - return; - - LayoutPoint topLeft = rect.location(); + RenderElement* container = this->container(repaintContainer, containerSkipped); + if (!container) + return adjustedRect; - if (o->isRenderBlockFlow() && !style().hasOutOfFlowPosition()) { - RenderBlock* cb = toRenderBlock(o); - if (cb->hasColumns()) { - LayoutRect repaintRect(topLeft, rect.size()); - cb->adjustRectForColumns(repaintRect); - topLeft = repaintRect.location(); - rect = repaintRect; - } - } + LayoutPoint topLeft = adjustedRect.location(); if (style().hasInFlowPosition() && layer()) { // Apply the in-flow position offset when invalidating a rectangle. The layer @@ -1204,41 +1307,35 @@ void RenderInline::computeRectForRepaint(const RenderLayerModelObject* repaintCo // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout, // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer. - rect.setLocation(topLeft); - if (o->hasOverflowClip()) { - RenderBox* containerBox = toRenderBox(o); - containerBox->applyCachedClipAndScrollOffsetForRepaint(rect); - if (rect.isEmpty()) - return; + adjustedRect.setLocation(topLeft); + if (container->hasOverflowClip()) { + downcast<RenderBox>(*container).applyCachedClipAndScrollPositionForRepaint(adjustedRect); + if (adjustedRect.isEmpty()) + return adjustedRect; } if (containerSkipped) { // If the repaintContainer is below o, then we need to map the rect into repaintContainer's coordinates. - LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o); - rect.move(-containerOffset); - return; + LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container); + adjustedRect.move(-containerOffset); + return adjustedRect; } - - o->computeRectForRepaint(repaintContainer, rect, fixed); + return container->computeRectForRepaint(adjustedRect, repaintContainer, context); } -LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const +LayoutSize RenderInline::offsetFromContainer(RenderElement& container, const LayoutPoint&, bool* offsetDependsOnPoint) const { - ASSERT(container == this->container()); + ASSERT(&container == this->container()); LayoutSize offset; if (isInFlowPositioned()) offset += offsetForInFlowPosition(); - container->adjustForColumns(offset, point); - - if (container->hasOverflowClip()) - offset -= toRenderBox(container)->scrolledContentOffset(); + if (is<RenderBox>(container)) + offset -= toLayoutSize(downcast<RenderBox>(container).scrollPosition()); if (offsetDependsOnPoint) - *offsetDependsOnPoint = container->hasColumns() - || (container->isBox() && container->style().isFlippedBlocksWritingMode()) - || container->isRenderFlowThread(); + *offsetDependsOnPoint = (is<RenderBox>(container) && container.style().isFlippedBlocksWritingMode()) || is<RenderFlowThread>(container); return offset; } @@ -1258,24 +1355,24 @@ void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintCont } bool containerSkipped; - RenderElement* o = container(repaintContainer, &containerSkipped); - if (!o) + RenderElement* container = this->container(repaintContainer, containerSkipped); + if (!container) return; - if (mode & ApplyContainerFlip && o->isBox()) { - if (o->style().isFlippedBlocksWritingMode()) { - IntPoint centerPoint = roundedIntPoint(transformState.mappedPoint()); - transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(centerPoint) - centerPoint); + if (mode & ApplyContainerFlip && is<RenderBox>(*container)) { + if (container->style().isFlippedBlocksWritingMode()) { + LayoutPoint centerPoint(transformState.mappedPoint()); + transformState.move(downcast<RenderBox>(*container).flipForWritingMode(centerPoint) - centerPoint); } mode &= ~ApplyContainerFlip; } - LayoutSize containerOffset = offsetFromContainer(o, roundedLayoutPoint(transformState.mappedPoint())); + LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(transformState.mappedPoint())); - bool preserve3D = mode & UseTransforms && (o->style().preserves3D() || style().preserves3D()); - if (mode & UseTransforms && shouldUseTransformFromContainer(o)) { + bool preserve3D = mode & UseTransforms && (container->style().preserves3D() || style().preserves3D()); + if (mode & UseTransforms && shouldUseTransformFromContainer(container)) { TransformationMatrix t; - getTransformFromContainer(o, containerOffset, t); + getTransformFromContainer(container, containerOffset, t); transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } else transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); @@ -1283,12 +1380,12 @@ void RenderInline::mapLocalToContainer(const RenderLayerModelObject* repaintCont if (containerSkipped) { // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe // to just subtract the delta between the repaintContainer and o. - LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(o); + LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container); transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); return; } - o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); + container->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); } const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const @@ -1296,19 +1393,19 @@ const RenderObject* RenderInline::pushMappingToContainer(const RenderLayerModelO ASSERT(ancestorToStopAt != this); bool ancestorSkipped; - RenderElement* container = this->container(ancestorToStopAt, &ancestorSkipped); + RenderElement* container = this->container(ancestorToStopAt, ancestorSkipped); if (!container) - return 0; + return nullptr; LayoutSize adjustmentForSkippedAncestor; if (ancestorSkipped) { // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe // to just subtract the delta between the ancestor and o. - adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container); + adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(*container); } bool offsetDependsOnPoint = false; - LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); + LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(), &offsetDependsOnPoint); bool preserve3D = container->style().preserves3D() || style().preserves3D(); if (shouldUseTransformFromContainer(container)) { @@ -1331,15 +1428,15 @@ void RenderInline::updateDragState(bool dragOn) continuation->updateDragState(dragOn); } -void RenderInline::childBecameNonInline(RenderObject* child) +void RenderInline::childBecameNonInline(RenderElement& child) { // We have to split the parent flow. RenderBlock* newBox = containingBlock()->createAnonymousBlock(); RenderBoxModelObject* oldContinuation = continuation(); setContinuation(newBox); - RenderObject* beforeChild = child->nextSibling(); - removeChildInternal(*child, NotifyChildren); - splitFlow(beforeChild, newBox, child, oldContinuation); + RenderObject* beforeChild = child.nextSibling(); + removeChildInternal(child, NotifyChildren); + splitFlow(beforeChild, newBox, &child, oldContinuation); } void RenderInline::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) @@ -1375,26 +1472,26 @@ void RenderInline::dirtyLineBoxes(bool fullLayout) if (!alwaysCreateLineBoxes()) { // We have to grovel into our children in order to dirty the appropriate lines. - for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (curr->isFloatingOrOutOfFlowPositioned()) + for (auto& current : childrenOfType<RenderObject>(*this)) { + if (current.isFloatingOrOutOfFlowPositioned()) continue; - if (curr->isBox() && !curr->needsLayout()) { - RenderBox* currBox = toRenderBox(curr); - if (currBox->inlineBoxWrapper()) - currBox->inlineBoxWrapper()->root().markDirty(); - } else if (!curr->selfNeedsLayout()) { - if (curr->isRenderInline()) { - RenderInline* currInline = toRenderInline(curr); - for (InlineFlowBox* childLine = currInline->firstLineBox(); childLine; childLine = childLine->nextLineBox()) + if (is<RenderBox>(current) && !current.needsLayout()) { + auto& renderBox = downcast<RenderBox>(current); + if (renderBox.inlineBoxWrapper()) + renderBox.inlineBoxWrapper()->root().markDirty(); + } else if (!current.selfNeedsLayout()) { + if (is<RenderInline>(current)) { + auto& renderInline = downcast<RenderInline>(current); + for (InlineFlowBox* childLine = renderInline.firstLineBox(); childLine; childLine = childLine->nextLineBox()) childLine->root().markDirty(); - } else if (curr->isText()) { - RenderText* currText = toRenderText(curr); - for (InlineTextBox* childText = currText->firstTextBox(); childText; childText = childText->nextTextBox()) + } else if (is<RenderText>(current)) { + auto& renderText = downcast<RenderText>(current); + for (InlineTextBox* childText = renderText.firstTextBox(); childText; childText = childText->nextTextBox()) childText->root().markDirty(); - } else if (curr->isLineBreak()) { - RenderLineBreak* currBR = toRenderLineBreak(curr); - if (currBR->inlineBoxWrapper()) - currBR->inlineBoxWrapper()->root().markDirty(); + } else if (is<RenderLineBreak>(current)) { + auto& renderBR = downcast<RenderLineBreak>(current); + if (renderBR.inlineBoxWrapper()) + renderBR.inlineBoxWrapper()->root().markDirty(); } } } @@ -1417,19 +1514,19 @@ InlineFlowBox* RenderInline::createAndAppendInlineFlowBox() setAlwaysCreateLineBoxes(); auto newFlowBox = createInlineFlowBox(); auto flowBox = newFlowBox.get(); - m_lineBoxes.appendLineBox(std::move(newFlowBox)); + m_lineBoxes.appendLineBox(WTFMove(newFlowBox)); return flowBox; } LayoutUnit RenderInline::lineHeight(bool firstLine, LineDirectionMode /*direction*/, LinePositionMode /*linePositionMode*/) const { - if (firstLine && document().styleSheetCollection().usesFirstLineRules()) { + if (firstLine && view().usesFirstLineRules()) { const RenderStyle& firstLineStyle = this->firstLineStyle(); if (&firstLineStyle != &style()) - return firstLineStyle.computedLineHeight(&view()); + return firstLineStyle.computedLineHeight(); } - return style().computedLineHeight(&view()); + return style().computedLineHeight(); } int RenderInline::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const @@ -1455,7 +1552,7 @@ LayoutSize RenderInline::offsetForInFlowPositionedInline(const RenderBox* child) LayoutUnit inlinePosition; LayoutUnit blockPosition; if (firstLineBox()) { - inlinePosition = roundedLayoutUnit(firstLineBox()->logicalLeft()); + inlinePosition = LayoutUnit::fromFloatRound(firstLineBox()->logicalLeft()); blockPosition = firstLineBox()->logicalTop(); } else { inlinePosition = layer()->staticInlinePosition(); @@ -1488,28 +1585,28 @@ void RenderInline::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } -void RenderInline::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) +void RenderInline::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) { AbsoluteRectsGeneratorContext context(rects, additionalOffset); generateLineBoxRects(context); for (auto& child : childrenOfType<RenderElement>(*this)) { - if (child.isListMarker()) + if (is<RenderListMarker>(child)) continue; FloatPoint pos(additionalOffset); // FIXME: This doesn't work correctly with transforms. if (child.hasLayer()) pos = child.localToContainerPoint(FloatPoint(), paintContainer); - else if (child.isBox()) - pos.move(toRenderBox(child).locationOffset()); + else if (is<RenderBox>(child)) + pos.move(downcast<RenderBox>(child).locationOffset()); child.addFocusRingRects(rects, flooredIntPoint(pos), paintContainer); } if (RenderBoxModelObject* continuation = this->continuation()) { if (continuation->isInline()) - continuation->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + continuation->containingBlock()->location() - containingBlock()->location()), paintContainer); + continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + continuation->containingBlock()->location() - containingBlock()->location())), paintContainer); else - continuation->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + toRenderBox(continuation)->location() - containingBlock()->location()), paintContainer); + continuation->addFocusRingRects(rects, flooredLayoutPoint(LayoutPoint(additionalOffset + downcast<RenderBox>(*continuation).location() - containingBlock()->location())), paintContainer); } } @@ -1517,24 +1614,26 @@ void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOf { if (!hasOutline()) return; - - RenderStyle& styleToUse = style(); - if (styleToUse.outlineStyleIsAuto() || hasOutlineAnnotation()) { - if (!theme().supportsFocusRing(&styleToUse)) { - // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. - paintFocusRing(paintInfo, paintOffset, &styleToUse); - } + + auto& styleToUse = style(); + // Only paint the focus ring by hand if the theme isn't able to draw it. + if (styleToUse.outlineStyleIsAuto() && !theme().supportsFocusRing(styleToUse)) { + Vector<LayoutRect> focusRingRects; + addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer); + paintFocusRing(paintInfo, styleToUse, focusRingRects); } - GraphicsContext* graphicsContext = paintInfo.context; - if (graphicsContext->paintingDisabled()) + if (hasOutlineAnnotation() && !styleToUse.outlineStyleIsAuto() && !theme().supportsFocusRing(styleToUse)) + addPDFURLRect(paintInfo, paintOffset); + + GraphicsContext& graphicsContext = paintInfo.context(); + if (graphicsContext.paintingDisabled()) return; - if (styleToUse.outlineStyleIsAuto() || styleToUse.outlineStyle() == BNONE) + if (styleToUse.outlineStyleIsAuto() || !styleToUse.hasOutline()) return; Vector<LayoutRect> rects; - rects.append(LayoutRect()); for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextLineBox()) { const RootInlineBox& rootBox = curr->root(); @@ -1545,128 +1644,156 @@ void RenderInline::paintOutline(PaintInfo& paintInfo, const LayoutPoint& paintOf rects.append(LayoutRect()); Color outlineColor = styleToUse.visitedDependentColor(CSSPropertyOutlineColor); - bool useTransparencyLayer = outlineColor.hasAlpha(); + bool useTransparencyLayer = !outlineColor.isOpaque(); if (useTransparencyLayer) { - graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255); - outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue()); + graphicsContext.beginTransparencyLayer(outlineColor.alphaAsFloat()); + outlineColor = outlineColor.opaqueColor(); } for (unsigned i = 1; i < rects.size() - 1; i++) paintOutlineForLine(graphicsContext, paintOffset, rects.at(i - 1), rects.at(i), rects.at(i + 1), outlineColor); if (useTransparencyLayer) - graphicsContext->endTransparencyLayer(); + graphicsContext.endTransparencyLayer(); } -void RenderInline::paintOutlineForLine(GraphicsContext* graphicsContext, const LayoutPoint& paintOffset, - const LayoutRect& lastline, const LayoutRect& thisline, const LayoutRect& nextline, - const Color outlineColor) +void RenderInline::paintOutlineForLine(GraphicsContext& graphicsContext, const LayoutPoint& paintOffset, + const LayoutRect& previousLine, const LayoutRect& thisLine, const LayoutRect& nextLine, const Color& outlineColor) { - const RenderStyle& styleToUse = style(); - int outlineWidth = styleToUse.outlineWidth(); - EBorderStyle outlineStyle = styleToUse.outlineStyle(); + const auto& styleToUse = style(); + float outlineOffset = styleToUse.outlineOffset(); + LayoutRect outlineBoxRect = thisLine; + outlineBoxRect.inflate(outlineOffset); + outlineBoxRect.moveBy(paintOffset); + if (outlineBoxRect.isEmpty()) + return; + float outlineWidth = styleToUse.outlineWidth(); + EBorderStyle outlineStyle = styleToUse.outlineStyle(); bool antialias = shouldAntialiasLines(graphicsContext); - int offset = style().outlineOffset(); - - LayoutRect box(LayoutPoint(paintOffset.x() + thisline.x() - offset, paintOffset.y() + thisline.y() - offset), - LayoutSize(thisline.width() + offset, thisline.height() + offset)); - - IntRect pixelSnappedBox = pixelSnappedIntRect(box); - if (pixelSnappedBox.isEmpty()) - return; - IntRect pixelSnappedLastLine = pixelSnappedIntRect(paintOffset.x() + lastline.x(), 0, lastline.width(), 0); - IntRect pixelSnappedNextLine = pixelSnappedIntRect(paintOffset.x() + nextline.x(), 0, nextline.width(), 0); + auto adjustedPreviousLine = previousLine; + adjustedPreviousLine.moveBy(paintOffset); + auto adjustedNextLine = nextLine; + adjustedNextLine.moveBy(paintOffset); + float adjacentWidth1 = 0; + float adjacentWidth2 = 0; // left edge - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.x() - outlineWidth, - pixelSnappedBox.y() - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), - pixelSnappedBox.x(), - pixelSnappedBox.maxY() + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : 0), - BSLeft, - outlineColor, outlineStyle, - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), - (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.maxX() - 1) <= thisline.x() ? outlineWidth : -outlineWidth), - antialias); + auto topLeft = outlineBoxRect.minXMinYCorner(); + if (previousLine.isEmpty() || thisLine.x() < previousLine.x() || (previousLine.maxX()) <= thisLine.x()) { + topLeft.move(-outlineWidth, -outlineWidth); + adjacentWidth1 = outlineWidth; + } else { + topLeft.move(-outlineWidth, 2 * outlineOffset); + adjacentWidth1 = -outlineWidth; + } + auto bottomRight = outlineBoxRect.minXMaxYCorner(); + if (nextLine.isEmpty() || thisLine.x() <= nextLine.x() || (nextLine.maxX()) <= thisLine.x()) { + bottomRight.move(0, outlineWidth); + adjacentWidth2 = outlineWidth; + } else { + bottomRight.move(0, -2 * outlineOffset); + adjacentWidth2 = -outlineWidth; + } + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSLeft, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); // right edge - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.maxX(), - pixelSnappedBox.y() - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : 0), - pixelSnappedBox.maxX() + outlineWidth, - pixelSnappedBox.maxY() + (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : 0), - BSRight, - outlineColor, outlineStyle, - (lastline.isEmpty() || lastline.maxX() < thisline.maxX() || (thisline.maxX() - 1) <= lastline.x() ? outlineWidth : -outlineWidth), - (nextline.isEmpty() || nextline.maxX() <= thisline.maxX() || (thisline.maxX() - 1) <= nextline.x() ? outlineWidth : -outlineWidth), - antialias); + topLeft = outlineBoxRect.maxXMinYCorner(); + if (previousLine.isEmpty() || previousLine.maxX() < thisLine.maxX() || thisLine.maxX() <= previousLine.x()) { + topLeft.move(0, -outlineWidth); + adjacentWidth1 = outlineWidth; + } else { + topLeft.move(0, 2 * outlineOffset); + adjacentWidth1 = -outlineWidth; + } + bottomRight = outlineBoxRect.maxXMaxYCorner(); + if (nextLine.isEmpty() || nextLine.maxX() <= thisLine.maxX() || thisLine.maxX() <= nextLine.x()) { + bottomRight.move(outlineWidth, outlineWidth); + adjacentWidth2 = outlineWidth; + } else { + bottomRight.move(outlineWidth, -2 * outlineOffset); + adjacentWidth2 = -outlineWidth; + } + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSRight, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + // upper edge - if (thisline.x() < lastline.x()) - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.x() - outlineWidth, - pixelSnappedBox.y() - outlineWidth, - std::min(pixelSnappedBox.maxX() + outlineWidth, (lastline.isEmpty() ? 1000000 : pixelSnappedLastLine.x())), - pixelSnappedBox.y(), - BSTop, outlineColor, outlineStyle, - outlineWidth, - (!lastline.isEmpty() && paintOffset.x() + lastline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, - antialias); + if (thisLine.x() < previousLine.x()) { + topLeft = outlineBoxRect.minXMinYCorner(); + topLeft.move(-outlineWidth, -outlineWidth); + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMinYCorner(); + bottomRight.move(outlineWidth, 0); + if (!previousLine.isEmpty() && adjustedPreviousLine.x() < bottomRight.x()) { + bottomRight.setX(adjustedPreviousLine.x() - outlineOffset); + adjacentWidth2 = -outlineWidth; + } else + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } - if (lastline.maxX() < thisline.maxX()) - drawLineForBoxSide(graphicsContext, - std::max(lastline.isEmpty() ? -1000000 : pixelSnappedLastLine.maxX(), pixelSnappedBox.x() - outlineWidth), - pixelSnappedBox.y() - outlineWidth, - pixelSnappedBox.maxX() + outlineWidth, - pixelSnappedBox.y(), - BSTop, outlineColor, outlineStyle, - (!lastline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + lastline.maxX()) ? -outlineWidth : outlineWidth, - outlineWidth, antialias); - - if (thisline.x() == thisline.maxX()) - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.x() - outlineWidth, - pixelSnappedBox.y() - outlineWidth, - pixelSnappedBox.maxX() + outlineWidth, - pixelSnappedBox.y(), - BSTop, outlineColor, outlineStyle, - outlineWidth, - outlineWidth, - antialias); + if (previousLine.maxX() < thisLine.maxX()) { + topLeft = outlineBoxRect.minXMinYCorner(); + topLeft.move(-outlineWidth, -outlineWidth); + if (!previousLine.isEmpty() && adjustedPreviousLine.maxX() > topLeft.x()) { + topLeft.setX(adjustedPreviousLine.maxX() + outlineOffset); + adjacentWidth1 = -outlineWidth; + } else + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMinYCorner(); + bottomRight.move(outlineWidth, 0); + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } + + if (thisLine.x() == thisLine.maxX()) { + topLeft = outlineBoxRect.minXMinYCorner(); + topLeft.move(-outlineWidth, -outlineWidth); + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMinYCorner(); + bottomRight.move(outlineWidth, 0); + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSTop, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } // lower edge - if (thisline.x() < nextline.x()) - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.x() - outlineWidth, - pixelSnappedBox.maxY(), - std::min(pixelSnappedBox.maxX() + outlineWidth, !nextline.isEmpty() ? pixelSnappedNextLine.x() + 1 : 1000000), - pixelSnappedBox.maxY() + outlineWidth, - BSBottom, outlineColor, outlineStyle, - outlineWidth, - (!nextline.isEmpty() && paintOffset.x() + nextline.x() + 1 < pixelSnappedBox.maxX() + outlineWidth) ? -outlineWidth : outlineWidth, - antialias); + if (thisLine.x() < nextLine.x()) { + topLeft = outlineBoxRect.minXMaxYCorner(); + topLeft.move(-outlineWidth, 0); + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMaxYCorner(); + bottomRight.move(outlineWidth, outlineWidth); + if (!nextLine.isEmpty() && (adjustedNextLine.x() < bottomRight.x())) { + bottomRight.setX(adjustedNextLine.x() - outlineOffset); + adjacentWidth2 = -outlineWidth; + } else + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } - if (nextline.maxX() < thisline.maxX()) - drawLineForBoxSide(graphicsContext, - std::max(!nextline.isEmpty() ? pixelSnappedNextLine.maxX() : -1000000, pixelSnappedBox.x() - outlineWidth), - pixelSnappedBox.maxY(), - pixelSnappedBox.maxX() + outlineWidth, - pixelSnappedBox.maxY() + outlineWidth, - BSBottom, outlineColor, outlineStyle, - (!nextline.isEmpty() && pixelSnappedBox.x() - outlineWidth < paintOffset.x() + nextline.maxX()) ? -outlineWidth : outlineWidth, - outlineWidth, antialias); - - if (thisline.x() == thisline.maxX()) - drawLineForBoxSide(graphicsContext, - pixelSnappedBox.x() - outlineWidth, - pixelSnappedBox.maxY(), - pixelSnappedBox.maxX() + outlineWidth, - pixelSnappedBox.maxY() + outlineWidth, - BSBottom, outlineColor, outlineStyle, - outlineWidth, - outlineWidth, - antialias); + if (nextLine.maxX() < thisLine.maxX()) { + topLeft = outlineBoxRect.minXMaxYCorner(); + topLeft.move(-outlineWidth, 0); + if (!nextLine.isEmpty() && adjustedNextLine.maxX() > topLeft.x()) { + topLeft.setX(adjustedNextLine.maxX() + outlineOffset); + adjacentWidth1 = -outlineWidth; + } else + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMaxYCorner(); + bottomRight.move(outlineWidth, outlineWidth); + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } + + if (thisLine.x() == thisLine.maxX()) { + topLeft = outlineBoxRect.minXMaxYCorner(); + topLeft.move(-outlineWidth, 0); + adjacentWidth1 = outlineWidth; + bottomRight = outlineBoxRect.maxXMaxYCorner(); + bottomRight.move(outlineWidth, outlineWidth); + adjacentWidth2 = outlineWidth; + drawLineForBoxSide(graphicsContext, FloatRect(topLeft, bottomRight), BSBottom, outlineColor, outlineStyle, adjacentWidth1, adjacentWidth2, antialias); + } } #if ENABLE(DASHBOARD_SUPPORT) @@ -1697,8 +1824,7 @@ void RenderInline::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) if (!container) container = this; - region.clip = region.bounds; - container->computeAbsoluteRepaintRect(region.clip); + region.clip = container->computeAbsoluteRepaintRect(region.bounds); if (region.clip.height() < 0) { region.clip.setHeight(0); region.clip.setWidth(0); |