diff options
| author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-27 21:51:42 +0200 |
|---|---|---|
| committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-05-27 21:51:42 +0200 |
| commit | be01689f43cf6882cf670d33df49ead1f570c53a (patch) | |
| tree | 4bb2161d8983b38e3e7ed37b4a50303bfd5e2e85 /Source/WebCore/rendering | |
| parent | a89b2ebb8e192c5e8cea21079bda2ee2c0c7dddd (diff) | |
| download | qtwebkit-be01689f43cf6882cf670d33df49ead1f570c53a.tar.gz | |
Imported WebKit commit 8d6c5efc74f0222dfc7bcce8d845d4a2707ed9e6 (http://svn.webkit.org/repository/webkit/trunk@118629)
Diffstat (limited to 'Source/WebCore/rendering')
52 files changed, 939 insertions, 296 deletions
diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 15867e1c6..e6a73d9a4 100755 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -2015,16 +2015,6 @@ LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); } - - // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now - // overhang from the previous sibling are added to our parent - RenderObject* prev = child->previousSibling(); - if (prev && prev->isRenderBlock()) { - RenderBlock* block = toRenderBlock(prev); - if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTop) - addOverhangingFloats(block, false); - } - return logicalTop; } diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index 565e3c96b..04ff3dbe3 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -44,6 +44,7 @@ #include "RenderBoxRegionInfo.h" #include "RenderFlexibleBox.h" #include "RenderFlowThread.h" +#include "RenderGeometryMap.h" #include "RenderInline.h" #include "RenderLayer.h" #include "RenderPart.h" @@ -437,6 +438,7 @@ void RenderBox::updateLayerTransform() IntRect RenderBox::absoluteContentBox() const { + // This is wrong with transforms and flipped writing modes. IntRect rect = pixelSnappedIntRect(contentBoxRect()); FloatPoint absPos = localToAbsolute(FloatPoint()); rect.move(absPos.x(), absPos.y()); @@ -1315,6 +1317,46 @@ void RenderBox::mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed); } +const RenderObject* RenderBox::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + ASSERT(ancestorToStopAt != this); + + bool ancestorSkipped; + RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped); + if (!container) + return 0; + + bool isFixedPos = style()->position() == FixedPosition; + bool hasTransform = hasLayer() && layer()->transform(); + + LayoutSize adjustmentForSkippedAncestor; + if (ancestorSkipped) { + // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe + // to just subtract the delta between the ancestor and o. + adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container); + } + + bool offsetDependsOnPoint = false; + LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); + + if (container->isRenderFlowThread()) + offsetDependsOnPoint = true; + + bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); + if (shouldUseTransformFromContainer(container)) { + TransformationMatrix t; + getTransformFromContainer(container, containerOffset, t); + t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); + + geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); + } else { + containerOffset += adjustmentForSkippedAncestor; + geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform); + } + + return ancestorSkipped ? ancestorToStopAt : container; +} + void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { // We don't expect absoluteToLocal() to be called during layout (yet) @@ -1332,7 +1374,7 @@ void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, Transfor RenderBoxModelObject::mapAbsoluteToLocalPoint(fixed, useTransforms, transformState); } -LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point) const +LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(o == container()); @@ -1350,6 +1392,9 @@ LayoutSize RenderBox::offsetFromContainer(RenderObject* o, const LayoutPoint& po offset = toLayoutSize(block->flipForWritingModeIncludingColumns(toLayoutPoint(offset))); o->adjustForColumns(offset, columnPoint); offset = block->flipForWritingMode(offset); + + if (offsetDependsOnPoint) + *offsetDependsOnPoint = true; } else offset += topLeftLocationOffset(); } @@ -3766,7 +3811,7 @@ LayoutRect RenderBox::layoutOverflowRectForPropagation(RenderStyle* parentStyle) rect = layer()->currentTransform().mapRect(rect); if (isRelPositioned()) - rect.move(relativePositionOffsetX(), relativePositionOffsetY()); + rect.move(relativePositionOffset()); // Now we need to flip back. flipForWritingMode(rect); diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index 9ff60e672..c3696ab8d 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -276,7 +276,7 @@ public: void setOverrideWidth(LayoutUnit); void clearOverrideSize(); - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const; + virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; LayoutUnit computeBorderBoxLogicalWidth(LayoutUnit width) const; LayoutUnit computeBorderBoxLogicalHeight(LayoutUnit height) const; @@ -519,6 +519,7 @@ protected: virtual bool shouldComputeSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject*, RenderGeometryMap&) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; void paintRootBoxFillLayers(const PaintInfo&); diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index f5b6500e5..1625f075b 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -345,10 +345,6 @@ void RenderBoxModelObject::destroyLayer() void RenderBoxModelObject::willBeDestroyed() { - // This must be done before we destroy the RenderObject. - if (m_layer) - m_layer->clearClipRects(); - // A continuation of this RenderObject should be destroyed at subclasses. ASSERT(!continuation()); @@ -463,48 +459,41 @@ void RenderBoxModelObject::updateBoxModelInfoFromStyle() setHorizontalWritingMode(styleToUse->isHorizontalWritingMode()); } -enum RelPosAxis { RelPosX, RelPosY }; - -static LayoutUnit accumulateRelativePositionOffsets(const RenderObject* child, RelPosAxis axis) +static LayoutSize accumulateRelativePositionOffsets(const RenderObject* child) { if (!child->isAnonymousBlock() || !child->isRelPositioned()) - return 0; - LayoutUnit offset = ZERO_LAYOUT_UNIT; + return LayoutSize(); + LayoutSize offset; RenderObject* p = toRenderBlock(child)->inlineElementContinuation(); while (p && p->isRenderInline()) { - if (p->isRelPositioned()) - offset += (axis == RelPosX) ? toRenderInline(p)->relativePositionOffsetX() : toRenderInline(p)->relativePositionOffsetY(); + if (p->isRelPositioned()) { + RenderInline* renderInline = toRenderInline(p); + offset += renderInline->relativePositionOffset(); + } p = p->parent(); } return offset; } -LayoutUnit RenderBoxModelObject::relativePositionOffsetX() const +LayoutSize RenderBoxModelObject::relativePositionOffset() const { - LayoutUnit offset = accumulateRelativePositionOffsets(this, RelPosX); + LayoutSize offset = accumulateRelativePositionOffsets(this); + + RenderBlock* containingBlock = this->containingBlock(); // Objects that shrink to avoid floats normally use available line width when computing containing block width. However // in the case of relative positioning using percentages, we can't do this. The offset should always be resolved using the // available width of the containing block. Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly // call availableWidth on our containing block. if (!style()->left().isAuto()) { - RenderBlock* cb = containingBlock(); - if (!style()->right().isAuto() && !cb->style()->isLeftToRightDirection()) - return -valueForLength(style()->right(), cb->availableWidth(), view()); - return offset + valueForLength(style()->left(), cb->availableWidth(), view()); - } - if (!style()->right().isAuto()) { - RenderBlock* cb = containingBlock(); - return offset + -valueForLength(style()->right(), cb->availableWidth(), view()); + if (!style()->right().isAuto() && !containingBlock->style()->isLeftToRightDirection()) + offset.setWidth(-valueForLength(style()->right(), containingBlock->availableWidth(), view())); + else + offset.expand(valueForLength(style()->left(), containingBlock->availableWidth(), view()), 0); + } else if (!style()->right().isAuto()) { + offset.expand(-valueForLength(style()->right(), containingBlock->availableWidth(), view()), 0); } - return offset; -} -LayoutUnit RenderBoxModelObject::relativePositionOffsetY() const -{ - LayoutUnit offset = accumulateRelativePositionOffsets(this, RelPosY); - - RenderBlock* containingBlock = this->containingBlock(); // If the containing block of a relatively positioned element does not // specify a height, a percentage top or bottom offset should be resolved as // auto. An exception to this is if the containing block has the WinIE quirk @@ -515,13 +504,13 @@ LayoutUnit RenderBoxModelObject::relativePositionOffsetY() const && (!containingBlock->style()->height().isAuto() || !style()->top().isPercent() || containingBlock->stretchesToViewport())) - return offset + valueForLength(style()->top(), containingBlock->availableHeight(), view()); + offset.expand(0, valueForLength(style()->top(), containingBlock->availableHeight(), view())); - if (!style()->bottom().isAuto() + else if (!style()->bottom().isAuto() && (!containingBlock->style()->height().isAuto() || !style()->bottom().isPercent() || containingBlock->stretchesToViewport())) - return offset + -valueForLength(style()->bottom(), containingBlock->availableHeight(), view()); + offset.expand(0, -valueForLength(style()->bottom(), containingBlock->availableHeight(), view())); return offset; } diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index b145e6f71..5e2f26b5b 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -58,9 +58,7 @@ public: RenderBoxModelObject(Node*); virtual ~RenderBoxModelObject(); - LayoutUnit relativePositionOffsetX() const; - LayoutUnit relativePositionOffsetY() const; - LayoutSize relativePositionOffset() const { return LayoutSize(relativePositionOffsetX(), relativePositionOffsetY()); } + LayoutSize relativePositionOffset() const; LayoutSize relativePositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? relativePositionOffset() : relativePositionOffset().transposedSize(); } // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) diff --git a/Source/WebCore/rendering/RenderFlexibleBox.cpp b/Source/WebCore/rendering/RenderFlexibleBox.cpp index 2feab4f75..8f0997b85 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderFlexibleBox.cpp @@ -35,6 +35,7 @@ #include "RenderLayer.h" #include "RenderView.h" #include <limits> +#include <wtf/MathExtras.h> namespace WebCore { @@ -593,7 +594,7 @@ LayoutUnit RenderFlexibleBox::preferredMainAxisContentExtentForChild(RenderBox* LayoutUnit mainAxisExtent = hasOrthogonalFlow(child) ? child->logicalHeight() : child->maxPreferredLogicalWidth(); return mainAxisExtent - mainAxisBorderAndPaddingExtentForChild(child); } - return minimumValueForLength(mainAxisLength, mainAxisContentExtent(), view()); + return std::max(LayoutUnit(0), minimumValueForLength(mainAxisLength, mainAxisContentExtent(), view())); } LayoutUnit RenderFlexibleBox::computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent) @@ -624,17 +625,17 @@ void RenderFlexibleBox::layoutFlexItems(FlexOrderIterator& iterator, WTF::Vector OrderedFlexItemList orderedChildren; LayoutUnit preferredMainAxisExtent; float totalPositiveFlexibility; - float totalNegativeFlexibility; + float totalWeightedNegativeFlexibility; LayoutUnit minMaxAppliedMainAxisExtent; LayoutUnit crossAxisOffset = flowAwareBorderBefore() + flowAwarePaddingBefore(); - while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalNegativeFlexibility, minMaxAppliedMainAxisExtent)) { + while (computeNextFlexLine(iterator, orderedChildren, preferredMainAxisExtent, totalPositiveFlexibility, totalWeightedNegativeFlexibility, minMaxAppliedMainAxisExtent)) { LayoutUnit availableFreeSpace = computeAvailableFreeSpace(preferredMainAxisExtent); FlexSign flexSign = (minMaxAppliedMainAxisExtent < preferredMainAxisExtent + availableFreeSpace) ? PositiveFlexibility : NegativeFlexibility; InflexibleFlexItemSize inflexibleItems; WTF::Vector<LayoutUnit> childSizes; - while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems, childSizes)) { - ASSERT(totalPositiveFlexibility >= 0 && totalNegativeFlexibility >= 0); + while (!resolveFlexibleLengths(flexSign, orderedChildren, availableFreeSpace, totalPositiveFlexibility, totalWeightedNegativeFlexibility, inflexibleItems, childSizes)) { + ASSERT(totalPositiveFlexibility >= 0 && totalWeightedNegativeFlexibility >= 0); ASSERT(inflexibleItems.size() > 0); } @@ -800,11 +801,11 @@ LayoutUnit RenderFlexibleBox::adjustChildSizeForMinAndMax(RenderBox* child, Layo return childSize; } -bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent) +bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent) { orderedChildren.clear(); preferredMainAxisExtent = 0; - totalPositiveFlexibility = totalNegativeFlexibility = 0; + totalPositiveFlexibility = totalWeightedNegativeFlexibility = 0; minMaxAppliedMainAxisExtent = 0; if (!iterator.currentChild()) @@ -828,7 +829,7 @@ bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, Ordered orderedChildren.append(child); preferredMainAxisExtent += childMainAxisMarginBoxExtent; totalPositiveFlexibility += child->style()->positiveFlex(); - totalNegativeFlexibility += child->style()->negativeFlex(); + totalWeightedNegativeFlexibility += child->style()->negativeFlex() * childMainAxisExtent; LayoutUnit childMinMaxAppliedMainAxisExtent = adjustChildSizeForMinAndMax(child, childMainAxisExtent, flexboxAvailableContentExtent); minMaxAppliedMainAxisExtent += childMinMaxAppliedMainAxisExtent - childMainAxisExtent + childMainAxisMarginBoxExtent; @@ -836,20 +837,21 @@ bool RenderFlexibleBox::computeNextFlexLine(FlexOrderIterator& iterator, Ordered return true; } -void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems) +void RenderFlexibleBox::freezeViolations(const WTF::Vector<Violation>& violations, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems) { for (size_t i = 0; i < violations.size(); ++i) { RenderBox* child = violations[i].child; LayoutUnit childSize = violations[i].childSize; - availableFreeSpace -= childSize - preferredMainAxisContentExtentForChild(child); + LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child); + availableFreeSpace -= childSize - preferredChildSize; totalPositiveFlexibility -= child->style()->positiveFlex(); - totalNegativeFlexibility -= child->style()->negativeFlex(); + totalWeightedNegativeFlexibility -= child->style()->negativeFlex() * preferredChildSize; inflexibleItems.set(child, childSize); } } // Returns true if we successfully ran the algorithm and sized the flex items. -bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes) +bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedFlexItemList& children, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, InflexibleFlexItemSize& inflexibleItems, WTF::Vector<LayoutUnit>& childSizes) { childSizes.clear(); LayoutUnit flexboxAvailableContentExtent = mainAxisContentExtent(); @@ -869,10 +871,10 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF else { LayoutUnit preferredChildSize = preferredMainAxisContentExtentForChild(child); LayoutUnit childSize = preferredChildSize; - if (availableFreeSpace > 0 && totalPositiveFlexibility > 0 && flexSign == PositiveFlexibility) + if (availableFreeSpace > 0 && totalPositiveFlexibility > 0 && flexSign == PositiveFlexibility && isfinite(totalPositiveFlexibility)) childSize += lroundf(availableFreeSpace * child->style()->positiveFlex() / totalPositiveFlexibility); - else if (availableFreeSpace < 0 && totalNegativeFlexibility > 0 && flexSign == NegativeFlexibility) - childSize += lroundf(availableFreeSpace * child->style()->negativeFlex() / totalNegativeFlexibility); + else if (availableFreeSpace < 0 && totalWeightedNegativeFlexibility > 0 && flexSign == NegativeFlexibility && isfinite(totalWeightedNegativeFlexibility)) + childSize += lroundf(availableFreeSpace * child->style()->negativeFlex() * preferredChildSize / totalWeightedNegativeFlexibility); LayoutUnit adjustedChildSize = adjustChildSizeForMinAndMax(child, childSize, flexboxAvailableContentExtent); childSizes.append(adjustedChildSize); @@ -888,7 +890,7 @@ bool RenderFlexibleBox::resolveFlexibleLengths(FlexSign flexSign, const OrderedF } if (totalViolation) - freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalPositiveFlexibility, totalNegativeFlexibility, inflexibleItems); + freezeViolations(totalViolation < 0 ? maxViolations : minViolations, availableFreeSpace, totalPositiveFlexibility, totalWeightedNegativeFlexibility, inflexibleItems); else availableFreeSpace -= usedFreeSpace; diff --git a/Source/WebCore/rendering/RenderFlexibleBox.h b/Source/WebCore/rendering/RenderFlexibleBox.h index 8383a46b8..ae61d631f 100644 --- a/Source/WebCore/rendering/RenderFlexibleBox.h +++ b/Source/WebCore/rendering/RenderFlexibleBox.h @@ -113,11 +113,11 @@ private: void computeMainAxisPreferredSizes(bool relayoutChildren, FlexOrderHashSet&); LayoutUnit lineBreakLength(); LayoutUnit adjustChildSizeForMinAndMax(RenderBox*, LayoutUnit childSize, LayoutUnit flexboxAvailableContentExtent); - bool computeNextFlexLine(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent); + bool computeNextFlexLine(FlexOrderIterator&, OrderedFlexItemList& orderedChildren, LayoutUnit& preferredMainAxisExtent, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, LayoutUnit& minMaxAppliedMainAxisExtent); LayoutUnit computeAvailableFreeSpace(LayoutUnit preferredMainAxisExtent); - bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes); - void freezeViolations(const WTF::Vector<Violation>&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalNegativeFlexibility, InflexibleFlexItemSize&); + bool resolveFlexibleLengths(FlexSign, const OrderedFlexItemList&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, InflexibleFlexItemSize&, WTF::Vector<LayoutUnit>& childSizes); + void freezeViolations(const WTF::Vector<Violation>&, LayoutUnit& availableFreeSpace, float& totalPositiveFlexibility, float& totalWeightedNegativeFlexibility, InflexibleFlexItemSize&); void setLogicalOverrideSize(RenderBox* child, LayoutUnit childPreferredSize); void prepareChildForPositionedLayout(RenderBox* child, LayoutUnit mainAxisOffset, LayoutUnit crossAxisOffset); diff --git a/Source/WebCore/rendering/RenderGeometryMap.cpp b/Source/WebCore/rendering/RenderGeometryMap.cpp new file mode 100644 index 000000000..65f189bb1 --- /dev/null +++ b/Source/WebCore/rendering/RenderGeometryMap.cpp @@ -0,0 +1,270 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "RenderGeometryMap.h" + +#include "RenderView.h" +#include "TransformState.h" + +namespace WebCore { + + +// Stores data about how to map from one renderer to its container. +class RenderGeometryMapStep { + WTF_MAKE_NONCOPYABLE(RenderGeometryMapStep); +public: + RenderGeometryMapStep(const RenderObject* renderer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform) + : m_renderer(renderer) + , m_accumulatingTransform(accumulatingTransform) + , m_isNonUniform(isNonUniform) + , m_isFixedPosition(isFixedPosition) + , m_hasTransform(hasTransform) + { + } + + FloatPoint mapPoint(const FloatPoint& p) const + { + if (!m_transform) + return p + m_offset; + + return m_transform->mapPoint(p); + } + + FloatQuad mapQuad(const FloatQuad& quad) const + { + if (!m_transform) { + FloatQuad q = quad; + q.move(m_offset); + return q; + } + + return m_transform->mapQuad(quad); + } + + const RenderObject* m_renderer; + LayoutSize m_offset; + OwnPtr<TransformationMatrix> m_transform; // Includes offset if non-null. + bool m_accumulatingTransform; + bool m_isNonUniform; // Mapping depends on the input point, e.g. because of CSS columns. + bool m_isFixedPosition; + bool m_hasTransform; +}; + + +RenderGeometryMap::RenderGeometryMap() + : m_insertionPosition(notFound) + , m_nonUniformStepsCount(0) + , m_transformedStepsCount(0) + , m_fixedStepsCount(0) +{ +} + +RenderGeometryMap::~RenderGeometryMap() +{ +} + +FloatPoint RenderGeometryMap::absolutePoint(const FloatPoint& p) const +{ + FloatPoint result; + + if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) + result = p + m_accumulatedOffset; + else { + TransformState transformState(TransformState::ApplyTransformDirection, p); + mapToAbsolute(transformState); + result = transformState.lastPlanarPoint(); + } + +#if !ASSERT_DISABLED + FloatPoint rendererMappedResult = m_mapping.last()->m_renderer->localToAbsolute(p, false, true); + ASSERT(rendererMappedResult == result); +#endif + + return result; +} + +FloatRect RenderGeometryMap::absoluteRect(const FloatRect& rect) const +{ + FloatRect result; + + if (!hasFixedPositionStep() && !hasTransformStep() && !hasNonUniformStep()) { + result = rect; + result.move(m_accumulatedOffset); + } else { + TransformState transformState(TransformState::ApplyTransformDirection, rect.center(), rect); + mapToAbsolute(transformState); + result = transformState.lastPlanarQuad().boundingBox(); + } + +#if !ASSERT_DISABLED + FloatRect rendererMappedResult = m_mapping.last()->m_renderer->localToAbsoluteQuad(rect).boundingBox(); + // Inspector creates renderers with negative width <https://bugs.webkit.org/show_bug.cgi?id=87194>. + // Taking FloatQuad bounds avoids spurious assertions because of that. + ASSERT(enclosingIntRect(rendererMappedResult) == enclosingIntRect(FloatQuad(result).boundingBox())); +#endif + + return result; +} + +void RenderGeometryMap::mapToAbsolute(TransformState& transformState) const +{ + // If the mapping includes something like columns, we have to go via renderers. + if (hasNonUniformStep()) { + bool fixed = false; + m_mapping.last()->m_renderer->mapLocalToContainer(0, fixed, true, transformState, RenderObject::ApplyContainerFlip); + return; + } + + bool inFixed = false; + + for (int i = m_mapping.size() - 1; i >= 0; --i) { + const RenderGeometryMapStep* currStep = m_mapping[i].get(); + + if (currStep->m_hasTransform) { + // If this box has a transform, it acts as a fixed position container for fixed descendants, + // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position. + inFixed &= currStep->m_isFixedPosition; + } else + inFixed |= currStep->m_isFixedPosition; + + if (!i) { + if (currStep->m_transform) + transformState.applyTransform(*currStep->m_transform.get()); + + // The root gets special treatment for fixed position + if (inFixed) + transformState.move(currStep->m_offset.width(), currStep->m_offset.height()); + } else { + TransformState::TransformAccumulation accumulate = currStep->m_accumulatingTransform ? TransformState::AccumulateTransform : TransformState::FlattenTransform; + if (currStep->m_transform) + transformState.applyTransform(*currStep->m_transform.get(), accumulate); + else + transformState.move(currStep->m_offset.width(), currStep->m_offset.height(), accumulate); + } + } + + transformState.flatten(); +} + +void RenderGeometryMap::pushMappingsToAncestor(const RenderObject* renderer, const RenderBoxModelObject* ancestor) +{ + const RenderObject* currRenderer = renderer; + + // We need to push mappings in reverse order here, so do insertions rather than appends. + m_insertionPosition = m_mapping.size(); + + do { + currRenderer = currRenderer->pushMappingToContainer(ancestor, *this); + } while (currRenderer && currRenderer != ancestor); + + m_insertionPosition = notFound; +} + +void RenderGeometryMap::push(const RenderObject* renderer, const LayoutSize& offsetFromContainer, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform) +{ + ASSERT(m_insertionPosition != notFound); + + OwnPtr<RenderGeometryMapStep> step = adoptPtr(new RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform)); + step->m_offset = offsetFromContainer; + + stepInserted(*step.get()); + m_mapping.insert(m_insertionPosition, step.release()); +} + +void RenderGeometryMap::push(const RenderObject* renderer, const TransformationMatrix& t, bool accumulatingTransform, bool isNonUniform, bool isFixedPosition, bool hasTransform) +{ + ASSERT(m_insertionPosition != notFound); + + OwnPtr<RenderGeometryMapStep> step = adoptPtr(new RenderGeometryMapStep(renderer, accumulatingTransform, isNonUniform, isFixedPosition, hasTransform)); + step->m_transform = adoptPtr(new TransformationMatrix(t)); + + stepInserted(*step.get()); + m_mapping.insert(m_insertionPosition, step.release()); +} + +void RenderGeometryMap::pushView(const RenderView* view, const LayoutSize& scrollOffset, const TransformationMatrix* t) +{ + ASSERT(m_insertionPosition != notFound); + + OwnPtr<RenderGeometryMapStep> step = adoptPtr(new RenderGeometryMapStep(view, false, false, false, t)); + step->m_offset = scrollOffset; + if (t) + step->m_transform = adoptPtr(new TransformationMatrix(*t)); + + ASSERT(!m_mapping.size()); // The view should always be the first thing pushed. + stepInserted(*step.get()); + m_mapping.insert(m_insertionPosition, step.release()); +} + +void RenderGeometryMap::popMappingsToAncestor(const RenderBoxModelObject* ancestor) +{ + ASSERT(m_mapping.size()); + + while (m_mapping.size() && m_mapping.last()->m_renderer != ancestor) { + stepRemoved(*m_mapping.last().get()); + m_mapping.removeLast(); + } +} + +void RenderGeometryMap::stepInserted(const RenderGeometryMapStep& step) +{ + // Offset on the first step is the RenderView's offset, which is only applied when we have fixed-position.s + if (m_mapping.size()) + m_accumulatedOffset += step.m_offset; + + if (step.m_isNonUniform) + ++m_nonUniformStepsCount; + + if (step.m_transform) + ++m_transformedStepsCount; + + if (step.m_isFixedPosition) + ++m_fixedStepsCount; +} + +void RenderGeometryMap::stepRemoved(const RenderGeometryMapStep& step) +{ + // Offset on the first step is the RenderView's offset, which is only applied when we have fixed-position.s + if (m_mapping.size() > 1) + m_accumulatedOffset -= step.m_offset; + + if (step.m_isNonUniform) { + ASSERT(m_nonUniformStepsCount); + --m_nonUniformStepsCount; + } + + if (step.m_transform) { + ASSERT(m_transformedStepsCount); + --m_transformedStepsCount; + } + + if (step.m_isFixedPosition) { + ASSERT(m_fixedStepsCount); + --m_fixedStepsCount; + } +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderGeometryMap.h b/Source/WebCore/rendering/RenderGeometryMap.h new file mode 100644 index 000000000..6a6120333 --- /dev/null +++ b/Source/WebCore/rendering/RenderGeometryMap.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2012 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef RenderGeometryMap_h +#define RenderGeometryMap_h + +#include "FloatPoint.h" +#include "FloatQuad.h" +#include "IntSize.h" +#include "RenderObject.h" +#include "TransformationMatrix.h" +#include <wtf/OwnPtr.h> + +namespace WebCore { + +class RenderGeometryMapStep; + +// Can be used while walking the Renderer tree to cache data about offsets and transforms. +class RenderGeometryMap { +public: + RenderGeometryMap(); + ~RenderGeometryMap(); + + FloatPoint absolutePoint(const FloatPoint&) const; + FloatRect absoluteRect(const FloatRect&) const; + + // Called by code walking the renderer or layer trees. + void pushMappingsToAncestor(const RenderObject*, const RenderBoxModelObject* ancestor); + void popMappingsToAncestor(const RenderBoxModelObject*); + + // The following methods should only be called by renderers inside a call to pushMappingsToAncestor(). + + // Push geometry info between this renderer and some ancestor. The ancestor must be its container() or some + // stacking context between the renderer and its container. + void push(const RenderObject*, const LayoutSize&, bool accumulatingTransform = false, bool isNonUniform = false, bool isFixedPosition = false, bool hasTransform = false); + void push(const RenderObject*, const TransformationMatrix&, bool accumulatingTransform = false, bool isNonUniform = false, bool isFixedPosition = false, bool hasTransform = false); + + // RenderView gets special treatment, because it applies the scroll offset only for elements inside in fixed position. + void pushView(const RenderView*, const LayoutSize& scrollOffset, const TransformationMatrix* = 0); + +private: + void mapToAbsolute(TransformState&) const; + + void stepInserted(const RenderGeometryMapStep&); + void stepRemoved(const RenderGeometryMapStep&); + + bool hasNonUniformStep() const { return m_nonUniformStepsCount; } + bool hasTransformStep() const { return m_transformedStepsCount; } + bool hasFixedPositionStep() const { return m_fixedStepsCount; } + + typedef Vector<OwnPtr<RenderGeometryMapStep> > RenderGeometryMapSteps; // FIXME: inline capacity? + + size_t m_insertionPosition; + int m_nonUniformStepsCount; + int m_transformedStepsCount; + int m_fixedStepsCount; + RenderGeometryMapSteps m_mapping; + LayoutSize m_accumulatedOffset; +}; + +} // namespace WebCore + +#endif // RenderGeometryMap_h diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index 0c88749f7..b8928161e 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -32,6 +32,7 @@ #include "RenderArena.h" #include "RenderBlock.h" #include "RenderFlowThread.h" +#include "RenderGeometryMap.h" #include "RenderLayer.h" #include "RenderTheme.h" #include "RenderView.h" @@ -1065,7 +1066,7 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, o->computeRectForRepaint(repaintContainer, rect, fixed); } -LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point) const +LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(container == this->container()); @@ -1078,6 +1079,9 @@ LayoutSize RenderInline::offsetFromContainer(RenderObject* container, const Layo if (container->hasOverflowClip()) offset -= toRenderBox(container)->scrolledContentOffset(); + if (offsetDependsOnPoint) + *offsetDependsOnPoint = container->hasColumns() || (container->isBox() && container->style()->isFlippedBlocksWritingMode()); + return offset; } @@ -1129,6 +1133,39 @@ void RenderInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, applyContainerFlip, wasFixed); } +const RenderObject* RenderInline::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + ASSERT(ancestorToStopAt != this); + + bool ancestorSkipped; + RenderObject* container = this->container(ancestorToStopAt, &ancestorSkipped); + if (!container) + return 0; + + LayoutSize adjustmentForSkippedAncestor; + if (ancestorSkipped) { + // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe + // to just subtract the delta between the ancestor and o. + adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(container); + } + + bool offsetDependsOnPoint = false; + LayoutSize containerOffset = offsetFromContainer(container, LayoutPoint(), &offsetDependsOnPoint); + + bool preserve3D = container->style()->preserves3D() || style()->preserves3D(); + if (shouldUseTransformFromContainer(container)) { + TransformationMatrix t; + getTransformFromContainer(container, containerOffset, t); + t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height()); // FIXME: right? + geometryMap.push(this, t, preserve3D, offsetDependsOnPoint); + } else { + containerOffset += adjustmentForSkippedAncestor; + geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint); + } + + return ancestorSkipped ? ancestorToStopAt : container; +} + void RenderInline::updateDragState(bool dragOn) { RenderBoxModelObject::updateDragState(dragOn); diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h index 2363f0b0a..4187f3187 100644 --- a/Source/WebCore/rendering/RenderInline.h +++ b/Source/WebCore/rendering/RenderInline.h @@ -49,7 +49,7 @@ public: virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const; + virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; IntRect linesBoundingBox() const; LayoutRect linesVisualOverflowBoundingBox() const; @@ -134,6 +134,7 @@ private: virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed) const; virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual VisiblePosition positionForPoint(const LayoutPoint&); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index 39afa3053..e0b56e7e5 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -125,25 +125,6 @@ using namespace HTMLNames; const int MinimumWidthWhileResizing = 100; const int MinimumHeightWhileResizing = 40; -void* ClipRects::operator new(size_t sz, RenderArena* renderArena) -{ - return renderArena->allocate(sz); -} - -void ClipRects::operator delete(void* ptr, size_t sz) -{ - // Stash size where destroy can find it. - *(size_t *)ptr = sz; -} - -void ClipRects::destroy(RenderArena* renderArena) -{ - delete this; - - // Recover the size left there for us by operator delete and free the memory. - renderArena->free(*(size_t *)this, this); -} - RenderLayer::RenderLayer(RenderBoxModelObject* renderer) : m_inResizeMode(false) , m_scrollDimensionsDirty(true) @@ -180,10 +161,6 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) , m_posZOrderList(0) , m_negZOrderList(0) , m_normalFlowList(0) - , m_clipRects(0) -#ifndef NDEBUG - , m_clipRectsRoot(0) -#endif , m_marquee(0) , m_staticInlinePosition(0) , m_staticBlockPosition(0) @@ -252,9 +229,6 @@ RenderLayer::~RenderLayer() clearBacking(true); #endif - // Make sure we have no lingering clip rects. - ASSERT(!m_clipRects); - if (m_scrollCorner) m_scrollCorner->destroy(); if (m_resizer) @@ -534,6 +508,9 @@ void RenderLayer::updateTransform() m_transform = adoptPtr(new TransformationMatrix); else m_transform.clear(); + + // Layers with transforms act as clip rects roots, so clear the cached clip rects here. + clearClipRectsIncludingDescendants(); } if (hasTransform) { @@ -1070,7 +1047,7 @@ void RenderLayer::setFilterBackendNeedsRepaintingInRect(const LayoutRect& rect, } #endif -RenderLayer* RenderLayer::clippingRoot() const +RenderLayer* RenderLayer::clippingRootForPainting() const { #if USE(ACCELERATED_COMPOSITING) if (isComposited()) @@ -2935,7 +2912,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* context, // Make sure the parent's clip rects have been calculated. ClipRect clipRect = paintDirtyRect; if (parent()) { - clipRect = backgroundClipRect(rootLayer, region, paintFlags & PaintLayerTemporaryClipRects); + clipRect = backgroundClipRect(rootLayer, region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects); clipRect.intersect(paintDirtyRect); // Push the parent coordinate space's clip. @@ -3044,7 +3021,7 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co #endif if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { - calculateRects(rootLayer, region, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, localPaintFlags & PaintLayerTemporaryClipRects); + calculateRects(rootLayer, region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); paintOffset = toPoint(layerBounds.location() - renderBoxLocation()); } @@ -3452,11 +3429,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont { // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. - bool useTemporaryClipRects = false; -#if USE(ACCELERATED_COMPOSITING) - useTemporaryClipRects = compositor()->inCompositingMode(); -#endif - useTemporaryClipRects |= renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars(); + bool useTemporaryClipRects = renderer()->view()->frameView()->containsScrollableAreaWithOverlayScrollbars(); LayoutRect hitTestArea = result.rectForPoint(hitTestPoint); @@ -3464,7 +3437,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont if (transform() && !appliedTransform) { // Make sure the parent's clip rects have been calculated. if (parent()) { - ClipRect clipRect = backgroundClipRect(rootLayer, result.region(), useTemporaryClipRects, IncludeOverlayScrollbarSize); + ClipRect clipRect = backgroundClipRect(rootLayer, result.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, IncludeOverlayScrollbarSize); // Go ahead and test the enclosing clip now. if (!clipRect.intersects(hitTestArea)) return 0; @@ -3525,7 +3498,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont ClipRect bgRect; ClipRect fgRect; ClipRect outlineRect; - calculateRects(rootLayer, result.region(), hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects, IncludeOverlayScrollbarSize); + calculateRects(rootLayer, result.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, IncludeOverlayScrollbarSize); // The following are used for keeping track of the z-depth of the hit point of 3d-transformed // descendants. @@ -3796,10 +3769,11 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend return 0; } -void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy) +void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy) { - if (m_clipRects) { - ASSERT(rootLayer == m_clipRectsRoot); + ASSERT(clipRectsType < NumCachedClipRectsTypes); + if (m_clipRectsCache && m_clipRectsCache->m_clipRects[clipRectsType]) { + ASSERT(rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); return; // We have the correct cached value. } @@ -3807,29 +3781,34 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* re // examine the parent. We want to cache clip rects with us as the root. RenderLayer* parentLayer = rootLayer != this ? parent() : 0; if (parentLayer) - parentLayer->updateClipRects(rootLayer, region, relevancy); + parentLayer->updateClipRects(rootLayer, region, clipRectsType, relevancy); ClipRects clipRects; - calculateClipRects(rootLayer, region, clipRects, true, relevancy); + calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy); - if (parentLayer && parentLayer->clipRects() && clipRects == *parentLayer->clipRects()) - m_clipRects = parentLayer->clipRects(); + if (!m_clipRectsCache) + m_clipRectsCache = adoptPtr(new ClipRectsCache); + + if (parentLayer && parentLayer->clipRects(clipRectsType) && clipRects == *parentLayer->clipRects(clipRectsType)) + m_clipRectsCache->m_clipRects[clipRectsType] = parentLayer->clipRects(clipRectsType); else - m_clipRects = new (renderer()->renderArena()) ClipRects(clipRects); - m_clipRects->ref(); + m_clipRectsCache->m_clipRects[clipRectsType] = ClipRects::create(clipRects); + + m_clipRectsCache->m_clipRects[clipRectsType]->ref(); #ifndef NDEBUG - m_clipRectsRoot = rootLayer; + m_clipRectsCache->m_clipRectsRoot[clipRectsType] = rootLayer; #endif } -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRects& clipRects, - bool useCached, OverlayScrollbarSizeRelevancy relevancy) const +void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const { if (!parent()) { // The root layer's clip rect is always infinite. clipRects.reset(PaintInfo::infiniteRect()); return; } + + bool useCached = clipRectsType != TemporaryClipRects; // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. @@ -3837,10 +3816,10 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* // Ensure that our parent's clip has been calculated so that we can examine the values. if (parentLayer) { - if (useCached && parentLayer->clipRects()) - clipRects = *parentLayer->clipRects(); + if (useCached && parentLayer->clipRects(clipRectsType)) + clipRects = *parentLayer->clipRects(clipRectsType); else - parentLayer->calculateClipRects(rootLayer, region, clipRects); + parentLayer->calculateClipRects(rootLayer, region, clipRectsType, clipRects); } else clipRects.reset(PaintInfo::infiniteRect()); @@ -3888,16 +3867,16 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* } } -void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRects& clipRects, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const +void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const { ASSERT(parent()); - if (temporaryClipRects) { - parent()->calculateClipRects(rootLayer, region, clipRects, false, relevancy); + if (clipRectsType == TemporaryClipRects) { + parent()->calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy); return; } - parent()->updateClipRects(rootLayer, region, relevancy); - clipRects = *parent()->clipRects(); + parent()->updateClipRects(rootLayer, region, clipRectsType, relevancy); + clipRects = *parent()->clipRects(clipRectsType); } static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position) @@ -3911,11 +3890,11 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect return parentRects.overflowClipRect(); } -ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, bool temporaryClipRects, OverlayScrollbarSizeRelevancy relevancy) const +ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy) const { ASSERT(parent()); ClipRects parentRects; - parentClipRects(rootLayer, region, parentRects, temporaryClipRects, relevancy); + parentClipRects(rootLayer, region, clipRectsType, parentRects, relevancy); ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); RenderView* view = renderer()->view(); ASSERT(view); @@ -3927,12 +3906,11 @@ ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderReg return backgroundClipRect; } -void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, bool temporaryClipRects, - OverlayScrollbarSizeRelevancy relevancy) const +void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, OverlayScrollbarSizeRelevancy relevancy) const { if (rootLayer != this && parent()) { - backgroundRect = backgroundClipRect(rootLayer, region, temporaryClipRects, relevancy); + backgroundRect = backgroundClipRect(rootLayer, region, clipRectsType, relevancy); backgroundRect.intersect(paintDirtyRect); } else backgroundRect = paintDirtyRect; @@ -3985,10 +3963,10 @@ LayoutRect RenderLayer::childrenClipRect() const // FIXME: border-radius not accounted for. // FIXME: Regions not accounted for. RenderView* renderView = renderer()->view(); - RenderLayer* clippingRootLayer = clippingRoot(); + RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox(); } @@ -3997,10 +3975,10 @@ LayoutRect RenderLayer::selfClipRect() const // FIXME: border-radius not accounted for. // FIXME: Regions not accounted for. RenderView* renderView = renderer()->view(); - RenderLayer* clippingRootLayer = clippingRoot(); + RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->documentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(backgroundRect.rect())).enclosingBoundingBox(); } @@ -4008,10 +3986,10 @@ LayoutRect RenderLayer::localClipRect() const { // FIXME: border-radius not accounted for. // FIXME: Regions not accounted for. - RenderLayer* clippingRootLayer = clippingRoot(); + RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + calculateRects(clippingRootLayer, 0, PaintingClipRects, PaintInfo::infiniteRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); LayoutRect clipRect = backgroundRect.rect(); if (clipRect == PaintInfo::infiniteRect()) @@ -4259,25 +4237,25 @@ IntRect RenderLayer::calculateLayerBounds(const RenderLayer* layer, const Render return pixelSnappedIntRect(unionBounds); } -void RenderLayer::clearClipRectsIncludingDescendants() +void RenderLayer::clearClipRectsIncludingDescendants(ClipRectsType typeToClear) { - if (!m_clipRects) + // FIXME: it's not clear how this layer not having clip rects guarantees that no descendants have any. + if (!m_clipRectsCache) return; - clearClipRects(); + clearClipRects(typeToClear); for (RenderLayer* l = firstChild(); l; l = l->nextSibling()) - l->clearClipRectsIncludingDescendants(); + l->clearClipRectsIncludingDescendants(typeToClear); } -void RenderLayer::clearClipRects() +void RenderLayer::clearClipRects(ClipRectsType typeToClear) { - if (m_clipRects) { - m_clipRects->deref(renderer()->renderArena()); - m_clipRects = 0; -#ifndef NDEBUG - m_clipRectsRoot = 0; -#endif + if (typeToClear == AllClipRectTypes) + m_clipRectsCache = nullptr; + else { + ASSERT(typeToClear < NumCachedClipRectsTypes); + m_clipRectsCache->m_clipRects[typeToClear] = nullptr; } } diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index 860a37290..ad23af708 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -129,27 +129,19 @@ inline ClipRect intersection(const ClipRect& a, const ClipRect& b) class ClipRects { public: - ClipRects() - : m_refCnt(0) - , m_fixed(false) + static PassRefPtr<ClipRects> create() { + return adoptRef(new ClipRects); } - ClipRects(const LayoutRect& r) - : m_overflowClipRect(r) - , m_fixedClipRect(r) - , m_posClipRect(r) - , m_refCnt(0) - , m_fixed(false) + static PassRefPtr<ClipRects> create(const ClipRects& other) { + return adoptRef(new ClipRects(other)); } - ClipRects(const ClipRects& other) - : m_overflowClipRect(other.overflowClipRect()) - , m_fixedClipRect(other.fixedClipRect()) - , m_posClipRect(other.posClipRect()) - , m_refCnt(0) - , m_fixed(other.fixed()) + ClipRects() + : m_refCnt(0) + , m_fixed(false) { } @@ -174,15 +166,11 @@ public: void setFixed(bool fixed) { m_fixed = fixed; } void ref() { m_refCnt++; } - void deref(RenderArena* renderArena) { if (--m_refCnt == 0) destroy(renderArena); } - - void destroy(RenderArena*); - - // Overloaded new operator. - void* operator new(size_t, RenderArena*); - - // Overridden to prevent the normal delete from being called. - void operator delete(void*, size_t); + void deref() + { + if (!--m_refCnt) + delete this; + } bool operator==(const ClipRects& other) const { @@ -202,10 +190,24 @@ public: } private: - // The normal operator new is disallowed on all render objects. - void* operator new(size_t) throw(); + ClipRects(const LayoutRect& r) + : m_overflowClipRect(r) + , m_fixedClipRect(r) + , m_posClipRect(r) + , m_refCnt(0) + , m_fixed(false) + { + } + + ClipRects(const ClipRects& other) + : m_overflowClipRect(other.overflowClipRect()) + , m_fixedClipRect(other.fixedClipRect()) + , m_posClipRect(other.posClipRect()) + , m_refCnt(0) + , m_fixed(other.fixed()) + { + } -private: ClipRect m_overflowClipRect; ClipRect m_fixedClipRect; ClipRect m_posClipRect; @@ -213,6 +215,30 @@ private: bool m_fixed : 1; }; +enum ClipRectsType { + PaintingClipRects, // Relative to painting ancestor. Used for painting. + RootRelativeClipRects, // Relative to the ancestor treated as the root (e.g. transformed layer). Used for hit testing. + AbsoluteClipRects, // Relative to the RenderView's layer. Used for compositing overlap testing. + NumCachedClipRectsTypes, + AllClipRectTypes, + TemporaryClipRects +}; + +struct ClipRectsCache { + ClipRectsCache() + { +#ifndef NDEBUG + for (int i = 0; i < NumCachedClipRectsTypes; ++i) + m_clipRectsRoot[i] = 0; +#endif + } + + RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes]; +#ifndef NDEBUG + const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes]; +#endif +}; + class RenderLayer : public ScrollableArea { public: friend class RenderReplica; @@ -371,8 +397,8 @@ public: const LayoutSize& relativePositionOffset() const { return m_relativeOffset; } - void clearClipRectsIncludingDescendants(); - void clearClipRects(); + void clearClipRectsIncludingDescendants(ClipRectsType typeToClear = AllClipRectTypes); + void clearClipRects(ClipRectsType typeToClear = AllClipRectTypes); void addBlockSelectionGapsBounds(const LayoutRect&); void clearBlockSelectionGapsBounds(); @@ -423,7 +449,7 @@ public: RenderLayer* enclosingScrollableLayer() const; // The layer relative to which clipping rects for this layer are computed. - RenderLayer* clippingRoot() const; + RenderLayer* clippingRootForPainting() const; #if USE(ACCELERATED_COMPOSITING) // Enclosing compositing layer; if includeSelf is true, may return this. @@ -472,16 +498,17 @@ public: // This method figures out our layerBounds in coordinates relative to // |rootLayer}. It also computes our background and foreground clip rects // for painting/event handling. - void calculateRects(const RenderLayer* rootLayer, RenderRegion*, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, + void calculateRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, - bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; // Compute and cache clip rects computed with the given layer as the root - void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); + void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); // Compute and return the clip rects. If useCached is true, will used previously computed clip rects on ancestors // (rather than computing them all from scratch up the parent chain). - void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRects&, bool useCached = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; - ClipRects* clipRects() const { return m_clipRects; } + void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + + ClipRects* clipRects(ClipRectsType type) const { ASSERT(type < NumCachedClipRectsTypes); return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0; } LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space. LayoutRect selfClipRect() const; // Returns the background clip rect of the layer in the document's coordinate space. @@ -767,8 +794,8 @@ private: void updateOrRemoveFilterEffect(); #endif - void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRects&, bool temporaryClipRects = false, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; - ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, bool temporaryClipRects, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior); RenderLayer* enclosingTransformedAncestor() const; @@ -905,11 +932,8 @@ protected: // overflow layers, but that may change in the future. Vector<RenderLayer*>* m_normalFlowList; - ClipRects* m_clipRects; // Cached clip rects used when painting and hit testing. -#ifndef NDEBUG - const RenderLayer* m_clipRectsRoot; // Root layer used to compute clip rects. -#endif - + OwnPtr<ClipRectsCache> m_clipRectsCache; + IntPoint m_cachedOverlayScrollbarOffset; RenderMarquee* m_marquee; // Used by layers with overflow:marquee diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index ee39912a9..1085eabc0 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -267,7 +267,7 @@ void RenderLayerBacking::updateCompositedBounds() LayoutRect clippingBounds = view->unscaledDocumentRect(); if (m_owningLayer != rootLayer) - clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, 0, true).rect()); // FIXME: Incorrect for CSS regions. + clippingBounds.intersect(m_owningLayer->backgroundClipRect(rootLayer, 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions. LayoutPoint delta; m_owningLayer->convertToLayerCoords(rootLayer, delta); @@ -465,7 +465,7 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() // Call calculateRects to get the backgroundRect which is what is used to clip the contents of this // layer. Note that we call it with temporaryClipRects = true because normally when computing clip rects // for a compositing layer, rootLayer is the layer itself. - IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, true).rect()); // FIXME: Incorrect for CSS regions. + IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, TemporaryClipRects).rect()); // FIXME: Incorrect for CSS regions. ASSERT(parentClipRect != PaintInfo::infiniteRect()); m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); m_ancestorClippingLayer->setSize(parentClipRect.size()); @@ -1112,6 +1112,17 @@ bool RenderLayerBacking::paintsIntoWindow() const return false; } +void RenderLayerBacking::setRequiresOwnBackingStore(bool flag) +{ + if (flag == m_requiresOwnBackingStore) + return; + + // This affects the answer to paintsIntoCompositedAncestor(), which in turn affects + // cached clip rects, so when it changes we have to clear clip rects on descendants. + m_owningLayer->clearClipRectsIncludingDescendants(PaintingClipRects); + m_requiresOwnBackingStore = flag; +} + void RenderLayerBacking::setContentsNeedDisplay() { ASSERT(!paintsIntoCompositedAncestor()); diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h index a6a03ac77..d8718858e 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.h +++ b/Source/WebCore/rendering/RenderLayerBacking.h @@ -101,7 +101,7 @@ public: // paints into some ancestor layer. bool paintsIntoCompositedAncestor() const { return !m_requiresOwnBackingStore; } - void setRequiresOwnBackingStore(bool flag) { m_requiresOwnBackingStore = flag; } + void setRequiresOwnBackingStore(bool); void setContentsNeedDisplay(); // r is in the coordinate space of the layer's render object diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index c402b593d..2a9d2ab07 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -45,6 +45,7 @@ #include "RenderApplet.h" #include "RenderEmbeddedObject.h" #include "RenderFullScreen.h" +#include "RenderGeometryMap.h" #include "RenderIFrame.h" #include "RenderLayerBacking.h" #include "RenderReplica.h" @@ -54,6 +55,7 @@ #include "ScrollingCoordinator.h" #include "Settings.h" #include "TiledBacking.h" +#include "TransformState.h" #if ENABLE(PLUGIN_PROXY_FOR_VIDEO) #include "HTMLMediaElement.h" @@ -398,9 +400,10 @@ void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType update bool layersChanged = false; if (m_compositingConsultsOverlap) { OverlapMap overlapTestRequestMap; - computeCompositingRequirements(updateRoot, &overlapTestRequestMap, compState, layersChanged); + RenderGeometryMap geometryMap; + computeCompositingRequirements(0, updateRoot, &geometryMap, &overlapTestRequestMap, compState, layersChanged); } else - computeCompositingRequirements(updateRoot, 0, compState, layersChanged); + computeCompositingRequirements(0, updateRoot, 0, 0, compState, layersChanged); needHierarchyUpdate |= layersChanged; } @@ -537,6 +540,9 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR if (innerCompositor && innerCompositor->inCompositingMode()) innerCompositor->updateRootLayerAttachment(); } + + if (layerChanged) + layer->clearClipRectsIncludingDescendants(PaintingClipRects); return layerChanged; } @@ -624,33 +630,37 @@ RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const Rend return 0; } -void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds, bool& boundsComputed) +void RenderLayerCompositor::addToOverlapMap(RenderGeometryMap& geometryMap, OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds, bool& boundsComputed) { if (layer->isRootLayer()) return; if (!boundsComputed) { - layerBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + layerBounds = enclosingIntRect(geometryMap.absoluteRect(layer->localBoundingBox())); // Empty rects never intersect, but we need them to for the purposes of overlap testing. if (layerBounds.isEmpty()) layerBounds.setSize(IntSize(1, 1)); boundsComputed = true; } - IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, true).rect()); // FIXME: Incorrect for CSS regions. + IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(rootRenderLayer(), 0, AbsoluteClipRects).rect()); // FIXME: Incorrect for CSS regions. clipRect.scale(pageScaleFactor()); clipRect.intersect(layerBounds); overlapMap.add(layer, clipRect); } -void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, RenderLayer* layer) +void RenderLayerCompositor::addToOverlapMapRecursive(RenderGeometryMap& geometryMap, OverlapMap& overlapMap, RenderLayer* layer, RenderLayer* ancestorLayer) { if (!canBeComposited(layer) || overlapMap.contains(layer)) return; + // A null ancestorLayer is an indication that 'layer' has already been pushed. + if (ancestorLayer) + geometryMap.pushMappingsToAncestor(layer->renderer(), ancestorLayer->renderer()); + IntRect bounds; bool haveComputedBounds = false; - addToOverlapMap(overlapMap, layer, bounds, haveComputedBounds); + addToOverlapMap(geometryMap, overlapMap, layer, bounds, haveComputedBounds); #if !ASSERT_DISABLED LayerListMutationDetector mutationChecker(layer); @@ -661,7 +671,7 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - addToOverlapMapRecursive(overlapMap, curLayer); + addToOverlapMapRecursive(geometryMap, overlapMap, curLayer, layer); } } } @@ -670,7 +680,7 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - addToOverlapMapRecursive(overlapMap, curLayer); + addToOverlapMapRecursive(geometryMap, overlapMap, curLayer, layer); } } @@ -679,10 +689,13 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - addToOverlapMapRecursive(overlapMap, curLayer); + addToOverlapMapRecursive(geometryMap, overlapMap, curLayer, layer); } } } + + if (ancestorLayer) + geometryMap.popMappingsToAncestor(ancestorLayer->renderer()); } // Recurse through the layers in z-index and overflow order (which is equivalent to painting order) @@ -694,11 +707,14 @@ void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, Ren // must be compositing so that its contents render over that child. // This implies that its positive z-index children must also be compositing. // -void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, OverlapMap* overlapMap, CompositingState& compositingState, bool& layersChanged) +void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* ancestorLayer, RenderLayer* layer, RenderGeometryMap* geometryMap, OverlapMap* overlapMap, CompositingState& compositingState, bool& layersChanged) { - layer->updateLayerPosition(); layer->updateLayerListsIfNeeded(); - + + // Should geometryMap be part of the overlap map? + if (geometryMap) + geometryMap->pushMappingsToAncestor(layer->renderer(), ancestorLayer ? ancestorLayer->renderer() : 0); + // Clear the flag layer->setHasCompositingDescendant(false); @@ -708,7 +724,8 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O IntRect absBounds; if (overlapMap && !overlapMap->isEmpty() && compositingState.m_testingOverlap) { // If we're testing for overlap, we only need to composite if we overlap something that is already composited. - absBounds = layer->renderer()->localToAbsoluteQuad(FloatRect(layer->localBoundingBox())).enclosingBoundingBox(); + absBounds = enclosingIntRect(geometryMap->absoluteRect(layer->localBoundingBox())); + // Empty rects never intersect, but we need them to for the purposes of overlap testing. if (absBounds.isEmpty()) absBounds.setSize(IntSize(1, 1)); @@ -757,7 +774,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O size_t listSize = negZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = negZOrderList->at(i); - computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); + computeCompositingRequirements(layer, curLayer, geometryMap, overlapMap, childState, layersChanged); // If we have to make a layer for this child, make one now so we can have a contents layer // (since we need to ensure that the -ve z-order child renders underneath our contents). @@ -777,7 +794,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O size_t listSize = normalFlowList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = normalFlowList->at(i); - computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); + computeCompositingRequirements(layer, curLayer, geometryMap, overlapMap, childState, layersChanged); } } @@ -786,7 +803,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O size_t listSize = posZOrderList->size(); for (size_t i = 0; i < listSize; ++i) { RenderLayer* curLayer = posZOrderList->at(i); - computeCompositingRequirements(curLayer, overlapMap, childState, layersChanged); + computeCompositingRequirements(layer, curLayer, geometryMap, overlapMap, childState, layersChanged); } } } @@ -803,7 +820,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O // the overlap map. Layers that do not composite will draw into their // compositing ancestor's backing, and so are still considered for overlap. if (overlapMap && childState.m_compositingAncestor && !childState.m_compositingAncestor->isRootLayer()) - addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); + addToOverlapMap(*geometryMap, *overlapMap, layer, absBounds, haveComputedBounds); // If we have a software transform, and we have layers under us, we need to also // be composited. Also, if we have opacity < 1, then we need to be a layer so that @@ -813,7 +830,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O childState.m_compositingAncestor = layer; if (overlapMap) { overlapMap->pushCompositingContainer(); - addToOverlapMapRecursive(*overlapMap, layer); + addToOverlapMapRecursive(*geometryMap, *overlapMap, layer); } willBeComposited = true; } @@ -842,7 +859,7 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O childState.m_compositingAncestor = layer; if (overlapMap) { overlapMap->pushCompositingContainer(); - addToOverlapMapRecursive(*overlapMap, layer); + addToOverlapMapRecursive(*geometryMap, *overlapMap, layer); } willBeComposited = true; } @@ -873,6 +890,9 @@ void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, O if (layer->reflectionLayer() && updateLayerCompositingState(layer->reflectionLayer(), CompositingChangeRepaintNow)) layersChanged = true; + + if (geometryMap) + geometryMap->popMappingsToAncestor(ancestorLayer ? ancestorLayer->renderer() : 0); } void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) @@ -1536,7 +1556,7 @@ bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const if (!computeClipRoot || computeClipRoot == layer) return false; - return layer->backgroundClipRect(computeClipRoot, 0, true).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. + return layer->backgroundClipRect(computeClipRoot, 0, TemporaryClipRects).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. } // Return true if the given layer is a stacking context and has compositing child diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h index e294b5866..273849352 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.h +++ b/Source/WebCore/rendering/RenderLayerCompositor.h @@ -34,6 +34,7 @@ namespace WebCore { class GraphicsLayer; class RenderEmbeddedObject; +class RenderGeometryMap; class RenderPart; class ScrollingCoordinator; #if ENABLE(VIDEO) @@ -238,13 +239,13 @@ private: // Repaint the given rect (which is layer's coords), and regions of child layers that intersect that rect. void recursiveRepaintLayerRect(RenderLayer*, const IntRect&); - void addToOverlapMap(OverlapMap&, RenderLayer*, IntRect& layerBounds, bool& boundsComputed); - void addToOverlapMapRecursive(OverlapMap&, RenderLayer*); + void addToOverlapMap(RenderGeometryMap&, OverlapMap&, RenderLayer*, IntRect& layerBounds, bool& boundsComputed); + void addToOverlapMapRecursive(RenderGeometryMap&, OverlapMap&, RenderLayer*, RenderLayer* ancestorLayer = 0); void updateCompositingLayersTimerFired(Timer<RenderLayerCompositor>*); // Returns true if any layer's compositing changed - void computeCompositingRequirements(RenderLayer*, OverlapMap*, struct CompositingState&, bool& layersChanged); + void computeCompositingRequirements(RenderLayer* ancestorLayer, RenderLayer*, RenderGeometryMap*, OverlapMap*, struct CompositingState&, bool& layersChanged); // Recurses down the tree, parenting descendant compositing layers and collecting an array of child layers for the current compositing layer. void rebuildCompositingLayerTree(RenderLayer*, Vector<GraphicsLayer*>& childGraphicsLayersOfEnclosingLayer, int depth); diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp index c28049c2b..72e12c881 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -127,37 +127,37 @@ static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, c context->drawRect(rect); context->restore(); - // Draw the buffered ranges. - // FIXME: Draw multiple ranges if there are multiple buffered ranges. http://webkit.org/b/85925 + // Draw the buffered range. Since the element may have multiple buffered ranges and it'd be + // distracting/'busy' to show all of them, show only the buffered range containing the current play head. IntRect bufferedRect = rect; bufferedRect.inflate(-style->borderLeftWidth()); - double bufferedWidth = 0.0; RefPtr<TimeRanges> bufferedTimeRanges = mediaElement->buffered(); - if (bufferedTimeRanges->length() > 0) { - // Account for the width of the slider thumb. - Image* mediaSliderThumb = getMediaSliderThumb(); - double thumbWidth = mediaSliderThumb->width() / 2.0 + 1.0; - double rectWidth = bufferedRect.width() - thumbWidth; - if (rectWidth < 0.0) - rectWidth = 0.0; - // Preserve old behavior pending resolution of UI design of multiple ranges (see FIXME above). - // http://webkit.org/b/85926 - double fakePercentLoaded = 0; - float duration = mediaElement->duration(); - if (duration && !isinf(duration)) - fakePercentLoaded = bufferedTimeRanges->end(bufferedTimeRanges->length() - 1, ASSERT_NO_EXCEPTION) / duration; - bufferedWidth = rectWidth * fakePercentLoaded + thumbWidth; - } - bufferedRect.setWidth(bufferedWidth); + float duration = mediaElement->duration(); + float currentTime = mediaElement->currentTime(); + if (isnan(duration) || isinf(duration) || !duration || isnan(currentTime)) + return true; + + for (unsigned i = 0; i < bufferedTimeRanges->length(); ++i) { + float start = bufferedTimeRanges->start(i, ASSERT_NO_EXCEPTION); + float end = bufferedTimeRanges->end(i, ASSERT_NO_EXCEPTION); + if (isnan(start) || isnan(end) || start > currentTime || end < currentTime) + continue; + float startFraction = start / duration; + float endFraction = end / duration; + float widthFraction = endFraction - startFraction; + bufferedRect.move(startFraction * bufferedRect.width(), 0); + bufferedRect.setWidth(widthFraction * bufferedRect.width()); + + // Don't bother drawing an empty area. + if (bufferedRect.isEmpty()) + return true; - // Don't bother drawing an empty area. - if (!bufferedRect.isEmpty()) { IntPoint sliderTopLeft = bufferedRect.location(); - IntPoint sliderTopRight = sliderTopLeft; - sliderTopRight.move(0, bufferedRect.height()); + IntPoint sliderBottomLeft = sliderTopLeft; + sliderBottomLeft.move(0, bufferedRect.height()); - RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderTopRight); + RefPtr<Gradient> gradient = Gradient::create(sliderTopLeft, sliderBottomLeft); Color startColor = object->style()->visitedDependentColor(CSSPropertyColor); gradient->addColorStop(0.0, startColor); gradient->addColorStop(1.0, Color(startColor.red() / 2, startColor.green() / 2, startColor.blue() / 2, startColor.alpha())); @@ -167,6 +167,7 @@ static bool paintMediaSlider(RenderObject* object, const PaintInfo& paintInfo, c context->setFillGradient(gradient); context->fillRect(bufferedRect); context->restore(); + return true; } return true; diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp index d29055e68..d7f43ff50 100644 --- a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp +++ b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "RenderMultiColumnBlock.h" +#include "RenderMultiColumnFlowThread.h" using namespace std; @@ -32,6 +33,7 @@ namespace WebCore { RenderMultiColumnBlock::RenderMultiColumnBlock(Node* node) : RenderBlock(node) + , m_flowThread(0) , m_columnCount(1) , m_columnWidth(0) { @@ -73,6 +75,22 @@ bool RenderMultiColumnBlock::recomputeLogicalWidth() return relayoutChildren; } +void RenderMultiColumnBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) +{ + if (!m_flowThread) { + m_flowThread = new (renderArena()) RenderMultiColumnFlowThread(document()); + m_flowThread->setStyle(RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK)); + RenderBlock::addChild(m_flowThread); // Always put the flow thread at the end. + } + + // Column sets are siblings of the flow thread. All children designed to be in the columns, however, are part + // of the flow thread itself. + if (newChild->isRenderMultiColumnSet()) + RenderBlock::addChild(newChild, beforeChild); + else + m_flowThread->addChild(newChild, beforeChild); +} + const char* RenderMultiColumnBlock::renderName() const { if (isFloating()) diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.h b/Source/WebCore/rendering/RenderMultiColumnBlock.h index 2ab642146..833c9bf71 100644 --- a/Source/WebCore/rendering/RenderMultiColumnBlock.h +++ b/Source/WebCore/rendering/RenderMultiColumnBlock.h @@ -31,6 +31,8 @@ namespace WebCore { +class RenderMultiColumnFlowThread; + class RenderMultiColumnBlock : public RenderBlock { public: RenderMultiColumnBlock(Node*); @@ -41,7 +43,13 @@ private: virtual bool recomputeLogicalWidth(); void computeColumnCountAndWidth(); + virtual void addChild(RenderObject* newChild, RenderObject* beforeChild = 0) OVERRIDE; + + RenderMultiColumnFlowThread* flowThread() const { return m_flowThread; } + private: + RenderMultiColumnFlowThread* m_flowThread; + unsigned m_columnCount; // The default column count/width that are based off our containing block width. These values represent only the default, LayoutUnit m_columnWidth; // since a multi-column block that is split across variable width pages or regions will have different column counts and widths in each. // These values will be cached (eventually) for multi-column blocks. diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp index e90ef4e3c..e553c5401 100644 --- a/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp +++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.cpp @@ -33,6 +33,10 @@ RenderMultiColumnFlowThread::RenderMultiColumnFlowThread(Node* node) { } +RenderMultiColumnFlowThread::~RenderMultiColumnFlowThread() +{ +} + const char* RenderMultiColumnFlowThread::renderName() const { return "RenderMultiColumnFlowThread"; diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h index f4a0a0420..6f236d1f4 100644 --- a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h +++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h @@ -34,7 +34,8 @@ namespace WebCore { class RenderMultiColumnFlowThread : public RenderFlowThread { public: RenderMultiColumnFlowThread(Node*); - + ~RenderMultiColumnFlowThread(); + private: virtual const char* renderName() const OVERRIDE; }; diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.h b/Source/WebCore/rendering/RenderMultiColumnSet.h index c5794c8df..f345a8ed3 100644 --- a/Source/WebCore/rendering/RenderMultiColumnSet.h +++ b/Source/WebCore/rendering/RenderMultiColumnSet.h @@ -45,6 +45,8 @@ class RenderMultiColumnSet : public RenderRegionSet { public: RenderMultiColumnSet(Node*, RenderFlowThread*); + virtual bool isRenderMultiColumnSet() const OVERRIDE { return true; } + private: virtual const char* renderName() const; }; diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 4eb16b835..1cd6d36dc 100755 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -46,6 +46,7 @@ #include "RenderCounter.h" #include "RenderDeprecatedFlexibleBox.h" #include "RenderFlexibleBox.h" +#include "RenderGeometryMap.h" #include "RenderImage.h" #include "RenderImageResourceStyleImage.h" #include "RenderInline.h" @@ -188,9 +189,11 @@ RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) case BOX: case INLINE_BOX: return new (arena) RenderDeprecatedFlexibleBox(node); +#if ENABLE(CSS3_FLEXBOX) case FLEX: case INLINE_FLEX: return new (arena) RenderFlexibleBox(node); +#endif } return 0; @@ -219,7 +222,6 @@ RenderObject::RenderObject(Node* node) RenderObject::~RenderObject() { - ASSERT(!node() || documentBeingDestroyed() || !frame()->view() || frame()->view()->layoutRoot() != this); #ifndef NDEBUG ASSERT(!m_hasAXObject); renderObjectCounter.decrement(); @@ -593,14 +595,26 @@ RenderBlock* RenderObject::firstLineBlock() const static inline bool objectIsRelayoutBoundary(const RenderObject* object) { - // FIXME: In future it may be possible to broaden this condition in order to improve performance. - // Table cells are excluded because even when their CSS height is fixed, their height() - // may depend on their contents. - return object->isTextControl() + // FIXME: In future it may be possible to broaden these conditions in order to improve performance. + if (object->isTextControl()) + return true; + #if ENABLE(SVG) - || object->isSVGRoot() + if (object->isSVGRoot()) + return true; #endif - || (object->hasOverflowClip() && !object->style()->width().isIntrinsicOrAuto() && !object->style()->height().isIntrinsicOrAuto() && !object->style()->height().isPercent() && !object->isTableCell()); + + if (!object->hasOverflowClip()) + return false; + + if (object->style()->width().isIntrinsicOrAuto() || object->style()->height().isIntrinsicOrAuto() || object->style()->height().isPercent()) + return false; + + // Table parts can't be relayout roots since the table is responsible for layouting all the parts. + if (object->isTablePart()) + return false; + + return true; } void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot) @@ -2031,6 +2045,7 @@ void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b if (!o) return; + // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called. LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint()); if (o->isBox() && o->style()->isFlippedBlocksWritingMode()) transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedLayoutPoint(transformState.mappedPoint())) - centerPoint); @@ -2046,6 +2061,24 @@ void RenderObject::mapLocalToContainer(RenderBoxModelObject* repaintContainer, b o->mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, DoNotApplyContainerFlip, wasFixed); } +const RenderObject* RenderObject::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != this); + + RenderObject* container = parent(); + if (!container) + return 0; + + // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called. + LayoutSize offset; + if (container->hasOverflowClip()) + offset = -toRenderBox(container)->scrolledContentOffset(); + + geometryMap.push(this, offset, hasColumns()); + + return container; +} + void RenderObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { RenderObject* o = parent(); @@ -2114,7 +2147,7 @@ FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, Ren return transformState.lastPlanarPoint(); } -LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point) const +LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(o == container()); @@ -2125,6 +2158,9 @@ LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& if (o->hasOverflowClip()) offset -= toRenderBox(o)->scrolledContentOffset(); + if (offsetDependsOnPoint) + *offsetDependsOnPoint = hasColumns(); + return offset; } @@ -2200,7 +2236,7 @@ bool RenderObject::hasOutlineAnnotation() const return node() && node()->isLink() && document()->printing(); } -RenderObject* RenderObject::container(RenderBoxModelObject* repaintContainer, bool* repaintContainerSkipped) const +RenderObject* RenderObject::container(const RenderBoxModelObject* repaintContainer, bool* repaintContainerSkipped) const { if (repaintContainerSkipped) *repaintContainerSkipped = false; @@ -2260,7 +2296,7 @@ bool RenderObject::isSelectionBorder() const inline void RenderObject::clearLayoutRootIfNeeded() const { - if (node() && !documentBeingDestroyed() && frame()) { + if (!documentBeingDestroyed() && frame()) { if (FrameView* view = frame()->view()) { if (view->layoutRoot() == this) { ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index f1032a534..ed90aac22 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -60,6 +60,7 @@ class RenderBoxModelObject; class RenderInline; class RenderBlock; class RenderFlowThread; +class RenderGeometryMap; class RenderLayer; class RenderTable; class RenderTheme; @@ -360,6 +361,9 @@ public: virtual bool isRenderFlowThread() const { return false; } virtual bool isRenderNamedFlowThread() const { return false; } + + virtual bool isRenderMultiColumnSet() const { return false; } + virtual bool isRenderScrollbarPart() const { return false; } bool canHaveRegionStyle() const { return isRenderBlock() && !isAnonymous() && !isRenderFlowThread(); } @@ -583,7 +587,7 @@ public: // Returns the object containing this one. Can be different from parent for positioned elements. // If repaintContainer and repaintContainerSkipped are not null, on return *repaintContainerSkipped // is true if the renderer returned is an ancestor of repaintContainer. - RenderObject* container(RenderBoxModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const; + RenderObject* container(const RenderBoxModelObject* repaintContainer = 0, bool* repaintContainerSkipped = 0) const; virtual RenderObject* hoverAncestor() const { return parent(); } @@ -684,7 +688,7 @@ public: // Return the offset from the container() renderer (excluding transforms). In multi-column layout, // different offsets apply at different points, so return the offset that applies to the given point. - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const; + virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; // Return the offset from an object up the container() chain. Asserts that none of the intermediate objects have transforms. LayoutSize offsetFromAncestorContainer(RenderObject*) const; @@ -881,6 +885,10 @@ public: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; + // Pushes state onto RenderGeometryMap about how to map coordinates from this renderer to its container, or ancestorToStopAt (whichever is encountered first). + // Returns the renderer which was mapped to (container or ancestorToStopAt). + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; + bool shouldUseTransformFromContainer(const RenderObject* container) const; void getTransformFromContainer(const RenderObject* container, const LayoutSize& offsetInContainer, TransformationMatrix&) const; diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index 10720c2b8..99ec92d7d 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -240,11 +240,11 @@ void RenderTableCell::setOverrideHeightFromRowHeight(LayoutUnit rowHeight) RenderBlock::setOverrideHeight(max<LayoutUnit>(0, rowHeight - borderBefore() - paddingBefore() - borderAfter() - paddingAfter())); } -LayoutSize RenderTableCell::offsetFromContainer(RenderObject* o, const LayoutPoint& point) const +LayoutSize RenderTableCell::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const { ASSERT(o == container()); - LayoutSize offset = RenderBlock::offsetFromContainer(o, point); + LayoutSize offset = RenderBlock::offsetFromContainer(o, point, offsetDependsOnPoint); if (parent()) offset.expand(-parentBox()->x(), -parentBox()->y()); diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index dac8a7606..2a5820e9e 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -152,7 +152,7 @@ private: virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const OVERRIDE; - virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&) const; + virtual LayoutSize offsetFromContainer(RenderObject*, const LayoutPoint&, bool* offsetDependsOnPoint = 0) const; virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual void computeRectForRepaint(RenderBoxModelObject* repaintContainer, LayoutRect&, bool fixed = false) const; diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index 7f44a75a0..db25e8149 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -403,6 +403,8 @@ int RenderTableSection::calcRowLogicalHeight() void RenderTableSection::layout() { ASSERT(needsLayout()); + ASSERT(!needsCellRecalc()); + ASSERT(!table()->needsSectionRecalc()); LayoutStateMaintainer statePusher(view(), this, locationOffset(), style()->isFlippedBlocksWritingMode()); for (RenderObject* child = children()->firstChild(); child; child = child->nextSibling()) { diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 51fc41745..39319ca1f 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -718,7 +718,7 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye // Calculate the clip rects we should use. LayoutRect layerBounds; ClipRect damageRect, clipRectToApply, outlineRect; - l->calculateRects(rootLayer, 0, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, true); + l->calculateRects(rootLayer, 0, TemporaryClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); // Ensure our lists are up-to-date. l->updateLayerListsIfNeeded(); diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index 8633104e3..aadb9b9b5 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -32,6 +32,7 @@ #include "HTMLFrameOwnerElement.h" #include "HitTestResult.h" #include "Page.h" +#include "RenderGeometryMap.h" #include "RenderLayer.h" #include "RenderNamedFlowThread.h" #include "RenderSelectionInfo.h" @@ -167,6 +168,27 @@ void RenderView::mapLocalToContainer(RenderBoxModelObject* repaintContainer, boo transformState.move(m_frameView->scrollOffsetForFixedPosition()); } +const RenderObject* RenderView::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + // If a container was specified, and was not 0 or the RenderView, + // then we should have found it by now. + ASSERT_ARG(ancestorToStopAt, !ancestorToStopAt || ancestorToStopAt == this); + + LayoutSize scrollOffset; + + if (m_frameView) + scrollOffset = m_frameView->scrollOffsetForFixedPosition(); + + if (!ancestorToStopAt && shouldUseTransformFromContainer(0)) { + TransformationMatrix t; + getTransformFromContainer(0, LayoutSize(), t); + geometryMap.pushView(this, scrollOffset, &t); + } else + geometryMap.pushView(this, scrollOffset); + + return 0; +} + void RenderView::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { if (fixed && m_frameView) @@ -733,10 +755,10 @@ LayoutRect RenderView::backgroundRect(RenderBox* backgroundRenderer) const IntRect RenderView::documentRect() const { - IntRect overflowRect(unscaledDocumentRect()); + FloatRect overflowRect(unscaledDocumentRect()); if (hasTransform()) overflowRect = layer()->currentTransform().mapRect(overflowRect); - return overflowRect; + return IntRect(overflowRect); } int RenderView::viewHeight() const diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h index 4ac061f72..e6a5722d8 100644 --- a/Source/WebCore/rendering/RenderView.h +++ b/Source/WebCore/rendering/RenderView.h @@ -188,6 +188,7 @@ public: protected: virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual void mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState&) const; virtual bool requiresColumns(int desiredColumnCount) const OVERRIDE; diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index ff8e0731e..d17bd313a 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -75,6 +75,8 @@ #include "RenderMenuList.cpp" #include "RenderMeter.cpp" #include "RenderMultiColumnBlock.cpp" +#include "RenderMultiColumnFlowThread.cpp" +#include "RenderMultiColumnSet.cpp" #include "RenderObject.cpp" #include "RenderObjectChildList.cpp" #include "RenderPart.cpp" diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index ba7677b10..55c739a07 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -409,8 +409,10 @@ enum EDisplay { TABLE, INLINE_TABLE, TABLE_ROW_GROUP, TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_ROW, TABLE_COLUMN_GROUP, TABLE_COLUMN, TABLE_CELL, - TABLE_CAPTION, BOX, INLINE_BOX, + TABLE_CAPTION, BOX, INLINE_BOX, +#if ENABLE(CSS3_FLEXBOX) FLEX, INLINE_FLEX, +#endif GRID, INLINE_GRID, NONE }; diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp index cf44efff1..c4f9a284d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp @@ -104,12 +104,6 @@ void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* old SVGResourcesCache::clientStyleChanged(this, diff, style()); } -void RenderSVGBlock::updateFromElement() -{ - RenderBlock::updateFromElement(); - SVGResourcesCache::clientUpdatedFromElement(this, style()); -} - } #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h index 9ef55a919..7f5b78532 100644 --- a/Source/WebCore/rendering/svg/RenderSVGBlock.h +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h @@ -45,7 +45,6 @@ private: virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void updateFromElement(); }; } diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp index a1fd8321d..7b2866113 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp @@ -87,6 +87,19 @@ void RenderSVGContainer::layout() setNeedsLayout(false); } +void RenderSVGContainer::addChild(RenderObject* child, RenderObject* beforeChild) +{ + RenderSVGModelObject::addChild(child, beforeChild); + SVGResourcesCache::clientWasAddedToTree(child, child->style()); +} + +void RenderSVGContainer::removeChild(RenderObject* child) +{ + SVGResourcesCache::clientWillBeRemovedFromTree(child); + RenderSVGModelObject::removeChild(child); +} + + bool RenderSVGContainer::selfWillPaint() { SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this); diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h index 5be036638..335732b84 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h @@ -53,6 +53,8 @@ protected: virtual void layout(); + virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&); virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp index 2918fe3a9..074944066 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp @@ -193,6 +193,11 @@ void RenderSVGForeignObject::mapLocalToContainer(RenderBoxModelObject* repaintCo SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } +const RenderObject* RenderSVGForeignObject::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + } #endif diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h index 4a1a8ac25..8fe0864c1 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h @@ -55,6 +55,7 @@ public: virtual bool isSVGForeignObject() const { return true; } virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool fixed, bool useTransforms, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } private: diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index bb1a367ac..057bfda00 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -84,6 +84,11 @@ void RenderSVGInline::mapLocalToContainer(RenderBoxModelObject* repaintContainer SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } +const RenderObject* RenderSVGInline::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const { const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this); @@ -114,21 +119,19 @@ void RenderSVGInline::styleDidChange(StyleDifference diff, const RenderStyle* ol SVGResourcesCache::clientStyleChanged(this, diff, style()); } -void RenderSVGInline::updateFromElement() -{ - RenderInline::updateFromElement(); - SVGResourcesCache::clientUpdatedFromElement(this, style()); -} - void RenderSVGInline::addChild(RenderObject* child, RenderObject* beforeChild) { RenderInline::addChild(child, beforeChild); + SVGResourcesCache::clientWasAddedToTree(child, child->style()); + if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) textRenderer->subtreeChildWasAdded(child); } void RenderSVGInline::removeChild(RenderObject* child) { + SVGResourcesCache::clientWillBeRemovedFromTree(child); + RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this); if (!textRenderer) { RenderInline::removeChild(child); diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h index 172062196..533a99aa6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.h +++ b/Source/WebCore/rendering/svg/RenderSVGInline.h @@ -48,6 +48,7 @@ public: virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect&, bool fixed = false) const; virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; private: @@ -56,9 +57,8 @@ private: virtual void willBeDestroyed(); 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 addChild(RenderObject* child, RenderObject* beforeChild = 0) OVERRIDE; virtual void removeChild(RenderObject*) OVERRIDE; }; diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index 48fd7d879..c1c27b09a 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -60,6 +60,11 @@ void RenderSVGModelObject::mapLocalToContainer(RenderBoxModelObject* repaintCont SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } +const RenderObject* RenderSVGModelObject::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + // Copied from RenderBox, this method likely requires further refactoring to work easily for both SVG and CSS Box Model content. // FIXME: This may also need to move into SVGRenderSupport as the RenderBox version depends // on borderBoundingBox() which SVG RenderBox subclases (like SVGRenderBlock) do not implement. @@ -106,12 +111,6 @@ void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyl SVGResourcesCache::clientStyleChanged(this, diff, style()); } -void RenderSVGModelObject::updateFromElement() -{ - RenderObject::updateFromElement(); - SVGResourcesCache::clientUpdatedFromElement(this, style()); -} - bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const LayoutPoint&, const LayoutPoint&, HitTestAction) { ASSERT_NOT_REACHED(); diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index b9692fe1d..d82600f57 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -59,9 +59,9 @@ public: virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual void styleWillChange(StyleDifference, const RenderStyle* newStyle); virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - virtual void updateFromElement(); static bool checkIntersection(RenderObject*, const FloatRect&); static bool checkEnclosure(RenderObject*, const FloatRect&); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp index 3dba672dd..80760fd48 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp @@ -165,7 +165,7 @@ void RenderSVGResourceContainer::registerResource() RenderObject* renderer = (*it)->renderer(); if (!renderer) continue; - SVGResourcesCache::clientUpdatedFromElement(renderer, renderer->style()); + SVGResourcesCache::clientStyleChanged(renderer, StyleDifferenceLayout, renderer->style()); renderer->setNeedsLayout(true); } } diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index 941185f55..663245333 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -326,10 +326,16 @@ void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldS SVGResourcesCache::clientStyleChanged(this, diff, style()); } -void RenderSVGRoot::updateFromElement() +void RenderSVGRoot::addChild(RenderObject* child, RenderObject* beforeChild) { - RenderReplaced::updateFromElement(); - SVGResourcesCache::clientUpdatedFromElement(this, style()); + RenderReplaced::addChild(child, beforeChild); + SVGResourcesCache::clientWasAddedToTree(child, child->style()); +} + +void RenderSVGRoot::removeChild(RenderObject* child) +{ + SVGResourcesCache::clientWillBeRemovedFromTree(child); + RenderReplaced::removeChild(child); } // RenderBox methods will expect coordinates w/o any transforms in coordinates @@ -391,6 +397,11 @@ void RenderSVGRoot::mapLocalToContainer(RenderBoxModelObject* repaintContainer, RenderReplaced::mapLocalToContainer(repaintContainer, fixed, useTransforms, transformState, ApplyContainerFlip, wasFixed); } +const RenderObject* RenderSVGRoot::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return RenderReplaced::pushMappingToContainer(ancestorToStopAt, geometryMap); +} + void RenderSVGRoot::updateCachedBoundaries() { m_objectBoundingBox = FloatRect(); diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h index c334afbe6..6fb569468 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.h +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h @@ -78,7 +78,8 @@ private: virtual void willBeDestroyed(); 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) OVERRIDE; + virtual void removeChild(RenderObject*) OVERRIDE; virtual const AffineTransform& localToParentTransform() const; @@ -95,6 +96,8 @@ private: virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const; virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; + virtual bool canBeSelectionLeaf() const { return false; } virtual bool canHaveChildren() const { return true; } diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index d918453c5..a2cae7dbb 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -115,6 +115,11 @@ void RenderSVGText::mapLocalToContainer(RenderBoxModelObject* repaintContainer, SVGRenderSupport::mapLocalToContainer(this, repaintContainer, transformState, wasFixed); } +const RenderObject* RenderSVGText::pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const +{ + return SVGRenderSupport::pushMappingToContainer(this, ancestorToStopAt, geometryMap); +} + static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes) { for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { @@ -524,11 +529,15 @@ FloatRect RenderSVGText::repaintRectInLocalCoordinates() const void RenderSVGText::addChild(RenderObject* child, RenderObject* beforeChild) { RenderSVGBlock::addChild(child, beforeChild); + + SVGResourcesCache::clientWasAddedToTree(child, child->style()); subtreeChildWasAdded(child); } void RenderSVGText::removeChild(RenderObject* child) { + SVGResourcesCache::clientWillBeRemovedFromTree(child); + Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; FontCachePurgePreventer fontCachePurgePreventer; subtreeChildWillBeRemoved(child, affectedAttributes); diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 56723f6c1..af950c341 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -76,6 +76,7 @@ private: virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect&, bool fixed = false) const; virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, bool useTransforms, bool fixed, TransformState&, ApplyContainerFlipOrNot = ApplyContainerFlip, bool* wasFixed = 0) const; + virtual const RenderObject* pushMappingToContainer(const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&) const; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual void removeChild(RenderObject*) OVERRIDE; virtual void willBeDestroyed() OVERRIDE; diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp index ddc7c9155..177ce9c44 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -28,6 +28,7 @@ #include "SVGRenderSupport.h" #include "NodeRenderStyle.h" +#include "RenderGeometryMap.h" #include "RenderLayer.h" #include "RenderSVGResource.h" #include "RenderSVGResourceClipper.h" @@ -85,6 +86,23 @@ void SVGRenderSupport::mapLocalToContainer(const RenderObject* object, RenderBox parent->mapLocalToContainer(repaintContainer, false, true, transformState, RenderObject::DoNotApplyContainerFlip, wasFixed); } +const RenderObject* SVGRenderSupport::pushMappingToContainer(const RenderObject* object, const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) +{ + ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != object); + + RenderObject* parent = object->parent(); + + // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform + // to map an element from SVG viewport coordinates to CSS box coordinates. + // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. + if (parent->isSVGRoot()) + geometryMap.push(object, TransformationMatrix(toRenderSVGRoot(parent)->localToBorderBoxTransform())); + else + geometryMap.push(object, LayoutSize()); + + return parent; +} + // Update a bounding box taking into account the validity of the other bounding box. static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) { diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h index e25b12f06..fa960f05e 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.h +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h @@ -34,6 +34,7 @@ class FloatPoint; class FloatRect; class ImageBuffer; class RenderBoxModelObject; +class RenderGeometryMap; class RenderObject; class RenderStyle; class RenderSVGRoot; @@ -64,6 +65,7 @@ public: static LayoutRect clippedOverflowRectForRepaint(const RenderObject*, RenderBoxModelObject* repaintContainer); static void computeFloatRectForRepaint(const RenderObject*, RenderBoxModelObject* repaintContainer, FloatRect&, bool fixed); static void mapLocalToContainer(const RenderObject*, RenderBoxModelObject* repaintContainer, TransformState&, bool* wasFixed = 0); + static const RenderObject* pushMappingToContainer(const RenderObject*, const RenderBoxModelObject* ancestorToStopAt, RenderGeometryMap&); // Shared between SVG renderers and resources. static void applyStrokeStyleToContext(GraphicsContext*, const RenderStyle*, const RenderObject*); diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp index 1715f6c04..87531ed3e 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp @@ -128,24 +128,44 @@ void SVGResourcesCache::clientLayoutChanged(RenderObject* object) void SVGResourcesCache::clientStyleChanged(RenderObject* renderer, StyleDifference diff, const RenderStyle* newStyle) { ASSERT(renderer); - if (diff == StyleDifferenceEqual) + if (diff == StyleDifferenceEqual || !renderer->parent()) return; // In this case the proper SVGFE*Element will decide whether the modified CSS properties require a relayout or repaint. if (renderer->isSVGResourceFilterPrimitive() && diff == StyleDifferenceRepaint) return; - clientUpdatedFromElement(renderer, newStyle); + // Dynamic changes of CSS properties like 'clip-path' may require us to recompute the associated resources for a renderer. + // FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed + // to be able to selectively rebuild individual resources, instead of all of them. + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); + cache->addResourcesFromRenderObject(renderer, newStyle); + + RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); } -void SVGResourcesCache::clientUpdatedFromElement(RenderObject* renderer, const RenderStyle* newStyle) +static inline bool rendererCanHaveResources(RenderObject* renderer) { ASSERT(renderer); ASSERT(renderer->parent()); + return renderer->node() && !renderer->isSVGInlineText(); +} +void SVGResourcesCache::clientWasAddedToTree(RenderObject* renderer, const RenderStyle* newStyle) +{ + if (!rendererCanHaveResources(renderer)) + return; SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); - cache->removeResourcesFromRenderObject(renderer); cache->addResourcesFromRenderObject(renderer, newStyle); +} + +void SVGResourcesCache::clientWillBeRemovedFromTree(RenderObject* renderer) +{ + if (!rendererCanHaveResources(renderer)) + return; + SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); + cache->removeResourcesFromRenderObject(renderer); RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); } diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.h b/Source/WebCore/rendering/svg/SVGResourcesCache.h index 72e526a67..633fcd73d 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCache.h +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.h @@ -37,10 +37,14 @@ public: SVGResourcesCache(); ~SVGResourcesCache(); - void addResourcesFromRenderObject(RenderObject*, const RenderStyle*); - void removeResourcesFromRenderObject(RenderObject*); static SVGResources* cachedResourcesForRenderObject(const RenderObject*); + // Called from all SVG renderers addChild() methods. + static void clientWasAddedToTree(RenderObject*, const RenderStyle* newStyle); + + // Called from all SVG renderers removeChild() methods. + static void clientWillBeRemovedFromTree(RenderObject*); + // Called from all SVG renderers destroy() methods - except for RenderSVGResourceContainer. static void clientDestroyed(RenderObject*); @@ -50,13 +54,13 @@ public: // Called from all SVG renderers styleDidChange() methods. static void clientStyleChanged(RenderObject*, StyleDifference, const RenderStyle* newStyle); - // Called from all SVG renderers updateFromElement() methods. - static void clientUpdatedFromElement(RenderObject*, const RenderStyle* newStyle); - // Called from RenderSVGResourceContainer::willBeDestroyed(). static void resourceDestroyed(RenderSVGResourceContainer*); private: + void addResourcesFromRenderObject(RenderObject*, const RenderStyle*); + void removeResourcesFromRenderObject(RenderObject*); + HashMap<const RenderObject*, SVGResources*> m_cache; }; |
