diff options
Diffstat (limited to 'Source/WebCore/rendering')
63 files changed, 1026 insertions, 904 deletions
diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp index 5969a3222..8254784f5 100644 --- a/Source/WebCore/rendering/EllipsisBox.cpp +++ b/Source/WebCore/rendering/EllipsisBox.cpp @@ -23,6 +23,7 @@ #include "Document.h" #include "GraphicsContext.h" #include "HitTestResult.h" +#include "InlineTextBox.h" #include "PaintInfo.h" #include "RenderBlock.h" #include "RootInlineBox.h" @@ -96,10 +97,11 @@ void EllipsisBox::paintSelection(GraphicsContext* context, const LayoutPoint& pa GraphicsContextStateSaver stateSaver(*context); LayoutUnit top = root()->selectionTop(); LayoutUnit h = root()->selectionHeight(); - // FIXME: We'll need to apply the correct clip rounding here: https://bugs.webkit.org/show_bug.cgi?id=63656 - context->clip(IntRect(x() + paintOffset.x(), top + paintOffset.y(), m_logicalWidth, h)); + LayoutRect clipRect(x() + paintOffset.x(), top + paintOffset.y(), m_logicalWidth, h); + alignSelectionRectToDevicePixels(clipRect); + context->clip(clipRect); // FIXME: Why is this always LTR? Fix by passing correct text run flags below. - context->drawHighlightForText(font, RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), IntPoint(x() + paintOffset.x(), y() + paintOffset.y() + top), h, c, style->colorSpace()); + context->drawHighlightForText(font, RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), roundedIntPoint(LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + top)), h, c, style->colorSpace()); } bool EllipsisBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index c19f1222f..66e1da96b 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2006, 2008, 2011 Apple Inc. All rights reserved. + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -47,53 +48,109 @@ namespace WebCore { using namespace HTMLNames; -HitTestResult::HitTestResult() - : m_isOverWidget(false) - , m_isRectBased(false) - , m_topPadding(0) +HitTestPoint::HitTestPoint() + : m_topPadding(0) , m_rightPadding(0) , m_bottomPadding(0) , m_leftPadding(0) - , m_shadowContentFilterPolicy(DoNotAllowShadowContent) - , m_region(0) + , m_isRectBased(false) { } -HitTestResult::HitTestResult(const LayoutPoint& point) +HitTestPoint::HitTestPoint(const LayoutPoint& point) : m_point(point) - , m_isOverWidget(false) - , m_isRectBased(false) , m_topPadding(0) , m_rightPadding(0) , m_bottomPadding(0) , m_leftPadding(0) - , m_shadowContentFilterPolicy(DoNotAllowShadowContent) - , m_region(0) + , m_isRectBased(false) { } -HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy allowShadowContent) +HitTestPoint::HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) : m_point(centerPoint) - , m_isOverWidget(false) , m_topPadding(topPadding) , m_rightPadding(rightPadding) , m_bottomPadding(bottomPadding) , m_leftPadding(leftPadding) - , m_shadowContentFilterPolicy(allowShadowContent) - , m_region(0) { // If all padding values passed in are zero then it is not a rect based hit test. m_isRectBased = topPadding || rightPadding || bottomPadding || leftPadding; +} + +HitTestPoint::HitTestPoint(const HitTestPoint& other) + : m_point(other.m_point) + , m_topPadding(other.m_topPadding) + , m_rightPadding(other.m_rightPadding) + , m_bottomPadding(other.m_bottomPadding) + , m_leftPadding(other.m_leftPadding) + , m_isRectBased(other.m_isRectBased) +{ +} + +HitTestPoint::~HitTestPoint() +{ +} + +HitTestPoint& HitTestPoint::operator=(const HitTestPoint& other) +{ + m_point = other.m_point; + m_topPadding = other.m_topPadding; + m_rightPadding = other.m_rightPadding; + m_bottomPadding = other.m_bottomPadding; + m_leftPadding = other.m_leftPadding; + m_isRectBased = other.m_isRectBased; + + return *this; +} + +IntRect HitTestPoint::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) +{ + IntPoint actualPoint(roundedIntPoint(point)); + actualPoint -= IntSize(leftPadding, topPadding); + + IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding); + // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1". + // FIXME: Remove this once non-rect based hit-detection stops using IntRect:intersects. + actualPadding += IntSize(1, 1); + + return IntRect(actualPoint, actualPadding); +} - // Make sure all padding values are clamped to zero if it is not a rect hit test. - if (!m_isRectBased) - m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0; +HitTestResult::HitTestResult() : HitTestPoint() + , m_isOverWidget(false) + , m_shadowContentFilterPolicy(DoNotAllowShadowContent) + , m_region(0) +{ +} + +HitTestResult::HitTestResult(const LayoutPoint& point) : HitTestPoint(point) + , m_isOverWidget(false) + , m_shadowContentFilterPolicy(DoNotAllowShadowContent) + , m_region(0) +{ +} + +HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy allowShadowContent) + : HitTestPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding) + , m_isOverWidget(false) + , m_shadowContentFilterPolicy(allowShadowContent) + , m_region(0) +{ +} + +HitTestResult::HitTestResult(const HitTestPoint& other, ShadowContentFilterPolicy allowShadowContent) + : HitTestPoint(other) + , m_isOverWidget(false) + , m_shadowContentFilterPolicy(allowShadowContent) + , m_region(0) +{ } HitTestResult::HitTestResult(const HitTestResult& other) - : m_innerNode(other.innerNode()) + : HitTestPoint(other) + , m_innerNode(other.innerNode()) , m_innerNonSharedNode(other.innerNonSharedNode()) - , m_point(other.point()) , m_localPoint(other.localPoint()) , m_innerURLElement(other.URLElement()) , m_scrollbar(other.scrollbar()) @@ -101,16 +158,7 @@ HitTestResult::HitTestResult(const HitTestResult& other) , m_shadowContentFilterPolicy(other.shadowContentFilterPolicy()) , m_region(other.region()) { - // Only copy the padding and NodeSet in case of rect hit test. - // Copying the later is rather expensive. - if ((m_isRectBased = other.isRectBasedTest())) { - m_topPadding = other.m_topPadding; - m_rightPadding = other.m_rightPadding; - m_bottomPadding = other.m_bottomPadding; - m_leftPadding = other.m_leftPadding; - } else - m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0; - + // Only copy the NodeSet in case of rect hit test. m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); } @@ -120,25 +168,17 @@ HitTestResult::~HitTestResult() HitTestResult& HitTestResult::operator=(const HitTestResult& other) { + HitTestPoint::operator=(other); m_innerNode = other.innerNode(); m_innerNonSharedNode = other.innerNonSharedNode(); - m_point = other.point(); m_localPoint = other.localPoint(); m_innerURLElement = other.URLElement(); m_scrollbar = other.scrollbar(); m_isOverWidget = other.isOverWidget(); - // Only copy the padding and NodeSet in case of rect hit test. - // Copying the later is rather expensive. - if ((m_isRectBased = other.isRectBasedTest())) { - m_topPadding = other.m_topPadding; - m_rightPadding = other.m_rightPadding; - m_bottomPadding = other.m_bottomPadding; - m_leftPadding = other.m_leftPadding; - } else - m_topPadding = m_rightPadding = m_bottomPadding = m_leftPadding = 0; + // Only copy the NodeSet in case of rect hit test. m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); - m_shadowContentFilterPolicy = other.shadowContentFilterPolicy(); + m_shadowContentFilterPolicy = other.shadowContentFilterPolicy(); m_region = other.m_region; @@ -198,7 +238,7 @@ bool HitTestResult::isSelected() const if (!frame) return false; - return frame->selection()->contains(m_point); + return frame->selection()->contains(point()); } String HitTestResult::spellingToolTip(TextDirection& dir) const @@ -209,7 +249,7 @@ String HitTestResult::spellingToolTip(TextDirection& dir) const if (!m_innerNonSharedNode) return String(); - DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(m_point, DocumentMarker::Grammar); + DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(point(), DocumentMarker::Grammar); if (!marker) return String(); @@ -225,7 +265,7 @@ String HitTestResult::replacedString() const if (!m_innerNonSharedNode) return String(); - DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(m_point, DocumentMarker::Replacement); + DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(point(), DocumentMarker::Replacement); if (!marker) return String(); @@ -652,18 +692,6 @@ void HitTestResult::append(const HitTestResult& other) } } -IntRect HitTestResult::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) -{ - IntPoint actualPoint(roundedIntPoint(point)); - actualPoint -= IntSize(leftPadding, topPadding); - - IntSize actualPadding(leftPadding + rightPadding, topPadding + bottomPadding); - // As IntRect is left inclusive and right exclusive (seeing IntRect::contains(x, y)), adding "1". - actualPadding += IntSize(1, 1); - - return IntRect(actualPoint, actualPadding); -} - const HitTestResult::NodeSet& HitTestResult::rectBasedTestResult() const { if (!m_rectBasedTestResult) diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h index e919472b2..a18fdb5a2 100644 --- a/Source/WebCore/rendering/HitTestResult.h +++ b/Source/WebCore/rendering/HitTestResult.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -22,6 +23,7 @@ #define HitTestResult_h #include "FloatRect.h" +#include "HitTestRequest.h" #include "LayoutTypes.h" #include "TextDirection.h" #include <wtf/Forward.h> @@ -44,7 +46,42 @@ class Scrollbar; enum ShadowContentFilterPolicy { DoNotAllowShadowContent, AllowShadowContent }; -class HitTestResult { +class HitTestPoint { +public: + + HitTestPoint(); + HitTestPoint(const LayoutPoint&); + // Pass non-negative padding values to perform a rect-based hit test. + HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + HitTestPoint(const HitTestPoint&); + ~HitTestPoint(); + HitTestPoint& operator=(const HitTestPoint&); + + LayoutPoint point() const { return m_point; } + IntPoint roundedPoint() const { return roundedIntPoint(m_point); } + + void setPoint(const LayoutPoint& p) { m_point = p; } + + // Rect-based hit test related methods. + bool isRectBasedTest() const { return m_isRectBased; } + IntRect rectForPoint(const LayoutPoint&) const; + static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + int topPadding() const { return m_topPadding; } + int rightPadding() const { return m_rightPadding; } + int bottomPadding() const { return m_bottomPadding; } + int leftPadding() const { return m_leftPadding; } + +private: + LayoutPoint m_point; + + int m_topPadding; + int m_rightPadding; + int m_bottomPadding; + int m_leftPadding; + bool m_isRectBased; +}; + +class HitTestResult : public HitTestPoint { public: typedef ListHashSet<RefPtr<Node> > NodeSet; @@ -52,14 +89,13 @@ public: HitTestResult(const LayoutPoint&); // Pass non-negative padding values to perform a rect-based hit test. HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy); + HitTestResult(const HitTestPoint&, ShadowContentFilterPolicy); HitTestResult(const HitTestResult&); ~HitTestResult(); HitTestResult& operator=(const HitTestResult&); Node* innerNode() const { return m_innerNode.get(); } Node* innerNonSharedNode() const { return m_innerNonSharedNode.get(); } - LayoutPoint point() const { return m_point; } - IntPoint roundedPoint() const { return roundedIntPoint(m_point); } LayoutPoint localPoint() const { return m_localPoint; } Element* URLElement() const { return m_innerURLElement.get(); } Scrollbar* scrollbar() const { return m_scrollbar.get(); } @@ -70,11 +106,11 @@ public: void setToNonShadowAncestor(); + const HitTestPoint& hitTestPoint() const { return *this; } ShadowContentFilterPolicy shadowContentFilterPolicy() const { return m_shadowContentFilterPolicy; } void setInnerNode(Node*); void setInnerNonSharedNode(Node*); - void setPoint(const LayoutPoint& p) { m_point = p; } void setLocalPoint(const LayoutPoint& p) { m_localPoint = p; } void setURLElement(Element*); void setScrollbar(Scrollbar*); @@ -110,15 +146,6 @@ public: bool mediaMuted() const; void toggleMediaMuteState() const; - // Rect-based hit test related methods. - bool isRectBasedTest() const { return m_isRectBased; } - IntRect rectForPoint(const LayoutPoint&) const; - static IntRect rectForPoint(const LayoutPoint&, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); - int topPadding() const { return m_topPadding; } - int rightPadding() const { return m_rightPadding; } - int bottomPadding() const { return m_bottomPadding; } - int leftPadding() const { return m_leftPadding; } - // Returns true if it is rect-based hit test and needs to continue until the rect is fully // enclosed by the boundaries of a node. bool addNodeToRectBasedTestResult(Node*, const LayoutPoint& pointInContainer, const IntRect& = IntRect()); @@ -139,19 +166,14 @@ private: RefPtr<Node> m_innerNode; RefPtr<Node> m_innerNonSharedNode; - LayoutPoint m_point; LayoutPoint m_localPoint; // A point in the local coordinate space of m_innerNonSharedNode's renderer. Allows us to efficiently // determine where inside the renderer we hit on subsequent operations. RefPtr<Element> m_innerURLElement; RefPtr<Scrollbar> m_scrollbar; bool m_isOverWidget; // Returns true if we are over a widget (and not in the border/padding area of a RenderWidget for example). - bool m_isRectBased; - int m_topPadding; - int m_rightPadding; - int m_bottomPadding; - int m_leftPadding; + ShadowContentFilterPolicy m_shadowContentFilterPolicy; - + RenderRegion* m_region; // The region we're inside. mutable OwnPtr<NodeSet> m_rectBasedTestResult; @@ -162,7 +184,7 @@ private: // y = p.y() - topPadding // width = leftPadding + rightPadding + 1 // height = topPadding + bottomPadding + 1 -inline IntRect HitTestResult::rectForPoint(const LayoutPoint& point) const +inline IntRect HitTestPoint::rectForPoint(const LayoutPoint& point) const { return rectForPoint(point, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding); } diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index cbd685d69..58c97dd69 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -517,8 +517,8 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& if (isRootInlineBox()) { // Examine our root box. - LayoutUnit ascent = 0; - LayoutUnit descent = 0; + int ascent = 0; + int descent = 0; rootBox->ascentAndDescentForBox(rootBox, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); if (strictMode || hasTextChildren() || (!checkChildren && hasTextDescendants())) { if (maxAscent < ascent || !setMaxAscent) { @@ -549,8 +549,8 @@ void InlineFlowBox::computeLogicalBoxHeights(RootInlineBox* rootBox, LayoutUnit& // 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)); - LayoutUnit ascent = 0; - LayoutUnit descent = 0; + int ascent = 0; + int descent = 0; rootBox->ascentAndDescentForBox(curr, textBoxDataMap, ascent, descent, affectsAscent, affectsDescent); LayoutUnit boxHeight = ascent + descent; diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 9550edb59..aafecbf6e 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -807,6 +807,22 @@ void InlineTextBox::selectionStartEnd(int& sPos, int& ePos) ePos = min(endPos - m_start, (int)m_len); } +void alignSelectionRectToDevicePixels(LayoutRect& rect) +{ + LayoutUnit maxX = floorToInt(rect.maxX()); + rect.setX(floorToInt(rect.x())); + rect.setWidth(maxX - rect.x()); +} + +#if !ENABLE(SUBPIXEL_LAYOUT) +void alignSelectionRectToDevicePixels(FloatRect& rect) +{ + float maxX = floorf(rect.maxX()); + rect.setX(floorf(rect.x())); + rect.setWidth(roundf(maxX - rect.x())); +} +#endif + void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& boxOrigin, RenderStyle* style, const Font& font, Color textColor) { if (context->paintingDisabled()) @@ -844,15 +860,18 @@ void InlineTextBox::paintSelection(GraphicsContext* context, const FloatPoint& b LayoutUnit selectionBottom = root()->selectionBottom(); LayoutUnit selectionTop = root()->selectionTopAdjustedForPrecedingBlock(); - int deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop; - int selHeight = max<LayoutUnit>(0, selectionBottom - selectionTop); + LayoutUnit deltaY = renderer()->style()->isFlippedLinesWritingMode() ? selectionBottom - logicalBottom() : logicalTop() - selectionTop; + LayoutUnit selHeight = max<LayoutUnit>(0, selectionBottom - selectionTop); +#if ENABLE(SUBPIXEL_LAYOUT) + LayoutPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); + LayoutRect clipRect(localOrigin, LayoutSize(m_logicalWidth, selHeight)); + alignSelectionRectToDevicePixels(clipRect); +#else FloatPoint localOrigin(boxOrigin.x(), boxOrigin.y() - deltaY); - FloatRect clipRect(localOrigin, FloatSize(m_logicalWidth, selHeight)); - float maxX = floorf(clipRect.maxX()); - clipRect.setX(floorf(clipRect.x())); - clipRect.setWidth(maxX - clipRect.x()); + alignSelectionRectToDevicePixels(clipRect); +#endif context->clip(clipRect); context->drawHighlightForText(font, textRun, localOrigin, selHeight, c, style->colorSpace(), sPos, ePos); diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index 1b7a3ad03..a3c08987c 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -213,6 +213,11 @@ inline RenderText* InlineTextBox::textRenderer() const return toRenderText(renderer()); } +void alignSelectionRectToDevicePixels(LayoutRect&); +#if !ENABLE(SUBPIXEL_LAYOUT) +void alignSelectionRectToDevicePixels(FloatRect&); +#endif + } // namespace WebCore #endif // InlineTextBox_h diff --git a/Source/WebCore/rendering/LayoutState.cpp b/Source/WebCore/rendering/LayoutState.cpp index 1fbfc0cdd..5f780dca0 100644 --- a/Source/WebCore/rendering/LayoutState.cpp +++ b/Source/WebCore/rendering/LayoutState.cpp @@ -196,16 +196,18 @@ void LayoutState::clearPaginationInformation() m_columnInfo = m_next->m_columnInfo; } -LayoutUnit LayoutState::pageLogicalOffset(LayoutUnit childLogicalOffset) const +LayoutUnit LayoutState::pageLogicalOffset(RenderBox* child, LayoutUnit childLogicalOffset) const { - return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height(); + if (child->isHorizontalWritingMode()) + return m_layoutOffset.height() + childLogicalOffset - m_pageOffset.height(); + return m_layoutOffset.width() + childLogicalOffset - m_pageOffset.width(); } -void LayoutState::addForcedColumnBreak(LayoutUnit childLogicalOffset) +void LayoutState::addForcedColumnBreak(RenderBox* child, LayoutUnit childLogicalOffset) { if (!m_columnInfo || m_columnInfo->columnHeight()) return; - m_columnInfo->addForcedBreak(pageLogicalOffset(childLogicalOffset)); + m_columnInfo->addForcedBreak(pageLogicalOffset(child, childLogicalOffset)); } void LayoutState::propagateLineGridInfo(RenderBox* renderer) diff --git a/Source/WebCore/rendering/LayoutState.h b/Source/WebCore/rendering/LayoutState.h index e1df24b4e..81d61e9cd 100644 --- a/Source/WebCore/rendering/LayoutState.h +++ b/Source/WebCore/rendering/LayoutState.h @@ -74,9 +74,9 @@ public: // The page logical offset is the object's offset from the top of the page in the page progression // direction (so an x-offset in vertical text and a y-offset for horizontal text). - LayoutUnit pageLogicalOffset(LayoutUnit childLogicalOffset) const; + LayoutUnit pageLogicalOffset(RenderBox*, LayoutUnit childLogicalOffset) const; - void addForcedColumnBreak(LayoutUnit childLogicalOffset); + void addForcedColumnBreak(RenderBox*, LayoutUnit childLogicalOffset); LayoutUnit pageLogicalHeight() const { return m_pageLogicalHeight; } bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; } diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 4c2899e0f..c3017a425 100755 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -932,6 +932,14 @@ void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, } RenderBox::addChild(newChild, beforeChild); + + // Handle positioning of run-ins. + if (newChild->isRunIn()) + moveRunInUnderSiblingBlockIfNeeded(newChild); + else if (RenderObject* prevSibling = newChild->previousSibling()) { + if (prevSibling->isRunIn()) + moveRunInUnderSiblingBlockIfNeeded(prevSibling); + } if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); @@ -1038,6 +1046,13 @@ void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) if (!child) return; + // Since we are going to have block children, we have to move + // back the run-in to its original place. + if (child->isRunIn()) { + moveRunInToOriginalPosition(child); + child = firstChild(); + } + deleteLineBoxTree(); while (child) { @@ -1503,7 +1518,7 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh statePusher.pop(); if (renderView->layoutState()->m_pageLogicalHeight) - setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(logicalTop())); + setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop())); updateLayerTransform(); @@ -1724,8 +1739,7 @@ bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginI { // Handle in the given order return handlePositionedChild(child, marginInfo) - || handleFloatingChild(child, marginInfo) - || handleRunInChild(child); + || handleFloatingChild(child, marginInfo); } @@ -1749,77 +1763,115 @@ bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& margin return false; } -bool RenderBlock::handleRunInChild(RenderBox* child) +static void destroyRunIn(RenderBoxModelObject* runIn) { - // See if we have a run-in element with inline children. If the - // children aren't inline, then just treat the run-in as a normal - // block. - if (!child->isRunIn() || !child->childrenInline()) - return false; + ASSERT(runIn->isRunIn()); + ASSERT(!runIn->firstChild()); + + // If it is a block run-in, delete its line box tree as well. This is needed as our + // children got moved and our line box tree is no longer valid. + if (runIn->isRenderBlock()) + toRenderBlock(runIn)->deleteLineBoxTree(); + runIn->destroy(); +} + +RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn) +{ + ASSERT(runIn->isRunIn()); + + // First we destroy any :before/:after content. It will be regenerated by the new run-in. + // Exception is if the run-in itself is generated. + if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) { + RenderObject* generatedContent; + if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer())) + generatedContent->destroy(); + if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer())) + generatedContent->destroy(); + } + + bool newRunInShouldBeBlock = !runIn->isRenderBlock(); + Node* runInNode = runIn->node(); + RenderBoxModelObject* newRunIn = 0; + if (newRunInShouldBeBlock) + newRunIn = new (renderArena()) RenderBlock(runInNode ? runInNode : document()); + else + newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); + newRunIn->setStyle(runIn->style()); + + runIn->moveAllChildrenTo(newRunIn, true); + + // If the run-in had an element, we need to set the new renderer. + if (runInNode) + runInNode->setRenderer(newRunIn); + + return newRunIn; +} + +void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn) +{ + ASSERT(runIn->isRunIn()); + + // See if we have inline children. If the children aren't inline, + // then just treat the run-in as a normal block. + if (!runIn->childrenInline()) + return; // FIXME: We don't handle non-block elements with run-in for now. - if (!child->isRenderBlock()) - return false; + if (!runIn->isRenderBlock()) + return; - // Run-in child shouldn't intrude into the sibling block if it is part of a + // We shouldn't run in into the sibling block if we are part of a // continuation chain. In that case, treat it as a normal block. - if (child->isElementContinuation() || child->virtualContinuation()) - return false; + if (runIn->isElementContinuation() || runIn->virtualContinuation()) + return; // Check if this node is allowed to run-in. E.g. <select> expects its renderer to // be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in. - Node* runInNode = child->node(); + Node* runInNode = runIn->node(); if (runInNode && runInNode->hasTagName(selectTag)) - return false; + return; - RenderBlock* blockRunIn = toRenderBlock(child); - RenderObject* curr = blockRunIn->nextSibling(); - if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned()) - return false; + RenderObject* curr = runIn->nextSibling(); + if (!curr || !curr->isRenderBlock() || !curr->childrenInline()) + return; - RenderBlock* currBlock = toRenderBlock(curr); + // Per CSS3, "A run-in cannot run in to a block that already starts with a + // run-in or that itself is a run-in". + if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn())) + return; - // First we destroy any :before/:after content. It will be regenerated by the new inline. - // Exception is if the run-in itself is generated. - if (child->style()->styleType() != BEFORE && child->style()->styleType() != AFTER) { - RenderObject* generatedContent; - if (child->getCachedPseudoStyle(BEFORE) && (generatedContent = child->beforePseudoElementRenderer())) - generatedContent->destroy(); - if (child->getCachedPseudoStyle(AFTER) && (generatedContent = child->afterPseudoElementRenderer())) - generatedContent->destroy(); - } + if (curr->isAnonymous() || curr->isFloatingOrPositioned()) + return; - // Remove the old child. - children()->removeChildNode(this, blockRunIn); + RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); + RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); + destroyRunIn(oldRunIn); - // Create an inline. - RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); - inlineRunIn->setStyle(blockRunIn->style()); + // Now insert the new child under |curr| block. Use addChild instead of insertChildNode + // since it handles correct placement of the children, especially where we cannot insert + // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. + curr->addChild(newRunIn, curr->firstChild()); +} - // Move the nodes from the old child to the new child - for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) { - RenderObject* nextSibling = runInChild->nextSibling(); - blockRunIn->children()->removeChildNode(blockRunIn, runInChild); - inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. - runInChild = nextSibling; - } +void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn) +{ + ASSERT(runIn->isRunIn()); - // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert - // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. - currBlock->addChild(inlineRunIn, currBlock->firstChild()); - - // If the run-in had an element, we need to set the new renderer. - if (runInNode) - runInNode->setRenderer(inlineRunIn); + // If we don't have a parent, there is nothing to move. This might + // happen if |this| got detached from parent after |runIn| run into |this|. + if (!parent()) + return; + + // An intruded run-in needs to be an inline. + if (!runIn->isRenderInline()) + return; - // Destroy the block run-in, which includes deleting its line box tree. - blockRunIn->deleteLineBoxTree(); - blockRunIn->destroy(); + RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); + RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); + destroyRunIn(oldRunIn); - // The block acts like an inline, so just null out its - // position. - - return true; + // Add the run-in block as our previous sibling. + parent()->addChild(newRunIn, this); } LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) @@ -2478,7 +2530,7 @@ void RenderBlock::markForPaginationRelayoutIfNeeded() if (needsLayout()) return; - if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset())) + if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset())) setChildNeedsLayout(true, MarkOnlyThis); } @@ -2621,6 +2673,7 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p if (!colCount) return; LayoutUnit currLogicalTopOffset = 0; + LayoutUnit colGap = columnGap(); for (unsigned i = 0; i < colCount; i++) { // For each rect, we clip to the rect, and then we adjust our coords. LayoutRect colRect = columnRectAt(colInfo, i); @@ -2639,10 +2692,19 @@ void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& p if (!info.rect.isEmpty()) { GraphicsContextStateSaver stateSaver(*context); + LayoutRect clipRect(colRect); + if (i < colCount - 1) { + if (isHorizontalWritingMode()) + clipRect.expand(colGap / 2, 0); + else + clipRect.expand(0, colGap / 2); + } // Each strip pushes a clip, since column boxes are specified as being // like overflow:hidden. - context->clip(colRect); + // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element + // are clipped according to the 'overflow' property. + context->clip(clipRect); // Adjust our x and y when painting. LayoutPoint adjustedPaintOffset = paintOffset + offset; @@ -3295,6 +3357,7 @@ LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const La return LayoutRect(); LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); + alignSelectionRectToDevicePixels(gapRect); if (paintInfo) paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); return gapRect; @@ -3311,6 +3374,7 @@ LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const L return LayoutRect(); LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); + alignSelectionRectToDevicePixels(gapRect); if (paintInfo) paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); return gapRect; @@ -4168,9 +4232,8 @@ LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildP if (logicalBottom > logicalHeight()) { // If the object is not in the list, we add it now. if (!containsFloat(r->m_renderer)) { - LayoutUnit leftOffset = isHorizontalWritingMode() ? -childLogicalLeft : -childLogicalTop; - LayoutUnit topOffset = isHorizontalWritingMode() ? -childLogicalTop : -childLogicalLeft; - FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); + LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft); + FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size())); floatingObj->m_renderer = r->m_renderer; // The nearest enclosing layer always paints the float (so that zindex and stacking @@ -4237,10 +4300,8 @@ void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOf FloatingObject* r = *prevIt; if (logicalBottomForFloat(r) > logicalTopOffset) { if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) { - LayoutUnit leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; - LayoutUnit topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; - - FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); + LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, logicalTopOffset) : LayoutSize(logicalTopOffset, logicalLeftOffset); + FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size())); // Applying the child's margin makes no sense in the case where the child was passed in. // since this margin was added already through the modification of the |logicalLeftOffset| variable @@ -4931,7 +4992,7 @@ bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, LayoutUnit p // maximum page break distance. if (!pageLogicalHeight) { LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(), - view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset()); + view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset()); columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); } } else if (contentLogicalHeight() > boundedMultiply(pageLogicalHeight, desiredColumnCount)) { @@ -5167,7 +5228,8 @@ void RenderBlock::computePreferredLogicalWidths() updateFirstLetter(); RenderStyle* styleToUse = style(); - if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0 && style()->marqueeBehavior() != MALTERNATE) + if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0 + && style()->marqueeBehavior() != MALTERNATE && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue())) m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(styleToUse->logicalWidth().value()); else { m_minPreferredLogicalWidth = 0; @@ -5701,7 +5763,7 @@ bool RenderBlock::hasLineIfEmpty() const if (!node()) return false; - if (node()->rendererIsEditable() && node()->rootEditableElement() == node()) + if (node()->isRootEditableElement()) return true; if (node()->isShadowRoot() && (node()->shadowHost()->hasTagName(inputTag))) @@ -5890,58 +5952,6 @@ static inline bool shouldSkipForFirstLetter(UChar c) return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c); } -RenderObject* RenderBlock::findLastObjectWithFirstLetterText(RenderObject* child, RenderObject* &firstLetterBlock) -{ - while (child) { - RenderObject* nextChild = child->nextSibling(); - // Style and skip over any objects such as quotes or punctuation - child = findLastObjectAfterFirstLetterPunctuation(child, firstLetterBlock); - if (child) - break; - child = nextChild; - } - return child; -} - -RenderObject* RenderBlock::findLastObjectAfterFirstLetterPunctuation(RenderObject* child, RenderObject* &firstLetterBlock) -{ - if (child->isText()) { - // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter - // "The first letter must occur on the first formatted line." - if (child->isBR()) - return child; - - // If child is a single punctuation mark or a Render Quote then style it as first-letter now and keep looking for further text, - bool textQuote = toRenderText(child)->textLength() == 1 && isPunctuationForFirstLetter(toRenderText(child)->characters()[0]); - if (child->isQuote() || textQuote) - addFirstLetter(child, firstLetterBlock); - else if (!toRenderText(child)->isAllCollapsibleWhitespace()) - return child; - return 0; - } - - if (child->isListMarker()) - return 0; - - if (child->isFloatingOrPositioned()) { - // Floats and positioned objects do not inherit their style from parents so if it is styled - // inspect its children for text, otherwise move on to its sibling. - if (child->style()->styleType() == FIRST_LETTER) - return findLastObjectWithFirstLetterText(child->firstChild(), firstLetterBlock); - return 0; - } - - if (child->isReplaced() || child->isRenderButton() || child->isMenuList()) - return child; - - if (child->style()->hasPseudoStyle(FIRST_LETTER) && child->canHaveChildren()) { - // We found a lower-level node with first-letter, which supersedes the higher-level style. - firstLetterBlock = child; - return findLastObjectWithFirstLetterText(child->firstChild(), firstLetterBlock); - } - return findLastObjectWithFirstLetterText(child->firstChild(), firstLetterBlock); -} - static inline RenderObject* findFirstLetterBlock(RenderBlock* start) { RenderObject* firstLetterBlock = start; @@ -6091,36 +6101,47 @@ void RenderBlock::updateFirstLetter() if (!firstLetterBlock) return; - // Check each sibling and drill into its inlines until we find a text node that is not all whitespace - // or is a line break. - RenderObject* firstLetterObject = firstLetterBlock->firstChild(); - - firstLetterObject = findLastObjectWithFirstLetterText(firstLetterObject, firstLetterBlock); + // Drill into inlines looking for our first text child. + RenderObject* currChild = firstLetterBlock->firstChild(); + while (currChild) { + if (currChild->isText()) + break; + if (currChild->isListMarker()) + currChild = currChild->nextSibling(); + else if (currChild->isFloatingOrPositioned()) { + if (currChild->style()->styleType() == FIRST_LETTER) { + currChild = currChild->firstChild(); + break; + } + currChild = currChild->nextSibling(); + } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) + break; + else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && canHaveGeneratedChildren(currChild)) { + // We found a lower-level node with first-letter, which supersedes the higher-level style + firstLetterBlock = currChild; + currChild = currChild->firstChild(); + } else + currChild = currChild->firstChild(); + } - if (!firstLetterObject) + if (!currChild) return; - - addFirstLetter(firstLetterObject, firstLetterBlock); -} - -void RenderBlock::addFirstLetter(RenderObject* firstLetterObject, RenderObject* &firstLetterBlock) -{ // If the child already has style, then it has already been created, so we just want // to update it. - if (firstLetterObject->parent()->style()->styleType() == FIRST_LETTER) { - updateFirstLetterStyle(firstLetterBlock, firstLetterObject); + if (currChild->parent()->style()->styleType() == FIRST_LETTER) { + updateFirstLetterStyle(firstLetterBlock, currChild); return; } - if (!firstLetterObject->isText() || firstLetterObject->isBR()) + if (!currChild->isText() || currChild->isBR()) return; // Our layout state is not valid for the repaints we are going to trigger by // adding and removing children of firstLetterContainer. LayoutStateDisabler layoutStateDisabler(view()); - createFirstLetterRenderer(firstLetterBlock, firstLetterObject); + createFirstLetterRenderer(firstLetterBlock, currChild); } // Helper methods for obtaining the last line, computing line counts and heights for line counts @@ -6635,7 +6656,7 @@ LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOff || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS); if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(logicalOffset); + view()->layoutState()->addForcedColumnBreak(child, logicalOffset); return nextPageLogicalTop(logicalOffset, IncludePageBoundary); } return logicalOffset; @@ -6652,7 +6673,7 @@ LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffs if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content. if (checkColumnBreaks) - view()->layoutState()->addForcedColumnBreak(logicalOffset); + view()->layoutState()->addForcedColumnBreak(child, logicalOffset); return nextPageLogicalTop(logicalOffset, IncludePageBoundary); } return logicalOffset; @@ -6776,7 +6797,9 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout lineBox->setPaginationStrut(0); LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight(); - if (!pageLogicalHeight || (hasUniformPageLogicalHeight && lineHeight > pageLogicalHeight) + // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are + // still going to add a strut, so that the visible overflow fits on a single page. + if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) || !hasNextPage(logicalOffset)) return; LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); @@ -6784,6 +6807,10 @@ void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, Layout // If we have a non-uniform page height, then we have to shift further possibly. if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight)) return; + if (lineHeight > pageLogicalHeight) { + // Split the top margin in order to avoid splitting the visible part of the line. + remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max(ZERO_LAYOUT_UNIT, logicalVisualOverflow.y() - lineBox->lineTopWithLeading())); + } LayoutUnit totalLogicalHeight = lineHeight + max(ZERO_LAYOUT_UNIT, logicalOffset); LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight); if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isPositioned() && !isTableCell()) @@ -7197,8 +7224,8 @@ inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::T inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject) { if (m_horizontalWritingMode) - return RenderBlock::FloatingObjectInterval(floatingObject->pixelSnappedY(), floatingObject->pixelSnappedMaxY(), floatingObject); - return RenderBlock::FloatingObjectInterval(floatingObject->pixelSnappedX(), floatingObject->pixelSnappedMaxX(), floatingObject); + return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject); + return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject); } void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject) @@ -7342,7 +7369,7 @@ String ValueToString<int>::string(const int value) String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject) { - return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->pixelSnappedX(), floatingObject->pixelSnappedY(), floatingObject->pixelSnappedMaxX(), floatingObject->pixelSnappedMaxY()); + return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY()); } #endif diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index a3cc33ea6..df4a6a2f0 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -505,9 +505,6 @@ private: void createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild); void updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer); - RenderObject* findLastObjectWithFirstLetterText(RenderObject* child, RenderObject* &firstLetterBlock); - RenderObject* findLastObjectAfterFirstLetterPunctuation(RenderObject* child, RenderObject* &firstLetterBlock); - void addFirstLetter(RenderObject* firstLetterObject, RenderObject* &firstLetterBlock); struct FloatWithRect { FloatWithRect(RenderBox* f) @@ -574,13 +571,6 @@ private: inline LayoutUnit width() const { return m_frameRect.width(); } inline LayoutUnit height() const { return m_frameRect.height(); } - inline int pixelSnappedX() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedX(); } - inline int pixelSnappedMaxX() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedMaxX(); } - inline int pixelSnappedY() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedY(); } - inline int pixelSnappedMaxY() const { ASSERT(isPlaced()); return m_frameRect.pixelSnappedMaxY(); } - inline int pixelSnappedWidth() const { return m_frameRect.pixelSnappedWidth(); } - inline int pixelSnappedHeight() const { return m_frameRect.pixelSnappedHeight(); } - void setX(LayoutUnit x) { ASSERT(!isInPlacedTree()); m_frameRect.setX(x); } void setY(LayoutUnit y) { ASSERT(!isInPlacedTree()); m_frameRect.setY(y); } void setWidth(LayoutUnit width) { ASSERT(!isInPlacedTree()); m_frameRect.setWidth(width); } @@ -622,11 +612,10 @@ private: LayoutUnit logicalRightForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->maxX() : child->maxY(); } LayoutUnit logicalWidthForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->width() : child->height(); } - int pixelSnappedLogicalTopForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->pixelSnappedY() : child->pixelSnappedX(); } - int pixelSnappedLogicalBottomForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->pixelSnappedMaxY() : child->pixelSnappedMaxX(); } - int pixelSnappedLogicalLeftForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->pixelSnappedX() : child->pixelSnappedY(); } - int pixelSnappedLogicalRightForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->pixelSnappedMaxX() : child->pixelSnappedMaxY(); } - int pixelSnappedLogicalWidthForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->pixelSnappedWidth() : child->pixelSnappedHeight(); } + int pixelSnappedLogicalTopForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->frameRect().pixelSnappedY() : child->frameRect().pixelSnappedX(); } + int pixelSnappedLogicalBottomForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->frameRect().pixelSnappedMaxY() : child->frameRect().pixelSnappedMaxX(); } + int pixelSnappedLogicalLeftForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->frameRect().pixelSnappedX() : child->frameRect().pixelSnappedY(); } + int pixelSnappedLogicalRightForFloat(const FloatingObject* child) const { return isHorizontalWritingMode() ? child->frameRect().pixelSnappedMaxX() : child->frameRect().pixelSnappedMaxY(); } void setLogicalTopForFloat(FloatingObject* child, LayoutUnit logicalTop) { @@ -911,7 +900,11 @@ private: bool handleSpecialChild(RenderBox* child, const MarginInfo&); bool handleFloatingChild(RenderBox* child, const MarginInfo&); bool handlePositionedChild(RenderBox* child, const MarginInfo&); - bool handleRunInChild(RenderBox* child); + + RenderBoxModelObject* createReplacementRunIn(RenderBoxModelObject* runIn); + void moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn); + void moveRunInToOriginalPosition(RenderObject* runIn); + LayoutUnit collapseMargins(RenderBox* child, MarginInfo&); LayoutUnit clearFloatsIfNeeded(RenderBox* child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos); LayoutUnit estimateLogicalTopPosition(RenderBox* child, const MarginInfo&, LayoutUnit& estimateWithoutPagination); diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 362d31fc7..922e72fa5 100755 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -2668,7 +2668,7 @@ void RenderBlock::addOverflowFromInlineChildren() { LayoutUnit endPadding = hasOverflowClip() ? paddingEnd() : ZERO_LAYOUT_UNIT; // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. - if (hasOverflowClip() && !endPadding && node() && node()->rendererIsEditable() && node() == node()->rootEditableElement() && style()->isLeftToRightDirection()) + if (hasOverflowClip() && !endPadding && node() && node()->isRootEditableElement() && style()->isLeftToRightDirection()) endPadding = 1; for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { addLayoutOverflow(curr->paddedLayoutOverflowRect(endPadding)); diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 199deb6b2..cf6615b22 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -4019,29 +4019,6 @@ bool RenderBox::hasRelativeLogicalHeight() const || style()->logicalMaxHeight().isPercent(); } -void RenderBox::moveChildTo(RenderBox* toBox, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) -{ - ASSERT(this == child->parent()); - ASSERT(!beforeChild || toBox == beforeChild->parent()); - if (fullRemoveInsert && toBox->isRenderBlock()) { - // Takes care of adding the new child correctly if toBlock and fromBlock - // have different kind of children (block vs inline). - toBox->addChild(virtualChildren()->removeChildNode(this, child), beforeChild); - } else - toBox->virtualChildren()->insertChildNode(toBox, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); -} - -void RenderBox::moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) -{ - ASSERT(!beforeChild || toBox == beforeChild->parent()); - for (RenderObject* child = startChild; child && child != endChild; ) { - // Save our next sibling as moveChildTo will clear it. - RenderObject* nextSibling = child->nextSibling(); - moveChildTo(toBox, child, beforeChild, fullRemoveInsert); - child = nextSibling; - } -} - static void markBoxForRelayoutAfterSplit(RenderBox* box) { // FIXME: The table code should handle that automatically. If not, diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 9f00a44e3..94fc105a6 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -73,6 +73,9 @@ public: LayoutUnit logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); } LayoutUnit logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); } + int pixelSnappedLogicalHeight() const { return style()->isHorizontalWritingMode() ? pixelSnappedHeight() : pixelSnappedWidth(); } + int pixelSnappedLogicalWidth() const { return style()->isHorizontalWritingMode() ? pixelSnappedWidth() : pixelSnappedHeight(); } + void setLogicalLeft(LayoutUnit left) { if (style()->isHorizontalWritingMode()) @@ -524,30 +527,6 @@ protected: void paintRootBoxFillLayers(const PaintInfo&); - // These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode. - // Since they are typically called only to move objects around within anonymous blocks (which only have layers in - // the case of column spans), the default for fullRemoveInsert is false rather than true. - void moveChildTo(RenderBox* toBox, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert = false); - void moveChildTo(RenderBox* to, RenderObject* child, bool fullRemoveInsert = false) - { - moveChildTo(to, child, 0, fullRemoveInsert); - } - void moveAllChildrenTo(RenderBox* toBox, bool fullRemoveInsert = false) - { - moveAllChildrenTo(toBox, 0, fullRemoveInsert); - } - void moveAllChildrenTo(RenderBox* toBox, RenderObject* beforeChild, bool fullRemoveInsert = false) - { - moveChildrenTo(toBox, firstChild(), 0, beforeChild, fullRemoveInsert); - } - // Move all of the kids from |startChild| up to but excluding |endChild|. 0 can be passed as the |endChild| to denote - // that all the kids from |startChild| onwards should be moved. - void moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, bool fullRemoveInsert = false) - { - moveChildrenTo(toBox, startChild, endChild, 0, fullRemoveInsert); - } - void moveChildrenTo(RenderBox* toBox, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false); - RenderObject* splitAnonymousBoxesAroundChild(RenderObject* beforeChild); private: diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index fcca1b3d5..b23ad9980 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -3017,4 +3017,27 @@ void RenderBoxModelObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransform transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform); } +void RenderBoxModelObject::moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) +{ + ASSERT(this == child->parent()); + ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); + if (fullRemoveInsert && (toBoxModelObject->isRenderBlock() || toBoxModelObject->isRenderInline())) { + // Takes care of adding the new child correctly if toBlock and fromBlock + // have different kind of children (block vs inline). + toBoxModelObject->addChild(virtualChildren()->removeChildNode(this, child), beforeChild); + } else + toBoxModelObject->virtualChildren()->insertChildNode(toBoxModelObject, virtualChildren()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); +} + +void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) +{ + ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent()); + for (RenderObject* child = startChild; child && child != endChild; ) { + // Save our next sibling as moveChildTo will clear it. + RenderObject* nextSibling = child->nextSibling(); + moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert); + child = nextSibling; + } +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index 6c88f0fbf..d0883a5ee 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -246,6 +246,30 @@ public: RenderObject* firstLetterRemainingText() const; void setFirstLetterRemainingText(RenderObject*); + // These functions are only used internally to manipulate the render tree structure via remove/insert/appendChildNode. + // Since they are typically called only to move objects around within anonymous blocks (which only have layers in + // the case of column spans), the default for fullRemoveInsert is false rather than true. + void moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert = false); + void moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, bool fullRemoveInsert = false) + { + moveChildTo(toBoxModelObject, child, 0, fullRemoveInsert); + } + void moveAllChildrenTo(RenderBoxModelObject* toBoxModelObject, bool fullRemoveInsert = false) + { + moveAllChildrenTo(toBoxModelObject, 0, fullRemoveInsert); + } + void moveAllChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* beforeChild, bool fullRemoveInsert = false) + { + moveChildrenTo(toBoxModelObject, firstChild(), 0, beforeChild, fullRemoveInsert); + } + // Move all of the kids from |startChild| up to but excluding |endChild|. 0 can be passed as the |endChild| to denote + // that all the kids from |startChild| onwards should be moved. + void moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, bool fullRemoveInsert = false) + { + moveChildrenTo(toBoxModelObject, startChild, endChild, 0, fullRemoveInsert); + } + void moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert = false); + private: virtual bool isBoxModelObject() const { return true; } diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp index b956d3946..7fae3c40f 100644 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp @@ -301,7 +301,7 @@ void RenderDeprecatedFlexibleBox::layoutBlock(bool relayoutChildren, LayoutUnit) updateLayerTransform(); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop())); // Update our scrollbars if we're overflow:auto/scroll/hidden now that we know if // we overflow or not. diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp index 55cfcfd4d..315c16f8a 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp @@ -102,11 +102,28 @@ bool RenderEmbeddedObject::allowsAcceleratedCompositing() const } #endif +static String unavailablePluginReplacementText(RenderEmbeddedObject::PluginUnavailabilityReason pluginUnavailabilityReason) +{ + switch (pluginUnavailabilityReason) { + case RenderEmbeddedObject::PluginMissing: + return missingPluginText(); + case RenderEmbeddedObject::PluginCrashed: + return crashedPluginText(); + case RenderEmbeddedObject::InsecurePluginVersion: + return insecurePluginVersionText(); + } + + ASSERT_NOT_REACHED(); + return String(); +} + void RenderEmbeddedObject::setPluginUnavailabilityReason(PluginUnavailabilityReason pluginUnavailabilityReason) { ASSERT(!m_showsUnavailablePluginIndicator); m_showsUnavailablePluginIndicator = true; m_pluginUnavailabilityReason = pluginUnavailabilityReason; + + m_unavailablePluginReplacementText = unavailablePluginReplacementText(pluginUnavailabilityReason); } bool RenderEmbeddedObject::showsUnavailablePluginIndicator() const @@ -193,8 +210,8 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumul fontDescription.setComputedSize(fontDescription.specifiedSize()); font = Font(fontDescription, 0, 0); font.update(0); - - run = TextRun(unavailablePluginReplacementText()); + + run = TextRun(m_unavailablePluginReplacementText); textWidth = font.width(run); replacementTextRect.setSize(FloatSize(textWidth + replacementTextRoundedRectLeftRightTextMargin * 2, replacementTextRoundedRectHeight)); @@ -207,21 +224,6 @@ bool RenderEmbeddedObject::getReplacementTextGeometry(const LayoutPoint& accumul return true; } -String RenderEmbeddedObject::unavailablePluginReplacementText() const -{ - switch (m_pluginUnavailabilityReason) { - case PluginMissing: - return missingPluginText(); - case PluginCrashed: - return crashedPluginText(); - case InsecurePluginVersion: - return insecurePluginVersionText(); - } - - ASSERT_NOT_REACHED(); - return String(); -} - void RenderEmbeddedObject::layout() { ASSERT(needsLayout()); diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.h b/Source/WebCore/rendering/RenderEmbeddedObject.h index 3564ff287..1e0bffb30 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.h +++ b/Source/WebCore/rendering/RenderEmbeddedObject.h @@ -78,12 +78,12 @@ private: bool isInUnavailablePluginIndicator(MouseEvent*) const; bool isInUnavailablePluginIndicator(const LayoutPoint&) const; bool getReplacementTextGeometry(const LayoutPoint& accumulatedOffset, FloatRect& contentRect, Path&, FloatRect& replacementTextRect, Font&, TextRun&, float& textWidth) const; - String unavailablePluginReplacementText() const; bool m_hasFallbackContent; // FIXME: This belongs on HTMLObjectElement. bool m_showsUnavailablePluginIndicator; PluginUnavailabilityReason m_pluginUnavailabilityReason; + String m_unavailablePluginReplacementText; bool m_unavailablePluginIndicatorIsPressed; bool m_mouseDownWasInUnavailablePluginIndicator; }; diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp index 393964ade..2e04a6bf9 100644 --- a/Source/WebCore/rendering/RenderFlowThread.cpp +++ b/Source/WebCore/rendering/RenderFlowThread.cpp @@ -292,16 +292,16 @@ void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* regio // RenderFlowThread should start painting its content in a position that is offset // from the region rect's current position. The amount of offset is equal to the location of // region in flow coordinates. - LayoutPoint renderFlowThreadOffset; + IntPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { LayoutRect flippedRegionRect(regionRect); flipForWritingMode(flippedRegionRect); - renderFlowThreadOffset = LayoutPoint(paintOffset - flippedRegionRect.location()); + renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedRegionRect.location()); } else - renderFlowThreadOffset = LayoutPoint(paintOffset - regionRect.location()); + renderFlowThreadOffset = roundedIntPoint(paintOffset - regionRect.location()); context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y()); - info.rect.moveBy(-roundedIntPoint(renderFlowThreadOffset)); + info.rect.moveBy(-renderFlowThreadOffset); layer()->paint(context, info.rect, 0, 0, region, RenderLayer::PaintLayerTemporaryClipRects); diff --git a/Source/WebCore/rendering/RenderFrameBase.cpp b/Source/WebCore/rendering/RenderFrameBase.cpp index 046288bff..aa82870d4 100644 --- a/Source/WebCore/rendering/RenderFrameBase.cpp +++ b/Source/WebCore/rendering/RenderFrameBase.cpp @@ -38,13 +38,26 @@ RenderFrameBase::RenderFrameBase(Element* element) { } -void RenderFrameBase::layoutWithFlattening(bool fixedWidth, bool fixedHeight) +inline bool shouldExpandFrame(LayoutUnit width, LayoutUnit height, bool hasFixedWidth, bool hasFixedHeight) +{ + // If the size computed to zero never expand. + if (!width || !height) + return false; + // Really small fixed size frames can't be meant to be scrolled and are there probably by mistake. Avoid expanding. + static unsigned smallestUsefullyScrollableDimension = 8; + if (hasFixedWidth && width < LayoutUnit(smallestUsefullyScrollableDimension)) + return false; + if (hasFixedHeight && height < LayoutUnit(smallestUsefullyScrollableDimension)) + return false; + return true; +} + +void RenderFrameBase::layoutWithFlattening(bool hasFixedWidth, bool hasFixedHeight) { FrameView* childFrameView = static_cast<FrameView*>(widget()); RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0; - // Do not expand frames which has zero width or height - if (!width() || !height() || !childRoot) { + if (!childRoot || !shouldExpandFrame(width(), height(), hasFixedWidth, hasFixedHeight)) { updateWidgetPosition(); if (childFrameView) childFrameView->layout(); @@ -69,7 +82,7 @@ void RenderFrameBase::layoutWithFlattening(bool fixedWidth, bool fixedHeight) int vBorder = borderTop() + borderBottom(); // make sure minimum preferred width is enforced - if (isScrollable || !fixedWidth) { + if (isScrollable || !hasFixedWidth) { setWidth(max(width(), childRoot->minPreferredLogicalWidth() + hBorder)); // update again to pass the new width to the child frame updateWidgetPosition(); @@ -77,9 +90,9 @@ void RenderFrameBase::layoutWithFlattening(bool fixedWidth, bool fixedHeight) } // expand the frame by setting frame height = content height - if (isScrollable || !fixedHeight || childRoot->isFrameSet()) + if (isScrollable || !hasFixedHeight || childRoot->isFrameSet()) setHeight(max<LayoutUnit>(height(), childFrameView->contentsHeight() + vBorder)); - if (isScrollable || !fixedWidth || childRoot->isFrameSet()) + if (isScrollable || !hasFixedWidth || childRoot->isFrameSet()) setWidth(max<LayoutUnit>(width(), childFrameView->contentsWidth() + hBorder)); updateWidgetPosition(); diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp index ac449a240..7c89d8db8 100644 --- a/Source/WebCore/rendering/RenderFrameSet.cpp +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -667,7 +667,7 @@ bool RenderFrameSet::flattenFrameSet() const void RenderFrameSet::startResizing(GridAxis& axis, int position) { int split = hitTestSplit(axis, position); - if (split == noSplit || !axis.m_allowBorder[split] || axis.m_preventResize[split]) { + if (split == noSplit || axis.m_preventResize[split]) { axis.m_splitBeingResized = noSplit; return; } @@ -746,13 +746,13 @@ bool RenderFrameSet::isResizingColumn() const bool RenderFrameSet::canResizeRow(const IntPoint& p) const { int r = hitTestSplit(m_rows, p.y()); - return r != noSplit && m_rows.m_allowBorder[r] && !m_rows.m_preventResize[r]; + return r != noSplit && !m_rows.m_preventResize[r]; } bool RenderFrameSet::canResizeColumn(const IntPoint& p) const { int c = hitTestSplit(m_cols, p.x()); - return c != noSplit && m_cols.m_allowBorder[c] && !m_cols.m_preventResize[c]; + return c != noSplit && !m_cols.m_preventResize[c]; } int RenderFrameSet::splitPosition(const GridAxis& axis, int split) const diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index 09d4e0d31..7049f8b50 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -141,7 +141,10 @@ void RenderImage::styleDidChange(StyleDifference diff, const RenderStyle* oldSty void RenderImage::imageChanged(WrappedImagePtr newImage, const IntRect* rect) { - if (documentBeingDestroyed()) + // FIXME (86669): Instead of the RenderImage determining whether its document is in the page + // cache, the RenderImage should remove itself as a client when its document is put into the + // page cache. + if (documentBeingDestroyed() || document()->inPageCache()) return; if (hasBoxDecorations() || hasMask()) diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 6804383ed..38a874b4a 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -932,14 +932,7 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* rep if (!firstLineBoxIncludingCulling() && !continuation()) return LayoutRect(); - // Find our leftmost position. - LayoutRect boundingBox(linesVisualOverflowBoundingBox()); - LayoutUnit left = boundingBox.x(); - LayoutUnit top = boundingBox.y(); - - // Now invalidate a rectangle. - LayoutUnit ow = style() ? style()->outlineSize() : 0; - + LayoutRect repaintRect(linesVisualOverflowBoundingBox()); bool hitRepaintContainer = false; // We need to add in the relative position offsets of any inlines (including us) up to our @@ -952,45 +945,41 @@ LayoutRect RenderInline::clippedOverflowRectForRepaint(RenderBoxModelObject* rep break; } if (inlineFlow->style()->position() == RelativePosition && inlineFlow->hasLayer()) - toRenderInline(inlineFlow)->layer()->relativePositionOffset(left, top); + repaintRect.move(toRenderInline(inlineFlow)->layer()->relativePositionOffset()); } - LayoutRect r(-ow + left, -ow + top, boundingBox.width() + ow * 2, boundingBox.height() + ow * 2); + LayoutUnit outlineSize = style()->outlineSize(); + repaintRect.inflate(outlineSize); if (hitRepaintContainer || !cb) - return r; + return repaintRect; if (cb->hasColumns()) - cb->adjustRectForColumns(r); + cb->adjustRectForColumns(repaintRect); if (cb->hasOverflowClip()) { // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint // anyway if its size does change. - LayoutRect repaintRect(r); repaintRect.move(-cb->scrolledContentOffset()); // For overflow:auto/scroll/hidden. LayoutRect boxRect(LayoutPoint(), cb->cachedSizeForOverflowClip()); - r = intersection(repaintRect, boxRect); + repaintRect.intersect(boxRect); } - cb->computeRectForRepaint(repaintContainer, r); + cb->computeRectForRepaint(repaintContainer, repaintRect); - if (ow) { + if (outlineSize) { for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { - if (!curr->isText()) { - LayoutRect childRect = curr->rectWithOutlineForRepaint(repaintContainer, ow); - r.unite(childRect); - } + if (!curr->isText()) + repaintRect.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineSize)); } - if (continuation() && !continuation()->isInline() && continuation()->parent()) { - LayoutRect contRect = continuation()->rectWithOutlineForRepaint(repaintContainer, ow); - r.unite(contRect); - } + if (continuation() && !continuation()->isInline() && continuation()->parent()) + repaintRect.unite(continuation()->rectWithOutlineForRepaint(repaintContainer, outlineSize)); } - return r; + return repaintRect; } LayoutRect RenderInline::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, LayoutUnit outlineWidth) const diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 1c1103ce9..a82d9369d 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -452,11 +452,16 @@ void RenderLayer::updateLayerPositions(LayoutPoint* offsetFromRoot, UpdateLayerP *offsetFromRoot = oldOffsetFromRoot; } -LayoutRect RenderLayer::repaintRectIncludingDescendants() const +LayoutRect RenderLayer::repaintRectIncludingNonCompositingDescendants() const { LayoutRect repaintRect = m_repaintRect; - for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - repaintRect.unite(child->repaintRectIncludingDescendants()); + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) { + // Don't include repaint rects for composited child layers; they will paint themselves and have a different origin. + if (child->isComposited()) + continue; + + repaintRect.unite(child->repaintRectIncludingNonCompositingDescendants()); + } return repaintRect; } @@ -736,17 +741,19 @@ bool RenderLayer::update3DTransformedDescendantStatus() if (m_3DTransformedDescendantStatusDirty) { m_has3DTransformedDescendant = false; + updateZOrderLists(); + // Transformed or preserve-3d descendants can only be in the z-order lists, not // in the normal flow list, so we only need to check those. - if (m_posZOrderList) { - for (unsigned i = 0; i < m_posZOrderList->size(); ++i) - m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus(); + if (Vector<RenderLayer*>* positiveZOrderList = posZOrderList()) { + for (unsigned i = 0; i < positiveZOrderList->size(); ++i) + m_has3DTransformedDescendant |= positiveZOrderList->at(i)->update3DTransformedDescendantStatus(); } // Now check our negative z-index children. - if (m_negZOrderList) { - for (unsigned i = 0; i < m_negZOrderList->size(); ++i) - m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus(); + if (Vector<RenderLayer*>* negativeZOrderList = negZOrderList()) { + for (unsigned i = 0; i < negativeZOrderList->size(); ++i) + m_has3DTransformedDescendant |= negativeZOrderList->at(i)->update3DTransformedDescendantStatus(); } m_3DTransformedDescendantStatusDirty = false; @@ -2211,16 +2218,19 @@ PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientat void RenderLayer::destroyScrollbar(ScrollbarOrientation orientation) { RefPtr<Scrollbar>& scrollbar = orientation == HorizontalScrollbar ? m_hBar : m_vBar; - if (scrollbar) { + if (!scrollbar) + return; + + if (!scrollbar->isCustomScrollbar()) { if (orientation == HorizontalScrollbar) willRemoveHorizontalScrollbar(scrollbar.get()); else willRemoveVerticalScrollbar(scrollbar.get()); - - scrollbar->removeFromParent(); - scrollbar->disconnectFromScrollableArea(); - scrollbar = 0; } + + scrollbar->removeFromParent(); + scrollbar->disconnectFromScrollableArea(); + scrollbar = 0; } bool RenderLayer::scrollsOverflow() const @@ -2432,13 +2442,12 @@ void RenderLayer::computeScrollDimensions() m_scrollDimensionsDirty = false; - m_scrollOverflow.setWidth(overflowLeft() - box->borderLeft()); - m_scrollOverflow.setHeight(overflowTop() - box->borderTop()); - m_scrollSize.setWidth(overflowRight() - overflowLeft()); m_scrollSize.setHeight(overflowBottom() - overflowTop()); - setScrollOrigin(IntPoint(-m_scrollOverflow.width(), -m_scrollOverflow.height())); + int scrollableLeftOverflow = overflowLeft() - box->borderLeft(); + int scrollableTopOverflow = overflowTop() - box->borderTop(); + setScrollOrigin(IntPoint(-scrollableLeftOverflow, -scrollableTopOverflow)); } bool RenderLayer::hasHorizontalOverflow() const @@ -2887,7 +2896,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, // but we need to ensure that we don't cache clip rects computed with the wrong root in this case. if (context->updatingControlTints() || (paintBehavior & PaintBehaviorFlattenCompositingLayers)) paintFlags |= PaintLayerTemporaryClipRects; - else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection) && !rootLayer->containsDirtyOverlayScrollbars()) { + else if (!backing()->paintsIntoWindow() && !backing()->paintsIntoCompositedAncestor() && !shouldDoSoftwarePaint(this, paintFlags & PaintLayerPaintingReflection) && !(rootLayer->containsDirtyOverlayScrollbars() && (paintFlags & PaintLayerPaintingOverlayScrollbars))) { // If this RenderLayer should paint into its backing, that will be done via RenderLayerBacking::paintIntoLayer(). return; } @@ -3080,7 +3089,7 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co } // Now walk the sorted list of children with negative z-indices. - paintList(m_negZOrderList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintList(negZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); } if (localPaintFlags & PaintLayerPaintingCompositingForegroundPhase) { @@ -3127,7 +3136,7 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co paintList(m_normalFlowList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); // Now walk the sorted list of children with positive z-indices. - paintList(m_posZOrderList, rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); + paintList(posZOrderList(), rootLayer, context, paintDirtyRect, paintBehavior, paintingRoot, region, overlapTestRequests, localPaintFlags); } if ((localPaintFlags & PaintLayerPaintingCompositingMaskPhase) && shouldPaintContent && renderer()->hasMask() && !selectionOnly) { @@ -3546,7 +3555,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont RenderLayer* candidateLayer = 0; // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. - RenderLayer* hitLayer = hitTestList(m_posZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint, + RenderLayer* hitLayer = hitTestList(posZOrderList(), rootLayer, request, result, hitTestRect, hitTestPoint, localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); if (hitLayer) { if (!depthSortDescendants) @@ -3566,7 +3575,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. if (fgRect.intersects(hitTestArea) && isSelfPaintingLayer()) { // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); + HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) @@ -3582,7 +3591,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Now check our negative z-index children. - hitLayer = hitTestList(m_negZOrderList, rootLayer, request, result, hitTestRect, hitTestPoint, + hitLayer = hitTestList(negZOrderList(), rootLayer, request, result, hitTestRect, hitTestPoint, localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); if (hitLayer) { if (!depthSortDescendants) @@ -3595,7 +3604,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont return candidateLayer; if (bgRect.intersects(hitTestArea) && isSelfPaintingLayer()) { - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); + HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) @@ -3651,7 +3660,7 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r for (int i = list->size() - 1; i >= 0; --i) { RenderLayer* childLayer = list->at(i); RenderLayer* hitLayer = 0; - HitTestResult tempResult(result.point(), result.topPadding(), result.rightPadding(), result.bottomPadding(), result.leftPadding(), result.shadowContentFilterPolicy()); + HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); if (childLayer->isPaginated()) hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants); else @@ -4140,8 +4149,13 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render { if (!layer->isSelfPaintingLayer()) return IntRect(); - + LayoutRect boundingBoxRect = layer->localBoundingBox(); + if (layer->renderer()->isBox()) + layer->renderBox()->flipForWritingMode(boundingBoxRect); + else + layer->renderer()->containingBlock()->flipForWritingMode(boundingBoxRect); + if (layer->renderer()->isRoot()) { // If the root layer becomes composited (e.g. because some descendant with negative z-index is composited), // then it has to be big enough to cover the viewport in order to display the background. This is akin diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 9b34e7f66..860a37290 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -369,7 +369,6 @@ public: void updateTransform(); - void relativePositionOffset(LayoutUnit& relX, LayoutUnit& relY) const { relX += m_relativeOffset.width(); relY += m_relativeOffset.height(); } const LayoutSize& relativePositionOffset() const { return m_relativeOffset; } void clearClipRectsIncludingDescendants(); @@ -394,6 +393,8 @@ public: return m_posZOrderList; } + bool hasNegativeZOrderList() const { return negZOrderList() && negZOrderList()->size(); } + Vector<RenderLayer*>* negZOrderList() const { ASSERT(!m_zOrderListsDirty); @@ -511,7 +512,7 @@ public: // Return a cached repaint rect, computed relative to the layer renderer's containerForRepaint. LayoutRect repaintRect() const { return m_repaintRect; } - LayoutRect repaintRectIncludingDescendants() const; + LayoutRect repaintRectIncludingNonCompositingDescendants() const; enum UpdateLayerPositionsAfterScrollFlag { NoFlag = 0, @@ -635,7 +636,7 @@ private: void updateScrollbarsAfterLayout(); friend IntSize RenderBox::scrolledContentOffset() const; - IntSize scrolledContentOffset() const { return scrollOffset() + m_scrollOverflow; } + IntSize scrolledContentOffset() const { return m_scrollOffset; } // The normal operator new is disallowed on all render objects. void* operator new(size_t) throw(); @@ -883,11 +884,9 @@ protected: // The layer's width/height IntSize m_layerSize; - // Our scroll offsets if the view is scrolled. + // This is the (scroll) offset from scrollOrigin(). IntSize m_scrollOffset; - IntSize m_scrollOverflow; - // The width/height of our scrolled area. LayoutSize m_scrollSize; diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 524aaf30a..ee39912a9 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -54,6 +54,8 @@ #include "StyleResolver.h" #include "TiledBacking.h" +#include <wtf/CurrentTime.h> + #if ENABLE(CSS_FILTERS) #include "FilterEffectRenderer.h" #endif @@ -323,6 +325,8 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() RenderLayerCompositor* compositor = this->compositor(); RenderObject* renderer = this->renderer(); + m_owningLayer->updateZOrderLists(); + bool layerConfigChanged = false; if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) layerConfigChanged = true; @@ -1206,6 +1210,9 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); + if (m_usingTiledCacheLayer) + m_owningLayer->renderer()->frame()->view()->setLastPaintTime(currentTime()); + InspectorInstrumentation::didPaint(cookie); } else if (graphicsLayer == layerForHorizontalScrollbar()) { paintScrollbar(m_owningLayer->horizontalScrollbar(), context, clip); diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index fbed9ae9a..06c62c342 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -576,7 +576,7 @@ IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* laye { if (!canBeComposited(layer)) return IntRect(); - return pixelSnappedIntRect(RenderLayer::calculateLayerBounds(layer, ancestorLayer)); + return RenderLayer::calculateLayerBounds(layer, ancestorLayer); } void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) @@ -1748,7 +1748,7 @@ bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* // object. bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const { - return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0); + return layer->hasNegativeZOrderList(); } bool RenderLayerCompositor::requiresScrollLayer(RootLayerAttachment attachment) const @@ -1982,6 +1982,9 @@ void RenderLayerCompositor::updateOverflowControlsLayers() #ifndef NDEBUG m_layerForHorizontalScrollbar->setName("horizontal scrollbar"); #endif + #if PLATFORM(MAC) && USE(CA) + m_layerForHorizontalScrollbar->setAcceleratesDrawing(acceleratedDrawingEnabled()); + #endif m_overflowControlsHostLayer->addChild(m_layerForHorizontalScrollbar.get()); if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) @@ -2001,6 +2004,9 @@ void RenderLayerCompositor::updateOverflowControlsLayers() #ifndef NDEBUG m_layerForVerticalScrollbar->setName("vertical scrollbar"); #endif + #if PLATFORM(MAC) && USE(CA) + m_layerForVerticalScrollbar->setAcceleratesDrawing(acceleratedDrawingEnabled()); + #endif m_overflowControlsHostLayer->addChild(m_layerForVerticalScrollbar.get()); if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) @@ -2020,6 +2026,9 @@ void RenderLayerCompositor::updateOverflowControlsLayers() #ifndef NDEBUG m_layerForScrollCorner->setName("scroll corner"); #endif + #if PLATFORM(MAC) && USE(CA) + m_layerForScrollCorner->setAcceleratesDrawing(acceleratedDrawingEnabled()); + #endif m_overflowControlsHostLayer->addChild(m_layerForScrollCorner.get()); } } else if (m_layerForScrollCorner) { diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 13f62f431..8a3094443 100755 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -56,6 +56,7 @@ #include "RenderRegion.h" #include "RenderRuby.h" #include "RenderRubyText.h" +#include "RenderScrollbarPart.h" #include "RenderTableCaption.h" #include "RenderTableCell.h" #include "RenderTableCol.h" @@ -189,8 +190,8 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) case BOX: case INLINE_BOX: return new (arena) RenderDeprecatedFlexibleBox(node); - case FLEXBOX: - case INLINE_FLEXBOX: + case FLEX: + case INLINE_FLEX: return new (arena) RenderFlexibleBox(node); } @@ -698,6 +699,8 @@ void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout() RenderBlock* RenderObject::containingBlock() const { RenderObject* o = parent(); + if (!o && isRenderScrollbarPart()) + o = toRenderScrollbarPart(this)->rendererOwningScrollbar(); if (!isText() && m_style->position() == FixedPosition) { while (o && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) o = o->parent(); diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 6af6e9a2f..9269df1a9 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -355,6 +355,7 @@ public: virtual bool isRenderFlowThread() const { return false; } virtual bool isRenderNamedFlowThread() const { return false; } + virtual bool isRenderScrollbarPart() const { return false; } bool canHaveRegionStyle() const { return isRenderBlock() && !isAnonymous() && !isRenderFlowThread(); } bool isRoot() const { return document()->documentElement() == m_node; } @@ -840,7 +841,7 @@ public: virtual bool isFlexingChildren() const { return false; } virtual bool isStretchingChildren() const { return false; } - // Virtual function helper for the new FlexibleBox Layout (display: -webkit-flexbox). + // Virtual function helper for the new FlexibleBox Layout (display: -webkit-flex). virtual bool isFlexibleBox() const { return false; } bool isFlexibleBoxIncludingDeprecated() const diff --git a/Source/WebCore/rendering/RenderQuote.cpp b/Source/WebCore/rendering/RenderQuote.cpp index 45e5991e7..c4dd0c9d8 100644 --- a/Source/WebCore/rendering/RenderQuote.cpp +++ b/Source/WebCore/rendering/RenderQuote.cpp @@ -250,7 +250,7 @@ PassRefPtr<StringImpl> RenderQuote::originalText() const switch (m_type) { case NO_OPEN_QUOTE: case NO_CLOSE_QUOTE: - return String("").impl(); + return emptyString().impl(); case CLOSE_QUOTE: if (index) --index; diff --git a/Source/WebCore/rendering/RenderScrollbar.cpp b/Source/WebCore/rendering/RenderScrollbar.cpp index 68d4a3bee..f8e33c650 100644 --- a/Source/WebCore/rendering/RenderScrollbar.cpp +++ b/Source/WebCore/rendering/RenderScrollbar.cpp @@ -270,11 +270,9 @@ void RenderScrollbar::updateScrollbarPart(ScrollbarPart partType, bool destroy) RenderScrollbarPart* partRenderer = m_parts.get(partType); if (!partRenderer && needRenderer) { partRenderer = new (owningRenderer()->renderArena()) RenderScrollbarPart(owningRenderer()->document(), this, partType); - partRenderer->setParent(owningRenderer()); m_parts.set(partType, partRenderer); } else if (partRenderer && !needRenderer) { m_parts.remove(partType); - partRenderer->setParent(0); partRenderer->destroy(); partRenderer = 0; } diff --git a/Source/WebCore/rendering/RenderScrollbarPart.cpp b/Source/WebCore/rendering/RenderScrollbarPart.cpp index 1a45be2de..0343ea21d 100644 --- a/Source/WebCore/rendering/RenderScrollbarPart.cpp +++ b/Source/WebCore/rendering/RenderScrollbarPart.cpp @@ -184,4 +184,11 @@ void RenderScrollbarPart::paintIntoRect(GraphicsContext* graphicsContext, const paint(paintInfo, paintOffset); } +RenderObject* RenderScrollbarPart::rendererOwningScrollbar() const +{ + if (!m_scrollbar) + return 0; + return m_scrollbar->owningRenderer(); +} + } diff --git a/Source/WebCore/rendering/RenderScrollbarPart.h b/Source/WebCore/rendering/RenderScrollbarPart.h index f481f5a2c..8c7a871fc 100644 --- a/Source/WebCore/rendering/RenderScrollbarPart.h +++ b/Source/WebCore/rendering/RenderScrollbarPart.h @@ -35,8 +35,6 @@ class RenderScrollbar; class RenderScrollbarPart : public RenderBlock { public: - friend class RenderScrollbar; - RenderScrollbarPart(Node*, RenderScrollbar* = 0, ScrollbarPart = NoPart); virtual ~RenderScrollbarPart(); @@ -55,6 +53,9 @@ public: virtual LayoutUnit marginLeft() const { ASSERT(isIntegerValue(m_marginLeft)); return m_marginLeft; } virtual LayoutUnit marginRight() const { ASSERT(isIntegerValue(m_marginRight)); return m_marginRight; } + virtual bool isRenderScrollbarPart() const { return true; } + RenderObject* rendererOwningScrollbar() const; + protected: virtual void styleWillChange(StyleDifference diff, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); @@ -71,6 +72,21 @@ private: ScrollbarPart m_part; }; +inline RenderScrollbarPart* toRenderScrollbarPart(RenderObject* object) +{ + ASSERT(!object || object->isRenderScrollbarPart()); + return static_cast<RenderScrollbarPart*>(object); +} + +inline const RenderScrollbarPart* toRenderScrollbarPart(const RenderObject* object) +{ + ASSERT(!object || object->isRenderScrollbarPart()); + return static_cast<const RenderScrollbarPart*>(object); +} + +// This will catch anyone doing an unnecessary cast. +void toRenderScrollbarPart(const RenderScrollbarPart*); + } // namespace WebCore #endif // RenderScrollbarPart_h diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index e7ada7044..28172ef94 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -456,7 +456,7 @@ void RenderTable::layout() statePusher.pop(); if (view()->layoutState()->pageLogicalHeight()) - setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); + setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(this, logicalTop())); bool didFullRepaint = repainter.repaintAfterLayout(); // Repaint with our new bounds if they are different from our old bounds. @@ -1215,18 +1215,41 @@ void RenderTable::updateFirstLetter() { } -LayoutUnit RenderTable::firstLineBoxBaseline() const +enum LineBox { FirstLineBox, LastLineBox }; + +static LayoutUnit getLineBoxBaseline(const RenderTable* table, LineBox lineBox) { - if (isWritingModeRoot()) + if (table->isWritingModeRoot()) return -1; - recalcSectionsIfNeeded(); + table->recalcSectionsIfNeeded(); - const RenderTableSection* topNonEmptySection = this->topNonEmptySection(); + const RenderTableSection* topNonEmptySection = table->topNonEmptySection(); if (!topNonEmptySection) return -1; - return topNonEmptySection->logicalTop() + topNonEmptySection->firstLineBoxBaseline(); + LayoutUnit baseline = topNonEmptySection->firstLineBoxBaseline(); + if (baseline > 0) + return topNonEmptySection->logicalTop() + baseline; + + // The 'first' linebox baseline in a table in the absence of any text in the first section + // is the top of the table. + if (lineBox == FirstLineBox) + return topNonEmptySection->logicalTop(); + + // The 'last' linebox baseline in a table is the baseline of text in the first + // cell in the first row/section, so if there is no text do not return a baseline. + return -1; +} + +LayoutUnit RenderTable::lastLineBoxBaseline() const +{ + return getLineBoxBaseline(this, LastLineBox); +} + +LayoutUnit RenderTable::firstLineBoxBaseline() const +{ + return getLineBoxBaseline(this, FirstLineBox); } LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h index b61c95dc1..1396eeb57 100644 --- a/Source/WebCore/rendering/RenderTable.h +++ b/Source/WebCore/rendering/RenderTable.h @@ -237,7 +237,8 @@ private: virtual void computePreferredLogicalWidths(); virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - virtual LayoutUnit firstLineBoxBaseline() const; + virtual LayoutUnit firstLineBoxBaseline() const OVERRIDE; + virtual LayoutUnit lastLineBoxBaseline() const OVERRIDE; virtual RenderBlock* firstLineBlock() const; virtual void updateFirstLetter(); diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index ec33a7c9f..fb0fe9200 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -186,6 +186,7 @@ void RenderTableCell::updateLogicalWidth(LayoutUnit w) void RenderTableCell::layout() { + updateFirstLetter(); layoutBlock(cellWidthChanged()); setCellWidthChanged(false); } @@ -604,7 +605,7 @@ CollapsedBorderValue RenderTableCell::computeCollapsedBeforeBorder(IncludeBorder return result; // (6) Previous row group's after border. - currSection = table->sectionAbove(currSection); + currSection = table->sectionAbove(currSection, SkipEmptySections); if (currSection) { result = chooseBorder(CollapsedBorderValue(currSection->style()->borderAfter(), includeColor ? currSection->style()->visitedDependentColor(afterColorProperty) : Color(), BROWGROUP), result); if (!result.exists()) @@ -682,7 +683,7 @@ CollapsedBorderValue RenderTableCell::computeCollapsedAfterBorder(IncludeBorderC return result; // (6) Following row group's before border. - currSection = table->sectionBelow(currSection); + currSection = table->sectionBelow(currSection, SkipEmptySections); if (currSection) { result = chooseBorder(result, CollapsedBorderValue(currSection->style()->borderBefore(), includeColor ? currSection->style()->visitedDependentColor(beforeColorProperty) : Color(), BROWGROUP)); if (!result.exists()) diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index d9889008b..3caa7b4f3 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -148,7 +148,7 @@ void RenderTableRow::layout() for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { if (child->isTableCell()) { RenderTableCell* cell = toRenderTableCell(child); - if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) + if (!cell->needsLayout() && paginated && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()) cell->setChildNeedsLayout(true, MarkOnlyThis); if (child->needsLayout()) { diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index a6f544ab5..7f44a75a0 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -370,7 +370,7 @@ int RenderTableSection::calcRowLogicalHeight() // find out the baseline EVerticalAlign va = cell->style()->verticalAlign(); - if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { + if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH) { LayoutUnit baselinePosition = cell->cellBaselinePosition(); if (baselinePosition > cell->borderBefore() + cell->paddingBefore()) { m_grid[r].baseline = max(m_grid[r].baseline, baselinePosition - cell->intrinsicPaddingBefore()); @@ -609,7 +609,7 @@ void RenderTableSection::layoutRows() // If the baseline moved, we may have to update the data for our row. Find out the new baseline. EVerticalAlign va = cell->style()->verticalAlign(); - if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB) { + if (va == BASELINE || va == TEXT_BOTTOM || va == TEXT_TOP || va == SUPER || va == SUB || va == LENGTH) { LayoutUnit baseline = cell->cellBaselinePosition(); if (baseline > cell->borderBefore() + cell->paddingBefore()) m_grid[r].baseline = max(m_grid[r].baseline, baseline); @@ -618,7 +618,7 @@ void RenderTableSection::layoutRows() int oldIntrinsicPaddingBefore = cell->intrinsicPaddingBefore(); int oldIntrinsicPaddingAfter = cell->intrinsicPaddingAfter(); - int logicalHeightWithoutIntrinsicPadding = cell->logicalHeight() - oldIntrinsicPaddingBefore - oldIntrinsicPaddingAfter; + int logicalHeightWithoutIntrinsicPadding = cell->pixelSnappedLogicalHeight() - oldIntrinsicPaddingBefore - oldIntrinsicPaddingAfter; int intrinsicPaddingBefore = 0; switch (cell->style()->verticalAlign()) { @@ -626,6 +626,7 @@ void RenderTableSection::layoutRows() case SUPER: case TEXT_TOP: case TEXT_BOTTOM: + case LENGTH: case BASELINE: { LayoutUnit b = cell->cellBaselinePosition(); if (b > cell->borderBefore() + cell->paddingBefore()) @@ -661,7 +662,7 @@ void RenderTableSection::layoutRows() if (intrinsicPaddingBefore != oldIntrinsicPaddingBefore || intrinsicPaddingAfter != oldIntrinsicPaddingAfter) cell->setNeedsLayout(true, MarkOnlyThis); - if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell->logicalTop()) != cell->pageLogicalOffset()) + if (!cell->needsLayout() && view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(cell, cell->logicalTop()) != cell->pageLogicalOffset()) cell->setChildNeedsLayout(true, MarkOnlyThis); cell->layoutIfNeeded(); @@ -949,7 +950,8 @@ LayoutUnit RenderTableSection::firstLineBoxBaseline() const for (size_t i = 0; i < firstRow.size(); ++i) { const CellStruct& cs = firstRow.at(i); const RenderTableCell* cell = cs.primaryCell(); - if (cell) + // Only cells with content have a baseline + if (cell && cell->contentLogicalHeight()) firstLineBaseline = max(firstLineBaseline, cell->logicalTop() + cell->paddingBefore() + cell->borderBefore() + cell->contentLogicalHeight()); } diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index ddc647570..8b138352e 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -208,6 +208,9 @@ bool RenderTextControl::hasValidAvgCharWidth(AtomicString family) { static HashSet<AtomicString>* fontFamiliesWithInvalidCharWidthMap = 0; + if (family.isEmpty()) + return false; + if (!fontFamiliesWithInvalidCharWidthMap) { fontFamiliesWithInvalidCharWidthMap = new HashSet<AtomicString>; diff --git a/Source/WebCore/rendering/RenderThemeMac.h b/Source/WebCore/rendering/RenderThemeMac.h index 22a614a0c..ebbb2352c 100644 --- a/Source/WebCore/rendering/RenderThemeMac.h +++ b/Source/WebCore/rendering/RenderThemeMac.h @@ -219,7 +219,7 @@ private: NSMenu* searchMenuTemplate() const; NSSliderCell* sliderThumbHorizontal() const; NSSliderCell* sliderThumbVertical() const; - NSTextFieldCell* textField(bool useNewGradient) const; + NSTextFieldCell* textField() const; #if ENABLE(METER_TAG) NSLevelIndicatorStyle levelIndicatorStyleFor(ControlPart) const; diff --git a/Source/WebCore/rendering/RenderThemeMac.mm b/Source/WebCore/rendering/RenderThemeMac.mm index 5e2d26738..28096e670 100644 --- a/Source/WebCore/rendering/RenderThemeMac.mm +++ b/Source/WebCore/rendering/RenderThemeMac.mm @@ -734,18 +734,22 @@ bool RenderThemeMac::paintTextField(RenderObject* o, const PaintInfo& paintInfo, { LocalCurrentGraphicsContext localContext(paintInfo.context); - bool useNewGradient = true; #if defined(BUILDING_ON_LION) || defined(BUILDING_ON_SNOW_LEOPARD) - // See comment in RenderThemeMac::textField() for a complete explanation of this. - useNewGradient = WebCore::deviceScaleFactor(o->frame()) != 1; - if (useNewGradient) { - useNewGradient = o->style()->hasAppearance() - && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white - && !o->style()->hasBackgroundImage(); + bool useNSTextFieldCell = o->style()->hasAppearance() + && o->style()->visitedDependentColor(CSSPropertyBackgroundColor) == Color::white + && !o->style()->hasBackgroundImage(); + + // We do not use NSTextFieldCell to draw styled text fields on Lion and SnowLeopard because + // there are a number of bugs on those platforms that require NSTextFieldCell to be in charge + // of painting its own background. We need WebCore to paint styled backgrounds, so we'll use + // this WebCoreSystemInterface function instead. + if (!useNSTextFieldCell) { + wkDrawBezeledTextFieldCell(r, isEnabled(o) && !isReadOnlyControl(o)); + return false; } #endif - NSTextFieldCell* textField = this->textField(useNewGradient); + NSTextFieldCell *textField = this->textField(); GraphicsContextStateSaver stateSaver(*paintInfo.context); @@ -2164,7 +2168,7 @@ NSSliderCell* RenderThemeMac::sliderThumbVertical() const return m_sliderThumbVertical.get(); } -NSTextFieldCell* RenderThemeMac::textField(bool useNewGradient) const +NSTextFieldCell* RenderThemeMac::textField() const { if (!m_textField) { m_textField.adoptNS([[WebCoreTextFieldCell alloc] initTextCell:@""]); @@ -2173,27 +2177,15 @@ NSTextFieldCell* RenderThemeMac::textField(bool useNewGradient) const [m_textField.get() setFocusRingType:NSFocusRingTypeExterior]; #if defined(BUILDING_ON_LION) || defined(BUILDING_ON_SNOW_LEOPARD) [m_textField.get() setDrawsBackground:YES]; + [m_textField.get() setBackgroundColor:[NSColor whiteColor]]; #else - UNUSED_PARAM(useNewGradient); + // Post-Lion, WebCore can be in charge of paintinng the background thanks to + // the workaround in place for <rdar://problem/11385461>, which is implemented + // above as _coreUIDrawOptionsWithFrame. [m_textField.get() setDrawsBackground:NO]; #endif } -#if defined(BUILDING_ON_LION) || defined(BUILDING_ON_SNOW_LEOPARD) - // This is a workaround for <rdar://problem/11385461> on Lion and SnowLeopard. Newer versions of the - // OS can always use the newer version of the text field with the workaround above in - // _coreUIDrawOptionsWithFrame. With this workaround for older OS's, when the deviceScaleFactor is 1, - // we have an old-school gradient bezel in text fields whether they are styled or not. This is fine and - // matches shipping Safari. When the deviceScaleFactor is greater than 1, text fields will have newer, - // AppKit-matching gradients that look much more appropriate at the higher resolutions. However, if the - // text field is styled in any way, we'll revert to the old-school bezel, which doesn't look great in - // HiDPI, but it looks better than the CSS border, which is the only alternative until 11385461 is resolved. - if (useNewGradient) - [m_textField.get() setBackgroundColor:[NSColor whiteColor]]; - else - [m_textField.get() setBackgroundColor:[NSColor clearColor]]; -#endif - return m_textField.get(); } diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index 4a3a2bc83..43ac53039 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -400,7 +400,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const { document()->updateStyleIfNeeded(); - typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectionMap; + typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectionMap; SelectionMap selectedObjects; RenderObject* os = m_selectionStart; @@ -408,13 +408,13 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - selectedObjects.set(os, new RenderSelectionInfo(os, clipToVisibleContent)); + selectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, clipToVisibleContent))); RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - RenderSelectionInfo* blockInfo = selectedObjects.get(cb); + OwnPtr<RenderSelectionInfo>& blockInfo = selectedObjects.add(cb, nullptr).iterator->second; if (blockInfo) break; - selectedObjects.set(cb, new RenderSelectionInfo(cb, clipToVisibleContent)); + blockInfo = adoptPtr(new RenderSelectionInfo(cb, clipToVisibleContent)); cb = cb->containingBlock(); } } @@ -426,7 +426,7 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const LayoutRect selRect; SelectionMap::iterator end = selectedObjects.end(); for (SelectionMap::iterator i = selectedObjects.begin(); i != end; ++i) { - RenderSelectionInfo* info = i->second; + RenderSelectionInfo* info = i->second.get(); // RenderSelectionInfo::rect() is in the coordinates of the repaintContainer, so map to page coordinates. LayoutRect currRect = info->rect(); if (RenderBoxModelObject* repaintContainer = info->repaintContainer()) { @@ -434,7 +434,6 @@ IntRect RenderView::selectionBounds(bool clipToVisibleContent) const currRect = absQuad.enclosingBoundingBox(); } selRect.unite(currRect); - delete info; } return pixelSnappedIntRect(selRect); } @@ -472,14 +471,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e int oldEndPos = m_selectionEndPos; // Objects each have a single selection rect to examine. - typedef HashMap<RenderObject*, RenderSelectionInfo*> SelectedObjectMap; + typedef HashMap<RenderObject*, OwnPtr<RenderSelectionInfo> > SelectedObjectMap; SelectedObjectMap oldSelectedObjects; SelectedObjectMap newSelectedObjects; // Blocks contain selected objects and fill gaps between them, either on the left, right, or in between lines and blocks. // In order to get the repaint rect right, we have to examine left, middle, and right rects individually, since otherwise // the union of those rects might remain the same even when changes have occurred. - typedef HashMap<RenderBlock*, RenderBlockSelectionInfo*> SelectedBlockMap; + typedef HashMap<RenderBlock*, OwnPtr<RenderBlockSelectionInfo> > SelectedBlockMap; SelectedBlockMap oldSelectedBlocks; SelectedBlockMap newSelectedBlocks; @@ -488,14 +487,14 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e while (os && os != stop) { if ((os->canBeSelectionLeaf() || os == m_selectionStart || os == m_selectionEnd) && os->selectionState() != SelectionNone) { // Blocks are responsible for painting line gaps and margin gaps. They must be examined as well. - oldSelectedObjects.set(os, new RenderSelectionInfo(os, true)); + oldSelectedObjects.set(os, adoptPtr(new RenderSelectionInfo(os, true))); if (blockRepaintMode == RepaintNewXOROld) { RenderBlock* cb = os->containingBlock(); while (cb && !cb->isRenderView()) { - RenderBlockSelectionInfo* blockInfo = oldSelectedBlocks.get(cb); + OwnPtr<RenderBlockSelectionInfo>& blockInfo = oldSelectedBlocks.add(cb, nullptr).iterator->second; if (blockInfo) break; - oldSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); + blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); cb = cb->containingBlock(); } } @@ -542,13 +541,13 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e o = start; while (o && o != stop) { if ((o->canBeSelectionLeaf() || o == start || o == end) && o->selectionState() != SelectionNone) { - newSelectedObjects.set(o, new RenderSelectionInfo(o, true)); + newSelectedObjects.set(o, adoptPtr(new RenderSelectionInfo(o, true))); RenderBlock* cb = o->containingBlock(); while (cb && !cb->isRenderView()) { - RenderBlockSelectionInfo* blockInfo = newSelectedBlocks.get(cb); + OwnPtr<RenderBlockSelectionInfo>& blockInfo = newSelectedBlocks.add(cb, nullptr).iterator->second; if (blockInfo) break; - newSelectedBlocks.set(cb, new RenderBlockSelectionInfo(cb)); + blockInfo = adoptPtr(new RenderBlockSelectionInfo(cb)); cb = cb->containingBlock(); } } @@ -556,15 +555,8 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e o = o->nextInPreOrder(); } - if (!m_frameView || blockRepaintMode == RepaintNothing) { - // We built the maps, but we aren't going to use them. - // We need to delete the values, otherwise they'll all leak! - deleteAllValues(oldSelectedObjects); - deleteAllValues(newSelectedObjects); - deleteAllValues(oldSelectedBlocks); - deleteAllValues(newSelectedBlocks); + if (!m_frameView || blockRepaintMode == RepaintNothing) return; - } m_frameView->beginDeferredRepaints(); @@ -572,7 +564,7 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e for (SelectedObjectMap::iterator i = oldSelectedObjects.begin(); i != oldObjectsEnd; ++i) { RenderObject* obj = i->first; RenderSelectionInfo* newInfo = newSelectedObjects.get(obj); - RenderSelectionInfo* oldInfo = i->second; + RenderSelectionInfo* oldInfo = i->second.get(); if (!newInfo || oldInfo->rect() != newInfo->rect() || oldInfo->state() != newInfo->state() || (m_selectionStart == obj && oldStartPos != m_selectionStartPos) || (m_selectionEnd == obj && oldEndPos != m_selectionEndPos)) { @@ -580,44 +572,34 @@ void RenderView::setSelection(RenderObject* start, int startPos, RenderObject* e if (newInfo) { newInfo->repaint(); newSelectedObjects.remove(obj); - delete newInfo; } } - delete oldInfo; } // Any new objects that remain were not found in the old objects dict, and so they need to be updated. SelectedObjectMap::iterator newObjectsEnd = newSelectedObjects.end(); - for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) { - RenderSelectionInfo* newInfo = i->second; - newInfo->repaint(); - delete newInfo; - } + for (SelectedObjectMap::iterator i = newSelectedObjects.begin(); i != newObjectsEnd; ++i) + i->second->repaint(); // Have any of the old blocks changed? SelectedBlockMap::iterator oldBlocksEnd = oldSelectedBlocks.end(); for (SelectedBlockMap::iterator i = oldSelectedBlocks.begin(); i != oldBlocksEnd; ++i) { RenderBlock* block = i->first; RenderBlockSelectionInfo* newInfo = newSelectedBlocks.get(block); - RenderBlockSelectionInfo* oldInfo = i->second; + RenderBlockSelectionInfo* oldInfo = i->second.get(); if (!newInfo || oldInfo->rects() != newInfo->rects() || oldInfo->state() != newInfo->state()) { oldInfo->repaint(); if (newInfo) { newInfo->repaint(); newSelectedBlocks.remove(block); - delete newInfo; } } - delete oldInfo; } // Any new blocks that remain were not found in the old blocks dict, and so they need to be updated. SelectedBlockMap::iterator newBlocksEnd = newSelectedBlocks.end(); - for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) { - RenderBlockSelectionInfo* newInfo = i->second; - newInfo->repaint(); - delete newInfo; - } + for (SelectedBlockMap::iterator i = newSelectedBlocks.begin(); i != newBlocksEnd; ++i) + i->second->repaint(); m_frameView->endDeferredRepaints(); } diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index 9b973b3b2..bcbe7bd89 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -708,7 +708,7 @@ LayoutRect RootInlineBox::paddedLayoutOverflowRect(LayoutUnit endPadding) const return lineLayoutOverflow; } -static void setAscentAndDescent(LayoutUnit& ascent, LayoutUnit& descent, LayoutUnit newAscent, LayoutUnit newDescent, bool& ascentDescentSet) +static void setAscentAndDescent(int& ascent, int& descent, int newAscent, int newDescent, bool& ascentDescentSet) { if (!ascentDescentSet) { ascentDescentSet = true; @@ -720,7 +720,7 @@ static void setAscentAndDescent(LayoutUnit& ascent, LayoutUnit& descent, LayoutU } } -void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, LayoutUnit& ascent, LayoutUnit& descent, +void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallbackFontsMap& textBoxDataMap, int& ascent, int& descent, bool& affectsAscent, bool& affectsDescent) const { bool ascentDescentSet = false; @@ -757,11 +757,11 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb usedFonts->append(box->renderer()->style(isFirstLineStyle())->font().primaryFont()); for (size_t i = 0; i < usedFonts->size(); ++i) { const FontMetrics& fontMetrics = usedFonts->at(i)->fontMetrics(); - LayoutUnit usedFontAscent = fontMetrics.ascent(baselineType()); - LayoutUnit usedFontDescent = fontMetrics.descent(baselineType()); - LayoutUnit halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2; - LayoutUnit usedFontAscentAndLeading = usedFontAscent + halfLeading; - LayoutUnit usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading; + int usedFontAscent = fontMetrics.ascent(baselineType()); + int usedFontDescent = fontMetrics.descent(baselineType()); + int halfLeading = (fontMetrics.lineSpacing() - fontMetrics.height()) / 2; + int usedFontAscentAndLeading = usedFontAscent + halfLeading; + int usedFontDescentAndLeading = fontMetrics.lineSpacing() - usedFontAscentAndLeading; if (includeFont) { setAscentAndDescent(ascent, descent, usedFontAscent, usedFontDescent, ascentDescentSet); setUsedFont = true; @@ -779,8 +779,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb // If leading is included for the box, then we compute that box. if (includeLeading && !setUsedFontWithLeading) { - LayoutUnit ascentWithLeading = box->baselinePosition(baselineType()); - LayoutUnit descentWithLeading = box->lineHeight() - ascentWithLeading; + int ascentWithLeading = box->baselinePosition(baselineType()); + int descentWithLeading = box->lineHeight() - ascentWithLeading; setAscentAndDescent(ascent, descent, ascentWithLeading, descentWithLeading, ascentDescentSet); // Examine the font box for inline flows and text boxes to see if any part of it is above the baseline. @@ -792,8 +792,8 @@ void RootInlineBox::ascentAndDescentForBox(InlineBox* box, GlyphOverflowAndFallb } if (includeFontForBox(box) && !setUsedFont) { - LayoutUnit fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); - LayoutUnit fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(); + int fontAscent = box->renderer()->style(isFirstLineStyle())->fontMetrics().ascent(); + int fontDescent = box->renderer()->style(isFirstLineStyle())->fontMetrics().descent(); setAscentAndDescent(ascent, descent, fontAscent, fontDescent, ascentDescentSet); affectsAscent = fontAscent - box->logicalTop() > 0; affectsDescent = fontDescent + box->logicalTop() > 0; diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h index 49aed00da..2edbddb2c 100644 --- a/Source/WebCore/rendering/RootInlineBox.h +++ b/Source/WebCore/rendering/RootInlineBox.h @@ -151,7 +151,7 @@ public: LayoutRect paddedLayoutOverflowRect(LayoutUnit endPadding) const; - void ascentAndDescentForBox(InlineBox*, GlyphOverflowAndFallbackFontsMap&, LayoutUnit& ascent, LayoutUnit& descent, bool& affectsAscent, bool& affectsDescent) const; + void ascentAndDescentForBox(InlineBox*, GlyphOverflowAndFallbackFontsMap&, int& ascent, int& descent, bool& affectsAscent, bool& affectsDescent) const; LayoutUnit verticalPositionForBox(InlineBox*, VerticalPositionCache&); bool includeLeadingForBox(InlineBox*) const; bool includeFontForBox(InlineBox*) const; diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp index 4297dd7ff..351f99e84 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.cpp @@ -48,6 +48,7 @@ RenderMathMLFenced::RenderMathMLFenced(Element* element) : RenderMathMLRow(element) , m_open(OpeningBraceChar) , m_close(ClosingBraceChar) + , m_closeFenceRenderer(0) { } @@ -94,49 +95,67 @@ void RenderMathMLFenced::makeFences() RenderObject* openFence = new (renderArena()) RenderMathMLOperator(node(), m_open); openFence->setStyle(createOperatorStyle()); RenderBlock::addChild(openFence, firstChild()); - RenderObject* closeFence = new (renderArena()) RenderMathMLOperator(node(), m_close); - closeFence->setStyle(createOperatorStyle()); - RenderBlock::addChild(closeFence); + m_closeFenceRenderer = new (renderArena()) RenderMathMLOperator(node(), m_close); + m_closeFenceRenderer->setStyle(createOperatorStyle()); + RenderBlock::addChild(m_closeFenceRenderer); } -void RenderMathMLFenced::addChild(RenderObject* child, RenderObject*) +void RenderMathMLFenced::addChild(RenderObject* child, RenderObject* beforeChild) { // make the fences if the render object is empty if (isEmpty()) updateFromElement(); + // FIXME: Adding or removing a child should possibly cause all later separators to shift places if they're different, + // as later child positions change by +1 or -1. + + RenderObject* separatorRenderer = 0; if (m_separators.get()) { unsigned int count = 0; for (Node* position = child->node(); position; position = position->previousSibling()) { - if (position->nodeType() == Node::ELEMENT_NODE) + if (position->isElementNode()) count++; } - - if (count > 1) { + if (!beforeChild) { + // We're adding at the end (before the closing fence), so a new separator would go before the new child, not after it. + --count; + } + // |count| is now the number of element children that will be before our new separator, i.e. it's the 1-based index of the separator. + + if (count > 0) { UChar separator; // Use the last separator if we've run out of specified separators. - if ((count - 1) >= m_separators.get()->length()) + if (count > m_separators.get()->length()) separator = (*m_separators.get())[m_separators.get()->length() - 1]; else - separator = (*m_separators.get())[count - 2]; + separator = (*m_separators.get())[count - 1]; - RenderObject* separatorObj = new (renderArena()) RenderMathMLOperator(node(), separator); - separatorObj->setStyle(createOperatorStyle()); - RenderBlock::addChild(separatorObj, lastChild()); + separatorRenderer = new (renderArena()) RenderMathMLOperator(node(), separator); + separatorRenderer->setStyle(createOperatorStyle()); } } // If we have a block, we'll wrap it in an inline-block. if (child->isBlockFlow() && child->style()->display() != INLINE_BLOCK) { // Block objects wrapper. - RenderBlock* block = createAlmostAnonymousBlock(INLINE_BLOCK); - RenderBlock::addChild(block, lastChild()); - block->addChild(child); - } else - RenderBlock::addChild(child, lastChild()); + block->addChild(child); + child = block; + } + + if (beforeChild) { + // Adding |x| before an existing |y| e.g. in element (y) - first insert our new child |x|, then its separator, to get (x, y). + RenderBlock::addChild(child, beforeChild); + if (separatorRenderer) + RenderBlock::addChild(separatorRenderer, beforeChild); + } else { + // Adding |y| at the end of an existing element e.g. (x) - insert the separator first before the closing fence, then |y|, to get (x, y). + if (separatorRenderer) + RenderBlock::addChild(separatorRenderer, m_closeFenceRenderer); + RenderBlock::addChild(child, m_closeFenceRenderer); + } } } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLFenced.h b/Source/WebCore/rendering/mathml/RenderMathMLFenced.h index b2bca9971..75324dcdc 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLFenced.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLFenced.h @@ -47,6 +47,8 @@ private: UChar m_open; UChar m_close; RefPtr<StringImpl> m_separators; + + RenderObject* m_closeFenceRenderer; }; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp index e6d5165a9..efeed1a1f 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.cpp @@ -31,15 +31,12 @@ #include "RenderMathMLRoot.h" #include "GraphicsContext.h" -#include "MathMLNames.h" #include "PaintInfo.h" using namespace std; namespace WebCore { -using namespace MathMLNames; - // FIXME: This whole file should be changed to work with various writing modes. See https://bugs.webkit.org/show_bug.cgi?id=48951. // Threshold above which the radical shape is modified to look nice with big bases (em) @@ -54,8 +51,10 @@ const float gRadicalBottomPointXFront = 0.5f; const int gRadicalBottomPointLower = 3; // Horizontal position of the top left point of the radical "dip" (* frontWidth) const float gRadicalDipLeftPointXFront = 0.8f; -// Vertical position of the top left point of the radical "dip" (* baseHeight) -const float gRadicalDipLeftPointYPos = 0.625f; +// Vertical position of the top left point of a sqrt radical "dip" (* baseHeight) +const float gSqrtRadicalDipLeftPointYPos = 0.5f; +// Vertical position of the top left point of an nth root radical "dip" (* baseHeight) +const float gRootRadicalDipLeftPointYPos = 0.625f; // Vertical shift of the left end point of the radical (em) const float gRadicalLeftEndYShiftEms = 0.05f; // Additional bottom root padding if baseHeight > threshold (em) @@ -81,6 +80,65 @@ RenderBoxModelObject* RenderMathMLRoot::index() const return toRenderBoxModelObject(index); } +void RenderMathMLRoot::computePreferredLogicalWidths() +{ + ASSERT(preferredLogicalWidthsDirty() && needsLayout()); + + computeChildrenPreferredLogicalHeights(); + + int baseHeight = firstChild() ? roundToInt(preferredLogicalHeightAfterSizing(firstChild())) : 0; + + int frontWidth = lroundf(gFrontWidthEms * style()->fontSize()); + + // Base height above which the shape of the root changes + float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); + if (baseHeight > thresholdHeight && thresholdHeight) { + float shift = min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); + m_overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); + m_intrinsicPaddingAfter = lroundf(gBigRootBottomPaddingEms * style()->fontSize()); + } else { + m_overbarLeftPointShift = 0; + m_intrinsicPaddingAfter = 0; + } + + int rootPad = lroundf(gSpaceAboveEms * style()->fontSize()); + m_intrinsicPaddingBefore = rootPad; + m_indexTop = 0; + if (RenderBoxModelObject* index = this->index()) { + m_intrinsicPaddingStart = roundToInt(index->maxPreferredLogicalWidth()) + m_overbarLeftPointShift; + + int indexHeight = roundToInt(preferredLogicalHeightAfterSizing(index)); + int partDipHeight = lroundf((1 - gRootRadicalDipLeftPointYPos) * baseHeight); + int rootExtraTop = partDipHeight + indexHeight - (baseHeight + rootPad); + if (rootExtraTop > 0) + m_intrinsicPaddingBefore += rootExtraTop; + else + m_indexTop = - rootExtraTop; + } else + m_intrinsicPaddingStart = frontWidth; + + RenderMathMLBlock::computePreferredLogicalWidths(); + + // Shrink our logical width to its probable value now without triggering unnecessary relayout of our children. + ASSERT(needsLayout() && logicalWidth() >= maxPreferredLogicalWidth()); + setLogicalWidth(maxPreferredLogicalWidth()); +} + +void RenderMathMLRoot::layout() +{ + // Our computePreferredLogicalWidths() may change our logical width and then layout our children, which + // RenderBlock::layout()'s relayoutChildren logic isn't expecting. + if (preferredLogicalWidthsDirty()) + computePreferredLogicalWidths(); + + RenderMathMLBlock::layout(); + + RenderBoxModelObject* index = this->index(); + // If |index|, it should be a RenderBlock here, unless the user has overriden its { position: absolute }. + if (index && index->isBox()) + toRenderBox(index)->setLogicalTop(m_indexTop); +} + void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) { RenderMathMLBlock::paint(info, paintOffset); @@ -88,24 +146,21 @@ void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) if (info.context->paintingDisabled()) return; - if (!index()) - return; + IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + contentBoxRect().location()); - IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + computedCSSContentBoxRect().location()); + int startX = adjustedPaintOffset.x(); + int frontWidth = lroundf(gFrontWidthEms * style()->fontSize()); + int overbarWidth = roundToInt(getBoxModelObjectWidth(firstChild())) + m_overbarLeftPointShift; int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); + int rootPad = lroundf(gSpaceAboveEms * style()->fontSize()); + adjustedPaintOffset.setY(adjustedPaintOffset.y() - rootPad); - int overbarWidth = roundToInt(getBoxModelObjectWidth(firstChild())) + m_overbarLeftPointShift; - int indexWidth = index()->pixelSnappedOffsetWidth(); - int frontWidth = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); - int startX = adjustedPaintOffset.x() + indexWidth + m_overbarLeftPointShift; - - int rootPad = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); - adjustedPaintOffset.setY(adjustedPaintOffset.y() + m_intrinsicPaddingBefore - rootPad); + float radicalDipLeftPointYPos = (index() ? gRootRadicalDipLeftPointYPos : gSqrtRadicalDipLeftPointYPos) * baseHeight; FloatPoint overbarLeftPoint(startX - m_overbarLeftPointShift, adjustedPaintOffset.y()); FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); - FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + gRadicalDipLeftPointYPos * baseHeight); + FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + radicalDipLeftPointYPos); FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style()->fontSize()); GraphicsContextStateSaver stateSaver(*info.context); @@ -153,46 +208,6 @@ void RenderMathMLRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) info.context->strokePath(line); } -void RenderMathMLRoot::layout() -{ - RenderBlock::layout(); - - if (!index()) - return; - - int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); - - // Base height above which the shape of the root changes - float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); - if (baseHeight > thresholdHeight && thresholdHeight) { - float shift = min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); - int frontWidth = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); - m_overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); - m_intrinsicPaddingAfter = static_cast<int>(roundf(gBigRootBottomPaddingEms * style()->fontSize())); - } else { - m_overbarLeftPointShift = 0; - m_intrinsicPaddingAfter = 0; - } - - RenderBoxModelObject* index = this->index(); - - m_intrinsicPaddingStart = index->pixelSnappedOffsetWidth() + m_overbarLeftPointShift; - - int rootPad = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); - int partDipHeight = static_cast<int>(roundf((1 - gRadicalDipLeftPointYPos) * baseHeight)); - int rootExtraTop = partDipHeight + index->pixelSnappedOffsetHeight() - (baseHeight + rootPad); - m_intrinsicPaddingBefore = rootPad + max(rootExtraTop, 0); - - setNeedsLayout(true, MarkOnlyThis); - setPreferredLogicalWidthsDirty(true, MarkOnlyThis); // FIXME: Can this really be right? - // FIXME: Preferred logical widths are currently wrong the first time through, relying on layout() to set m_intrinsicPaddingStart. - RenderBlock::layout(); - - // |index| should be a RenderBlock here, unless the user has overriden its { position: absolute }. - if (rootExtraTop < 0 && index->isBox()) - toRenderBox(index)->setLogicalTop(-rootExtraTop); -} - } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h index 65ec82dc7..cd5d6e6e2 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLRoot.h @@ -32,7 +32,7 @@ namespace WebCore { -// Render base^(1/index), using radical notation. +// Render base^(1/index), or sqrt(base) via the derived class RenderMathMLSquareRoot, using radical notation. class RenderMathMLRoot : public RenderMathMLBlock { public: RenderMathMLRoot(Element*); @@ -45,10 +45,13 @@ protected: private: virtual const char* renderName() const { return "RenderMathMLRoot"; } + virtual void computePreferredLogicalWidths() OVERRIDE; + // This may return 0 for a non-MathML index (which won't occur in valid MathML). RenderBoxModelObject* index() const; int m_overbarLeftPointShift; + int m_indexTop; }; } diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp index 86975dbfb..b4b07a2cf 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp +++ b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.cpp @@ -30,45 +30,12 @@ #include "RenderMathMLSquareRoot.h" -#include "GraphicsContext.h" -#include "MathMLNames.h" -#include "PaintInfo.h" #include "RenderMathMLRow.h" -using namespace std; - namespace WebCore { -using namespace MathMLNames; - -// FIXME: This whole file should be changed to work with various writing modes. See https://bugs.webkit.org/show_bug.cgi?id=48951. - -// Threshold above which the radical shape is modified to look nice with big bases (em) -const float gThresholdBaseHeightEms = 1.5f; -// Normal width of the front of the radical sign, before the base & overbar (em) -const float gFrontWidthEms = 0.75f; -// Gap between the base and overbar (em) -const float gSpaceAboveEms = 0.2f; -// Horizontal position of the bottom point of the radical (* frontWidth) -const float gRadicalBottomPointXFront = 0.5f; -// Lower the radical sign's bottom point (px) -const int gRadicalBottomPointLower = 3; -// Horizontal position of the top left point of the radical "dip" (* frontWidth) -const float gRadicalDipLeftPointXFront = 0.8f; -// Vertical position of the top left point of the radical "dip" (* baseHeight) -const float gRadicalDipLeftPointYPos = 0.5f; -// Vertical shift of the left end point of the radical (em) -const float gRadicalLeftEndYShiftEms = 0.05f; -// Additional bottom root padding if baseHeight > threshold (em) -const float gBigRootBottomPaddingEms = 0.2f; - -// Radical line thickness (em) -const float gRadicalLineThicknessEms = 0.02f; -// Radical thick line thickness (em) -const float gRadicalThickLineThicknessEms = 0.1f; - RenderMathMLSquareRoot::RenderMathMLSquareRoot(Element* element) - : RenderMathMLBlock(element) + : RenderMathMLRoot(element) { } @@ -77,7 +44,7 @@ void RenderMathMLSquareRoot::addChild(RenderObject* newChild, RenderObject* befo if (!firstChild()) { RenderMathMLRow* newMRow = RenderMathMLRow::createAnonymousWithParentRenderer(this); - RenderMathMLBlock::addChild(newMRow); + RenderMathMLRoot::addChild(newMRow); // newMRow->isAnonymousBlock() is false because newMRow's display is INLINE_BLOCK, // so we don't need to worry about removeLeftoverAnonymousBlock(). @@ -88,106 +55,6 @@ void RenderMathMLSquareRoot::addChild(RenderObject* newChild, RenderObject* befo firstChild()->addChild(newChild, beforeChild); } -void RenderMathMLSquareRoot::computePreferredLogicalWidths() -{ - m_intrinsicPaddingStart = static_cast<int>(roundf(gFrontWidthEms * style()->fontSize())); - - RenderMathMLBlock::computePreferredLogicalWidths(); -} - -void RenderMathMLSquareRoot::computeLogicalHeight() -{ - int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); - float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); - m_intrinsicPaddingAfter = baseHeight > thresholdHeight ? static_cast<int>(roundf(gBigRootBottomPaddingEms * style()->fontSize())) : 0; - setLogicalHeight(baseHeight + borderAndPaddingLogicalHeight()); - - RenderMathMLBlock::computeLogicalHeight(); -} - -void RenderMathMLSquareRoot::layout() -{ - m_intrinsicPaddingBefore = static_cast<int>(roundf(gSpaceAboveEms * style()->fontSize())); - - RenderMathMLBlock::layout(); -} - -void RenderMathMLSquareRoot::paint(PaintInfo& info, const LayoutPoint& paintOffset) -{ - RenderMathMLBlock::paint(info, paintOffset); - - if (info.context->paintingDisabled()) - return; - - IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset + location() + computedCSSContentBoxRect().location()); - - int baseHeight = roundToInt(getBoxModelObjectHeight(firstChild())); - int overbarWidth = roundToInt(getBoxModelObjectWidth(firstChild())); - - int frontWidth = m_intrinsicPaddingStart; - int overbarLeftPointShift = 0; - // Base height above which the shape of the root changes - float thresholdHeight = gThresholdBaseHeightEms * style()->fontSize(); - - if (baseHeight > thresholdHeight && thresholdHeight) { - float shift = min<float>((baseHeight - thresholdHeight) / thresholdHeight, 1.0f); - overbarLeftPointShift = static_cast<int>(shift * gRadicalBottomPointXFront * frontWidth); - } - - overbarWidth += overbarLeftPointShift; - - int startX = adjustedPaintOffset.x() + frontWidth; - - FloatPoint overbarLeftPoint(startX - overbarLeftPointShift, adjustedPaintOffset.y()); - FloatPoint bottomPoint(startX - gRadicalBottomPointXFront * frontWidth, adjustedPaintOffset.y() + baseHeight + gRadicalBottomPointLower); - FloatPoint dipLeftPoint(startX - gRadicalDipLeftPointXFront * frontWidth, adjustedPaintOffset.y() + gRadicalDipLeftPointYPos * baseHeight); - FloatPoint leftEnd(startX - frontWidth, dipLeftPoint.y() + gRadicalLeftEndYShiftEms * style()->fontSize()); - - GraphicsContextStateSaver stateSaver(*info.context); - - info.context->setStrokeThickness(gRadicalLineThicknessEms * style()->fontSize()); - info.context->setStrokeStyle(SolidStroke); - info.context->setStrokeColor(style()->visitedDependentColor(CSSPropertyColor), ColorSpaceDeviceRGB); - info.context->setLineJoin(MiterJoin); - info.context->setMiterLimit(style()->fontSize()); - - Path root; - - root.moveTo(FloatPoint(overbarLeftPoint.x() + overbarWidth, adjustedPaintOffset.y())); - // draw top - root.addLineTo(overbarLeftPoint); - // draw from top left corner to bottom point of radical - root.addLineTo(bottomPoint); - // draw from bottom point to top of left part of radical base "dip" - root.addLineTo(dipLeftPoint); - // draw to end - root.addLineTo(leftEnd); - - info.context->strokePath(root); - - GraphicsContextStateSaver maskStateSaver(*info.context); - - // Build a mask to draw the thick part of the root. - Path mask; - - mask.moveTo(overbarLeftPoint); - mask.addLineTo(bottomPoint); - mask.addLineTo(dipLeftPoint); - mask.addLineTo(FloatPoint(2 * dipLeftPoint.x() - leftEnd.x(), 2 * dipLeftPoint.y() - leftEnd.y())); - - info.context->clip(mask); - - // Draw the thick part of the root. - info.context->setStrokeThickness(gRadicalThickLineThicknessEms * style()->fontSize()); - info.context->setLineCap(SquareCap); - - Path line; - line.moveTo(bottomPoint); - line.addLineTo(dipLeftPoint); - - info.context->strokePath(line); -} - } #endif // ENABLE(MATHML) diff --git a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h index ea6d324db..b0270efbb 100644 --- a/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h +++ b/Source/WebCore/rendering/mathml/RenderMathMLSquareRoot.h @@ -28,12 +28,12 @@ #if ENABLE(MATHML) -#include "RenderMathMLBlock.h" +#include "RenderMathMLRoot.h" namespace WebCore { // Render sqrt(base), using radical notation. -class RenderMathMLSquareRoot : public RenderMathMLBlock { +class RenderMathMLSquareRoot : public RenderMathMLRoot { public: RenderMathMLSquareRoot(Element*); @@ -43,12 +43,6 @@ private: virtual const char* renderName() const { return "RenderMathMLSquareRoot"; } virtual bool createsAnonymousWrapper() const OVERRIDE { return true; } - - virtual void computePreferredLogicalWidths() OVERRIDE; - virtual void computeLogicalHeight() OVERRIDE; - virtual void layout() OVERRIDE; - - virtual void paint(PaintInfo&, const LayoutPoint&) OVERRIDE; }; } diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index 741acc6e5..a24ac9dc8 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -410,7 +410,7 @@ enum EDisplay { TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_ROW, TABLE_COLUMN_GROUP, TABLE_COLUMN, TABLE_CELL, TABLE_CAPTION, BOX, INLINE_BOX, - FLEXBOX, INLINE_FLEXBOX, + FLEX, INLINE_FLEX, #if ENABLE(CSS_GRID_LAYOUT) GRID, INLINE_GRID, #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h index ca000f50b..9ef55a919 100644 --- a/Source/WebCore/rendering/svg/RenderSVGBlock.h +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h @@ -34,13 +34,15 @@ public: virtual LayoutRect visualOverflowRect() const; +protected: + virtual void willBeDestroyed() OVERRIDE; + private: virtual void setStyle(PassRefPtr<RenderStyle>); virtual void updateBoxModelInfoFromStyle(); virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; - virtual void willBeDestroyed(); virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateFromElement(); diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index 98af8e958..77b4fe956 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -124,7 +124,22 @@ void RenderSVGInline::addChild(RenderObject* child, RenderObject* beforeChild) { RenderInline::addChild(child, beforeChild); if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeChildAdded(child); + textRenderer->subtreeChildWasAdded(child); +} + +void RenderSVGInline::removeChild(RenderObject* child) +{ + RenderSVGText* textRenderer = child->isSVGInlineText() ? RenderSVGText::locateRenderSVGTextAncestor(this) : 0; + if (!textRenderer) { + RenderInline::removeChild(child); + return; + } + + RenderSVGInlineText* text = toRenderSVGInlineText(child); + Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; + textRenderer->subtreeChildWillBeRemoved(text, affectedAttributes); + RenderInline::removeChild(child); + textRenderer->subtreeChildWasRemoved(affectedAttributes); } } diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h index 8aa4ab875..172062196 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.h +++ b/Source/WebCore/rendering/svg/RenderSVGInline.h @@ -57,7 +57,9 @@ private: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); virtual void updateFromElement(); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject*) OVERRIDE; }; } diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index a0df4113e..eff707724 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -72,25 +72,11 @@ RenderSVGInlineText::RenderSVGInlineText(Node* n, PassRefPtr<StringImpl> string) { } -void RenderSVGInlineText::willBeDestroyed() -{ - RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this); - if (!textRenderer) { - RenderText::willBeDestroyed(); - return; - } - - Vector<SVGTextLayoutAttributes*> affectedAttributes; - textRenderer->subtreeChildWillBeDestroyed(this, affectedAttributes); - RenderText::willBeDestroyed(); - textRenderer->subtreeChildWasDestroyed(this, affectedAttributes); -} - void RenderSVGInlineText::setTextInternal(PassRefPtr<StringImpl> text) { RenderText::setTextInternal(text); if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeTextChanged(this); + textRenderer->subtreeTextDidChange(this); } void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) @@ -115,7 +101,7 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle // The text metrics may be influenced by style changes. if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeStyleChanged(this); + textRenderer->subtreeStyleDidChange(this); } InlineTextBox* RenderSVGInlineText::createTextBox() diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index 51378fd07..ab81ca99f 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -48,7 +48,6 @@ public: private: virtual const char* renderName() const { return "RenderSVGInlineText"; } - virtual void willBeDestroyed(); virtual void setTextInternal(PassRefPtr<StringImpl>); virtual void styleDidChange(StyleDifference, const RenderStyle*); diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp index 4fc5e2376..fd16ef29d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResource.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp @@ -27,8 +27,10 @@ #include "Frame.h" #include "FrameView.h" +#include "RenderSVGResourceClipper.h" #include "RenderSVGResourceContainer.h" #include "RenderSVGResourceFilter.h" +#include "RenderSVGResourceMasker.h" #include "RenderSVGResourceSolidColor.h" #include "SVGResources.h" #include "SVGResourcesCache.h" @@ -161,15 +163,21 @@ RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() return s_sharedSolidPaintingResource; } -static inline void removeFromFilterCacheAndInvalidateDependencies(RenderObject* object, bool needsLayout) +static inline void removeFromCacheAndInvalidateDependencies(RenderObject* object, bool needsLayout) { ASSERT(object); -#if ENABLE(FILTERS) if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) { +#if ENABLE(FILTERS) if (RenderSVGResourceFilter* filter = resources->filter()) filter->removeClientFromCache(object); - } #endif + if (RenderSVGResourceMasker* masker = resources->masker()) + masker->removeClientFromCache(object); + + if (RenderSVGResourceClipper* clipper = resources->clipper()) + clipper->removeClientFromCache(object); + } + if (!object->node() || !object->node()->isSVGElement()) return; HashSet<SVGElement*>* dependencies = object->document()->accessSVGExtensions()->setOfElementsReferencingTarget(static_cast<SVGElement*>(object->node())); @@ -191,12 +199,12 @@ void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject* if (needsLayout) object->setNeedsLayout(true); - removeFromFilterCacheAndInvalidateDependencies(object, needsLayout); + removeFromCacheAndInvalidateDependencies(object, needsLayout); // Invalidate resources in ancestor chain, if needed. RenderObject* current = object->parent(); while (current) { - removeFromFilterCacheAndInvalidateDependencies(current, needsLayout); + removeFromCacheAndInvalidateDependencies(current, needsLayout); if (current->isSVGResourceContainer()) { // This will process the rest of the ancestors. diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index f0f0b9c32..2bb583cac 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -57,12 +57,17 @@ namespace WebCore { RenderSVGText::RenderSVGText(SVGTextElement* node) : RenderSVGBlock(node) , m_needsReordering(false) - , m_needsPositioningValuesUpdate(true) + , m_needsPositioningValuesUpdate(false) , m_needsTransformUpdate(true) - , m_needsTextMetricsUpdate(true) + , m_needsTextMetricsUpdate(false) { } +RenderSVGText::~RenderSVGText() +{ + ASSERT(m_layoutAttributes.isEmpty()); +} + bool RenderSVGText::isChildAllowed(RenderObject* child, RenderStyle*) const { return child->isInline(); @@ -110,29 +115,19 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } -void RenderSVGText::subtreeChildAdded(RenderObject* child) +static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes) { - ASSERT(child); - if (m_needsPositioningValuesUpdate) - return; - - // The positioning elements cache doesn't include the new 'child' yet. Clear the - // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it. - invalidateTextPositioningElements(); - - FontCachePurgePreventer fontCachePurgePreventer; - for (RenderObject* descendant = child; descendant; descendant = descendant->nextInPreOrder(child)) { + for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { if (descendant->isSVGInlineText()) - m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(descendant)); + attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes()); } - - rebuildLayoutAttributes(); } static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) { ASSERT(start); ASSERT(locateElement); + // FIXME: Make this iterative. for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { if (child->isSVGInlineText()) { RenderSVGInlineText* text = toRenderSVGInlineText(child); @@ -160,53 +155,70 @@ static inline bool findPreviousAndNextAttributes(RenderObject* start, RenderSVGI return false; } -void RenderSVGText::subtreeChildWillBeDestroyed(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*>& affectedAttributes) +inline bool RenderSVGText::shouldHandleSubtreeMutations() const { - ASSERT(text); - - // The positioning elements cache depends on the size of each text renderer in the - // subtree. If this changes, clear the cache. It's going to be rebuilt below. - invalidateTextPositioningElements(); + if (beingDestroyed() || !everHadLayout()) { + ASSERT(m_layoutAttributes.isEmpty()); + ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements()); + return false; + } + return true; +} - if (m_needsPositioningValuesUpdate) +void RenderSVGText::subtreeChildWasAdded(RenderObject* child) +{ + ASSERT(child); + if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; - // This logic requires that the 'text' child is still inserted in the tree. - bool stopAfterNext = false; - SVGTextLayoutAttributes* previous = 0; - SVGTextLayoutAttributes* next = 0; - findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); - if (previous) - affectedAttributes.append(previous); - if (next) - affectedAttributes.append(next); - - SVGTextLayoutAttributes* currentLayoutAttributes = text->layoutAttributes(); - - size_t position = m_layoutAttributes.find(currentLayoutAttributes); - ASSERT(position != notFound); - m_layoutAttributes.remove(position); + // The positioning elements cache doesn't include the new 'child' yet. Clear the + // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it. + m_layoutAttributesBuilder.clearTextPositioningElements(); - ASSERT(!m_layoutAttributes.contains(currentLayoutAttributes)); -} + // Detect changes in layout attributes and only measure those text parts that have changed! + Vector<SVGTextLayoutAttributes*> newLayoutAttributes; + collectLayoutAttributes(this, newLayoutAttributes); + if (newLayoutAttributes.isEmpty()) { + ASSERT(m_layoutAttributes.isEmpty()); + return; + } -static inline void recursiveCollectLayoutAttributes(RenderObject* start, Vector<SVGTextLayoutAttributes*>& attributes) -{ - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - attributes.append(toRenderSVGInlineText(child)->layoutAttributes()); - continue; + // Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added. + size_t size = newLayoutAttributes.size(); + SVGTextLayoutAttributes* attributes = 0; + for (size_t i = 0; i < size; ++i) { + attributes = newLayoutAttributes[i]; + if (m_layoutAttributes.find(attributes) == notFound) { + // Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes. + bool stopAfterNext = false; + SVGTextLayoutAttributes* previous = 0; + SVGTextLayoutAttributes* next = 0; + ASSERT_UNUSED(child, attributes->context() == child); + findPreviousAndNextAttributes(this, attributes->context(), stopAfterNext, previous, next); + + if (previous) + m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context()); + m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context()); + if (next) + m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context()); + break; } - - recursiveCollectLayoutAttributes(child, attributes); } + +#ifndef NDEBUG + // Verify that m_layoutAttributes only differs by a maximum of one entry. + for (size_t i = 0; i < size; ++i) + ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes); +#endif + + m_layoutAttributes = newLayoutAttributes; } static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector<SVGTextLayoutAttributes*>& expectedLayoutAttributes) { #ifndef NDEBUG Vector<SVGTextLayoutAttributes*> newLayoutAttributes; - recursiveCollectLayoutAttributes(text, newLayoutAttributes); + collectLayoutAttributes(text, newLayoutAttributes); ASSERT(newLayoutAttributes == expectedLayoutAttributes); #else UNUSED_PARAM(text); @@ -214,24 +226,67 @@ static inline void checkLayoutAttributesConsistency(RenderSVGText* text, Vector< #endif } -void RenderSVGText::subtreeChildWasDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes) +void RenderSVGText::willBeDestroyed() { - if (documentBeingDestroyed() || affectedAttributes.isEmpty()) + m_layoutAttributes.clear(); + m_layoutAttributesBuilder.clearTextPositioningElements(); + + RenderSVGBlock::willBeDestroyed(); +} + +void RenderSVGText::subtreeChildWillBeRemoved(RenderSVGInlineText* text, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) +{ + ASSERT(text); + if (!shouldHandleSubtreeMutations()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); - size_t size = affectedAttributes.size(); - for (size_t i = 0; i < size; ++i) - m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttributes[i]->context()); + // The positioning elements cache depends on the size of each text renderer in the + // subtree. If this changes, clear the cache. It's going to be rebuilt below. + m_layoutAttributesBuilder.clearTextPositioningElements(); + if (m_layoutAttributes.isEmpty()) + return; + + // This logic requires that the 'text' child is still inserted in the tree. + bool stopAfterNext = false; + SVGTextLayoutAttributes* previous = 0; + SVGTextLayoutAttributes* next = 0; + if (!documentBeingDestroyed()) + findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); + + if (previous) + affectedAttributes.append(previous); + if (next) + affectedAttributes.append(next); + + size_t position = m_layoutAttributes.find(text->layoutAttributes()); + ASSERT(position != notFound); + m_layoutAttributes.remove(position); } -void RenderSVGText::subtreeStyleChanged(RenderSVGInlineText* text) +void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) +{ + if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) { + ASSERT(affectedAttributes.isEmpty()); + return; + } + + // This is called immediately after subtreeChildWillBeDestroyed, once the RenderSVGInlineText::willBeDestroyed() method + // passes on to the base class, which removes us from the render tree. At this point we can update the layout attributes. + unsigned size = affectedAttributes.size(); + for (unsigned i = 0; i < size; ++i) + m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(affectedAttributes[i]->context()); +} + +void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) { ASSERT(text); - if (m_needsPositioningValuesUpdate) + if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) return; + checkLayoutAttributesConsistency(this, m_layoutAttributes); + // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. FontCachePurgePreventer fontCachePurgePreventer; @@ -241,31 +296,37 @@ void RenderSVGText::subtreeStyleChanged(RenderSVGInlineText* text) } } -void RenderSVGText::subtreeTextChanged(RenderSVGInlineText* text) +void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text) { ASSERT(text); + ASSERT(!beingDestroyed()); + if (!everHadLayout()) { + ASSERT(m_layoutAttributes.isEmpty()); + ASSERT(!m_layoutAttributesBuilder.numberOfTextPositioningElements()); + return; + } // The positioning elements cache depends on the size of each text renderer in the // subtree. If this changes, clear the cache. It's going to be rebuilt below. - invalidateTextPositioningElements(); - - if (m_needsPositioningValuesUpdate) - return; + m_layoutAttributesBuilder.clearTextPositioningElements(); - FontCachePurgePreventer fontCachePurgePreventer; + checkLayoutAttributesConsistency(this, m_layoutAttributes); for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { if (descendant->isSVGInlineText()) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(descendant)); } } -void RenderSVGText::invalidateTextPositioningElements() +static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0) { - // Clear the text positioning elements. This should be called when either the children - // of a DOM text element have changed, or the length of the text in any child element - // has changed. Failure to clear may leave us with invalid elements, as other code paths - // do not always cause the position elements to be marked invalid before use. - m_layoutAttributesBuilder.clearTextPositioningElements(); + for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) { + if (!descendant->isSVGInlineText()) + continue; + RenderSVGInlineText* text = toRenderSVGInlineText(descendant); + text->updateScaledFont(); + if (builder) + builder->rebuildMetricsForTextRenderer(text); + } } void RenderSVGText::layout() @@ -281,27 +342,43 @@ void RenderSVGText::layout() updateCachedBoundariesInParents = true; } - // If the root layout size changed (eg. window size changes) or the positioning values change - // or the transform to the root context has changed then recompute the on-screen font size. - if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { - for (RenderObject* descendant = this; descendant; descendant = descendant->nextInPreOrder(this)) { - if (descendant->isSVGInlineText()) - toRenderSVGInlineText(descendant)->updateScaledFont(); - } + if (!everHadLayout()) { + // When laying out initially, collect all layout attributes, build the character data map, + // and propogate resulting SVGLayoutAttributes to all RenderSVGInlineText children in the subtree. + ASSERT(m_layoutAttributes.isEmpty()); + collectLayoutAttributes(this, m_layoutAttributes); + updateFontInAllDescendants(this); + m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); - rebuildAllLayoutAttributes(); - updateCachedBoundariesInParents = true; + m_needsReordering = true; m_needsTextMetricsUpdate = false; - } + m_needsPositioningValuesUpdate = false; + updateCachedBoundariesInParents = true; + } else if (m_needsPositioningValuesUpdate) { + // When the x/y/dx/dy/rotate lists change, recompute the layout attributes, and eventually + // update the on-screen font objects as well in all descendants. + if (m_needsTextMetricsUpdate) { + updateFontInAllDescendants(this); + m_needsTextMetricsUpdate = false; + } - if (m_needsPositioningValuesUpdate) { - // Perform SVG text layout phase one (see SVGTextLayoutAttributesBuilder for details). - m_layoutAttributesBuilder.buildLayoutAttributesForWholeTree(this); + m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; + } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(this)->isLayoutSizeChanged()) { + // If the root layout size changed (eg. window size changes) or the transform to the root + // context has changed then recompute the on-screen font size. + updateFontInAllDescendants(this, &m_layoutAttributesBuilder); + + ASSERT(!m_needsReordering); + ASSERT(!m_needsPositioningValuesUpdate); + m_needsTextMetricsUpdate = false; + updateCachedBoundariesInParents = true; } + checkLayoutAttributesConsistency(this, m_layoutAttributes); + // Reduced version of RenderBlock::layoutBlock(), which only takes care of SVG text. // All if branches that could cause early exit in RenderBlocks layoutBlock() method are turned into assertions. ASSERT(!isInline()); @@ -437,7 +514,21 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild) { RenderSVGBlock::addChild(child, beforeChild); - subtreeChildAdded(child); + subtreeChildWasAdded(child); +} + +void RenderSVGText::removeChild(RenderObject* child) +{ + if (!child->isSVGInlineText()) { + RenderSVGBlock::removeChild(child); + return; + } + + RenderSVGInlineText* text = toRenderSVGInlineText(child); + Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; + subtreeChildWillBeRemoved(text, affectedAttributes); + RenderSVGBlock::removeChild(child); + subtreeChildWasRemoved(affectedAttributes); } // Fix for <rdar://problem/8048875>. We should not render :first-line CSS Style @@ -453,42 +544,6 @@ void RenderSVGText::updateFirstLetter() { } -void RenderSVGText::rebuildAllLayoutAttributes() -{ - m_layoutAttributes.clear(); - recursiveCollectLayoutAttributes(this, m_layoutAttributes); - if (m_layoutAttributes.isEmpty()) - return; - - m_layoutAttributesBuilder.rebuildMetricsForWholeTree(this); -} - -void RenderSVGText::rebuildLayoutAttributes() -{ - if (m_layoutAttributes.isEmpty()) { - rebuildAllLayoutAttributes(); - return; - } - - // Detect changes in layout attributes and only measure those text parts that have changed! - Vector<SVGTextLayoutAttributes*> newLayoutAttributes; - recursiveCollectLayoutAttributes(this, newLayoutAttributes); - if (newLayoutAttributes.isEmpty()) { - m_layoutAttributes.clear(); - return; - } - - // Compare m_layoutAttributes with newLayoutAttributes to figure out which attributes got added. - size_t size = newLayoutAttributes.size(); - for (size_t i = 0; i < size; ++i) { - SVGTextLayoutAttributes* attributes = newLayoutAttributes[i]; - if (m_layoutAttributes.find(attributes) == notFound) - m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->context()); - } - - m_layoutAttributes = newLayoutAttributes; -} - } #endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 23a0b6a9a..ee7b3d027 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -36,6 +36,7 @@ class RenderSVGInlineText; class RenderSVGText : public RenderSVGBlock { public: RenderSVGText(SVGTextElement*); + virtual ~RenderSVGText(); virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; @@ -50,15 +51,11 @@ public: bool needsReordering() const { return m_needsReordering; } Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; } - void subtreeChildAdded(RenderObject*); - void subtreeChildWillBeDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes); - void subtreeChildWasDestroyed(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*>& affectedAttributes); - void subtreeStyleChanged(RenderSVGInlineText*); - void subtreeTextChanged(RenderSVGInlineText*); - - // Call this method when either the children of a DOM text element have changed, or the length of - // the text in any child element has changed. - void invalidateTextPositioningElements(); + void subtreeChildWasAdded(RenderObject*); + void subtreeChildWillBeRemoved(RenderSVGInlineText*, Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); + void subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes); + void subtreeStyleDidChange(RenderSVGInlineText*); + void subtreeTextDidChange(RenderSVGInlineText*); private: virtual const char* renderName() const { return "RenderSVGText"; } @@ -80,6 +77,8 @@ private: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); + virtual void removeChild(RenderObject*) OVERRIDE; + virtual void willBeDestroyed() OVERRIDE; virtual FloatRect objectBoundingBox() const { return frameRect(); } virtual FloatRect strokeBoundingBox() const; @@ -91,8 +90,7 @@ private: virtual RenderBlock* firstLineBlock() const; virtual void updateFirstLetter(); - void rebuildAllLayoutAttributes(); - void rebuildLayoutAttributes(); + bool shouldHandleSubtreeMutations() const; bool m_needsReordering : 1; bool m_needsPositioningValuesUpdate : 1; diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp index b206cb6c2..ddc7c9155 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -197,8 +197,10 @@ void SVGRenderSupport::layoutChildren(RenderObject* start, bool selfNeedsLayout) // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object if (child->isSVGShape()) toRenderSVGShape(child)->setNeedsShapeUpdate(); - else if (child->isSVGText()) + else if (child->isSVGText()) { + toRenderSVGText(child)->setNeedsTextMetricsUpdate(); toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); + } needsLayout = true; } diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp index 067bf6bb9..be2a12fe9 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp @@ -41,41 +41,27 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(Render if (!textRoot) return; - if (!buildLayoutAttributesIfNeeded(textRoot)) - return; - - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); -} + if (m_textPositions.isEmpty()) { + m_characterDataMap.clear(); -void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForWholeTree(RenderSVGText* textRoot) -{ - ASSERT(textRoot); + m_textLength = 0; + const UChar* lastCharacter = 0; + collectTextPositioningElements(textRoot, lastCharacter); - if (!buildLayoutAttributesIfNeeded(textRoot)) - return; + if (!m_textLength) + return; - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); -} + buildCharacterDataMap(textRoot); + } -void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text) -{ - ASSERT(text); - m_metricsBuilder.measureTextRenderer(text); + m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, text, m_characterDataMap); } -void SVGTextLayoutAttributesBuilder::rebuildMetricsForWholeTree(RenderSVGText* textRoot) +bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText* textRoot) { ASSERT(textRoot); - Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes(); - - size_t layoutAttributesSize = layoutAttributes.size(); - for (size_t i = 0; i < layoutAttributesSize; ++i) - m_metricsBuilder.measureTextRenderer(layoutAttributes[i]->context()); -} -bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded(RenderSVGText* textRoot) -{ - ASSERT(textRoot); + m_characterDataMap.clear(); if (m_textPositions.isEmpty()) { m_textLength = 0; @@ -83,14 +69,20 @@ bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesIfNeeded(RenderSVGText collectTextPositioningElements(textRoot, lastCharacter); } - m_characterDataMap.clear(); if (!m_textLength) return false; - buildLayoutAttributes(textRoot); + buildCharacterDataMap(textRoot); + m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); return true; } +void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text) +{ + ASSERT(text); + m_metricsBuilder.measureTextRenderer(text); +} + static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, const UChar*& lastCharacter) { if (text->style()->whiteSpace() == PRE) { @@ -140,10 +132,8 @@ void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject } } -void SVGTextLayoutAttributesBuilder::buildLayoutAttributes(RenderSVGText* textRoot) +void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRoot) { - ASSERT(m_textLength); - SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot); ASSERT(outermostTextElement); diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h index 45fad2400..7dac96f4d 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h @@ -43,14 +43,14 @@ class SVGTextLayoutAttributesBuilder { WTF_MAKE_NONCOPYABLE(SVGTextLayoutAttributesBuilder); public: SVGTextLayoutAttributesBuilder(); - void buildLayoutAttributesForWholeTree(RenderSVGText*); + bool buildLayoutAttributesForForSubtree(RenderSVGText*); void buildLayoutAttributesForTextRenderer(RenderSVGInlineText*); - void rebuildMetricsForWholeTree(RenderSVGText*); void rebuildMetricsForTextRenderer(RenderSVGInlineText*); // Invoked whenever the underlying DOM tree changes, so that m_textPositions is rebuild. void clearTextPositioningElements() { m_textPositions.clear(); } + unsigned numberOfTextPositioningElements() const { return m_textPositions.size(); } private: struct TextPosition { @@ -66,9 +66,8 @@ private: unsigned length; }; - bool buildLayoutAttributesIfNeeded(RenderSVGText*); + void buildCharacterDataMap(RenderSVGText*); void collectTextPositioningElements(RenderObject*, const UChar*& lastCharacter); - void buildLayoutAttributes(RenderSVGText*); void fillCharacterDataMap(const TextPosition&); private: diff --git a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp index c94f0c74a..81fc325a1 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp @@ -48,7 +48,7 @@ bool SVGTextMetricsBuilder::advance() if (int(m_textPosition) >= m_run.charactersLength()) return false; -#if PLATFORM(QT) +#if PLATFORM(QT) && !HAVE(QRAWFONT) advanceComplexText(); #else if (m_isComplexText) @@ -62,7 +62,7 @@ bool SVGTextMetricsBuilder::advance() void SVGTextMetricsBuilder::advanceSimpleText() { -#if PLATFORM(QT) +#if PLATFORM(QT) && !HAVE(QRAWFONT) ASSERT_NOT_REACHED(); #else unsigned metricsLength = m_simpleWidthIterator->advance(m_textPosition + 1); @@ -115,7 +115,7 @@ void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlin m_run = SVGTextMetrics::constructTextRun(text, text->characters(), 0, text->textLength()); m_isComplexText = scaledFont.codePath(m_run) == Font::Complex; -#if !PLATFORM(QT) +#if !PLATFORM(QT) || HAVE(QRAWFONT) if (m_isComplexText) m_simpleWidthIterator.clear(); else |