diff options
Diffstat (limited to 'Source/WebCore/rendering')
152 files changed, 3132 insertions, 1613 deletions
diff --git a/Source/WebCore/rendering/ColumnInfo.h b/Source/WebCore/rendering/ColumnInfo.h index 553564c53..dc2584d8e 100644 --- a/Source/WebCore/rendering/ColumnInfo.h +++ b/Source/WebCore/rendering/ColumnInfo.h @@ -26,7 +26,7 @@ #ifndef ColumnInfo_h #define ColumnInfo_h -#include "LayoutTypes.h" +#include "LayoutTypesInlineMethods.h" #include <wtf/Vector.h> namespace WebCore { diff --git a/Source/WebCore/rendering/EllipsisBox.cpp b/Source/WebCore/rendering/EllipsisBox.cpp index c25673d93..902df2b0a 100644 --- a/Source/WebCore/rendering/EllipsisBox.cpp +++ b/Source/WebCore/rendering/EllipsisBox.cpp @@ -121,7 +121,7 @@ void EllipsisBox::paintSelection(GraphicsContext* context, const LayoutPoint& pa context->drawHighlightForText(font, RenderBlock::constructTextRun(renderer(), font, m_str, style, TextRun::AllowTrailingExpansion), roundedIntPoint(LayoutPoint(x() + paintOffset.x(), y() + paintOffset.y() + top)), h, c, style->colorSpace()); } -bool EllipsisBox::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, LayoutUnit, LayoutUnit) +bool EllipsisBox::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, LayoutUnit, LayoutUnit) { return false; } diff --git a/Source/WebCore/rendering/EllipsisBox.h b/Source/WebCore/rendering/EllipsisBox.h index c759a397e..699767847 100644 --- a/Source/WebCore/rendering/EllipsisBox.h +++ b/Source/WebCore/rendering/EllipsisBox.h @@ -40,7 +40,7 @@ public: } virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; void setSelectionState(RenderObject::SelectionState s) { m_selectionState = s; } IntRect selectionRect(); diff --git a/Source/WebCore/rendering/FilterEffectRenderer.cpp b/Source/WebCore/rendering/FilterEffectRenderer.cpp index 6d411995d..78ed248ff 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.cpp +++ b/Source/WebCore/rendering/FilterEffectRenderer.cpp @@ -29,6 +29,7 @@ #include "FilterEffectRenderer.h" +#include "ColorSpace.h" #include "Document.h" #include "FEColorMatrix.h" #include "FEComponentTransfer.h" @@ -45,6 +46,7 @@ #include "CustomFilterGlobalContext.h" #include "CustomFilterProgram.h" #include "CustomFilterOperation.h" +#include "CustomFilterValidatedProgram.h" #include "FECustomFilter.h" #include "RenderView.h" #include "Settings.h" @@ -89,6 +91,26 @@ static bool isCSSCustomFilterEnabled(Document* document) Settings* settings = document->settings(); return settings && settings->isCSSCustomFilterEnabled() && settings->webGLEnabled(); } + +static PassRefPtr<FECustomFilter> createCustomFilterEffect(Filter* filter, Document* document, CustomFilterOperation* operation) +{ + if (!isCSSCustomFilterEnabled(document)) + return 0; + + RefPtr<CustomFilterProgram> program = operation->program(); + if (!program->isLoaded()) + return 0; + + CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext(); + globalContext->prepareContextIfNeeded(document->view()->hostWindow()); + RefPtr<CustomFilterValidatedProgram> validatedProgram = globalContext->getValidatedProgram(program->programInfo()); + if (!validatedProgram->isInitialized()) + return 0; + + return FECustomFilter::create(filter, globalContext, validatedProgram, operation->parameters(), + operation->meshRows(), operation->meshColumns(), + operation->meshBoxType(), operation->meshType()); +} #endif FilterEffectRenderer::FilterEffectRenderer() @@ -322,23 +344,12 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope dropShadowOperation->x(), dropShadowOperation->y(), dropShadowOperation->color(), 1); break; } -#if ENABLE(CSS_SHADERS) +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) case FilterOperation::CUSTOM: { -#if ENABLE(WEBGL) - if (!isCSSCustomFilterEnabled(document)) - continue; - CustomFilterOperation* customFilterOperation = static_cast<CustomFilterOperation*>(filterOperation); - RefPtr<CustomFilterProgram> program = customFilterOperation->program(); - if (program->isLoaded()) { - CustomFilterGlobalContext* globalContext = document->renderView()->customFilterGlobalContext(); - globalContext->prepareContextIfNeeded(document->view()->hostWindow()); - effect = FECustomFilter::create(this, globalContext, program, customFilterOperation->parameters(), - customFilterOperation->meshRows(), customFilterOperation->meshColumns(), - customFilterOperation->meshBoxType(), customFilterOperation->meshType()); + effect = createCustomFilterEffect(this, document, customFilterOperation); + if (effect) m_hasCustomShaderFilter = true; - } -#endif break; } #endif @@ -349,6 +360,7 @@ bool FilterEffectRenderer::build(Document* document, const FilterOperations& ope if (effect) { // Unlike SVG, filters applied here should not clip to their primitive subregions. effect->setClipsToBounds(false); + effect->setColorSpace(ColorSpaceDeviceRGB); if (filterOperation->getOperationType() != FilterOperation::REFERENCE) { effect->inputEffects().append(previousEffect); diff --git a/Source/WebCore/rendering/FilterEffectRenderer.h b/Source/WebCore/rendering/FilterEffectRenderer.h index 0db987b3c..bc53cdc14 100644 --- a/Source/WebCore/rendering/FilterEffectRenderer.h +++ b/Source/WebCore/rendering/FilterEffectRenderer.h @@ -32,8 +32,10 @@ #include "FilterEffect.h" #include "FilterOperations.h" #include "FloatRect.h" +#include "FractionalLayoutRect.h" #include "GraphicsContext.h" #include "ImageBuffer.h" +#include "LayoutTypesInlineMethods.h" #include "SVGFilterBuilder.h" #include "SourceGraphic.h" @@ -111,7 +113,7 @@ public: bool hasFilterThatMovesPixels() const { return m_hasFilterThatMovesPixels; } LayoutRect computeSourceImageRectForDirtyRect(const LayoutRect& filterBoxRect, const LayoutRect& dirtyRect); -#if ENABLE(CSS_SHADERS) +#if ENABLE(CSS_SHADERS) && ENABLE(WEBGL) bool hasCustomShaderFilter() const { return m_hasCustomShaderFilter; } #endif private: diff --git a/Source/WebCore/rendering/FlowThreadController.cpp b/Source/WebCore/rendering/FlowThreadController.cpp index 476c924b8..9edd0aa7e 100644 --- a/Source/WebCore/rendering/FlowThreadController.cpp +++ b/Source/WebCore/rendering/FlowThreadController.cpp @@ -31,12 +31,11 @@ #include "FlowThreadController.h" +#include "NamedFlowCollection.h" #include "RenderFlowThread.h" -#include "RenderFlowThreadContainer.h" #include "RenderNamedFlowThread.h" #include "StyleInheritedData.h" #include "WebKitNamedFlow.h" -#include "WebKitNamedFlowCollection.h" #include <wtf/text/AtomicString.h> namespace WebCore { @@ -49,7 +48,6 @@ PassOwnPtr<FlowThreadController> FlowThreadController::create(RenderView* view) FlowThreadController::FlowThreadController(RenderView* view) : m_view(view) , m_currentRenderFlowThread(0) - , m_flowThreadContainer(0) , m_isRenderNamedFlowThreadOrderDirty(false) { } @@ -60,11 +58,6 @@ FlowThreadController::~FlowThreadController() RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(const AtomicString& name) { - if (!m_flowThreadContainer) { - m_flowThreadContainer = new (m_view->renderArena()) RenderFlowThreadContainer(m_view->document()); - m_flowThreadContainer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style())); - m_view->addChild(m_flowThreadContainer); - } if (!m_renderNamedFlowThreadList) m_renderNamedFlowThreadList = adoptPtr(new RenderNamedFlowThreadList()); else { @@ -75,7 +68,7 @@ RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(cons } } - WebKitNamedFlowCollection* namedFlows = m_view->document()->namedFlows(); + NamedFlowCollection* namedFlows = m_view->document()->namedFlows(); // Sanity check for the absence of a named flow in the "CREATED" state with the same name. ASSERT(!namedFlows->flowByName(name)); @@ -84,8 +77,8 @@ RenderNamedFlowThread* FlowThreadController::ensureRenderFlowThreadWithName(cons flowRenderer->setStyle(RenderFlowThread::createFlowThreadStyle(m_view->style())); m_renderNamedFlowThreadList->add(flowRenderer); - // Keep the flow renderer as a child of RenderFlowThreadContainer. - m_flowThreadContainer->addChild(flowRenderer); + // Keep the flow renderer as a child of RenderView. + m_view->addChild(flowRenderer); setIsRenderNamedFlowThreadOrderDirty(true); @@ -105,6 +98,23 @@ void FlowThreadController::layoutRenderNamedFlowThreads() { ASSERT(m_renderNamedFlowThreadList); + // Remove the left-over flow threads. + RenderNamedFlowThreadList toRemoveList; + for (RenderNamedFlowThreadList::iterator iter = m_renderNamedFlowThreadList->begin(); iter != m_renderNamedFlowThreadList->end(); ++iter) { + RenderNamedFlowThread* flowRenderer = *iter; + if (flowRenderer->isMarkedForDestruction()) + toRemoveList.add(flowRenderer); + } + + if (toRemoveList.size() > 0) + setIsRenderNamedFlowThreadOrderDirty(true); + + for (RenderNamedFlowThreadList::iterator iter = toRemoveList.begin(); iter != toRemoveList.end(); ++iter) { + RenderNamedFlowThread* flowRenderer = *iter; + m_renderNamedFlowThreadList->remove(flowRenderer); + flowRenderer->destroy(); + } + if (isRenderNamedFlowThreadOrderDirty()) { // Arrange the thread list according to dependencies. RenderNamedFlowThreadList sortedList; @@ -146,10 +156,4 @@ void FlowThreadController::unregisterNamedFlowContentNode(Node* contentNode) m_mapNamedFlowContentNodes.remove(contentNode); } -void FlowThreadController::removeFlowThread(RenderNamedFlowThread* flowThread) -{ - m_renderNamedFlowThreadList->remove(flowThread); - setIsRenderNamedFlowThreadOrderDirty(true); -} - } // namespace WebCore diff --git a/Source/WebCore/rendering/FlowThreadController.h b/Source/WebCore/rendering/FlowThreadController.h index 58edb2cf1..0aef61130 100644 --- a/Source/WebCore/rendering/FlowThreadController.h +++ b/Source/WebCore/rendering/FlowThreadController.h @@ -37,7 +37,6 @@ namespace WebCore { class RenderFlowThread; -class RenderFlowThreadContainer; class RenderNamedFlowThread; typedef ListHashSet<RenderNamedFlowThread*> RenderNamedFlowThreadList; @@ -66,7 +65,6 @@ public: void registerNamedFlowContentNode(Node*, RenderNamedFlowThread*); void unregisterNamedFlowContentNode(Node*); - void removeFlowThread(RenderNamedFlowThread*); protected: FlowThreadController(RenderView*); @@ -74,7 +72,6 @@ protected: private: RenderView* m_view; RenderFlowThread* m_currentRenderFlowThread; - RenderFlowThreadContainer* m_flowThreadContainer; bool m_isRenderNamedFlowThreadOrderDirty; OwnPtr<RenderNamedFlowThreadList> m_renderNamedFlowThreadList; // maps a content node to its render flow thread. diff --git a/Source/WebCore/rendering/HitTestRequest.h b/Source/WebCore/rendering/HitTestRequest.h index e6a5231bb..1900900f1 100644 --- a/Source/WebCore/rendering/HitTestRequest.h +++ b/Source/WebCore/rendering/HitTestRequest.h @@ -34,7 +34,12 @@ public: Release = 1 << 4, IgnoreClipping = 1 << 5, SVGClipContent = 1 << 6, - TouchEvent = 1 << 7 + TouchEvent = 1 << 7, + AllowShadowContent = 1 << 8, + AllowChildFrameContent = 1 << 9, + // FIXME: Get rid of the two options below if possible. + ChildFrameHitTest = 1 << 10, + TestChildFrameScrollBars = 1 << 11 }; typedef unsigned HitTestRequestType; @@ -52,6 +57,10 @@ public: bool svgClipContent() const { return m_requestType & SVGClipContent; } bool touchEvent() const { return m_requestType & TouchEvent; } bool mouseEvent() const { return !touchEvent(); } + bool allowsShadowContent() const { return m_requestType & AllowShadowContent; } + bool allowsChildFrameContent() const { return m_requestType & AllowChildFrameContent; } + bool isChildFrameHitTest() const { return m_requestType & ChildFrameHitTest; } + bool shouldTestChildFrameScrollBars() const { return m_requestType & TestChildFrameScrollBars; } // Convenience functions bool touchMove() const { return move() && touchEvent(); } diff --git a/Source/WebCore/rendering/HitTestResult.cpp b/Source/WebCore/rendering/HitTestResult.cpp index 0745763d1..8063c812e 100644 --- a/Source/WebCore/rendering/HitTestResult.cpp +++ b/Source/WebCore/rendering/HitTestResult.cpp @@ -48,14 +48,14 @@ namespace WebCore { using namespace HTMLNames; -HitTestPoint::HitTestPoint() +HitTestLocation::HitTestLocation() : m_region(0) , m_isRectBased(false) , m_isRectilinear(true) { } -HitTestPoint::HitTestPoint(const LayoutPoint& point) +HitTestLocation::HitTestLocation(const LayoutPoint& point) : m_point(point) , m_boundingBox(rectForPoint(point, 0, 0, 0, 0)) , m_transformedPoint(point) @@ -66,7 +66,7 @@ HitTestPoint::HitTestPoint(const LayoutPoint& point) { } -HitTestPoint::HitTestPoint(const FloatPoint& point) +HitTestLocation::HitTestLocation(const FloatPoint& point) : m_point(flooredLayoutPoint(point)) , m_boundingBox(rectForPoint(m_point, 0, 0, 0, 0)) , m_transformedPoint(point) @@ -77,7 +77,7 @@ HitTestPoint::HitTestPoint(const FloatPoint& point) { } -HitTestPoint::HitTestPoint(const FloatPoint& point, const FloatQuad& quad) +HitTestLocation::HitTestLocation(const FloatPoint& point, const FloatQuad& quad) : m_transformedPoint(point) , m_transformedRect(quad) , m_region(0) @@ -88,7 +88,7 @@ HitTestPoint::HitTestPoint(const FloatPoint& point, const FloatQuad& quad) m_isRectilinear = quad.isRectilinear(); } -HitTestPoint::HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) +HitTestLocation::HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) : m_point(centerPoint) , m_boundingBox(rectForPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding)) , m_transformedPoint(centerPoint) @@ -99,19 +99,19 @@ HitTestPoint::HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, m_transformedRect = FloatQuad(m_boundingBox); } -HitTestPoint::HitTestPoint(const HitTestPoint& other, const LayoutSize& offset, RenderRegion* region) +HitTestLocation::HitTestLocation(const HitTestLocation& other, const LayoutSize& offset, RenderRegion* region) : m_point(other.m_point) , m_boundingBox(other.m_boundingBox) , m_transformedPoint(other.m_transformedPoint) , m_transformedRect(other.m_transformedRect) - , m_region(region) + , m_region(region ? region : other.m_region) , m_isRectBased(other.m_isRectBased) , m_isRectilinear(other.m_isRectilinear) { move(offset); } -HitTestPoint::HitTestPoint(const HitTestPoint& other) +HitTestLocation::HitTestLocation(const HitTestLocation& other) : m_point(other.m_point) , m_boundingBox(other.m_boundingBox) , m_transformedPoint(other.m_transformedPoint) @@ -122,11 +122,11 @@ HitTestPoint::HitTestPoint(const HitTestPoint& other) { } -HitTestPoint::~HitTestPoint() +HitTestLocation::~HitTestLocation() { } -HitTestPoint& HitTestPoint::operator=(const HitTestPoint& other) +HitTestLocation& HitTestLocation::operator=(const HitTestLocation& other) { m_point = other.m_point; m_boundingBox = other.m_boundingBox; @@ -139,7 +139,7 @@ HitTestPoint& HitTestPoint::operator=(const HitTestPoint& other) return *this; } -void HitTestPoint::move(const LayoutSize& offset) +void HitTestLocation::move(const LayoutSize& offset) { m_point.move(offset); m_transformedPoint.move(offset); @@ -148,7 +148,7 @@ void HitTestPoint::move(const LayoutSize& offset) } template<typename RectType> -bool HitTestPoint::intersectsRect(const RectType& rect) const +bool HitTestLocation::intersectsRect(const RectType& rect) const { // FIXME: When the hit test is not rect based we should use rect.contains(m_point). // That does change some corner case tests though. @@ -169,17 +169,17 @@ bool HitTestPoint::intersectsRect(const RectType& rect) const return m_transformedRect.intersectsRect(rect); } -bool HitTestPoint::intersects(const LayoutRect& rect) const +bool HitTestLocation::intersects(const LayoutRect& rect) const { return intersectsRect(rect); } -bool HitTestPoint::intersects(const FloatRect& rect) const +bool HitTestLocation::intersects(const FloatRect& rect) const { return intersectsRect(rect); } -IntRect HitTestPoint::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) +IntRect HitTestLocation::rectForPoint(const LayoutPoint& point, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) { IntPoint actualPoint(flooredIntPoint(point)); actualPoint -= IntSize(leftPadding, topPadding); @@ -192,41 +192,36 @@ IntRect HitTestPoint::rectForPoint(const LayoutPoint& point, unsigned topPadding return IntRect(actualPoint, actualPadding); } -HitTestResult::HitTestResult() : HitTestPoint() +HitTestResult::HitTestResult() : HitTestLocation() , m_isOverWidget(false) - , m_shadowContentFilterPolicy(DoNotAllowShadowContent) { } -HitTestResult::HitTestResult(const LayoutPoint& point) : HitTestPoint(point) +HitTestResult::HitTestResult(const LayoutPoint& point) : HitTestLocation(point) , m_isOverWidget(false) - , m_shadowContentFilterPolicy(DoNotAllowShadowContent) { } -HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy allowShadowContent) - : HitTestPoint(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding) +HitTestResult::HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding) + : HitTestLocation(centerPoint, topPadding, rightPadding, bottomPadding, leftPadding) , m_isOverWidget(false) - , m_shadowContentFilterPolicy(allowShadowContent) { } -HitTestResult::HitTestResult(const HitTestPoint& other, ShadowContentFilterPolicy allowShadowContent) - : HitTestPoint(other) +HitTestResult::HitTestResult(const HitTestLocation& other) + : HitTestLocation(other) , m_isOverWidget(false) - , m_shadowContentFilterPolicy(allowShadowContent) { } HitTestResult::HitTestResult(const HitTestResult& other) - : HitTestPoint(other) + : HitTestLocation(other) , m_innerNode(other.innerNode()) , m_innerNonSharedNode(other.innerNonSharedNode()) , m_localPoint(other.localPoint()) , m_innerURLElement(other.URLElement()) , m_scrollbar(other.scrollbar()) , m_isOverWidget(other.isOverWidget()) - , m_shadowContentFilterPolicy(other.shadowContentFilterPolicy()) { // Only copy the NodeSet in case of rect hit test. m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); @@ -238,7 +233,7 @@ HitTestResult::~HitTestResult() HitTestResult& HitTestResult::operator=(const HitTestResult& other) { - HitTestPoint::operator=(other); + HitTestLocation::operator=(other); m_innerNode = other.innerNode(); m_innerNonSharedNode = other.innerNonSharedNode(); m_localPoint = other.localPoint(); @@ -248,7 +243,6 @@ HitTestResult& HitTestResult::operator=(const HitTestResult& other) // Only copy the NodeSet in case of rect hit test. m_rectBasedTestResult = adoptPtr(other.m_rectBasedTestResult ? new NodeSet(*other.m_rectBasedTestResult) : 0); - m_shadowContentFilterPolicy = other.shadowContentFilterPolicy(); return *this; } @@ -674,7 +668,7 @@ bool HitTestResult::isContentEditable() const return m_innerNonSharedNode->rendererIsEditable(); } -bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& pointInContainer, const LayoutRect& rect) +bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const LayoutRect& rect) { // If it is not a rect-based hit test, this method has to be no-op. // Return false, so the hit test stops. @@ -685,12 +679,12 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& if (!node) return true; - if (m_shadowContentFilterPolicy == DoNotAllowShadowContent) + if (!request.allowsShadowContent()) node = node->shadowAncestorNode(); mutableRectBasedTestResult().add(node); - bool regionFilled = rect.contains(pointInContainer.boundingBox()); + bool regionFilled = rect.contains(locationInContainer.boundingBox()); // FIXME: This code (incorrectly) attempts to correct for culled inline nodes. See https://bugs.webkit.org/show_bug.cgi?id=85849. if (node->renderer()->isInline() && !regionFilled) { for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) { @@ -709,7 +703,7 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& return !regionFilled; } -bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& pointInContainer, const FloatRect& rect) +bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestRequest& request, const HitTestLocation& locationInContainer, const FloatRect& rect) { // If it is not a rect-based hit test, this method has to be no-op. // Return false, so the hit test stops. @@ -720,12 +714,12 @@ bool HitTestResult::addNodeToRectBasedTestResult(Node* node, const HitTestPoint& if (!node) return true; - if (m_shadowContentFilterPolicy == DoNotAllowShadowContent) + if (!request.allowsShadowContent()) node = node->shadowAncestorNode(); mutableRectBasedTestResult().add(node); - bool regionFilled = rect.contains(pointInContainer.boundingBox()); + bool regionFilled = rect.contains(locationInContainer.boundingBox()); // FIXME: This code (incorrectly) attempts to correct for culled inline nodes. See https://bugs.webkit.org/show_bug.cgi?id=85849. if (node->renderer()->isInline() && !regionFilled) { for (RenderObject* curr = node->renderer()->parent(); curr; curr = curr->parent()) { @@ -784,7 +778,7 @@ Vector<String> HitTestResult::dictationAlternatives() const if (!m_innerNonSharedNode) return Vector<String>(); - DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(hitTestPoint().point(), DocumentMarker::DictationAlternatives); + DocumentMarker* marker = m_innerNonSharedNode->document()->markers()->markerContainingPoint(hitTestLocation().point(), DocumentMarker::DictationAlternatives); if (!marker) return Vector<String>(); diff --git a/Source/WebCore/rendering/HitTestResult.h b/Source/WebCore/rendering/HitTestResult.h index 9d16bf042..bac96a2b1 100644 --- a/Source/WebCore/rendering/HitTestResult.h +++ b/Source/WebCore/rendering/HitTestResult.h @@ -25,7 +25,7 @@ #include "FloatQuad.h" #include "FloatRect.h" #include "HitTestRequest.h" -#include "LayoutTypes.h" +#include "LayoutTypesInlineMethods.h" #include "TextDirection.h" #include <wtf/Forward.h> #include <wtf/ListHashSet.h> @@ -45,22 +45,20 @@ class Node; class RenderRegion; class Scrollbar; -enum ShadowContentFilterPolicy { DoNotAllowShadowContent, AllowShadowContent }; - -class HitTestPoint { +class HitTestLocation { public: - HitTestPoint(); - HitTestPoint(const LayoutPoint&); - HitTestPoint(const FloatPoint&); - HitTestPoint(const FloatPoint&, const FloatQuad&); + HitTestLocation(); + HitTestLocation(const LayoutPoint&); + HitTestLocation(const FloatPoint&); + HitTestLocation(const FloatPoint&, const FloatQuad&); // Pass non-zero padding values to perform a rect-based hit test. - HitTestPoint(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); - // Make a copy the HitTestPoint in a new region by applying given offset to internal point and area. - HitTestPoint(const HitTestPoint&, const LayoutSize& offset, RenderRegion*); - HitTestPoint(const HitTestPoint&); - ~HitTestPoint(); - HitTestPoint& operator=(const HitTestPoint&); + HitTestLocation(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + // Make a copy the HitTestLocation in a new region by applying given offset to internal point and area. + HitTestLocation(const HitTestLocation&, const LayoutSize& offset, RenderRegion* = 0); + HitTestLocation(const HitTestLocation&); + ~HitTestLocation(); + HitTestLocation& operator=(const HitTestLocation&); LayoutPoint point() const { return m_point; } IntPoint roundedPoint() const { return roundedIntPoint(m_point); } @@ -102,15 +100,15 @@ private: bool m_isRectilinear; }; -class HitTestResult : public HitTestPoint { +class HitTestResult : public HitTestLocation { public: typedef ListHashSet<RefPtr<Node> > NodeSet; HitTestResult(); HitTestResult(const LayoutPoint&); // Pass non-negative padding values to perform a rect-based hit test. - HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding, ShadowContentFilterPolicy); - HitTestResult(const HitTestPoint&, ShadowContentFilterPolicy); + HitTestResult(const LayoutPoint& centerPoint, unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding); + HitTestResult(const HitTestLocation&); HitTestResult(const HitTestResult&); ~HitTestResult(); HitTestResult& operator=(const HitTestResult&); @@ -124,8 +122,7 @@ public: void setToNonShadowAncestor(); - const HitTestPoint& hitTestPoint() const { return *this; } - ShadowContentFilterPolicy shadowContentFilterPolicy() const { return m_shadowContentFilterPolicy; } + const HitTestLocation& hitTestLocation() const { return *this; } void setInnerNode(Node*); void setInnerNonSharedNode(Node*); @@ -166,8 +163,8 @@ public: // Returns true if it is rect-based hit test and needs to continue until the rect is fully // enclosed by the boundaries of a node. - bool addNodeToRectBasedTestResult(Node*, const HitTestPoint& pointInContainer, const LayoutRect& = LayoutRect()); - bool addNodeToRectBasedTestResult(Node*, const HitTestPoint& pointInContainer, const FloatRect&); + bool addNodeToRectBasedTestResult(Node*, const HitTestRequest&, const HitTestLocation& pointInContainer, const LayoutRect& = LayoutRect()); + bool addNodeToRectBasedTestResult(Node*, const HitTestRequest&, const HitTestLocation& pointInContainer, const FloatRect&); void append(const HitTestResult&); // If m_rectBasedTestResult is 0 then set it to a new NodeSet. Return *m_rectBasedTestResult. Lazy allocation makes @@ -194,8 +191,6 @@ private: RefPtr<Scrollbar> m_scrollbar; bool m_isOverWidget; // Returns true if we are over a widget (and not in the border/padding area of a RenderWidget for example). - ShadowContentFilterPolicy m_shadowContentFilterPolicy; - mutable OwnPtr<NodeSet> m_rectBasedTestResult; }; diff --git a/Source/WebCore/rendering/HitTestingTransformState.cpp b/Source/WebCore/rendering/HitTestingTransformState.cpp index 6d9cc7629..6d6c33e91 100644 --- a/Source/WebCore/rendering/HitTestingTransformState.cpp +++ b/Source/WebCore/rendering/HitTestingTransformState.cpp @@ -26,6 +26,7 @@ #include "config.h" #include "HitTestingTransformState.h" +#include "FractionalLayoutRect.h" #include <wtf/PassOwnPtr.h> namespace WebCore { diff --git a/Source/WebCore/rendering/InlineBox.cpp b/Source/WebCore/rendering/InlineBox.cpp index be3c9c7cf..01742e5bf 100644 --- a/Source/WebCore/rendering/InlineBox.cpp +++ b/Source/WebCore/rendering/InlineBox.cpp @@ -243,12 +243,12 @@ void InlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, Layo } } -bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) +bool InlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { // Hit test all phases of replaced elements atomically, as though the replaced element established its // own stacking context. (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1 // specification.) - return renderer()->hitTest(request, result, pointInContainer, accumulatedOffset); + return renderer()->hitTest(request, result, locationInContainer, accumulatedOffset); } const RootInlineBox* InlineBox::root() const diff --git a/Source/WebCore/rendering/InlineBox.h b/Source/WebCore/rendering/InlineBox.h index 0edab2c33..d8f7e3c17 100644 --- a/Source/WebCore/rendering/InlineBox.h +++ b/Source/WebCore/rendering/InlineBox.h @@ -95,7 +95,7 @@ public: } virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom); // Overloaded new operator. void* operator new(size_t, RenderArena*); diff --git a/Source/WebCore/rendering/InlineFlowBox.cpp b/Source/WebCore/rendering/InlineFlowBox.cpp index 126db27f9..9ad0fcfa1 100644 --- a/Source/WebCore/rendering/InlineFlowBox.cpp +++ b/Source/WebCore/rendering/InlineFlowBox.cpp @@ -36,6 +36,7 @@ #include "RenderRubyRun.h" #include "RenderRubyText.h" #include "RenderTableCell.h" +#include "RenderView.h" #include "RootInlineBox.h" #include "Text.h" @@ -971,18 +972,18 @@ void InlineFlowBox::setOverflowFromLogicalRects(const LayoutRect& logicalLayoutO setVisualOverflow(visualOverflow, lineTop, lineBottom); } -bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) +bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { LayoutRect overflowRect(visualOverflowRect(lineTop, lineBottom)); flipForWritingMode(overflowRect); overflowRect.moveBy(accumulatedOffset); - if (!pointInContainer.intersects(overflowRect)) + if (!locationInContainer.intersects(overflowRect)) return false; // Check children first. for (InlineBox* curr = lastChild(); curr; curr = curr->prevOnLine()) { - if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, pointInContainer, accumulatedOffset, lineTop, lineBottom)) { - renderer()->updateHitTestResult(result, pointInContainer.point() - toLayoutSize(accumulatedOffset)); + if ((curr->renderer()->isText() || !curr->boxModelObject()->hasSelfPaintingLayer()) && curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { + renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } @@ -1010,9 +1011,9 @@ bool InlineFlowBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& re flipForWritingMode(rect); rect.moveBy(accumulatedOffset); - if (visibleToHitTesting() && pointInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space. - if (!result.addNodeToRectBasedTestResult(renderer()->node(), pointInContainer, rect)) + if (visibleToHitTesting() && locationInContainer.intersects(rect)) { + renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); // Don't add in m_x or m_y here, we want coords in the containing block's space. + if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) return true; } diff --git a/Source/WebCore/rendering/InlineFlowBox.h b/Source/WebCore/rendering/InlineFlowBox.h index 32839f15f..5a34f6c65 100644 --- a/Source/WebCore/rendering/InlineFlowBox.h +++ b/Source/WebCore/rendering/InlineFlowBox.h @@ -116,7 +116,7 @@ public: void paintFillLayer(const PaintInfo&, const Color&, const FillLayer*, const LayoutRect&, CompositeOperator = CompositeSourceOver); void paintBoxShadow(const PaintInfo&, RenderStyle*, ShadowStyle, const LayoutRect&); virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; bool boxShadowCanBeAppliedToBackground(const FillLayer&) const; diff --git a/Source/WebCore/rendering/InlineTextBox.cpp b/Source/WebCore/rendering/InlineTextBox.cpp index 7d63031da..5bc3b7652 100644 --- a/Source/WebCore/rendering/InlineTextBox.cpp +++ b/Source/WebCore/rendering/InlineTextBox.cpp @@ -349,7 +349,7 @@ bool InlineTextBox::isLineBreak() const return renderer()->isBR() || (renderer()->style()->preserveNewline() && len() == 1 && (*textRenderer()->text())[start()] == '\n'); } -bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) +bool InlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit /* lineTop */, LayoutUnit /*lineBottom*/) { if (isLineBreak()) return false; @@ -357,9 +357,9 @@ bool InlineTextBox::nodeAtPoint(const HitTestRequest&, HitTestResult& result, co FloatPoint boxOrigin = locationIncludingFlipping(); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); - if (m_truncation != cFullTruncation && visibleToHitTesting() && pointInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - toLayoutSize(accumulatedOffset))); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), pointInContainer, rect)) + if (m_truncation != cFullTruncation && visibleToHitTesting() && locationInContainer.intersects(rect)) { + renderer()->updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(accumulatedOffset))); + if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) return true; } return false; diff --git a/Source/WebCore/rendering/InlineTextBox.h b/Source/WebCore/rendering/InlineTextBox.h index a3e7630e6..06ba040fc 100644 --- a/Source/WebCore/rendering/InlineTextBox.h +++ b/Source/WebCore/rendering/InlineTextBox.h @@ -115,7 +115,7 @@ public: protected: virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; public: RenderText* textRenderer() const; diff --git a/Source/WebCore/rendering/LayoutRepainter.h b/Source/WebCore/rendering/LayoutRepainter.h index 57400faeb..6f63e82d3 100644 --- a/Source/WebCore/rendering/LayoutRepainter.h +++ b/Source/WebCore/rendering/LayoutRepainter.h @@ -26,7 +26,7 @@ #ifndef LayoutRepainter_h #define LayoutRepainter_h -#include "LayoutTypes.h" +#include "LayoutTypesInlineMethods.h" namespace WebCore { diff --git a/Source/WebCore/rendering/LayoutState.cpp b/Source/WebCore/rendering/LayoutState.cpp index 1dff9533e..1e4442f2f 100644 --- a/Source/WebCore/rendering/LayoutState.cpp +++ b/Source/WebCore/rendering/LayoutState.cpp @@ -83,7 +83,7 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz // If we establish a new page height, then cache the offset to the top of the first page. // We can compare this later on to figure out what part of the page we're actually on, - if (pageLogicalHeight || m_columnInfo) { + if (pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread()) { m_pageLogicalHeight = pageLogicalHeight; bool isFlipped = renderer->style()->isFlippedBlocksWritingMode(); m_pageOffset = LayoutSize(m_layoutOffset.width() + (!isFlipped ? renderer->borderLeft() + renderer->paddingLeft() : renderer->borderRight() + renderer->paddingRight()), @@ -109,7 +109,7 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz m_layoutDelta = m_next->m_layoutDelta; - m_isPaginated = m_pageLogicalHeight || m_columnInfo; + m_isPaginated = m_pageLogicalHeight || m_columnInfo || renderer->isRenderFlowThread(); if (lineGrid() && renderer->hasColumns() && renderer->style()->hasInlineColumnAxis()) computeLineGridPaginationOrigin(renderer); @@ -121,23 +121,6 @@ LayoutState::LayoutState(LayoutState* prev, RenderBox* renderer, const LayoutSiz // FIXME: <http://bugs.webkit.org/show_bug.cgi?id=13443> Apply control clip if present. } -LayoutState::LayoutState(LayoutState* prev, RenderFlowThread* flowThread, bool regionsChanged) - : m_clipped(false) - , m_isPaginated(true) - , m_pageLogicalHeight(1) // Use a fake height here. That value is not important, just needs to be non-zero. - , m_pageLogicalHeightChanged(regionsChanged) - , m_columnInfo(0) - , m_lineGrid(0) - , m_next(prev) -#ifndef NDEBUG - , m_renderer(flowThread) -#endif -{ -#ifdef NDEBUG - UNUSED_PARAM(flowThread); -#endif -} - LayoutState::LayoutState(RenderObject* root) : m_clipped(false) , m_isPaginated(false) diff --git a/Source/WebCore/rendering/LayoutState.h b/Source/WebCore/rendering/LayoutState.h index 81d61e9cd..152c80465 100644 --- a/Source/WebCore/rendering/LayoutState.h +++ b/Source/WebCore/rendering/LayoutState.h @@ -57,7 +57,6 @@ public: } LayoutState(LayoutState*, RenderBox*, const LayoutSize& offset, LayoutUnit pageHeight, bool pageHeightChanged, ColumnInfo*); - LayoutState(LayoutState*, RenderFlowThread*, bool regionsChanged); LayoutState(RenderObject*); void destroy(RenderArena*); diff --git a/Source/WebCore/rendering/LayoutTypes.h b/Source/WebCore/rendering/LayoutTypes.h index 51967f8e9..ff7e6c274 100644 --- a/Source/WebCore/rendering/LayoutTypes.h +++ b/Source/WebCore/rendering/LayoutTypes.h @@ -36,132 +36,24 @@ #ifndef LayoutTypes_h #define LayoutTypes_h -#include "FloatRect.h" -#include "FractionalLayoutBoxExtent.h" -#include "FractionalLayoutRect.h" -#include "FractionalLayoutUnit.h" -#include "IntRect.h" - -#include <wtf/MathExtras.h> - namespace WebCore { -typedef FractionalLayoutUnit LayoutUnit; +class FractionalLayoutBoxExtent; +class FractionalLayoutPoint; +class FractionalLayoutRect; +class FractionalLayoutSize; +class FractionalLayoutUnit; + +typedef FractionalLayoutBoxExtent LayoutBoxExtent; typedef FractionalLayoutPoint LayoutPoint; -typedef FractionalLayoutSize LayoutSize; typedef FractionalLayoutRect LayoutRect; -typedef FractionalLayoutBoxExtent LayoutBoxExtent; +typedef FractionalLayoutSize LayoutSize; +typedef FractionalLayoutUnit LayoutUnit; #define MAX_LAYOUT_UNIT LayoutUnit::max() #define MIN_LAYOUT_UNIT LayoutUnit::min() #define ZERO_LAYOUT_UNIT LayoutUnit(0) -inline FractionalLayoutRect enclosingLayoutRect(const FloatRect& rect) -{ - return enclosingIntRect(rect); -} - -inline LayoutSize roundedLayoutSize(const FloatSize& s) -{ -#if ENABLE(SUBPIXEL_LAYOUT) - return FractionalLayoutSize(s); -#else - return roundedIntSize(s); -#endif -} - -inline IntRect pixelSnappedIntRect(LayoutUnit left, LayoutUnit top, LayoutUnit width, LayoutUnit height) -{ - return IntRect(left.round(), top.round(), snapSizeToPixel(width, left), snapSizeToPixel(height, top)); -} - -inline IntRect pixelSnappedIntRectFromEdges(LayoutUnit left, LayoutUnit top, LayoutUnit right, LayoutUnit bottom) -{ - return IntRect(left.round(), top.round(), snapSizeToPixel(right - left, left), snapSizeToPixel(bottom - top, top)); -} - -inline LayoutPoint roundedLayoutPoint(const FloatPoint& p) -{ -#if ENABLE(SUBPIXEL_LAYOUT) - return FractionalLayoutPoint(p); -#else - return roundedIntPoint(p); -#endif -} - -inline LayoutPoint flooredLayoutPoint(const FloatPoint& p) -{ - return flooredFractionalLayoutPoint(p); -} - -inline LayoutPoint flooredLayoutPoint(const FloatSize& s) -{ - return flooredLayoutPoint(FloatPoint(s)); -} - -inline int roundToInt(LayoutUnit value) -{ - return value.round(); -} - -inline int floorToInt(LayoutUnit value) -{ - return value.floor(); -} - -inline LayoutUnit roundedLayoutUnit(float value) -{ -#if ENABLE(SUBPIXEL_LAYOUT) - return FractionalLayoutUnit::fromFloatRound(value); -#else - return static_cast<int>(lroundf(value)); -#endif -} - -inline LayoutUnit ceiledLayoutUnit(float value) -{ -#if ENABLE(SUBPIXEL_LAYOUT) - return FractionalLayoutUnit::fromFloatCeil(value); -#else - return ceilf(value); -#endif -} - -inline LayoutUnit absoluteValue(const LayoutUnit& value) -{ - return value.abs(); -} - -inline LayoutSize toLayoutSize(const LayoutPoint& p) -{ - return LayoutSize(p.x(), p.y()); -} - -inline LayoutPoint toLayoutPoint(const LayoutSize& p) -{ - return LayoutPoint(p.width(), p.height()); -} - -inline LayoutUnit layoutMod(const LayoutUnit& numerator, const LayoutUnit& denominator) -{ - return numerator % denominator; -} - -inline IntSize pixelSnappedIntSize(const FractionalLayoutSize& s, const FractionalLayoutPoint& p) -{ - return IntSize(snapSizeToPixel(s.width(), p.x()), snapSizeToPixel(s.height(), p.y())); -} - -inline IntRect pixelSnappedIntRect(LayoutPoint location, LayoutSize size) -{ - return IntRect(roundedIntPoint(location), pixelSnappedIntSize(size, location)); -} - -inline bool isIntegerValue(const LayoutUnit value) -{ - return value.toInt() == value; -} - } // namespace WebCore #endif // LayoutTypes_h diff --git a/Source/WebCore/rendering/LayoutTypesInlineMethods.h b/Source/WebCore/rendering/LayoutTypesInlineMethods.h new file mode 100644 index 000000000..3cb4a0fdb --- /dev/null +++ b/Source/WebCore/rendering/LayoutTypesInlineMethods.h @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 Google 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: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT + * OWNER 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 LayoutTypesInlineMethods_h +#define LayoutTypesInlineMethods_h + +#include "FloatRect.h" +#include "FractionalLayoutBoxExtent.h" +#include "FractionalLayoutRect.h" +#include "FractionalLayoutUnit.h" +#include "IntRect.h" +#include "LayoutTypes.h" + +#include <wtf/MathExtras.h> + +namespace WebCore { + +inline FractionalLayoutRect enclosingLayoutRect(const FloatRect& rect) +{ + return enclosingIntRect(rect); +} + +inline LayoutSize roundedLayoutSize(const FloatSize& s) +{ +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutSize(s); +#else + return roundedIntSize(s); +#endif +} + +inline IntRect pixelSnappedIntRect(LayoutUnit left, LayoutUnit top, LayoutUnit width, LayoutUnit height) +{ + return IntRect(left.round(), top.round(), snapSizeToPixel(width, left), snapSizeToPixel(height, top)); +} + +inline IntRect pixelSnappedIntRectFromEdges(LayoutUnit left, LayoutUnit top, LayoutUnit right, LayoutUnit bottom) +{ + return IntRect(left.round(), top.round(), snapSizeToPixel(right - left, left), snapSizeToPixel(bottom - top, top)); +} + +inline LayoutPoint roundedLayoutPoint(const FloatPoint& p) +{ +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutPoint(p); +#else + return roundedIntPoint(p); +#endif +} + +inline LayoutPoint flooredLayoutPoint(const FloatPoint& p) +{ + return flooredFractionalLayoutPoint(p); +} + +inline LayoutPoint flooredLayoutPoint(const FloatSize& s) +{ + return flooredLayoutPoint(FloatPoint(s)); +} + +inline int roundToInt(LayoutUnit value) +{ + return value.round(); +} + +inline int floorToInt(LayoutUnit value) +{ + return value.floor(); +} + +inline LayoutUnit roundedLayoutUnit(float value) +{ +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutUnit::fromFloatRound(value); +#else + return static_cast<int>(lroundf(value)); +#endif +} + +inline LayoutUnit ceiledLayoutUnit(float value) +{ +#if ENABLE(SUBPIXEL_LAYOUT) + return FractionalLayoutUnit::fromFloatCeil(value); +#else + return ceilf(value); +#endif +} + +inline LayoutUnit absoluteValue(const LayoutUnit& value) +{ + return value.abs(); +} + +inline LayoutSize toLayoutSize(const LayoutPoint& p) +{ + return LayoutSize(p.x(), p.y()); +} + +inline LayoutPoint toLayoutPoint(const LayoutSize& p) +{ + return LayoutPoint(p.width(), p.height()); +} + +inline LayoutUnit layoutMod(const LayoutUnit& numerator, const LayoutUnit& denominator) +{ + return numerator % denominator; +} + +inline IntSize pixelSnappedIntSize(const FractionalLayoutSize& s, const FractionalLayoutPoint& p) +{ + return IntSize(snapSizeToPixel(s.width(), p.x()), snapSizeToPixel(s.height(), p.y())); +} + +inline IntRect pixelSnappedIntRect(LayoutPoint location, LayoutSize size) +{ + return IntRect(roundedIntPoint(location), pixelSnappedIntSize(size, location)); +} + +inline bool isIntegerValue(const LayoutUnit value) +{ + return value.toInt() == value; +} + +} // namespace WebCore + +#endif // LayoutTypesInlineMethods_h diff --git a/Source/WebCore/rendering/PaintInfo.h b/Source/WebCore/rendering/PaintInfo.h index 7ed743272..88a3c7abc 100644 --- a/Source/WebCore/rendering/PaintInfo.h +++ b/Source/WebCore/rendering/PaintInfo.h @@ -32,7 +32,7 @@ #include "GraphicsContext.h" #include "IntRect.h" -#include "LayoutTypes.h" +#include "LayoutTypesInlineMethods.h" #include "PaintPhase.h" #include <limits> #include <wtf/HashMap.h> diff --git a/Source/WebCore/rendering/RenderBlock.cpp b/Source/WebCore/rendering/RenderBlock.cpp index 119cbb7fd..10216bc00 100755 --- a/Source/WebCore/rendering/RenderBlock.cpp +++ b/Source/WebCore/rendering/RenderBlock.cpp @@ -61,6 +61,9 @@ #include "ShadowRoot.h" #include "TransformState.h" #include <wtf/StdLibExtras.h> +#if ENABLE(CSS_EXCLUSIONS) +#include "WrapShapeInfo.h" +#endif using namespace std; using namespace WTF; @@ -275,6 +278,10 @@ void RenderBlock::willBeDestroyed() if (lineGridBox()) lineGridBox()->destroy(renderArena()); +#if ENABLE(CSS_EXCLUSIONS) + WrapShapeInfo::removeWrapShapeInfoForRenderBlock(this); +#endif + if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0)) gDelayedUpdateScrollInfoSet->remove(this); @@ -320,6 +327,12 @@ void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldSty { RenderBox::styleDidChange(diff, oldStyle); +#if ENABLE(CSS_EXCLUSIONS) + // FIXME: Bug 89993: Style changes should affect the WrapShapeInfos for other render blocks that + // share the same WrapShapeInfo + updateWrapShapeInfoAfterStyleChange(style()->wrapShapeInside(), oldStyle ? oldStyle->wrapShapeInside() : 0); +#endif + if (!isAnonymousBlock()) { // Ensure that all of our continuation blocks pick up the new style. for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) { @@ -1366,6 +1379,21 @@ void RenderBlock::layout() clearLayoutOverflow(); } +#if ENABLE(CSS_EXCLUSIONS) +void RenderBlock::updateWrapShapeInfoAfterStyleChange(const BasicShape* wrapShape, const BasicShape* oldWrapShape) +{ + // FIXME: A future optimization would do a deep comparison for equality. + if (wrapShape == oldWrapShape) + return; + + if (wrapShape) { + WrapShapeInfo* wrapShapeInfo = WrapShapeInfo::ensureWrapShapeInfoForRenderBlock(this); + wrapShapeInfo->dirtyWrapShapeSize(); + } else + WrapShapeInfo::removeWrapShapeInfoForRenderBlock(this); +} +#endif + void RenderBlock::computeInitialRegionRangeForBlock() { if (inRenderFlowThread()) { @@ -1422,6 +1450,9 @@ void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalH colInfo->clearForcedBreaks(); colInfo->setPaginationUnit(paginationUnit()); + } else if (isRenderFlowThread()) { + pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height. + pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalHeightChanged(); } } @@ -1461,6 +1492,11 @@ void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeigh relayoutChildren = true; } computeInitialRegionRangeForBlock(); +#if ENABLE(CSS_EXCLUSIONS) + // FIXME: Bug 93547: Resolve logical height for percentage based vertical lengths + if (WrapShapeInfo* wrapShapeInfo = this->wrapShapeInfo()) + wrapShapeInfo->computeShapeSize(logicalWidth(), 0); +#endif // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track // our current maximal positive and negative margins. These values are used when we @@ -2049,28 +2085,28 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin // For self-collapsing blocks that clear, they can still collapse their // margins with following siblings. Reset the current margins to represent // the self-collapsing block's margins only. - // CSS2.1 states: - // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin. - // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the - // self-collapsing block's bottom margin. - bool atBottomOfBlock = true; - for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) { - if (!curr->isFloatingOrOutOfFlowPositioned()) - atBottomOfBlock = false; - } - MarginValues childMargins = marginValuesForChild(child); - if (atBottomOfBlock) { - marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); - marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); - } else { - marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); - marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); - } - - // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom - // of the parent block). - setLogicalHeight(child->logicalTop() - max(ZERO_LAYOUT_UNIT, marginInfo.margin())); + marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); + marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); + + // CSS2.1 states: + // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with + // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block." + // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings + // for a block with height - if none is found then don't allow the margins to collapse with the parent. + bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren(); + for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) { + if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock()) + wouldCollapseMarginsWithParent = false; + } + if (wouldCollapseMarginsWithParent) + marginInfo.setCanCollapseMarginAfterWithChildren(false); + + // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top" + // Move the top of the child box to the bottom of the float ignoring the child's top margin. + LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child); + setLogicalHeight(child->logicalTop() - collapsedMargin); + heightIncrease -= collapsedMargin; } else // Increase our height by the amount we had to clear. setLogicalHeight(logicalHeight() + heightIncrease); @@ -2084,8 +2120,14 @@ LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& margin setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin); marginInfo.setAtBeforeSideOfBlock(false); } - - return yPos + heightIncrease; + + LayoutUnit logicalTop = yPos + heightIncrease; + // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it + // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now. + if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop) + toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop); + + return logicalTop; } void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const @@ -2122,7 +2164,7 @@ void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& pos // Make sure to update the block margins now for the grandchild box so that we're looking at current values. if (grandchildBox->needsLayout()) { - grandchildBox->computeBlockDirectionMargins(this); + grandchildBox->computeAndSetBlockDirectionMargins(this); grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk()); grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk()); } @@ -2246,7 +2288,10 @@ void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit after marginInfo.setAtAfterSideOfBlock(true); // If we can't collapse with children then go ahead and add in the bottom margin. + // Don't do this for ordinary anonymous blocks as only the enclosing box should add in + // its margin. if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() + && (!isAnonymousBlock() || isAnonymousColumnsBlock() || isAnonymousColumnSpanBlock()) && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk())) setLogicalHeight(logicalHeight() + marginInfo.margin()); @@ -2366,7 +2411,7 @@ void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, Lay LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); // The child is a normal flow object. Compute the margins we will use for collapsing now. - child->computeBlockDirectionMargins(this); + child->computeAndSetBlockDirectionMargins(this); // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE. RenderStyle* childStyle = child->style(); @@ -2615,14 +2660,6 @@ void RenderBlock::layoutPositionedObjects(bool relayoutChildren) r->layoutIfNeeded(); - // Adjust the static position of a center-aligned inline positioned object with a block child now that the child's width has been computed. - if (!r->parent()->isRenderView() && r->parent()->isRenderBlock() && r->firstChild() && r->style()->position() == AbsolutePosition - && r->style()->isOriginalDisplayInlineType() && (r->style()->textAlign() == CENTER || r->style()->textAlign() == WEBKIT_CENTER)) { - RenderBlock* block = toRenderBlock(r->parent()); - LayoutUnit blockHeight = block->logicalHeight(); - block->setStaticInlinePositionForChild(r, blockHeight, block->startAlignedOffsetForLine(r, blockHeight, false)); - } - // Lay out again if our estimate was wrong. if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) { r->setChildNeedsLayout(true, MarkOnlyThis); @@ -3177,9 +3214,10 @@ bool RenderBlock::isSelectionRoot() const return false; if (isBody() || isRoot() || hasOverflowClip() - || isInFlowPositioned() || isFloatingOrOutOfFlowPositioned() + || isPositioned() || isFloating() || isTableCell() || isInlineBlockOrInlineTable() - || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()) + || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot() + || isRenderFlowThread()) return true; if (view() && view()->selectionStart()) { @@ -3723,7 +3761,7 @@ RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) o->layoutIfNeeded(); else { o->computeLogicalWidth(); - o->computeBlockDirectionMargins(this); + o->computeAndSetBlockDirectionMargins(this); } setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o)); @@ -4473,6 +4511,8 @@ bool RenderBlock::hasOverhangingFloat(RenderBox* renderer) void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset) { + ASSERT(!avoidsFloats()); + // If the parent or previous sibling doesn't have any floats to add, don't bother. if (!prev->m_floatingObjects) return; @@ -4641,15 +4681,15 @@ LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop) return result; } -bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) +bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) { if (!scrollsOverflow()) return false; - return layer()->hitTestOverflowControls(result, roundedIntPoint(pointInContainer - toLayoutSize(accumulatedOffset))); + return layer()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset))); } -bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { LayoutPoint adjustedLocation(accumulatedOffset + location()); LayoutSize localOffset = toLayoutSize(adjustedLocation); @@ -4659,21 +4699,21 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu LayoutRect overflowBox = visualOverflowRect(); flipForWritingMode(overflowBox); overflowBox.moveBy(adjustedLocation); - if (!pointInContainer.intersects(overflowBox)) + if (!locationInContainer.intersects(overflowBox)) return false; } - if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, pointInContainer.point(), adjustedLocation)) { - updateHitTestResult(result, pointInContainer.point() - localOffset); + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) { + updateHitTestResult(result, locationInContainer.point() - localOffset); // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet. - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer)) + if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer)) return true; } // If we have clipping, then we can't have any spillout. bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); bool useClip = (hasControlClip() || useOverflowClip); - bool checkChildren = !useClip || (hasControlClip() ? pointInContainer.intersects(controlClipRect(adjustedLocation)) : pointInContainer.intersects(overflowClipRect(adjustedLocation, pointInContainer.region(), IncludeOverlayScrollbarSize))); + bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize))); if (checkChildren) { // Hit test descendants first. LayoutSize scrolledOffset(localOffset); @@ -4682,14 +4722,14 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Hit test contents if we don't have columns. if (!hasColumns()) { - if (hitTestContents(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { - updateHitTestResult(result, pointInContainer.point() - localOffset); + if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { + updateHitTestResult(result, locationInContainer.point() - localOffset); return true; } - if (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, toLayoutPoint(scrolledOffset))) + if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset))) return true; - } else if (hitTestColumns(request, result, pointInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { - updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - localOffset)); + } else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { + updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset)); return true; } } @@ -4697,9 +4737,9 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Now hit test our background if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { LayoutRect boundsRect(adjustedLocation, size()); - if (visibleToHitTesting() && pointInContainer.intersects(boundsRect)) { - updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - localOffset)); - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) + if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) { + updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset)); + if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect)) return true; } } @@ -4707,7 +4747,7 @@ bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu return false; } -bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset) +bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) { if (!m_floatingObjects) return false; @@ -4726,8 +4766,8 @@ bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& re LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset)); - if (floatingObject->m_renderer->hitTest(request, result, pointInContainer, childPoint)) { - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(childPoint)); + if (floatingObject->m_renderer->hitTest(request, result, locationInContainer, childPoint)) { + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint)); return true; } } @@ -4795,48 +4835,48 @@ private: LayoutRect m_colRect; }; -bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { // We need to do multiple passes, breaking up our hit testing into strips. if (!hasColumns()) return false; for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { - LayoutRect hitRect = pointInContainer.boundingBox(); + LayoutRect hitRect = locationInContainer.boundingBox(); LayoutRect colRect = it.columnRect(); colRect.moveBy(accumulatedOffset); - if (pointInContainer.intersects(colRect)) { + if (locationInContainer.intersects(colRect)) { // The point is inside this column. // Adjust accumulatedOffset to change where we hit test. LayoutSize offset; it.adjust(offset); LayoutPoint finalLocation = accumulatedOffset + offset; if (!result.isRectBasedTest() || colRect.contains(hitRect)) - return hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, pointInContainer, finalLocation)); + return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation)); - hitTestContents(request, result, pointInContainer, finalLocation, hitTestAction); + hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction); } } return false; } -void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& pointInContainer) const +void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const { for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { LayoutRect colRect = it.columnRect(); - if (colRect.contains(pointInContainer)) { + if (colRect.contains(locationInContainer)) { it.adjust(offset); return; } } } -bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { if (childrenInline() && !isTable()) { // We have to hit-test our line boxes. - if (m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction)) + if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction)) return true; } else { // Hit test our children. @@ -4845,7 +4885,7 @@ bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& childHitTest = HitTestChildBlockBackground; for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset); - if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, pointInContainer, childPoint, childHitTest)) + if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest)) return true; } } @@ -6851,11 +6891,11 @@ bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBou // See if we're in the last region. LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset; - RenderRegion* region = enclosingRenderFlowThread()->renderRegionForLine(pageOffset, this); + RenderRegion* region = enclosingRenderFlowThread()->regionAtBlockOffset(pageOffset, this); if (!region) return false; if (region->isLastRegion()) - return region->style()->regionOverflow() == BreakRegionOverflow + return region->isRenderRegionSet() || region->style()->regionOverflow() == BreakRegionOverflow || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->offsetFromLogicalTopOfFirstPage()); return true; } @@ -6938,7 +6978,7 @@ LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const return 0; return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight); } - return enclosingRenderFlowThread()->regionLogicalTopForLine(cumulativeOffset); + return enclosingRenderFlowThread()->pageLogicalTopForOffset(cumulativeOffset); } LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const @@ -6946,7 +6986,7 @@ LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const RenderView* renderView = view(); if (!inRenderFlowThread()) return renderView->layoutState()->m_pageLogicalHeight; - return enclosingRenderFlowThread()->regionLogicalHeightForLine(offset + offsetFromLogicalTopOfFirstPage()); + return enclosingRenderFlowThread()->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage()); } LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const @@ -6965,7 +7005,7 @@ LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, P return remainingHeight; } - return enclosingRenderFlowThread()->regionRemainingLogicalHeightForLine(offset, pageBoundaryRule); + return enclosingRenderFlowThread()->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule); } LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins) @@ -7172,7 +7212,7 @@ RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const if (!flowThread || !flowThread->hasValidRegionInfo()) return 0; - return flowThread->renderRegionForLine(offsetFromLogicalTopOfFirstPage() + blockOffset, true); + return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true); } void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition) @@ -7329,6 +7369,8 @@ const char* RenderBlock::renderName() const return "RenderBlock (generated)"; if (isRelPositioned()) return "RenderBlock (relative positioned)"; + if (isStickyPositioned()) + return "RenderBlock (sticky positioned)"; if (isRunIn()) return "RenderBlock (run-in)"; return "RenderBlock"; diff --git a/Source/WebCore/rendering/RenderBlock.h b/Source/WebCore/rendering/RenderBlock.h index a31b26ed6..a33eeaf5b 100644 --- a/Source/WebCore/rendering/RenderBlock.h +++ b/Source/WebCore/rendering/RenderBlock.h @@ -29,16 +29,20 @@ #include "RenderBox.h" #include "RenderLineBoxList.h" #include "RootInlineBox.h" +#include "TextBreakIterator.h" #include "TextRun.h" #include <wtf/OwnPtr.h> #include <wtf/ListHashSet.h> +#if ENABLE(CSS_EXCLUSIONS) +#include "WrapShapeInfo.h" +#endif + namespace WebCore { class BidiContext; class InlineIterator; class LayoutStateMaintainer; -class LazyLineBreakIterator; class LineLayoutState; class LineWidth; class RenderInline; @@ -48,6 +52,7 @@ struct BidiRun; struct PaintInfo; class LineInfo; class RenderRubyRun; +class TextLayout; template <class Iterator, class Run> class BidiResolver; template <class Run> class BidiRunList; @@ -195,7 +200,7 @@ public: : logicalWidth() - logicalRightOffsetForLine(position, firstLine, logicalHeight); } - LayoutUnit startAlignedOffsetForLine(RenderBox* child, LayoutUnit position, bool firstLine); + LayoutUnit startAlignedOffsetForLine(LayoutUnit position, bool firstLine); LayoutUnit textIndentOffset() const; virtual VisiblePosition positionForPoint(const LayoutPoint&); @@ -229,7 +234,7 @@ public: void adjustRectForColumns(LayoutRect&) const; virtual void adjustForColumns(LayoutSize&, const LayoutPoint&) const; - void adjustForColumnRect(LayoutSize& offset, const LayoutPoint& pointInContainer) const; + void adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const; void addContinuationWithOutline(RenderInline*); bool paintsContinuationOutline(RenderInline*); @@ -396,6 +401,13 @@ public: void showLineTreeAndMark(const InlineBox* = 0, const char* = 0, const InlineBox* = 0, const char* = 0, const RenderObject* = 0) const; #endif +#if ENABLE(CSS_EXCLUSIONS) + WrapShapeInfo* wrapShapeInfo() const + { + return style()->wrapShapeInside() && WrapShapeInfo::isWrapShapeInfoEnabledForRenderBlock(this) ? WrapShapeInfo::wrapShapeInfoForRenderBlock(this) : 0; + } +#endif + protected: virtual void willBeDestroyed(); @@ -431,7 +443,7 @@ protected: virtual ETextAlign textAlignmentForLine(bool endsWithSoftBreak) const; virtual void adjustInlineDirectionLineBounds(int /* expansionOpportunityCount */, float& /* logicalLeft */, float& /* logicalWidth */) const { } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual void computePreferredLogicalWidths(); @@ -485,6 +497,9 @@ protected: virtual void checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight); private: +#if ENABLE(CSS_EXCLUSIONS) + void updateWrapShapeInfoAfterStyleChange(const BasicShape*, const BasicShape* oldWrapShape); +#endif virtual RenderObjectChildList* virtualChildren() { return children(); } virtual const RenderObjectChildList* virtualChildren() const { return children(); } @@ -692,7 +707,16 @@ private: LayoutPoint computeLogicalLocationForFloat(const FloatingObject*, LayoutUnit logicalTopOffset) const; // The following functions' implementations are in RenderBlockLineLayout.cpp. - typedef std::pair<RenderText*, LazyLineBreakIterator> LineBreakIteratorInfo; + struct RenderTextInfo { + // Destruction of m_layout requires TextLayout to be a complete type, so the constructor and destructor are made non-inline to avoid compilation errors. + RenderTextInfo(); + ~RenderTextInfo(); + + RenderText* m_text; + OwnPtr<TextLayout> m_layout; + LazyLineBreakIterator m_lineBreakIterator; + }; + class LineBreaker { public: LineBreaker(RenderBlock* block) @@ -701,7 +725,7 @@ private: reset(); } - InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, LineBreakIteratorInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines); + InlineIterator nextLineBreak(InlineBidiResolver&, LineInfo&, RenderTextInfo&, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines); bool lineWasHyphenated() { return m_hyphenated; } const Vector<RenderBox*>& positionedObjects() { return m_positionedObjects; } @@ -770,11 +794,11 @@ private: LayoutUnit lowestFloatLogicalBottom(FloatingObject::Type = FloatingObject::FloatLeftRight) const; LayoutUnit nextFloatLogicalBottomBelow(LayoutUnit) const; - virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); - bool hitTestFloats(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset); + virtual bool hitTestColumns(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); + virtual bool hitTestContents(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); + bool hitTestFloats(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset); - virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset); + virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset); void computeInlinePreferredLogicalWidths(); void computeBlockPreferredLogicalWidths(); @@ -906,6 +930,7 @@ private: bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; } bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; } bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; } + void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; } bool quirkContainer() const { return m_quirkContainer; } bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; } bool marginBeforeQuirk() const { return m_marginBeforeQuirk; } diff --git a/Source/WebCore/rendering/RenderBlockLineLayout.cpp b/Source/WebCore/rendering/RenderBlockLineLayout.cpp index 55377d986..c0c3404ad 100755 --- a/Source/WebCore/rendering/RenderBlockLineLayout.cpp +++ b/Source/WebCore/rendering/RenderBlockLineLayout.cpp @@ -36,7 +36,6 @@ #include "RenderRubyRun.h" #include "RenderView.h" #include "Settings.h" -#include "TextBreakIterator.h" #include "TrailingFloatsRootInlineBox.h" #include "VerticalPositionCache.h" #include "break_lines.h" @@ -46,6 +45,10 @@ #include <wtf/Vector.h> #include <wtf/unicode/CharacterNames.h> +#if ENABLE(CSS_EXCLUSIONS) +#include "WrapShapeInfo.h" +#endif + #if ENABLE(SVG) #include "RenderSVGInlineText.h" #include "SVGRootInlineBox.h" @@ -70,9 +73,21 @@ public: , m_left(0) , m_right(0) , m_availableWidth(0) +#if ENABLE(CSS_EXCLUSIONS) + , m_segment(0) +#endif , m_isFirstLine(isFirstLine) { ASSERT(block); +#if ENABLE(CSS_EXCLUSIONS) + WrapShapeInfo* wrapShapeInfo = m_block->wrapShapeInfo(); + // FIXME: Bug 91878: Add support for multiple segments, currently we only support one + if (wrapShapeInfo && wrapShapeInfo->lineState() == WrapShapeInfo::LINE_INSIDE_SHAPE) { + // All interior shape positions should have at least one segment + ASSERT(wrapShapeInfo->hasSegments()); + m_segment = &wrapShapeInfo->segments()[0]; + } +#endif updateAvailableWidth(); } #if ENABLE(SUBPIXEL_LAYOUT) @@ -114,6 +129,9 @@ private: float m_left; float m_right; float m_availableWidth; +#if ENABLE(CSS_EXCLUSIONS) + const LineSegment* m_segment; +#endif bool m_isFirstLine; }; @@ -138,6 +156,13 @@ inline void LineWidth::updateAvailableWidth() m_left = m_block->logicalLeftOffsetForLine(height, m_isFirstLine, logicalHeight); m_right = m_block->logicalRightOffsetForLine(height, m_isFirstLine, logicalHeight); +#if ENABLE(CSS_EXCLUSIONS) + if (m_segment) { + m_left = max<float>(m_segment->logicalLeft, m_left); + m_right = min<float>(m_segment->logicalRight, m_right); + } +#endif + computeAvailableWidthFromLeftAndRight(); } @@ -397,9 +422,9 @@ static inline InlineBox* createInlineBoxForRenderer(RenderObject* obj, bool isRo static inline void dirtyLineBoxesForRenderer(RenderObject* o, bool fullLayout) { if (o->isText()) { - if (o->preferredLogicalWidthsDirty() && (o->isCounter() || o->isQuote())) - toRenderText(o)->computePreferredLogicalWidths(0); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed. - toRenderText(o)->dirtyLineBoxes(fullLayout); + RenderText* renderText = toRenderText(o); + renderText->updateTextIfNeeded(); // FIXME: Counters depend on this hack. No clue why. Should be investigated and removed. + renderText->dirtyLineBoxes(fullLayout); } else toRenderInline(o)->dirtyLineBoxes(fullLayout); } @@ -777,7 +802,15 @@ void RenderBlock::computeInlineDirectionPositionsForLine(RootInlineBox* lineBox, // box is only affected if it is the first child of its parent element." bool firstLine = lineInfo.isFirstLine() && !(isAnonymousBlock() && parent()->firstChild() != this); float logicalLeft = pixelSnappedLogicalLeftOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight); - float availableLogicalWidth = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight) - logicalLeft; + float logicalRight = pixelSnappedLogicalRightOffsetForLine(logicalHeight(), firstLine, lineLogicalHeight); +#if ENABLE(CSS_EXCLUSIONS) + WrapShapeInfo* wrapShapeInfo = this->wrapShapeInfo(); + if (wrapShapeInfo && wrapShapeInfo->lineState() == WrapShapeInfo::LINE_INSIDE_SHAPE) { + logicalLeft = max<float>(roundToInt(wrapShapeInfo->segments()[0].logicalLeft), logicalLeft); + logicalRight = min<float>(floorToInt(wrapShapeInfo->segments()[0].logicalRight), logicalRight); + } +#endif + float availableLogicalWidth = logicalRight - logicalLeft; bool needsWordSpacing = false; float totalLogicalWidth = lineBox->getFlowSpacingLogicalWidth(); @@ -888,12 +921,12 @@ static void setStaticPositions(RenderBlock* block, RenderBox* child) // A relative positioned inline encloses us. In this case, we also have to determine our // position as though we were an inline. Set |staticInlinePosition| and |staticBlockPosition| on the relative positioned // inline so that we can obtain the value later. - toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(child, blockHeight, false)); + toRenderInline(containerBlock)->layer()->setStaticInlinePosition(block->startAlignedOffsetForLine(blockHeight, false)); toRenderInline(containerBlock)->layer()->setStaticBlockPosition(blockHeight); } if (child->style()->isOriginalDisplayInlineType()) - block->setStaticInlinePositionForChild(child, blockHeight, block->startAlignedOffsetForLine(child, blockHeight, false)); + block->setStaticInlinePositionForChild(child, blockHeight, block->startAlignedOffsetForLine(blockHeight, false)); else block->setStaticInlinePositionForChild(child, blockHeight, block->startOffsetForContent(blockHeight)); child->layer()->setStaticBlockPosition(blockHeight); @@ -1240,6 +1273,15 @@ void RenderBlock::layoutRunsAndFloats(LineLayoutState& layoutState, bool hasInli repaintDirtyFloats(layoutState.floats()); } +RenderBlock::RenderTextInfo::RenderTextInfo() + : m_text(0) +{ +} + +RenderBlock::RenderTextInfo::~RenderTextInfo() +{ +} + void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, InlineBidiResolver& resolver, const InlineIterator& cleanLineStart, const BidiStatus& cleanLineBidiStatus, unsigned consecutiveHyphenatedLines) { RenderStyle* styleToUse = style(); @@ -1247,11 +1289,18 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin LineMidpointState& lineMidpointState = resolver.midpointState(); InlineIterator end = resolver.position(); bool checkForEndLineMatch = layoutState.endLine(); - LineBreakIteratorInfo lineBreakIteratorInfo; + RenderTextInfo renderTextInfo; VerticalPositionCache verticalPositionCache; LineBreaker lineBreaker(this); +#if ENABLE(CSS_EXCLUSIONS) + WrapShapeInfo* wrapShapeInfo = this->wrapShapeInfo(); + // Move to the top of the shape inside to begin layout + if (wrapShapeInfo && logicalHeight() < wrapShapeInfo->shapeTop()) + setLogicalHeight(wrapShapeInfo->shapeTop()); +#endif + while (!end.atEnd()) { // FIXME: Is this check necessary before the first iteration or can it be moved to the end? if (checkForEndLineMatch) { @@ -1270,7 +1319,13 @@ void RenderBlock::layoutRunsAndFloatsInRange(LineLayoutState& layoutState, Inlin const InlineIterator oldEnd = end; bool isNewUBAParagraph = layoutState.lineInfo().previousLineBrokeCleanly(); FloatingObject* lastFloatFromPreviousLine = (m_floatingObjects && !m_floatingObjects->set().isEmpty()) ? m_floatingObjects->set().last() : 0; - end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), lineBreakIteratorInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines); +#if ENABLE(CSS_EXCLUSIONS) + // FIXME: Bug 89993: If the wrap shape comes from a parent, we will need to adjust + // the height coordinate + if (wrapShapeInfo) + wrapShapeInfo->computeSegmentsForLine(logicalHeight()); +#endif + end = lineBreaker.nextLineBreak(resolver, layoutState.lineInfo(), renderTextInfo, lastFloatFromPreviousLine, consecutiveHyphenatedLines); if (resolver.position().atEnd()) { // FIXME: We shouldn't be creating any runs in nextLineBreak to begin with! // Once BidiRunList is separated from BidiResolver this will not be needed. @@ -1970,11 +2025,14 @@ static bool shouldSkipWhitespaceAfterStartObject(RenderBlock* block, RenderObjec return false; } -static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace) +static inline float textWidth(RenderText* text, unsigned from, unsigned len, const Font& font, float xPos, bool isFixedPitch, bool collapseWhiteSpace, TextLayout* layout = 0) { if (isFixedPitch || (!from && len == text->textLength()) || text->style()->hasTextCombine()) return text->width(from, len, font, xPos); + if (layout) + return Font::width(*layout, from, len); + TextRun run = RenderBlock::constructTextRun(text, font, text->characters() + from, len, text->style()); run.setCharactersLength(text->textLength() - from); ASSERT(run.charactersLength() >= run.length()); @@ -2136,8 +2194,7 @@ void RenderBlock::LineBreaker::reset() m_clear = CNONE; } -InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, - LineBreakIteratorInfo& lineBreakIteratorInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines) +InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resolver, LineInfo& lineInfo, RenderTextInfo& renderTextInfo, FloatingObject* lastFloatFromPreviousLine, unsigned consecutiveHyphenatedLines) { reset(); @@ -2376,6 +2433,14 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol ASSERT(current.m_pos == t->textLength()); } + if (renderTextInfo.m_text != t) { + t->updateTextIfNeeded(); + renderTextInfo.m_text = t; + renderTextInfo.m_layout = f.createLayout(t, width.currentWidth(), collapseWhiteSpace); + renderTextInfo.m_lineBreakIterator.reset(t->characters(), t->textLength(), style->locale()); + } + TextLayout* textLayout = renderTextInfo.m_layout.get(); + for (; current.m_pos < t->textLength(); current.fastIncrementInTextNode()) { bool previousCharacterIsSpace = currentCharacterIsSpace; bool previousCharacterIsWS = currentCharacterIsWS; @@ -2397,16 +2462,11 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol if ((breakAll || breakWords) && !midWordBreak) { wrapW += charWidth; bool midWordBreakIsBeforeSurrogatePair = U16_IS_LEAD(c) && current.m_pos + 1 < t->textLength() && U16_IS_TRAIL(t->characters()[current.m_pos + 1]); - charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace); + charWidth = textWidth(t, current.m_pos, midWordBreakIsBeforeSurrogatePair ? 2 : 1, f, width.committedWidth() + wrapW, isFixedPitch, collapseWhiteSpace, textLayout); midWordBreak = width.committedWidth() + wrapW + charWidth > width.availableWidth(); } - if ((lineBreakIteratorInfo.first != t) || (lineBreakIteratorInfo.second.string() != t->characters())) { - lineBreakIteratorInfo.first = t; - lineBreakIteratorInfo.second.reset(t->characters(), t->textLength(), style->locale()); - } - - bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(lineBreakIteratorInfo.second, current.m_pos, current.m_nextBreakablePosition, breakNBSP) + bool betweenWords = c == '\n' || (currWS != PRE && !atStart && isBreakable(renderTextInfo.m_lineBreakIterator, current.m_pos, current.m_nextBreakablePosition, breakNBSP) && (style->hyphens() != HyphensNone || (current.previousInSameNode() != softHyphen))); if (betweenWords || midWordBreak) { @@ -2428,9 +2488,9 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol float additionalTmpW; if (wordTrailingSpaceWidth && currentCharacterIsSpace) - additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) - wordTrailingSpaceWidth + lastSpaceWordSpacing; + additionalTmpW = textWidth(t, lastSpace, current.m_pos + 1 - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) - wordTrailingSpaceWidth + lastSpaceWordSpacing; else - additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + additionalTmpW = textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing; width.addUncommittedWidth(additionalTmpW); if (!appliedStartWidth) { width.addUncommittedWidth(inlineLogicalWidth(current.m_obj, true, false)); @@ -2447,7 +2507,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol // as candidate width for this line. bool lineWasTooWide = false; if (width.fitsOnLine() && currentCharacterIsWS && currentStyle->breakOnlyAfterWhiteSpace() && !midWordBreak) { - float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + (applyWordSpacing ? wordSpacing : 0); + float charWidth = textWidth(t, current.m_pos, 1, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + (applyWordSpacing ? wordSpacing : 0); // Check if line is too big even without the extra space // at the end of the line. If it is not, do nothing. // If the line needs the extra whitespace to be too long, @@ -2573,7 +2633,7 @@ InlineIterator RenderBlock::LineBreaker::nextLineBreak(InlineBidiResolver& resol } // IMPORTANT: current.m_pos is > length here! - float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace) + lastSpaceWordSpacing; + float additionalTmpW = ignoringSpaces ? 0 : textWidth(t, lastSpace, current.m_pos - lastSpace, f, width.currentWidth(), isFixedPitch, collapseWhiteSpace, textLayout) + lastSpaceWordSpacing; width.addUncommittedWidth(additionalTmpW + inlineLogicalWidth(current.m_obj, !appliedStartWidth, includeEndWidth)); includeEndWidth = false; @@ -2830,7 +2890,7 @@ bool RenderBlock::positionNewFloatOnLine(FloatingObject* newFloat, FloatingObjec return true; } -LayoutUnit RenderBlock::startAlignedOffsetForLine(RenderBox* child, LayoutUnit position, bool firstLine) +LayoutUnit RenderBlock::startAlignedOffsetForLine(LayoutUnit position, bool firstLine) { ETextAlign textAlign = style()->textAlign(); @@ -2838,15 +2898,13 @@ LayoutUnit RenderBlock::startAlignedOffsetForLine(RenderBox* child, LayoutUnit p return startOffsetForLine(position, firstLine); // updateLogicalWidthForAlignment() handles the direction of the block so no need to consider it here - float logicalLeft; - float availableLogicalWidth; - logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false); - availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft; - float totalLogicalWidth = logicalWidthForChild(child); + float totalLogicalWidth = 0; + float logicalLeft = logicalLeftOffsetForLine(logicalHeight(), false); + float availableLogicalWidth = logicalRightOffsetForLine(logicalHeight(), false) - logicalLeft; updateLogicalWidthForAlignment(textAlign, 0, logicalLeft, totalLogicalWidth, availableLogicalWidth, 0); if (!style()->isLeftToRightDirection()) - return logicalWidth() - (logicalLeft + totalLogicalWidth); + return logicalWidth() - logicalLeft; return logicalLeft; } diff --git a/Source/WebCore/rendering/RenderBox.cpp b/Source/WebCore/rendering/RenderBox.cpp index f16457b5e..792b9c28b 100644 --- a/Source/WebCore/rendering/RenderBox.cpp +++ b/Source/WebCore/rendering/RenderBox.cpp @@ -134,16 +134,7 @@ void RenderBox::willBeDestroyed() { clearOverrideSize(); - if (style()) { - RenderBlock::removePercentHeightDescendantIfNeeded(this); - - if (RenderView* view = this->view()) { - if (FrameView* frameView = view->frameView()) { - if (style()->position() == FixedPosition) - frameView->removeFixedObject(this); - } - } - } + RenderBlock::removePercentHeightDescendantIfNeeded(this); RenderBoxModelObject::willBeDestroyed(); } @@ -205,17 +196,6 @@ void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle* newStyl } else if (newStyle && isBody()) view()->repaint(); - if (FrameView *frameView = view()->frameView()) { - bool newStyleIsFixed = newStyle && newStyle->position() == FixedPosition; - bool oldStyleIsFixed = oldStyle && oldStyle->position() == FixedPosition; - if (newStyleIsFixed != oldStyleIsFixed) { - if (newStyleIsFixed) - frameView->addFixedObject(this); - else - frameView->removeFixedObject(this); - } - } - RenderBoxModelObject::styleWillChange(diff, newStyle); } @@ -433,7 +413,7 @@ void RenderBox::updateLayerTransform() layer()->updateTransform(); } -LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) +LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const { RenderStyle* styleToUse = style(); if (!styleToUse->logicalMaxWidth().isUndefined()) @@ -441,7 +421,7 @@ LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWi return max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, availableWidth, cb, region, offsetFromLogicalTopOfFirstPage)); } -LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight) +LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight) const { RenderStyle* styleToUse = style(); if (!styleToUse->logicalMaxHeight().isUndefined()) { @@ -758,25 +738,25 @@ LayoutUnit RenderBox::computeContentBoxLogicalHeight(LayoutUnit height) const } // Hit Testing -bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { LayoutPoint adjustedLocation = accumulatedOffset + location(); // Check kids first. for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { - if (!child->hasLayer() && child->nodeAtPoint(request, result, pointInContainer, adjustedLocation, action)) { - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(adjustedLocation)); + if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) { + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); return true; } } // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). - LayoutRect boundsRect = borderBoxRectInRegion(pointInContainer.region()); + LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); boundsRect.moveBy(adjustedLocation); - if (visibleToHitTesting() && action == HitTestForeground && pointInContainer.intersects(boundsRect)) { - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(adjustedLocation)); - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) + if (visibleToHitTesting() && action == HitTestForeground && locationInContainer.intersects(boundsRect)) { + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); + if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect)) return true; } @@ -1171,7 +1151,7 @@ LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region return clipRect; } -LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) +LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const { RenderRegion* containingBlockRegion = 0; LayoutUnit logicalTopPosition = logicalTop(); @@ -1374,9 +1354,6 @@ const RenderObject* RenderBox::pushMappingToContainer(const RenderBoxModelObject void RenderBox::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { - // We don't expect absoluteToLocal() to be called during layout (yet) - ASSERT(!view() || !view()->layoutStateEnabled()); - bool isFixedPos = style()->position() == FixedPosition; bool hasTransform = hasLayer() && layer()->transform(); if (hasTransform) { @@ -1577,7 +1554,7 @@ void RenderBox::computeRectForRepaint(RenderBoxModelObject* repaintContainer, La if (position == AbsolutePosition && o->isInFlowPositioned() && o->isRenderInline()) topLeft += toRenderInline(o)->offsetForInFlowPositionedInline(this); - else if ((position == RelativePosition) && layer()) { + else if ((position == RelativePosition || position == StickyPosition) && layer()) { // Apply the relative position offset when invalidating a rectangle. The layer // is translated, but the render box isn't, so we need to do this to get the // right dirty rect. Since this is called from RenderObject::setStyle, the relative position @@ -1640,15 +1617,26 @@ void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect) void RenderBox::computeLogicalWidth() { - computeLogicalWidthInRegion(); + LogicalExtentComputedValues computedValues; + computeLogicalWidthInRegion(computedValues); + + setLogicalWidth(computedValues.m_extent); + setLogicalLeft(computedValues.m_position); + setMarginStart(computedValues.m_margins.m_start); + setMarginEnd(computedValues.m_margins.m_end); } -void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) +void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const { + computedValues.m_extent = logicalWidth(); + computedValues.m_position = logicalLeft(); + computedValues.m_margins.m_start = marginStart(); + computedValues.m_margins.m_end = marginEnd(); + if (isOutOfFlowPositioned()) { // FIXME: This calculation is not patched for block-flow yet. // https://bugs.webkit.org/show_bug.cgi?id=46500 - computePositionedLogicalWidth(region, offsetFromLogicalTopOfFirstPage); + computePositionedLogicalWidth(computedValues, region, offsetFromLogicalTopOfFirstPage); return; } @@ -1661,7 +1649,7 @@ void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit off // FIXME: Account for block-flow in flexible boxes. // https://bugs.webkit.org/show_bug.cgi?id=46418 if (hasOverrideWidth() && parent()->isFlexibleBoxIncludingDeprecated()) { - setLogicalWidth(overrideLogicalContentWidth() + borderAndPaddingLogicalWidth()); + computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth(); return; } @@ -1672,7 +1660,7 @@ void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit off bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching); RenderStyle* styleToUse = style(); - Length logicalWidthLength = (treatAsReplaced) ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth(); + Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse->logicalWidth(); RenderBlock* cb = containingBlock(); LayoutUnit containerLogicalWidth = max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region, offsetFromLogicalTopOfFirstPage)); @@ -1684,44 +1672,53 @@ void RenderBox::computeLogicalWidthInRegion(RenderRegion* region, LayoutUnit off if (isInline() && !isInlineBlockOrInlineTable()) { // just calculate margins RenderView* renderView = view(); - setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView)); - setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView)); + computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView); + computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView); if (treatAsReplaced) - setLogicalWidth(max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth())); + computedValues.m_extent = max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth()); return; } // Width calculations if (treatAsReplaced) - setLogicalWidth(logicalWidthLength.value() + borderAndPaddingLogicalWidth()); + computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth(); else { LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage); - setLogicalWidth(constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage)); + computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region, offsetFromLogicalTopOfFirstPage); } // Fieldsets are currently the only objects that stretch to their minimum width. if (stretchesToMinIntrinsicLogicalWidth()) - setLogicalWidth(max(logicalWidth(), minPreferredLogicalWidth())); + computedValues.m_extent = max(computedValues.m_extent, minPreferredLogicalWidth()); // Margin calculations. if (hasPerpendicularContainingBlock || isFloating() || isInline()) { RenderView* renderView = view(); - setMarginStart(minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView)); - setMarginEnd(minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView)); + computedValues.m_margins.m_start = minimumValueForLength(styleToUse->marginStart(), containerLogicalWidth, renderView); + computedValues.m_margins.m_end = minimumValueForLength(styleToUse->marginEnd(), containerLogicalWidth, renderView); } else { LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth; if (avoidsFloats() && cb->containsFloats()) containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region, offsetFromLogicalTopOfFirstPage); - computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth()); + bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); + computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent, + hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start, + hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end); } - if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (logicalWidth() + marginStart() + marginEnd()) - && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated()) - cb->setMarginEndForChild(this, containerLogicalWidth - logicalWidth() - cb->marginStartForChild(this)); + if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end) + && !isFloating() && !isInline() && !cb->isFlexibleBoxIncludingDeprecated()) { + LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb->marginStartForChild(this); + bool hasInvertedDirection = cb->style()->isLeftToRightDirection() != style()->isLeftToRightDirection(); + if (hasInvertedDirection) + computedValues.m_margins.m_start = newMargin; + else + computedValues.m_margins.m_end = newMargin; + } } LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, LayoutUnit availableLogicalWidth, - const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) + const RenderBlock* cb, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const { RenderStyle* styleToUse = style(); Length logicalWidth; @@ -1820,7 +1817,7 @@ bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const return false; } -void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth) +void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const { const RenderStyle* containingBlockStyle = containingBlock->style(); Length marginStartLength = style()->marginStartUsing(containingBlockStyle); @@ -1829,8 +1826,8 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo if (isFloating() || isInline()) { // Inline blocks/tables and floats don't have their margins increased. - containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView)); - containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView)); + marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView); + marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView); return; } @@ -1841,15 +1838,15 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth, renderView); LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth, renderView); LayoutUnit centeredMarginBoxStart = max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2); - containingBlock->setMarginStartForChild(this, centeredMarginBoxStart + marginStartWidth); - containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this) + marginEndWidth); + marginStart = centeredMarginBoxStart + marginStartWidth; + marginEnd = containerWidth - childWidth - marginStart + marginEndWidth; return; } // Case Two: The object is being pushed to the start of the containing block's available logical width. if (marginEndLength.isAuto() && childWidth < containerWidth) { - containingBlock->setMarginStartForChild(this, valueForLength(marginStartLength, containerWidth, renderView)); - containingBlock->setMarginEndForChild(this, containerWidth - childWidth - containingBlock->marginStartForChild(this)); + marginStart = valueForLength(marginStartLength, containerWidth, renderView); + marginEnd = containerWidth - childWidth - marginStart; return; } @@ -1857,15 +1854,15 @@ void RenderBox::computeInlineDirectionMargins(RenderBlock* containingBlock, Layo bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_LEFT) || (containingBlockStyle->isLeftToRightDirection() && containingBlockStyle->textAlign() == WEBKIT_RIGHT)); if ((marginStartLength.isAuto() && childWidth < containerWidth) || pushToEndFromTextAlign) { - containingBlock->setMarginEndForChild(this, valueForLength(marginEndLength, containerWidth, renderView)); - containingBlock->setMarginStartForChild(this, containerWidth - childWidth - containingBlock->marginEndForChild(this)); + marginEnd = valueForLength(marginEndLength, containerWidth, renderView); + marginStart = containerWidth - childWidth - marginEnd; return; } // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3). In that case // auto margins will just turn into 0. - containingBlock->setMarginStartForChild(this, minimumValueForLength(marginStartLength, containerWidth, renderView)); - containingBlock->setMarginEndForChild(this, minimumValueForLength(marginEndLength, containerWidth, renderView)); + marginStart = minimumValueForLength(marginStartLength, containerWidth, renderView); + marginEnd = minimumValueForLength(marginEndLength, containerWidth, renderView); } RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags cacheFlag) const @@ -1887,21 +1884,12 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout || isTableCell() || !isBlockFlow() || isRenderFlowThread()) return 0; - // FIXME: It's gross to cast away the const, but it would be a huge refactoring to - // change all width computation to avoid updating any member variables, and it would be pretty lame to - // make all the variables mutable as well. RenderFlowThread* flowThread = enclosingRenderFlowThread(); if (flowThread->style()->writingMode() != style()->writingMode()) return 0; - LayoutUnit oldLogicalWidth = logicalWidth(); - LayoutUnit oldLogicalLeft = logicalLeft(); - LayoutUnit oldMarginStart = marginStart(); - LayoutUnit oldMarginEnd = marginEnd(); - - RenderBox* mutableBox = const_cast<RenderBox*>(this); - - mutableBox->computeLogicalWidthInRegion(region, offsetFromLogicalTopOfFirstPage); + LogicalExtentComputedValues computedValues; + computeLogicalWidthInRegion(computedValues, region, offsetFromLogicalTopOfFirstPage); // Now determine the insets based off where this object is supposed to be positioned. RenderBlock* cb = containingBlock(); @@ -1911,22 +1899,16 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout LayoutUnit containingBlockLogicalWidth = cb->logicalWidth(); LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth; - LayoutUnit marginStartInRegion = marginStart(); - LayoutUnit startMarginDelta = marginStartInRegion - oldMarginStart; - LayoutUnit logicalWidthInRegion = logicalWidth(); - LayoutUnit logicalLeftInRegion = logicalLeft(); - LayoutUnit widthDelta = logicalWidthInRegion - oldLogicalWidth; - LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - oldLogicalLeft : startMarginDelta; + LayoutUnit marginStartInRegion = computedValues.m_margins.m_start; + LayoutUnit startMarginDelta = marginStartInRegion - marginStart(); + LayoutUnit logicalWidthInRegion = computedValues.m_extent; + LayoutUnit logicalLeftInRegion = computedValues.m_position; + LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth(); + LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta; LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion); - LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (oldLogicalLeft + oldLogicalWidth); + LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth()); LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta; - // Set our values back. - mutableBox->setLogicalWidth(oldLogicalWidth); - mutableBox->setLogicalLeft(oldLogicalLeft); - mutableBox->setMarginStart(oldMarginStart); - mutableBox->setMarginEnd(oldMarginEnd); - LayoutUnit logicalLeftOffset = 0; if (!isOutOfFlowPositioned() && avoidsFloats() && cb->containsFloats()) { @@ -1953,26 +1935,74 @@ RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, Layout return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted); } +static bool shouldFlipBeforeAfterMargins(const RenderStyle* containingBlockStyle, const RenderStyle* childStyle) +{ + ASSERT(containingBlockStyle->isHorizontalWritingMode() != childStyle->isHorizontalWritingMode()); + WritingMode childWritingMode = childStyle->writingMode(); + bool shouldFlip = false; + switch (containingBlockStyle->writingMode()) { + case TopToBottomWritingMode: + shouldFlip = (childWritingMode == RightToLeftWritingMode); + break; + case BottomToTopWritingMode: + shouldFlip = (childWritingMode == RightToLeftWritingMode); + break; + case RightToLeftWritingMode: + shouldFlip = (childWritingMode == BottomToTopWritingMode); + break; + case LeftToRightWritingMode: + shouldFlip = (childWritingMode == BottomToTopWritingMode); + break; + } + + if (!containingBlockStyle->isLeftToRightDirection()) + shouldFlip = !shouldFlip; + + return shouldFlip; +} + void RenderBox::computeLogicalHeight() { + LogicalExtentComputedValues computedValues; + computeLogicalHeight(computedValues); + + setLogicalHeight(computedValues.m_extent); + setLogicalTop(computedValues.m_position); + setMarginBefore(computedValues.m_margins.m_before); + setMarginAfter(computedValues.m_margins.m_after); +} + +void RenderBox::computeLogicalHeight(LogicalExtentComputedValues& computedValues) const +{ + computedValues.m_extent = logicalHeight(); + computedValues.m_position = logicalTop(); + // Cell height is managed by the table and inline non-replaced elements do not support a height property. if (isTableCell() || (isInline() && !isReplaced())) return; Length h; if (isOutOfFlowPositioned()) - computePositionedLogicalHeight(); + computePositionedLogicalHeight(computedValues); else { RenderBlock* cb = containingBlock(); bool hasPerpendicularContainingBlock = cb->isHorizontalWritingMode() != isHorizontalWritingMode(); - if (!hasPerpendicularContainingBlock) - computeBlockDirectionMargins(cb); + if (!hasPerpendicularContainingBlock) { + bool shouldFlipBeforeAfter = cb->style()->writingMode() != style()->writingMode(); + computeBlockDirectionMargins(cb, + shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, + shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); + } // For tables, calculate margins only. if (isTable()) { - if (hasPerpendicularContainingBlock) - computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight()); + if (hasPerpendicularContainingBlock) { + bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style()); + computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), logicalHeight(), + shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, + shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); + } return; } @@ -2018,10 +2048,14 @@ void RenderBox::computeLogicalHeight() heightResult = h.value() + borderAndPaddingLogicalHeight(); } - setLogicalHeight(heightResult); + computedValues.m_extent = heightResult; - if (hasPerpendicularContainingBlock) - computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult); + if (hasPerpendicularContainingBlock) { + bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb->style(), style()); + computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult, + shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before, + shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after); + } } // WinIE quirk: The <html> block always fills the entire canvas in quirks mode. The <body> always fills the @@ -2045,15 +2079,15 @@ void RenderBox::computeLogicalHeight() visHeight = view()->viewWidth(); } if (isRoot()) - setLogicalHeight(max(logicalHeight(), visHeight - margins)); + computedValues.m_extent = max(computedValues.m_extent, visHeight - margins); else { LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight(); - setLogicalHeight(max(logicalHeight(), visHeight - marginsBordersPadding)); + computedValues.m_extent = max(computedValues.m_extent, visHeight - marginsBordersPadding); } } } -LayoutUnit RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height) +LayoutUnit RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height) const { LayoutUnit logicalHeight = computeContentLogicalHeightUsing(heightType, height); if (logicalHeight != -1) @@ -2066,10 +2100,10 @@ LayoutUnit RenderBox::computeLogicalClientHeight(SizeType heightType, const Leng LayoutUnit heightIncludingScrollbar = computeContentLogicalHeightUsing(heightType, height); if (heightIncludingScrollbar == -1) return -1; - return std::max(LayoutUnit(0), computeContentBoxLogicalHeight(heightIncludingScrollbar) - scrollbarLogicalHeight()); + return std::max<LayoutUnit>(0, computeContentBoxLogicalHeight(heightIncludingScrollbar) - scrollbarLogicalHeight()); } -LayoutUnit RenderBox::computeContentLogicalHeightUsing(SizeType heightType, const Length& height) +LayoutUnit RenderBox::computeContentLogicalHeightUsing(SizeType heightType, const Length& height) const { if (height.isAuto()) return heightType == MinSize ? 0 : -1; @@ -2082,7 +2116,7 @@ LayoutUnit RenderBox::computeContentLogicalHeightUsing(SizeType heightType, cons return -1; } -LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) +LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) const { LayoutUnit result = -1; @@ -2098,7 +2132,7 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) break; skippedAutoHeightContainingBlock = true; cb = cb->containingBlock(); - cb->addPercentHeightDescendant(this); + cb->addPercentHeightDescendant(const_cast<RenderBox*>(this)); } RenderStyle* cbstyle = cb->style(); @@ -2138,9 +2172,11 @@ LayoutUnit RenderBox::computePercentageLogicalHeight(const Length& height) result = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight()); } else if (cbstyle->logicalHeight().isPercent() && !isOutOfFlowPositionedWithSpecifiedHeight) { // We need to recur and compute the percentage height for our containing block. - result = cb->computePercentageLogicalHeight(cbstyle->logicalHeight()); - if (result != -1) - result = cb->computeContentBoxLogicalHeight(result); + LayoutUnit heightWithScrollbar = cb->computePercentageLogicalHeight(cbstyle->logicalHeight()); + if (heightWithScrollbar != -1) { + LayoutUnit contentBoxHeightWithScrollbar = cb->computeContentBoxLogicalHeight(heightWithScrollbar); + result = max<LayoutUnit>(0, contentBoxHeightWithScrollbar - cb->scrollbarLogicalHeight()); + } } else if (cb->isRenderView() || (cb->isBody() && document()->inQuirksMode()) || isOutOfFlowPositionedWithSpecifiedHeight) { // Don't allow this to affect the block' height() member variable, since this // can get called while the block is still laying out its kids. @@ -2270,10 +2306,7 @@ LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType sizeType, Lengt cb = cb->containingBlock(); } } - availableHeight = computeContentBoxLogicalHeight(valueForLength(logicalHeight, availableHeight)); - if (cb->isBox() && cb->style()->logicalHeight().isFixed()) - availableHeight = max<LayoutUnit>(0, availableHeight - toRenderBox(cb)->scrollbarLogicalHeight()); - return availableHeight; + return computeContentBoxLogicalHeight(valueForLength(logicalHeight, availableHeight)); } case ViewportPercentageWidth: case ViewportPercentageHeight: @@ -2291,9 +2324,6 @@ LayoutUnit RenderBox::availableLogicalHeight() const LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const { - if (h.isFixed()) - return computeContentBoxLogicalHeight(h.value()); - if (isRenderView()) return isHorizontalWritingMode() ? toRenderView(this)->frameView()->visibleHeight() : toRenderView(this)->frameView()->visibleWidth(); @@ -2303,19 +2333,16 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const if (isTableCell() && (h.isAuto() || h.isPercent())) return overrideLogicalContentHeight(); - if (h.isPercent()) { - LayoutUnit availableHeight; - // https://bugs.webkit.org/show_bug.cgi?id=64046 - // For absolutely positioned elements whose containing block is based on a block-level element, - // the percentage is calculated with respect to the height of the padding box of that element - if (isOutOfFlowPositioned()) - availableHeight = containingBlockLogicalHeightForPositioned(containingBlock()); - else - availableHeight = containingBlock()->availableLogicalHeight(); + if (h.isPercent() && isOutOfFlowPositioned()) { + LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(containingBlock()); return computeContentBoxLogicalHeight(valueForLength(h, availableHeight)); } - // FIXME: We can't just check top/bottom here. + LayoutUnit heightIncludingScrollbar = computeContentLogicalHeightUsing(MainOrPreferredSize, h); + if (heightIncludingScrollbar != -1) + return std::max<LayoutUnit>(0, computeContentBoxLogicalHeight(heightIncludingScrollbar) - scrollbarLogicalHeight()); + + // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode. // https://bugs.webkit.org/show_bug.cgi?id=46500 if (isRenderBlock() && isOutOfFlowPositioned() && style()->height().isAuto() && !(style()->top().isAuto() || style()->bottom().isAuto())) { RenderBlock* block = const_cast<RenderBlock*>(toRenderBlock(this)); @@ -2329,13 +2356,13 @@ LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h) const return containingBlock()->availableLogicalHeight(); } -void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock) +void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const { if (isTableCell()) { // FIXME: Not right if we allow cells to have different directionality than the table. If we do allow this, though, // we may just do it with an extra anonymous block inside the cell. - setMarginBefore(0); - setMarginAfter(0); + marginBefore = 0; + marginAfter = 0; return; } @@ -2344,8 +2371,17 @@ void RenderBox::computeBlockDirectionMargins(const RenderBlock* containingBlock) LayoutUnit cw = containingBlockLogicalWidthForContent(); RenderView* renderView = view(); RenderStyle* containingBlockStyle = containingBlock->style(); - containingBlock->setMarginBeforeForChild(this, minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView)); - containingBlock->setMarginAfterForChild(this, minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView)); + marginBefore = minimumValueForLength(style()->marginBeforeUsing(containingBlockStyle), cw, renderView); + marginAfter = minimumValueForLength(style()->marginAfterUsing(containingBlockStyle), cw, renderView); +} + +void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock) +{ + LayoutUnit marginBefore; + LayoutUnit marginAfter; + computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter); + containingBlock->setMarginBeforeForChild(this, marginBefore); + containingBlock->setMarginAfterForChild(this, marginAfter); } LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject* containingBlock, RenderRegion* region, @@ -2496,10 +2532,10 @@ static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRigh } } -void RenderBox::computePositionedLogicalWidth(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) +void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const { if (isReplaced()) { - computePositionedLogicalWidthReplaced(); // FIXME: Patch for regions when we add replaced element support. + computePositionedLogicalWidthReplaced(computedValues); // FIXME: Patch for regions when we add replaced element support. return; } @@ -2534,8 +2570,6 @@ void RenderBox::computePositionedLogicalWidth(RenderRegion* region, LayoutUnit o const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth(); const Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop(); const Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom(); - LayoutUnit& marginLogicalLeftAlias = m_marginBox.mutableLogicalLeft(style()->writingMode()); - LayoutUnit& marginLogicalRightAlias = m_marginBox.mutableLogicalRight(style()->writingMode()); Length logicalLeftLength = style()->logicalLeft(); Length logicalRightLength = style()->logicalRight(); @@ -2569,70 +2603,57 @@ void RenderBox::computePositionedLogicalWidth(RenderRegion* region, LayoutUnit o computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region); // Calculate constraint equation values for 'width' case. - LayoutUnit logicalWidthResult; - LayoutUnit logicalLeftResult; computePositionedLogicalWidthUsing(MainOrPreferredSize, style()->logicalWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, - logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult); - setLogicalWidth(logicalWidthResult); - setLogicalLeft(logicalLeftResult); + computedValues); // Calculate constraint equation values for 'max-width' case. if (!style()->logicalMaxWidth().isUndefined()) { - LayoutUnit maxLogicalWidth; - LayoutUnit maxMarginLogicalLeft; - LayoutUnit maxMarginLogicalRight; - LayoutUnit maxLogicalLeftPos; + LogicalExtentComputedValues maxValues; computePositionedLogicalWidthUsing(MaxSize, style()->logicalMaxWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, - maxLogicalWidth, maxMarginLogicalLeft, maxMarginLogicalRight, maxLogicalLeftPos); + maxValues); - if (logicalWidth() > maxLogicalWidth) { - setLogicalWidth(maxLogicalWidth); - marginLogicalLeftAlias = maxMarginLogicalLeft; - marginLogicalRightAlias = maxMarginLogicalRight; - setLogicalLeft(maxLogicalLeftPos); + if (computedValues.m_extent > maxValues.m_extent) { + computedValues.m_extent = maxValues.m_extent; + computedValues.m_position = maxValues.m_position; + computedValues.m_margins.m_start = maxValues.m_margins.m_start; + computedValues.m_margins.m_end = maxValues.m_margins.m_end; } } // Calculate constraint equation values for 'min-width' case. if (!style()->logicalMinWidth().isZero()) { - LayoutUnit minLogicalWidth; - LayoutUnit minMarginLogicalLeft; - LayoutUnit minMarginLogicalRight; - LayoutUnit minLogicalLeftPos; + LogicalExtentComputedValues minValues; computePositionedLogicalWidthUsing(MinSize, style()->logicalMinWidth(), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, - minLogicalWidth, minMarginLogicalLeft, minMarginLogicalRight, minLogicalLeftPos); + minValues); - if (logicalWidth() < minLogicalWidth) { - setLogicalWidth(minLogicalWidth); - marginLogicalLeftAlias = minMarginLogicalLeft; - marginLogicalRightAlias = minMarginLogicalRight; - setLogicalLeft(minLogicalLeftPos); + if (computedValues.m_extent < minValues.m_extent) { + computedValues.m_extent = minValues.m_extent; + computedValues.m_position = minValues.m_position; + computedValues.m_margins.m_start = minValues.m_margins.m_start; + computedValues.m_margins.m_end = minValues.m_margins.m_end; } } - if (stretchesToMinIntrinsicLogicalWidth() && logicalWidth() < minPreferredLogicalWidth() - bordersPlusPadding) { + if (stretchesToMinIntrinsicLogicalWidth() && computedValues.m_extent < minPreferredLogicalWidth() - bordersPlusPadding) { computePositionedLogicalWidthUsing(MainOrPreferredSize, Length(minPreferredLogicalWidth() - bordersPlusPadding, Fixed), containerBlock, containerDirection, containerLogicalWidth, bordersPlusPadding, logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight, - logicalWidthResult, marginLogicalLeftAlias, marginLogicalRightAlias, logicalLeftResult); - setLogicalWidth(logicalWidthResult); - setLogicalLeft(logicalLeftResult); + computedValues); } - // Put logicalWidth() into correct form. - setLogicalWidth(logicalWidth() + bordersPlusPadding); + computedValues.m_extent += bordersPlusPadding; // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions. if (inRenderFlowThread() && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock->isHorizontalWritingMode()) { - LayoutUnit logicalLeftPos = logicalLeft(); + LayoutUnit logicalLeftPos = computedValues.m_position; const RenderBlock* cb = toRenderBlock(containerBlock); LayoutUnit cbPageOffset = offsetFromLogicalTopOfFirstPage - logicalTop(); RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); @@ -2641,7 +2662,7 @@ void RenderBox::computePositionedLogicalWidth(RenderRegion* region, LayoutUnit o RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset); if (boxInfo) { logicalLeftPos += boxInfo->logicalLeft(); - setLogicalLeft(logicalLeftPos); + computedValues.m_position = logicalLeftPos; } } } @@ -2661,7 +2682,7 @@ static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding, Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, - LayoutUnit& logicalWidthValue, LayoutUnit& marginLogicalLeftValue, LayoutUnit& marginLogicalRightValue, LayoutUnit& logicalLeftPos) + LogicalExtentComputedValues& computedValues) const { if (widthSizeType == MinSize && logicalWidth.isAuto()) logicalWidth = Length(0, Fixed); @@ -2676,6 +2697,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt bool logicalLeftIsAuto = logicalLeft.isAuto(); bool logicalRightIsAuto = logicalRight.isAuto(); RenderView* renderView = view(); + LayoutUnit& marginLogicalLeftValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end; + LayoutUnit& marginLogicalRightValue = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start; if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { /*-----------------------------------------------------------------------*\ @@ -2694,9 +2717,9 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt // case because the value is not used for any further calculations. logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + computedValues.m_extent = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); - const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView) + bordersPlusPadding); // Margins are now the only unknown if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) { @@ -2791,8 +2814,8 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding; LayoutUnit availableWidth = availableSpace - logicalRightValue; - logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); - logicalLeftValue = availableSpace - (logicalWidthValue + logicalRightValue); + computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth); + logicalLeftValue = availableSpace - (computedValues.m_extent + logicalRightValue); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && logicalRightIsAuto) { // RULE 3: (use shrink-to-fit for width, and no need solve of right) logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); @@ -2801,19 +2824,19 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding; LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding; LayoutUnit availableWidth = availableSpace - logicalLeftValue; - logicalWidthValue = min(max(preferredMinWidth, availableWidth), preferredWidth); + computedValues.m_extent = min(max(preferredMinWidth, availableWidth), preferredWidth); } else if (logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 4: (solve for left) - logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); - logicalLeftValue = availableSpace - (logicalWidthValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); + computedValues.m_extent = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + logicalLeftValue = availableSpace - (computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth, renderView)); } else if (!logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) { // RULE 5: (solve for width) logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalWidthValue = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); + computedValues.m_extent = availableSpace - (logicalLeftValue + valueForLength(logicalRight, containerLogicalWidth, renderView)); } else if (!logicalLeftIsAuto && !logicalWidthIsAuto && logicalRightIsAuto) { // RULE 6: (no need solve for right) logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); - logicalWidthValue = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); + computedValues.m_extent = computeContentBoxLogicalWidth(valueForLength(logicalWidth, containerLogicalWidth, renderView)); } } @@ -2828,13 +2851,13 @@ void RenderBox::computePositionedLogicalWidthUsing(SizeType widthSizeType, Lengt InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - logicalLeftPos = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()); + computedValues.m_position = logicalLeftValue + marginLogicalLeftValue + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()); return; } } - logicalLeftPos = logicalLeftValue + marginLogicalLeftValue; - computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidthValue, containerBlock, containerLogicalWidth); + computedValues.m_position = logicalLeftValue + marginLogicalLeftValue; + computeLogicalLeftPositionedOffset(computedValues.m_position, this, computedValues.m_extent, containerBlock, containerLogicalWidth); } static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom, const RenderBox* child, const RenderBoxModelObject* containerBlock) @@ -2851,10 +2874,10 @@ static void computeBlockStaticDistance(Length& logicalTop, Length& logicalBottom logicalTop.setValue(Fixed, staticLogicalTop); } -void RenderBox::computePositionedLogicalHeight() +void RenderBox::computePositionedLogicalHeight(LogicalExtentComputedValues& computedValues) const { if (isReplaced()) { - computePositionedLogicalHeightReplaced(); + computePositionedLogicalHeightReplaced(computedValues); return; } @@ -2874,9 +2897,6 @@ void RenderBox::computePositionedLogicalHeight() const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight(); const Length marginBefore = styleToUse->marginBefore(); const Length marginAfter = styleToUse->marginAfter(); - LayoutUnit& marginBeforeAlias = m_marginBox.mutableBefore(styleToUse->writingMode()); - LayoutUnit& marginAfterAlias = m_marginBox.mutableAfter(styleToUse->writingMode()); - Length logicalTopLength = styleToUse->logicalTop(); Length logicalBottomLength = styleToUse->logicalBottom(); @@ -2901,62 +2921,52 @@ void RenderBox::computePositionedLogicalHeight() // Calculate the static distance if needed. computeBlockStaticDistance(logicalTopLength, logicalBottomLength, this, containerBlock); - LayoutUnit logicalHeightResult; // Needed to compute overflow. - LayoutUnit logicalTopPos; - // Calculate constraint equation values for 'height' case. computePositionedLogicalHeightUsing(MainOrPreferredSize, styleToUse->logicalHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, - logicalHeightResult, marginBeforeAlias, marginAfterAlias, logicalTopPos); - setLogicalTop(logicalTopPos); + computedValues); // Avoid doing any work in the common case (where the values of min-height and max-height are their defaults). // see FIXME 2 // Calculate constraint equation values for 'max-height' case. if (!styleToUse->logicalMaxHeight().isUndefined()) { - LayoutUnit maxLogicalHeight; - LayoutUnit maxMarginBefore; - LayoutUnit maxMarginAfter; - LayoutUnit maxLogicalTopPos; + LogicalExtentComputedValues maxValues; computePositionedLogicalHeightUsing(MaxSize, styleToUse->logicalMaxHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, - maxLogicalHeight, maxMarginBefore, maxMarginAfter, maxLogicalTopPos); + maxValues); - if (logicalHeightResult > maxLogicalHeight) { - logicalHeightResult = maxLogicalHeight; - marginBeforeAlias = maxMarginBefore; - marginAfterAlias = maxMarginAfter; - setLogicalTop(maxLogicalTopPos); + if (computedValues.m_extent > maxValues.m_extent) { + computedValues.m_extent = maxValues.m_extent; + computedValues.m_position = maxValues.m_position; + computedValues.m_margins.m_before = maxValues.m_margins.m_before; + computedValues.m_margins.m_after = maxValues.m_margins.m_after; } } // Calculate constraint equation values for 'min-height' case. if (!styleToUse->logicalMinHeight().isZero()) { - LayoutUnit minLogicalHeight; - LayoutUnit minMarginBefore; - LayoutUnit minMarginAfter; - LayoutUnit minLogicalTopPos; + LogicalExtentComputedValues minValues; computePositionedLogicalHeightUsing(MinSize, styleToUse->logicalMinHeight(), containerBlock, containerLogicalHeight, bordersPlusPadding, logicalTopLength, logicalBottomLength, marginBefore, marginAfter, - minLogicalHeight, minMarginBefore, minMarginAfter, minLogicalTopPos); + minValues); - if (logicalHeightResult < minLogicalHeight) { - logicalHeightResult = minLogicalHeight; - marginBeforeAlias = minMarginBefore; - marginAfterAlias = minMarginAfter; - setLogicalTop(minLogicalTopPos); + if (computedValues.m_extent < minValues.m_extent) { + computedValues.m_extent = minValues.m_extent; + computedValues.m_position = minValues.m_position; + computedValues.m_margins.m_before = minValues.m_margins.m_before; + computedValues.m_margins.m_after = minValues.m_margins.m_after; } } // Set final height value. - setLogicalHeight(logicalHeightResult + bordersPlusPadding); + computedValues.m_extent += bordersPlusPadding; // Adjust logicalTop if we need to for perpendicular writing modes in regions. if (inRenderFlowThread() && isHorizontalWritingMode() != containerBlock->isHorizontalWritingMode()) { - LayoutUnit logicalTopPos = logicalTop(); + LayoutUnit logicalTopPos = computedValues.m_position; const RenderBlock* cb = toRenderBlock(containerBlock); LayoutUnit cbPageOffset = cb->offsetFromLogicalTopOfFirstPage() - logicalLeft(); RenderRegion* cbRegion = cb->regionAtBlockOffset(cbPageOffset); @@ -2965,7 +2975,7 @@ void RenderBox::computePositionedLogicalHeight() RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(cbRegion, cbPageOffset); if (boxInfo) { logicalTopPos += boxInfo->logicalLeft(); - setLogicalTop(logicalTopPos); + computedValues.m_position = logicalTopPos; } } } @@ -2996,7 +3006,7 @@ static void computeLogicalTopPositionedOffset(LayoutUnit& logicalTopPos, const R void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Length logicalHeightLength, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, Length logicalTop, Length logicalBottom, Length marginBefore, Length marginAfter, - LayoutUnit& logicalHeightValue, LayoutUnit& marginBeforeValue, LayoutUnit& marginAfterValue, LayoutUnit& logicalTopPos) + LogicalExtentComputedValues& computedValues) const { if (heightSizeType == MinSize && logicalHeightLength.isAuto()) logicalHeightLength = Length(0, Fixed); @@ -3005,6 +3015,7 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len // converted to the static position in computePositionedLogicalHeight() ASSERT(!(logicalTop.isAuto() && logicalBottom.isAuto())); + LayoutUnit logicalHeightValue; LayoutUnit contentLogicalHeight = logicalHeight() - bordersPlusPadding; LayoutUnit logicalTopValue = 0; @@ -3041,20 +3052,20 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len if (marginBefore.isAuto() && marginAfter.isAuto()) { // Both margins auto, solve for equality // NOTE: This may result in negative values. - marginBeforeValue = availableSpace / 2; // split the difference - marginAfterValue = availableSpace - marginBeforeValue; // account for odd valued differences + computedValues.m_margins.m_before = availableSpace / 2; // split the difference + computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; // account for odd valued differences } else if (marginBefore.isAuto()) { // Solve for top margin - marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView); - marginBeforeValue = availableSpace - marginAfterValue; + computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = availableSpace - computedValues.m_margins.m_after; } else if (marginAfter.isAuto()) { // Solve for bottom margin - marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterValue = availableSpace - marginBeforeValue; + computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView); + computedValues.m_margins.m_after = availableSpace - computedValues.m_margins.m_before; } else { // Over-constrained, (no need solve for bottom) - marginBeforeValue = valueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterValue = valueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = valueForLength(marginBefore, containerLogicalHeight, renderView); + computedValues.m_margins.m_after = valueForLength(marginAfter, containerLogicalHeight, renderView); } } else { /*--------------------------------------------------------------------*\ @@ -3083,10 +3094,10 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len // because the value is not used for any further calculations. // Calculate margins, 'auto' margins are ignored. - marginBeforeValue = minimumValueForLength(marginBefore, containerLogicalHeight, renderView); - marginAfterValue = minimumValueForLength(marginAfter, containerLogicalHeight, renderView); + computedValues.m_margins.m_before = minimumValueForLength(marginBefore, containerLogicalHeight, renderView); + computedValues.m_margins.m_after = minimumValueForLength(marginAfter, containerLogicalHeight, renderView); - const LayoutUnit availableSpace = containerLogicalHeight - (marginBeforeValue + marginAfterValue + bordersPlusPadding); + const LayoutUnit availableSpace = containerLogicalHeight - (computedValues.m_margins.m_before + computedValues.m_margins.m_after + bordersPlusPadding); // Use rule/case that applies. if (logicalTopIsAuto && logicalHeightIsAuto && !logicalBottomIsAuto) { @@ -3111,13 +3122,14 @@ void RenderBox::computePositionedLogicalHeightUsing(SizeType heightSizeType, Len logicalTopValue = valueForLength(logicalTop, containerLogicalHeight, renderView); } } + computedValues.m_extent = logicalHeightValue; // Use computed values to calculate the vertical position. - logicalTopPos = logicalTopValue + marginBeforeValue; - computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeightValue, containerBlock, containerLogicalHeight); + computedValues.m_position = logicalTopValue + computedValues.m_margins.m_before; + computeLogicalTopPositionedOffset(computedValues.m_position, this, logicalHeightValue, containerBlock, containerLogicalHeight); } -void RenderBox::computePositionedLogicalWidthReplaced() +void RenderBox::computePositionedLogicalWidthReplaced(LogicalExtentComputedValues& computedValues) const { // The following is based off of the W3C Working Draft from April 11, 2006 of // CSS 2.1: Section 10.3.8 "Absolutely positioned, replaced elements" @@ -3141,8 +3153,8 @@ void RenderBox::computePositionedLogicalWidthReplaced() Length logicalRight = style()->logicalRight(); Length marginLogicalLeft = isHorizontal ? style()->marginLeft() : style()->marginTop(); Length marginLogicalRight = isHorizontal ? style()->marginRight() : style()->marginBottom(); - LayoutUnit& marginLogicalLeftAlias = m_marginBox.mutableLogicalLeft(style()->writingMode()); - LayoutUnit& marginLogicalRightAlias = m_marginBox.mutableLogicalRight(style()->writingMode()); + LayoutUnit& marginLogicalLeftAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end; + LayoutUnit& marginLogicalRightAlias = style()->isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start; /*-----------------------------------------------------------------------*\ * 1. The used value of 'width' is determined as for inline replaced @@ -3151,9 +3163,9 @@ void RenderBox::computePositionedLogicalWidthReplaced() // NOTE: This value of width is FINAL in that the min/max width calculations // are dealt with in computeReplacedWidth(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setLogicalWidth(computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth()); + computedValues.m_extent = computeReplacedLogicalWidth() + borderAndPaddingLogicalWidth(); - const LayoutUnit availableSpace = containerLogicalWidth - logicalWidth(); + const LayoutUnit availableSpace = containerLogicalWidth - computedValues.m_extent; /*-----------------------------------------------------------------------*\ * 2. If both 'left' and 'right' have the value 'auto', then if 'direction' @@ -3249,7 +3261,7 @@ void RenderBox::computePositionedLogicalWidthReplaced() logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth, renderView); // If the containing block is right-to-left, then push the left position as far to the right as possible if (containerDirection == RTL) { - int totalLogicalWidth = logicalWidth() + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; + int totalLogicalWidth = computedValues.m_extent + logicalLeftValue + logicalRightValue + marginLogicalLeftAlias + marginLogicalRightAlias; logicalLeftValue = containerLogicalWidth - (totalLogicalWidth - logicalLeftValue); } } @@ -3276,17 +3288,17 @@ void RenderBox::computePositionedLogicalWidthReplaced() InlineFlowBox* firstLine = flow->firstLineBox(); InlineFlowBox* lastLine = flow->lastLineBox(); if (firstLine && lastLine && firstLine != lastLine) { - setLogicalLeft(logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft())); + computedValues.m_position = logicalLeftValue + marginLogicalLeftAlias + lastLine->borderLogicalLeft() + (lastLine->logicalLeft() - firstLine->logicalLeft()); return; } } LayoutUnit logicalLeftPos = logicalLeftValue + marginLogicalLeftAlias; - computeLogicalLeftPositionedOffset(logicalLeftPos, this, logicalWidth(), containerBlock, containerLogicalWidth); - setLogicalLeft(logicalLeftPos.round()); + computeLogicalLeftPositionedOffset(logicalLeftPos, this, computedValues.m_extent, containerBlock, containerLogicalWidth); + computedValues.m_position = logicalLeftPos.round(); } -void RenderBox::computePositionedLogicalHeightReplaced() +void RenderBox::computePositionedLogicalHeightReplaced(LogicalExtentComputedValues& computedValues) const { // The following is based off of the W3C Working Draft from April 11, 2006 of // CSS 2.1: Section 10.6.5 "Absolutely positioned, replaced elements" @@ -3302,8 +3314,8 @@ void RenderBox::computePositionedLogicalHeightReplaced() // Variables to solve. Length marginBefore = style()->marginBefore(); Length marginAfter = style()->marginAfter(); - LayoutUnit& marginBeforeAlias = m_marginBox.mutableBefore(style()->writingMode()); - LayoutUnit& marginAfterAlias = m_marginBox.mutableAfter(style()->writingMode()); + LayoutUnit& marginBeforeAlias = computedValues.m_margins.m_before; + LayoutUnit& marginAfterAlias = computedValues.m_margins.m_after; Length logicalTop = style()->logicalTop(); Length logicalBottom = style()->logicalBottom(); @@ -3316,8 +3328,8 @@ void RenderBox::computePositionedLogicalHeightReplaced() // NOTE: This value of height is FINAL in that the min/max height calculations // are dealt with in computeReplacedHeight(). This means that the steps to produce // correct max/min in the non-replaced version, are not necessary. - setLogicalHeight(computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight()); - const LayoutUnit availableSpace = containerLogicalHeight - logicalHeight(); + computedValues.m_extent = computeReplacedLogicalHeight() + borderAndPaddingLogicalHeight(); + const LayoutUnit availableSpace = containerLogicalHeight - computedValues.m_extent; /*-----------------------------------------------------------------------*\ * 2. If both 'top' and 'bottom' have the value 'auto', replace 'top' @@ -3411,8 +3423,8 @@ void RenderBox::computePositionedLogicalHeightReplaced() // Use computed values to calculate the vertical position. LayoutUnit logicalTopPos = logicalTopValue + marginBeforeAlias; - computeLogicalTopPositionedOffset(logicalTopPos, this, logicalHeight(), containerBlock, containerLogicalHeight); - setLogicalTop(logicalTopPos.round()); + computeLogicalTopPositionedOffset(logicalTopPos, this, computedValues.m_extent, containerBlock, containerLogicalHeight); + computedValues.m_position = logicalTopPos.round(); } LayoutRect RenderBox::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit* extraWidthToEndOfLine) diff --git a/Source/WebCore/rendering/RenderBox.h b/Source/WebCore/rendering/RenderBox.h index f011714cb..ed70a94b8 100644 --- a/Source/WebCore/rendering/RenderBox.h +++ b/Source/WebCore/rendering/RenderBox.h @@ -44,7 +44,7 @@ public: // hasAutoZIndex only returns true if the element is positioned or a flex-item since // position:static elements that are not flex-items get their z-index coerced to auto. - virtual bool requiresLayer() const OVERRIDE { return isRoot() || isOutOfFlowPositioned() || isInFlowPositioned() || isTransparent() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns() || !style()->hasAutoZIndex(); } + virtual bool requiresLayer() const OVERRIDE { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns() || !style()->hasAutoZIndex(); } // Use this with caution! No type checking is done! RenderBox* firstChildBox() const; @@ -75,8 +75,8 @@ public: LayoutUnit logicalWidth() const { return style()->isHorizontalWritingMode() ? width() : height(); } LayoutUnit logicalHeight() const { return style()->isHorizontalWritingMode() ? height() : width(); } - LayoutUnit constrainLogicalWidthInRegionByMinMax(LayoutUnit, LayoutUnit, RenderBlock*, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT); - LayoutUnit constrainLogicalHeightByMinMax(LayoutUnit); + LayoutUnit constrainLogicalWidthInRegionByMinMax(LayoutUnit, LayoutUnit, RenderBlock*, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT) const; + LayoutUnit constrainLogicalHeightByMinMax(LayoutUnit) const; int pixelSnappedLogicalHeight() const { return style()->isHorizontalWritingMode() ? pixelSnappedHeight() : pixelSnappedWidth(); } int pixelSnappedLogicalWidth() const { return style()->isHorizontalWritingMode() ? pixelSnappedWidth() : pixelSnappedHeight(); } @@ -284,7 +284,7 @@ public: virtual void layout(); virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual LayoutUnit minPreferredLogicalWidth() const; virtual LayoutUnit maxPreferredLogicalWidth() const; @@ -306,12 +306,37 @@ public: virtual void borderFitAdjust(LayoutRect&) const { } // Shrink the box in which the border paints if border-fit is set. + struct ComputedMarginValues { + ComputedMarginValues() + : m_before(0) + , m_after(0) + , m_start(0) + , m_end(0) + { + } + LayoutUnit m_before; + LayoutUnit m_after; + LayoutUnit m_start; + LayoutUnit m_end; + }; + struct LogicalExtentComputedValues { + LogicalExtentComputedValues() + : m_extent(0) + , m_position(0) + { + } + + LayoutUnit m_extent; + LayoutUnit m_position; + ComputedMarginValues m_margins; + }; // Resolve auto margins in the inline direction of the containing block so that objects can be pushed to the start, middle or end // of the containing block. - void computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth); + void computeInlineDirectionMargins(RenderBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const; // Used to resolve margins in the containing block's block-flow direction. - void computeBlockDirectionMargins(const RenderBlock* containingBlock); + void computeBlockDirectionMargins(const RenderBlock* containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const; + void computeAndSetBlockDirectionMargins(const RenderBlock* containingBlock); enum RenderBoxRegionInfoFlags { CacheRenderBoxRegionInfo, DoNotCacheRenderBoxRegionInfo }; LayoutRect borderBoxRectInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage = 0, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; @@ -338,12 +363,13 @@ public: LayoutUnit containingBlockLogicalWidthForContentInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; LayoutUnit containingBlockAvailableLineWidthInRegion(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; LayoutUnit perpendicularContainingBlockLogicalHeight() const; - + virtual void computeLogicalWidth(); virtual void computeLogicalHeight(); + void computeLogicalHeight(LogicalExtentComputedValues&) const; RenderBoxRegionInfo* renderBoxRegionInfo(RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage, RenderBoxRegionInfoFlags = CacheRenderBoxRegionInfo) const; - void computeLogicalWidthInRegion(RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT); + void computeLogicalWidthInRegion(LogicalExtentComputedValues&, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = ZERO_LAYOUT_UNIT) const; bool stretchesToViewport() const { @@ -359,12 +385,12 @@ public: bool sizesLogicalWidthToFitContent(SizeType) const; virtual bool stretchesToMinIntrinsicLogicalWidth() const { return false; } - LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage); + LayoutUnit shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock* cb, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; - LayoutUnit computeLogicalWidthInRegionUsing(SizeType, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage); - LayoutUnit computeLogicalHeightUsing(SizeType, const Length& height); + LayoutUnit computeLogicalWidthInRegionUsing(SizeType, LayoutUnit availableLogicalWidth, const RenderBlock* containingBlock, RenderRegion*, LayoutUnit offsetFromLogicalTopOfFirstPage) const; + LayoutUnit computeLogicalHeightUsing(SizeType, const Length& height) const; LayoutUnit computeLogicalClientHeight(SizeType, const Length& height); - LayoutUnit computeContentLogicalHeightUsing(SizeType, const Length& height); + LayoutUnit computeContentLogicalHeightUsing(SizeType, const Length& height) const; LayoutUnit computeReplacedLogicalWidthUsing(SizeType, Length width) const; LayoutUnit computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, bool includeMaxWidth = true) const; LayoutUnit computeReplacedLogicalHeightUsing(SizeType, Length height) const; @@ -373,7 +399,7 @@ public: virtual LayoutUnit computeReplacedLogicalWidth(bool includeMaxWidth = true) const; virtual LayoutUnit computeReplacedLogicalHeight() const; - LayoutUnit computePercentageLogicalHeight(const Length& height); + LayoutUnit computePercentageLogicalHeight(const Length& height) const; // Block flows subclass availableWidth/Height to handle multi column layout (shrinking the width/height available to children when laying out.) virtual LayoutUnit availableLogicalWidth() const { return contentLogicalWidth(); } @@ -536,7 +562,7 @@ protected: void paintCustomHighlight(const LayoutPoint&, const AtomicString& type, bool behindText); #endif - void computePositionedLogicalWidth(RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0); + void computePositionedLogicalWidth(LogicalExtentComputedValues&, RenderRegion* = 0, LayoutUnit offsetFromLogicalTopOfFirstPage = 0) const; virtual bool shouldComputeSizeAsReplaced() const { return isReplaced() && !isInlineBlockOrInlineTable(); } @@ -561,24 +587,26 @@ private: LayoutUnit offsetFromLogicalTopOfFirstPage = 0, bool checkForPerpendicularWritingMode = true) const; LayoutUnit containingBlockLogicalHeightForPositioned(const RenderBoxModelObject* containingBlock, bool checkForPerpendicularWritingMode = true) const; - void computePositionedLogicalHeight(); + void computePositionedLogicalHeight(LogicalExtentComputedValues&) const; void computePositionedLogicalWidthUsing(SizeType, Length logicalWidth, const RenderBoxModelObject* containerBlock, TextDirection containerDirection, LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding, Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight, - LayoutUnit& logicalWidthValue, LayoutUnit& marginLogicalLeftValue, LayoutUnit& marginLogicalRightValue, LayoutUnit& logicalLeftPos); + LogicalExtentComputedValues&) const; void computePositionedLogicalHeightUsing(SizeType, Length logicalHeight, const RenderBoxModelObject* containerBlock, LayoutUnit containerLogicalHeight, LayoutUnit bordersPlusPadding, Length logicalTop, Length logicalBottom, Length marginLogicalTop, Length marginLogicalBottom, - LayoutUnit& logicalHeightValue, LayoutUnit& marginLogicalTopValue, LayoutUnit& marginLogicalBottomValue, LayoutUnit& logicalTopPos); + LogicalExtentComputedValues&) const; - void computePositionedLogicalHeightReplaced(); - void computePositionedLogicalWidthReplaced(); + void computePositionedLogicalHeightReplaced(LogicalExtentComputedValues&) const; + void computePositionedLogicalWidthReplaced(LogicalExtentComputedValues&) const; // This function calculates the minimum and maximum preferred widths for an object. // These values are used in shrink-to-fit layout systems. // These include tables, positioned objects, floats and flexible boxes. virtual void computePreferredLogicalWidths() { setPreferredLogicalWidthsDirty(false); } + virtual LayoutRect frameRectForStickyPositioning() const OVERRIDE { return frameRect(); } + private: // The width/height of the contents + borders + padding. The x/y location is relative to our container (which is not always our parent). LayoutRect m_frameRect; diff --git a/Source/WebCore/rendering/RenderBoxModelObject.cpp b/Source/WebCore/rendering/RenderBoxModelObject.cpp index 7dcd24129..8deeddf38 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.cpp +++ b/Source/WebCore/rendering/RenderBoxModelObject.cpp @@ -37,6 +37,7 @@ #include "RenderInline.h" #include "RenderLayer.h" #include "RenderView.h" +#include "ScrollingConstraints.h" #include "Settings.h" #include "TransformState.h" #include <wtf/CurrentTime.h> @@ -348,6 +349,15 @@ void RenderBoxModelObject::willBeDestroyed() // A continuation of this RenderObject should be destroyed at subclasses. ASSERT(!continuation()); + if (isPositioned()) { + if (RenderView* view = this->view()) { + if (FrameView* frameView = view->frameView()) { + if (style()->hasViewportConstrainedPosition()) + frameView->removeViewportConstrainedObject(this); + } + } + } + // If this is a first-letter object with a remaining text fragment then the // entry needs to be cleared from the map. if (firstLetterRemainingText()) @@ -446,6 +456,17 @@ void RenderBoxModelObject::styleDidChange(StyleDifference diff, const RenderStyl if (s_hadLayer && layer()->isSelfPaintingLayer() != s_layerWasSelfPainting) setChildNeedsLayout(true); } + + if (FrameView *frameView = view()->frameView()) { + bool newStyleIsViewportConstained = style()->hasViewportConstrainedPosition(); + bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition(); + if (newStyleIsViewportConstained != oldStyleIsViewportConstrained) { + if (newStyleIsViewportConstained && layer()) + frameView->addViewportConstrainedObject(this); + else + frameView->removeViewportConstrainedObject(this); + } + } } void RenderBoxModelObject::updateBoxModelInfoFromStyle() @@ -456,6 +477,7 @@ void RenderBoxModelObject::updateBoxModelInfoFromStyle() setHasBoxDecorations(hasBackground() || styleToUse->hasBorder() || styleToUse->hasAppearance() || styleToUse->boxShadow()); setInline(styleToUse->isDisplayInlineType()); setRelPositioned(styleToUse->position() == RelativePosition); + setStickyPositioned(styleToUse->position() == StickyPosition); setHorizontalWritingMode(styleToUse->isHorizontalWritingMode()); } @@ -534,6 +556,8 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L if (!isOutOfFlowPositioned()) { if (isRelPositioned()) referencePoint.move(relativePositionOffset()); + else if (isStickyPositioned()) + referencePoint.move(stickyPositionOffset()); const RenderObject* curr = parent(); while (curr != offsetParent) { // FIXME: What are we supposed to do inside SVG content? @@ -542,7 +566,7 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L referencePoint.move(curr->parent()->offsetForColumns(referencePoint)); curr = curr->parent(); } - if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isRelPositioned() && !offsetParent->isOutOfFlowPositioned()) + if (offsetParent->isBox() && offsetParent->isBody() && !offsetParent->isPositioned()) referencePoint.moveBy(toRenderBox(offsetParent)->topLeftLocation()); } } @@ -550,11 +574,73 @@ LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const L return referencePoint; } +void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& viewportRect) const +{ + RenderBlock* containingBlock = this->containingBlock(); + + LayoutRect containerContentRect = containingBlock->contentBoxRect(); + + LayoutUnit minLeftMargin = minimumValueForLength(style()->marginLeft(), containingBlock->availableLogicalWidth(), view()); + LayoutUnit minTopMargin = minimumValueForLength(style()->marginTop(), containingBlock->availableLogicalWidth(), view()); + LayoutUnit minRightMargin = minimumValueForLength(style()->marginRight(), containingBlock->availableLogicalWidth(), view()); + LayoutUnit minBottomMargin = minimumValueForLength(style()->marginBottom(), containingBlock->availableLogicalWidth(), view()); + + // Compute the container-relative area within which the sticky element is allowed to move. + containerContentRect.move(minLeftMargin, minTopMargin); + containerContentRect.contract(minLeftMargin + minRightMargin, minTopMargin + minBottomMargin); + constraints.setAbsoluteContainingBlockRect(containingBlock->localToAbsoluteQuad(FloatRect(containerContentRect)).boundingBox()); + + LayoutRect stickyBoxRect = frameRectForStickyPositioning(); + LayoutRect flippedStickyBoxRect = stickyBoxRect; + containingBlock->flipForWritingMode(flippedStickyBoxRect); + LayoutPoint stickyLocation = flippedStickyBoxRect.location(); + + // FIXME: sucks to call localToAbsolute again, but we can't just offset from the previously computed rect if there are transforms. + FloatRect absContainerFrame = containingBlock->localToAbsoluteQuad(FloatRect(FloatPoint(), containingBlock->size())).boundingBox(); + // We can't call localToAbsolute on |this| because that will recur. FIXME: For now, assume that |this| is not transformed. + FloatRect absoluteStickyBoxRect(absContainerFrame.location() + stickyLocation, flippedStickyBoxRect.size()); + constraints.setAbsoluteStickyBoxRect(absoluteStickyBoxRect); + + if (!style()->left().isAuto()) { + constraints.setLeftOffset(valueForLength(style()->left(), viewportRect.width(), view())); + constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); + } + + if (!style()->right().isAuto()) { + constraints.setRightOffset(valueForLength(style()->right(), viewportRect.width(), view())); + constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight); + } + + if (!style()->top().isAuto()) { + constraints.setTopOffset(valueForLength(style()->top(), viewportRect.height(), view())); + constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); + } + + if (!style()->bottom().isAuto()) { + constraints.setBottomOffset(valueForLength(style()->bottom(), viewportRect.height(), view())); + constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom); + } +} + +LayoutSize RenderBoxModelObject::stickyPositionOffset() const +{ + LayoutRect viewportRect = view()->frameView()->visibleContentRect(); + + StickyPositionViewportConstraints constraints; + computeStickyPositionConstraints(constraints, viewportRect); + + // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms). + return LayoutSize(constraints.computeStickyOffset(viewportRect)); +} + LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const { if (isRelPositioned()) return relativePositionOffset(); + if (isStickyPositioned()) + return stickyPositionOffset(); + return LayoutSize(); } @@ -2730,9 +2816,6 @@ bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext* context) void RenderBoxModelObject::mapAbsoluteToLocalPoint(bool fixed, bool useTransforms, TransformState& transformState) const { - // We don't expect absoluteToLocal() to be called during layout (yet) - ASSERT(!view() || !view()->layoutStateEnabled()); - RenderObject* o = container(); if (!o) return; diff --git a/Source/WebCore/rendering/RenderBoxModelObject.h b/Source/WebCore/rendering/RenderBoxModelObject.h index 8d5e83e7a..6ee354c9a 100644 --- a/Source/WebCore/rendering/RenderBoxModelObject.h +++ b/Source/WebCore/rendering/RenderBoxModelObject.h @@ -24,6 +24,7 @@ #ifndef RenderBoxModelObject_h #define RenderBoxModelObject_h +#include "LayoutTypesInlineMethods.h" #include "RenderObject.h" #include "ShadowData.h" @@ -50,6 +51,7 @@ enum ContentChangeType { }; class KeyframeList; +class StickyPositionViewportConstraints; // This class is the base for all objects that adhere to the CSS box model as described // at http://www.w3.org/TR/CSS21/box.html @@ -62,6 +64,10 @@ public: LayoutSize relativePositionOffset() const; LayoutSize relativePositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? relativePositionOffset() : relativePositionOffset().transposedSize(); } + void computeStickyPositionConstraints(StickyPositionViewportConstraints&, const FloatRect& viewportRect) const; + LayoutSize stickyPositionOffset() const; + LayoutSize stickyPositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? stickyPositionOffset() : stickyPositionOffset().transposedSize(); } + LayoutSize offsetForInFlowPosition() const; // IE extensions. Used to calculate offsetWidth/Height. Overridden by inlines (RenderFlow) @@ -82,7 +88,8 @@ public: bool hasSelfPaintingLayer() const; RenderLayer* layer() const { return m_layer; } - virtual bool requiresLayer() const { return isRoot() || isOutOfFlowPositioned() || isInFlowPositioned() || isTransparent() || hasTransform() || hasHiddenBackface() || hasMask() || hasReflection() || hasFilter() || style()->specifiesColumns(); } + + virtual bool requiresLayer() const { return isRoot() || isPositioned() || createsGroup() || hasClipPath() || hasTransform() || hasHiddenBackface() || hasReflection() || style()->specifiesColumns(); } // This will work on inlines to return the bounding box of all of the lines' border boxes. virtual IntRect borderBoundingBox() const = 0; @@ -275,6 +282,8 @@ public: private: virtual bool isBoxModelObject() const { return true; } + + virtual LayoutRect frameRectForStickyPositioning() const = 0; IntSize calculateFillTileSize(const FillLayer*, const IntSize& scaledPositioningAreaSize) const; diff --git a/Source/WebCore/rendering/RenderCounter.cpp b/Source/WebCore/rendering/RenderCounter.cpp index de45d895e..e3496b136 100644 --- a/Source/WebCore/rendering/RenderCounter.cpp +++ b/Source/WebCore/rendering/RenderCounter.cpp @@ -30,6 +30,7 @@ #include "RenderListItem.h" #include "RenderListMarker.h" #include "RenderStyle.h" +#include "RenderView.h" #include <wtf/StdLibExtras.h> #ifndef NDEBUG @@ -40,7 +41,7 @@ namespace WebCore { using namespace HTMLNames; -typedef HashMap<RefPtr<AtomicStringImpl>, RefPtr<CounterNode> > CounterMap; +typedef HashMap<AtomicString, RefPtr<CounterNode> > CounterMap; typedef HashMap<const RenderObject*, OwnPtr<CounterMap> > CounterMaps; static CounterNode* makeCounterNode(RenderObject*, const AtomicString& identifier, bool alwaysCreateCounter); @@ -241,20 +242,11 @@ static bool planCounter(RenderObject* object, const AtomicString& identifier, bo return false; // Counters are forbidden from all other pseudo elements. } - if (const CounterDirectiveMap* directivesMap = style->counterDirectives()) { - CounterDirectives directives = directivesMap->get(identifier.impl()); - if (directives.m_reset) { - value = directives.m_resetValue; - if (directives.m_increment) - value += directives.m_incrementValue; - isReset = true; - return true; - } - if (directives.m_increment) { - value = directives.m_incrementValue; - isReset = false; - return true; - } + const CounterDirectives directives = style->getCounterDirectives(identifier); + if (directives.isDefined()) { + value = directives.combinedValue(); + isReset = directives.isReset(); + return true; } if (identifier == "list-item") { @@ -420,7 +412,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id if (object->hasCounterNodeMap()) { if (CounterMap* nodeMap = counterMaps().get(object)) { - if (CounterNode* node = nodeMap->get(identifier.impl()).get()) + if (CounterNode* node = nodeMap->get(identifier).get()) return node; } } @@ -443,7 +435,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id counterMaps().set(object, adoptPtr(nodeMap)); object->setHasCounterNodeMap(true); } - nodeMap->set(identifier.impl(), newNode); + nodeMap->set(identifier, newNode); if (newNode->parent()) return newNode.get(); // Checking if some nodes that were previously counter tree root nodes @@ -455,7 +447,7 @@ static CounterNode* makeCounterNode(RenderObject* object, const AtomicString& id skipDescendants = false; if (!currentRenderer->hasCounterNodeMap()) continue; - CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier.impl()).get(); + CounterNode* currentCounter = maps.get(currentRenderer)->get(identifier).get(); if (!currentCounter) continue; skipDescendants = true; @@ -537,6 +529,11 @@ PassRefPtr<StringImpl> RenderCounter::originalText() const return text.impl(); } +void RenderCounter::updateText() +{ + computePreferredLogicalWidths(0); +} + void RenderCounter::computePreferredLogicalWidths(float lead) { setTextInternal(originalText()); @@ -558,8 +555,8 @@ static void destroyCounterNodeWithoutMapRemoval(const AtomicString& identifier, for (RefPtr<CounterNode> child = node->lastDescendant(); child && child != node; child = previous) { previous = child->previousInPreOrder(); child->parent()->removeChild(child.get()); - ASSERT(counterMaps().get(child->owner())->get(identifier.impl()) == child); - counterMaps().get(child->owner())->remove(identifier.impl()); + ASSERT(counterMaps().get(child->owner())->get(identifier) == child); + counterMaps().get(child->owner())->remove(identifier); } if (CounterNode* parent = node->parent()) parent->removeChild(node); @@ -574,8 +571,7 @@ void RenderCounter::destroyCounterNodes(RenderObject* owner) CounterMap* map = mapsIterator->second.get(); CounterMap::const_iterator end = map->end(); for (CounterMap::const_iterator it = map->begin(); it != end; ++it) { - AtomicString identifier(it->first.get()); - destroyCounterNodeWithoutMapRemoval(identifier, it->second.get()); + destroyCounterNodeWithoutMapRemoval(it->first, it->second.get()); } maps.remove(mapsIterator); owner->setHasCounterNodeMap(false); @@ -586,7 +582,7 @@ void RenderCounter::destroyCounterNode(RenderObject* owner, const AtomicString& CounterMap* map = counterMaps().get(owner); if (!map) return; - CounterMap::iterator mapIterator = map->find(identifier.impl()); + CounterMap::iterator mapIterator = map->find(identifier); if (mapIterator == map->end()) return; destroyCounterNodeWithoutMapRemoval(identifier, mapIterator->second.get()); @@ -629,22 +625,22 @@ static void updateCounters(RenderObject* renderer) CounterDirectiveMap::const_iterator end = directiveMap->end(); if (!renderer->hasCounterNodeMap()) { for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) - makeCounterNode(renderer, AtomicString(it->first.get()), false); + makeCounterNode(renderer, it->first, false); return; } CounterMap* counterMap = counterMaps().get(renderer); ASSERT(counterMap); for (CounterDirectiveMap::const_iterator it = directiveMap->begin(); it != end; ++it) { - RefPtr<CounterNode> node = counterMap->get(it->first.get()); + RefPtr<CounterNode> node = counterMap->get(it->first); if (!node) { - makeCounterNode(renderer, AtomicString(it->first.get()), false); + makeCounterNode(renderer, it->first, false); continue; } RefPtr<CounterNode> newParent = 0; RefPtr<CounterNode> newPreviousSibling = 0; - findPlaceForCounter(renderer, AtomicString(it->first.get()), node->hasResetType(), newParent, newPreviousSibling); - if (node != counterMap->get(it->first.get())) + findPlaceForCounter(renderer, it->first, node->hasResetType(), newParent, newPreviousSibling); + if (node != counterMap->get(it->first)) continue; CounterNode* parent = node->parent(); if (newParent == parent && newPreviousSibling == node->previousSibling()) @@ -652,7 +648,7 @@ static void updateCounters(RenderObject* renderer) if (parent) parent->removeChild(node.get()); if (newParent) - newParent->insertAfter(node.get(), newPreviousSibling.get(), it->first.get()); + newParent->insertAfter(node.get(), newPreviousSibling.get(), it->first); } } @@ -688,17 +684,17 @@ void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderSty if (oldMapIt != oldMapEnd) { if (oldMapIt->second == it->second) continue; - RenderCounter::destroyCounterNode(renderer, it->first.get()); + RenderCounter::destroyCounterNode(renderer, it->first); } // We must create this node here, because the changed node may be a node with no display such as // as those created by the increment or reset directives and the re-layout that will happen will // not catch the change if the node had no children. - makeCounterNode(renderer, it->first.get(), false); + makeCounterNode(renderer, it->first, false); } // Destroying old counters that do not exist in the new counterDirective map. for (CounterDirectiveMap::const_iterator it = oldCounterDirectives->begin(); it !=oldMapEnd; ++it) { if (!newCounterDirectives->contains(it->first)) - RenderCounter::destroyCounterNode(renderer, it->first.get()); + RenderCounter::destroyCounterNode(renderer, it->first); } } else { if (renderer->hasCounterNodeMap()) @@ -710,7 +706,7 @@ void RenderCounter::rendererStyleChanged(RenderObject* renderer, const RenderSty // We must create this node here, because the added node may be a node with no display such as // as those created by the increment or reset directives and the re-layout that will happen will // not catch the change if the node had no children. - makeCounterNode(renderer, it->first.get(), false); + makeCounterNode(renderer, it->first, false); } } } @@ -735,7 +731,7 @@ void showCounterRendererTree(const WebCore::RenderObject* renderer, const char* fprintf(stderr, "%p N:%p P:%p PS:%p NS:%p C:%p\n", current, current->node(), current->parent(), current->previousSibling(), current->nextSibling(), current->hasCounterNodeMap() ? - counterName ? WebCore::counterMaps().get(current)->get(identifier.impl()).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0); + counterName ? WebCore::counterMaps().get(current)->get(identifier).get() : (WebCore::CounterNode*)1 : (WebCore::CounterNode*)0); } fflush(stderr); } diff --git a/Source/WebCore/rendering/RenderCounter.h b/Source/WebCore/rendering/RenderCounter.h index 6ba936f86..548828647 100644 --- a/Source/WebCore/rendering/RenderCounter.h +++ b/Source/WebCore/rendering/RenderCounter.h @@ -48,6 +48,7 @@ private: virtual bool isCounter() const; virtual PassRefPtr<StringImpl> originalText() const; + virtual void updateText() OVERRIDE; virtual void computePreferredLogicalWidths(float leadWidth); // Removes the reference to the CounterNode associated with this renderer. diff --git a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp index 8fa73ae4f..e2fe1cf5c 100644 --- a/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp +++ b/Source/WebCore/rendering/RenderDeprecatedFlexibleBox.cpp @@ -379,7 +379,7 @@ void RenderDeprecatedFlexibleBox::layoutHorizontalBox(bool relayoutChildren) continue; // Compute the child's vertical margins. - child->computeBlockDirectionMargins(this); + child->computeAndSetBlockDirectionMargins(this); if (!child->needsLayout()) child->markForPaginationRelayoutIfNeeded(); @@ -684,7 +684,7 @@ void RenderDeprecatedFlexibleBox::layoutVerticalBox(bool relayoutChildren) } // Compute the child's vertical margins. - child->computeBlockDirectionMargins(this); + child->computeAndSetBlockDirectionMargins(this); // Add in the child's marginTop to our height. setHeight(height() + child->marginTop()); diff --git a/Source/WebCore/rendering/RenderDialog.cpp b/Source/WebCore/rendering/RenderDialog.cpp new file mode 100644 index 000000000..4fb940925 --- /dev/null +++ b/Source/WebCore/rendering/RenderDialog.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 Google 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 AND ITS CONTRIBUTORS "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 OR ITS 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 "RenderDialog.h" + +#if ENABLE(DIALOG_ELEMENT) +#include "FrameView.h" +#include "LayoutRepainter.h" +#include "RenderLayer.h" +#include "RenderView.h" + +namespace WebCore { + +void RenderDialog::layout() +{ + LayoutRepainter repainter(*this, true); + LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); + + RenderBlock::layout(); + + RenderStyle* styleToUse = style(); + if (styleToUse->position() != AbsolutePosition || !styleToUse->top().isAuto() || !styleToUse->bottom().isAuto()) { + statePusher.pop(); + return; + } + + // Adjust the dialog's position to be centered in or at the top of the viewport. + // FIXME: Figure out what to do in vertical writing mode. + FrameView* frameView = document()->view(); + int scrollTop = frameView->scrollOffset().height(); + FloatPoint absolutePoint(0, scrollTop); + int visibleHeight = frameView->visibleContentRect(true).height(); + if (height() < visibleHeight) + absolutePoint.move(0, (visibleHeight - height()) / 2); + FloatPoint localPoint = containingBlock()->absoluteToLocal(absolutePoint); + LayoutUnit localTop = LayoutSize(localPoint.x(), localPoint.y()).height(); + setY(localTop); + + statePusher.pop(); + // FIXME: Since there is always a layer here, repainter shouldn't be necessary. But without it, the dialog is sometimes not painted (see bug 90670). + repainter.repaintAfterLayout(); +} + +} + +#endif diff --git a/Source/WebCore/rendering/RenderDialog.h b/Source/WebCore/rendering/RenderDialog.h new file mode 100644 index 000000000..ea669469e --- /dev/null +++ b/Source/WebCore/rendering/RenderDialog.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2012 Google 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 AND ITS CONTRIBUTORS "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 OR ITS 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 RenderDialog_h +#define RenderDialog_h + +#if ENABLE(DIALOG_ELEMENT) +#include "RenderBlock.h" +#include "RenderWidget.h" + +namespace WebCore { + +class HTMLDialogElement; + +class RenderDialog : public RenderBlock { +public: + explicit RenderDialog(Node* node) + : RenderBlock(node) + { } + + virtual ~RenderDialog() { } + virtual void layout() OVERRIDE; + +private: + virtual const char* renderName() const { return "RenderDialog"; } + virtual bool isDialog() const OVERRIDE { return true; } +}; + +} // namespace WebCore + +#endif + +#endif // RenderDialog_h diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.cpp b/Source/WebCore/rendering/RenderEmbeddedObject.cpp index 135959420..dcb3cc3b0 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.cpp +++ b/Source/WebCore/rendering/RenderEmbeddedObject.cpp @@ -265,16 +265,16 @@ void RenderEmbeddedObject::viewCleared() } } -bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderEmbeddedObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (!RenderPart::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction)) + if (!RenderPart::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; if (!widget() || !widget()->isPluginViewBase()) return true; PluginViewBase* view = static_cast<PluginViewBase*>(widget()); - IntPoint roundedPoint = pointInContainer.roundedPoint(); + IntPoint roundedPoint = locationInContainer.roundedPoint(); if (Scrollbar* horizontalScrollbar = view->horizontalScrollbar()) { if (horizontalScrollbar->shouldParticipateInHitTesting() && horizontalScrollbar->frameRect().contains(roundedPoint)) { diff --git a/Source/WebCore/rendering/RenderEmbeddedObject.h b/Source/WebCore/rendering/RenderEmbeddedObject.h index 6edc9bfb7..3f318b167 100644 --- a/Source/WebCore/rendering/RenderEmbeddedObject.h +++ b/Source/WebCore/rendering/RenderEmbeddedObject.h @@ -71,7 +71,7 @@ private: virtual void layout(); virtual void viewCleared(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier, Node** stopNode); virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier, Node** stopNode); diff --git a/Source/WebCore/rendering/RenderFlowThread.cpp b/Source/WebCore/rendering/RenderFlowThread.cpp index f3e47df47..059ff4818 100644 --- a/Source/WebCore/rendering/RenderFlowThread.cpp +++ b/Source/WebCore/rendering/RenderFlowThread.cpp @@ -52,6 +52,9 @@ RenderFlowThread::RenderFlowThread(Node* node) , m_regionsHaveUniformLogicalWidth(true) , m_regionsHaveUniformLogicalHeight(true) , m_overset(true) + , m_hasRegionsWithStyling(false) + , m_dispatchRegionLayoutUpdateEvent(false) + , m_pageLogicalHeightChanged(false) { ASSERT(node->document()->cssRegionsEnabled()); setIsAnonymous(false); @@ -130,7 +133,7 @@ private: void RenderFlowThread::layout() { - bool regionsChanged = m_regionsInvalidated && everHadLayout(); + m_pageLogicalHeightChanged = m_regionsInvalidated && everHadLayout(); if (m_regionsInvalidated) { m_regionsInvalidated = false; m_hasValidRegions = false; @@ -148,8 +151,8 @@ void RenderFlowThread::layout() region->deleteAllRenderBoxRegionInfo(); - LayoutUnit regionLogicalWidth = region->logicalWidthForFlowThreadContent(); - LayoutUnit regionLogicalHeight = region->logicalHeightForFlowThreadContent(); + LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); + LayoutUnit regionLogicalHeight = region->pageLogicalHeight(); if (!m_hasValidRegions) m_hasValidRegions = true; @@ -171,21 +174,24 @@ void RenderFlowThread::layout() if (!region->isValid()) continue; - LayoutUnit regionLogicalWidth = region->logicalWidthForFlowThreadContent(); - LayoutUnit regionLogicalHeight = region->logicalHeightForFlowThreadContent(); + LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); + LayoutUnit regionLogicalHeight = region->logicalHeightOfAllFlowThreadContent(); LayoutRect regionRect(style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth() - regionLogicalWidth, logicalHeight, regionLogicalWidth, regionLogicalHeight); - region->setRegionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect()); + region->setFlowThreadPortionRect(isHorizontalWritingMode() ? regionRect : regionRect.transposedRect()); logicalHeight += regionLogicalHeight; } } } CurrentRenderFlowThreadMaintainer currentFlowThreadSetter(this); - LayoutStateMaintainer statePusher(view(), this, regionsChanged); RenderBlock::layout(); - statePusher.pop(); - + + m_pageLogicalHeightChanged = false; + + if (lastRegion()) + lastRegion()->expandToEncompassFlowThreadContentsIfNeeded(); + if (shouldDispatchRegionLayoutUpdateEvent()) dispatchRegionLayoutUpdateEvent(); } @@ -198,7 +204,7 @@ void RenderFlowThread::computeLogicalWidth() if (!region->isValid()) continue; ASSERT(!region->needsLayout()); - logicalWidth = max(region->logicalWidthForFlowThreadContent(), logicalWidth); + logicalWidth = max(region->pageLogicalWidth(), logicalWidth); } setLogicalWidth(logicalWidth); @@ -208,7 +214,7 @@ void RenderFlowThread::computeLogicalWidth() if (!region->isValid()) continue; - LayoutUnit regionLogicalWidth = region->logicalWidthForFlowThreadContent(); + LayoutUnit regionLogicalWidth = region->pageLogicalWidth(); if (regionLogicalWidth != logicalWidth) { LayoutUnit logicalLeft = style()->direction() == LTR ? ZERO_LAYOUT_UNIT : logicalWidth - regionLogicalWidth; region->setRenderBoxRegionInfo(this, logicalLeft, regionLogicalWidth, false); @@ -225,13 +231,13 @@ void RenderFlowThread::computeLogicalHeight() if (!region->isValid()) continue; ASSERT(!region->needsLayout()); - logicalHeight += region->logicalHeightForFlowThreadContent(); + logicalHeight += region->logicalHeightOfAllFlowThreadContent(); } setLogicalHeight(logicalHeight); } -void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* region, const LayoutPoint& paintOffset) +void RenderFlowThread::paintFlowThreadPortionInRegion(PaintInfo& paintInfo, RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint& paintOffset) const { GraphicsContext* context = paintInfo.context; if (!context) @@ -240,9 +246,7 @@ void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* regio // Adjust the clipping rect for the region. // paintOffset contains the offset where the painting should occur // adjusted with the region padding and border. - LayoutRect regionRect(region->regionRect()); - LayoutRect regionOversetRect(region->regionOversetRect()); - LayoutRect regionClippingRect(paintOffset + (regionOversetRect.location() - regionRect.location()), regionOversetRect.size()); + LayoutRect regionClippingRect(paintOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); PaintInfo info(paintInfo); info.rect.intersect(pixelSnappedIntRect(regionClippingRect)); @@ -254,14 +258,14 @@ void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* regio // RenderFlowThread should start painting its content in a position that is offset // from the region rect's current position. The amount of offset is equal to the location of - // region in flow coordinates. + // the flow thread portion in the flow thread's local coordinates. IntPoint renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { - LayoutRect flippedRegionRect(regionRect); - flipForWritingMode(flippedRegionRect); - renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedRegionRect.location()); + LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); + flipForWritingMode(flippedFlowThreadPortionRect); + renderFlowThreadOffset = roundedIntPoint(paintOffset - flippedFlowThreadPortionRect.location()); } else - renderFlowThreadOffset = roundedIntPoint(paintOffset - regionRect.location()); + renderFlowThreadOffset = roundedIntPoint(paintOffset - flowThreadPortionRect.location()); context->translate(renderFlowThreadOffset.x(), renderFlowThreadOffset.y()); info.rect.moveBy(-renderFlowThreadOffset); @@ -272,29 +276,27 @@ void RenderFlowThread::paintIntoRegion(PaintInfo& paintInfo, RenderRegion* regio } } -bool RenderFlowThread::hitTestRegion(RenderRegion* region, const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset) +bool RenderFlowThread::hitTestFlowThreadPortionInRegion(RenderRegion* region, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const { - LayoutRect regionRect(region->regionRect()); - LayoutRect regionOversetRect = region->regionOversetRect(); - LayoutRect regionClippingRect(accumulatedOffset + (regionOversetRect.location() - regionRect.location()), regionOversetRect.size()); - if (!regionClippingRect.contains(pointInContainer.point())) + LayoutRect regionClippingRect(accumulatedOffset + (flowThreadPortionOverflowRect.location() - flowThreadPortionRect.location()), flowThreadPortionOverflowRect.size()); + if (!regionClippingRect.contains(locationInContainer.point())) return false; LayoutSize renderFlowThreadOffset; if (style()->isFlippedBlocksWritingMode()) { - LayoutRect flippedRegionRect(regionRect); - flipForWritingMode(flippedRegionRect); - renderFlowThreadOffset = accumulatedOffset - flippedRegionRect.location(); + LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); + flipForWritingMode(flippedFlowThreadPortionRect); + renderFlowThreadOffset = accumulatedOffset - flippedFlowThreadPortionRect.location(); } else - renderFlowThreadOffset = accumulatedOffset - regionRect.location(); + renderFlowThreadOffset = accumulatedOffset - flowThreadPortionRect.location(); // Always ignore clipping, since the RenderFlowThread has nothing to do with the bounds of the FrameView. HitTestRequest newRequest(request.type() | HitTestRequest::IgnoreClipping); - // Make a new temporary hitTestPoint in the new region. - HitTestPoint newHitTestPoint(pointInContainer, -renderFlowThreadOffset, region); + // Make a new temporary HitTestLocation in the new region. + HitTestLocation newHitTestLocation(locationInContainer, -renderFlowThreadOffset, region); - bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestPoint, result); + bool isPointInsideFlowThread = layer()->hitTest(newRequest, newHitTestLocation, result); // FIXME: Should we set result.m_localPoint back to the RenderRegion's coordinate space or leave it in the RenderFlowThread's coordinate // space? Right now it's staying in the RenderFlowThread's coordinate space, which may end up being ok. We will know more when we get around to @@ -315,37 +317,22 @@ void RenderFlowThread::repaintRectangleInRegions(const LayoutRect& repaintRect, if (!shouldRepaint(repaintRect) || !hasValidRegionInfo()) return; + LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the regions are somewhere else. + + // We can't use currentFlowThread as it is possible to have interleaved flow threads and the wrong one could be used. + // Let each region figure out the proper enclosing flow thread. + CurrentRenderFlowThreadDisabler disabler(view()); + for (RenderRegionList::iterator iter = m_regionList.begin(); iter != m_regionList.end(); ++iter) { RenderRegion* region = *iter; if (!region->isValid()) continue; - // We only have to issue a repaint in this region if the region rect intersects the repaint rect. - LayoutRect flippedRegionRect(region->regionRect()); - LayoutRect flippedRegionOversetRect(region->regionOversetRect()); - flipForWritingMode(flippedRegionRect); // Put the region rects into physical coordinates. - flipForWritingMode(flippedRegionOversetRect); - - LayoutRect clippedRect(repaintRect); - clippedRect.intersect(flippedRegionOversetRect); - if (clippedRect.isEmpty()) - continue; - - // Put the region rect into the region's physical coordinate space. - clippedRect.setLocation(region->contentBoxRect().location() + (clippedRect.location() - flippedRegionRect.location())); - - // Now switch to the region's writing mode coordinate space and let it repaint itself. - region->flipForWritingMode(clippedRect); - LayoutStateDisabler layoutStateDisabler(view()); // We can't use layout state to repaint, since the region is somewhere else. - - // Can't use currentFlowThread as it possible to have imbricated flow threads and the wrong one could be used, - // so, we let each region figure out the proper enclosing flow thread - CurrentRenderFlowThreadDisabler disabler(view()); - region->repaintRectangle(clippedRect, immediate); + region->repaintFlowThreadContent(repaintRect, immediate); } } -RenderRegion* RenderFlowThread::renderRegionForLine(LayoutUnit position, bool extendLastRegion) const +RenderRegion* RenderFlowThread::regionAtBlockOffset(LayoutUnit offset, bool extendLastRegion) const { ASSERT(!m_regionsInvalidated); @@ -360,58 +347,52 @@ RenderRegion* RenderFlowThread::renderRegionForLine(LayoutUnit position, bool ex if (!region->isValid()) continue; - if (position <= 0) + if (offset <= 0) return region; - LayoutRect regionRect = region->regionRect(); - - if ((useHorizontalWritingMode && position < regionRect.maxY()) || (!useHorizontalWritingMode && position < regionRect.maxX())) + LayoutRect regionRect = region->flowThreadPortionRect(); + if ((useHorizontalWritingMode && offset < regionRect.maxY()) || (!useHorizontalWritingMode && offset < regionRect.maxX())) return region; - if (extendLastRegion) + if (extendLastRegion || region->isRenderRegionSet()) lastValidRegion = region; } return lastValidRegion; } -LayoutUnit RenderFlowThread::regionLogicalTopForLine(LayoutUnit position) const +LayoutUnit RenderFlowThread::pageLogicalTopForOffset(LayoutUnit offset) const { - RenderRegion* region = renderRegionForLine(position); - if (!region) - return 0; - return isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x(); + RenderRegion* region = regionAtBlockOffset(offset); + return region ? region->pageLogicalTopForOffset(offset) : ZERO_LAYOUT_UNIT; } -LayoutUnit RenderFlowThread::regionLogicalWidthForLine(LayoutUnit position) const +LayoutUnit RenderFlowThread::pageLogicalWidthForOffset(LayoutUnit offset) const { - RenderRegion* region = renderRegionForLine(position, true); - if (!region) - return contentLogicalWidth(); - return isHorizontalWritingMode() ? region->regionRect().width() : region->regionRect().height(); + RenderRegion* region = regionAtBlockOffset(offset, true); + return region ? region->pageLogicalWidth() : contentLogicalWidth(); } -LayoutUnit RenderFlowThread::regionLogicalHeightForLine(LayoutUnit position) const +LayoutUnit RenderFlowThread::pageLogicalHeightForOffset(LayoutUnit offset) const { - RenderRegion* region = renderRegionForLine(position); - if (!region) - return 0; - return isHorizontalWritingMode() ? region->regionRect().height() : region->regionRect().width(); + RenderRegion* region = regionAtBlockOffset(offset); + return region ? region->pageLogicalHeight() : ZERO_LAYOUT_UNIT; } -LayoutUnit RenderFlowThread::regionRemainingLogicalHeightForLine(LayoutUnit position, PageBoundaryRule pageBoundaryRule) const +LayoutUnit RenderFlowThread::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const { - RenderRegion* region = renderRegionForLine(position); + RenderRegion* region = regionAtBlockOffset(offset); if (!region) - return 0; - - LayoutUnit regionLogicalBottom = isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX(); - LayoutUnit remainingHeight = regionLogicalBottom - position; + return ZERO_LAYOUT_UNIT; + + LayoutUnit pageLogicalTop = region->pageLogicalTopForOffset(offset); + LayoutUnit pageLogicalHeight = region->pageLogicalHeight(); + LayoutUnit pageLogicalBottom = pageLogicalTop + pageLogicalHeight; + LayoutUnit remainingHeight = pageLogicalBottom - offset; if (pageBoundaryRule == IncludePageBoundary) { // If IncludePageBoundary is set, the line exactly on the top edge of a // region will act as being part of the previous region. - LayoutUnit regionHeight = isHorizontalWritingMode() ? region->regionRect().height() : region->regionRect().width(); - remainingHeight = intMod(remainingHeight, regionHeight); + remainingHeight = intMod(remainingHeight, pageLogicalHeight); } return remainingHeight; } @@ -429,11 +410,11 @@ RenderRegion* RenderFlowThread::mapFromFlowToRegion(TransformState& transformSta // Note: Using the center in order to avoid rounding errors. LayoutPoint center = boxRect.center(); - RenderRegion* renderRegion = renderRegionForLine(isHorizontalWritingMode() ? center.y() : center.x(), true); + RenderRegion* renderRegion = regionAtBlockOffset(isHorizontalWritingMode() ? center.y() : center.x(), true); if (!renderRegion) return 0; - LayoutRect flippedRegionRect(renderRegion->regionRect()); + LayoutRect flippedRegionRect(renderRegion->flowThreadPortionRect()); flipForWritingMode(flippedRegionRect); transformState.move(renderRegion->contentBoxRect().location() - flippedRegionRect.location()); @@ -541,7 +522,7 @@ LayoutUnit RenderFlowThread::contentLogicalLeftOfFirstRegion() const RenderRegion* region = *iter; if (!region->isValid()) continue; - return isHorizontalWritingMode() ? region->regionRect().x() : region->regionRect().y(); + return isHorizontalWritingMode() ? region->flowThreadPortionRect().x() : region->flowThreadPortionRect().y(); } ASSERT_NOT_REACHED(); return 0; @@ -605,8 +586,8 @@ void RenderFlowThread::setRegionRangeForBox(const RenderBox* box, LayoutUnit off return; // FIXME: Not right for differing writing-modes. - RenderRegion* startRegion = renderRegionForLine(offsetFromLogicalTopOfFirstPage, true); - RenderRegion* endRegion = renderRegionForLine(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true); + RenderRegion* startRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage, true); + RenderRegion* endRegion = regionAtBlockOffset(offsetFromLogicalTopOfFirstPage + box->logicalHeight(), true); RenderRegionRangeMap::iterator it = m_regionRangeMap.find(box); if (it == m_regionRangeMap.end()) { m_regionRangeMap.set(box, RenderRegionRange(startRegion, endRegion)); @@ -669,8 +650,8 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE region->setRegionState(RenderRegion::RegionUndefined); continue; } - LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->regionRect().y() : region->regionRect().x()); - LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->regionRect().maxY() : region->regionRect().maxX()); + LayoutUnit flowMin = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().y() : region->flowThreadPortionRect().x()); + LayoutUnit flowMax = height - (isHorizontalWritingMode() ? region->flowThreadPortionRect().maxY() : region->flowThreadPortionRect().maxX()); RenderRegion::RegionState previousState = region->regionState(); RenderRegion::RegionState state = RenderRegion::RegionFit; if (flowMin <= 0) @@ -688,7 +669,7 @@ void RenderFlowThread::computeOverflowStateForRegions(LayoutUnit oldClientAfterE } // With the regions overflow state computed we can also set the overset flag for the named flow. - // If there are no valid regions in the chain, overset is true + // If there are no valid regions in the chain, overset is true. m_overset = lastReg ? lastReg->regionState() == RenderRegion::RegionOverset : true; } diff --git a/Source/WebCore/rendering/RenderFlowThread.h b/Source/WebCore/rendering/RenderFlowThread.h index 34dec69d8..32803adde 100644 --- a/Source/WebCore/rendering/RenderFlowThread.h +++ b/Source/WebCore/rendering/RenderFlowThread.h @@ -73,11 +73,11 @@ public: virtual void removeRegionFromThread(RenderRegion*); const RenderRegionList& renderRegionList() const { return m_regionList; } - void computeLogicalWidth(); - void computeLogicalHeight(); + virtual void computeLogicalWidth() OVERRIDE; + virtual void computeLogicalHeight() OVERRIDE; - void paintIntoRegion(PaintInfo&, RenderRegion*, const LayoutPoint& paintOffset); - bool hitTestRegion(RenderRegion*, const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset); + void paintFlowThreadPortionInRegion(PaintInfo&, RenderRegion*, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const LayoutPoint&) const; + bool hitTestFlowThreadPortionInRegion(RenderRegion*, LayoutRect flowThreadPortionRect, LayoutRect flowThreadPortionOverflowRect, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) const; bool hasRegions() const { return m_regionList.size(); } bool hasValidRegions() const { ASSERT(!m_regionsInvalidated); return m_hasValidRegions; } @@ -94,11 +94,11 @@ public: void repaintRectangleInRegions(const LayoutRect&, bool immediate); - LayoutUnit regionLogicalTopForLine(LayoutUnit position) const; - LayoutUnit regionLogicalWidthForLine(LayoutUnit position) const; - LayoutUnit regionLogicalHeightForLine(LayoutUnit position) const; - LayoutUnit regionRemainingLogicalHeightForLine(LayoutUnit position, PageBoundaryRule = IncludePageBoundary) const; - RenderRegion* renderRegionForLine(LayoutUnit position, bool extendLastRegion = false) const; + LayoutUnit pageLogicalTopForOffset(LayoutUnit) const; + LayoutUnit pageLogicalWidthForOffset(LayoutUnit) const; + LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const; + LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule = IncludePageBoundary) const; + RenderRegion* regionAtBlockOffset(LayoutUnit, bool extendLastRegion = false) const; bool regionsHaveUniformLogicalWidth() const { return m_regionsHaveUniformLogicalWidth; } bool regionsHaveUniformLogicalHeight() const { return m_regionsHaveUniformLogicalHeight; } @@ -129,6 +129,8 @@ public: // Check if the object is in region and the region is part of this flow thread. bool objectInFlowRegion(const RenderObject*, const RenderRegion*) const; + bool pageLogicalHeightChanged() const { return m_pageLogicalHeightChanged; } + protected: virtual const char* renderName() const = 0; @@ -180,6 +182,7 @@ protected: bool m_overset; bool m_hasRegionsWithStyling; bool m_dispatchRegionLayoutUpdateEvent; + bool m_pageLogicalHeightChanged; }; inline RenderFlowThread* toRenderFlowThread(RenderObject* object) diff --git a/Source/WebCore/rendering/RenderFlowThreadContainer.cpp b/Source/WebCore/rendering/RenderFlowThreadContainer.cpp deleted file mode 100644 index 680ac4ec0..000000000 --- a/Source/WebCore/rendering/RenderFlowThreadContainer.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 "RenderFlowThreadContainer.h" - -namespace WebCore { - -RenderFlowThreadContainer::RenderFlowThreadContainer(Node* node) -: RenderFlowThread(node) -{ -} - -void RenderFlowThreadContainer::layout() -{ - ASSERT(needsLayout()); - setNeedsLayout(false); -} - -} // namespace WebCore diff --git a/Source/WebCore/rendering/RenderFlowThreadContainer.h b/Source/WebCore/rendering/RenderFlowThreadContainer.h deleted file mode 100644 index 5a958ce3a..000000000 --- a/Source/WebCore/rendering/RenderFlowThreadContainer.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 RenderFlowThreadContainer_h -#define RenderFlowThreadContainer_h - - -#include "RenderFlowThread.h" - -namespace WebCore { - -class RenderFlowThreadContainer: public RenderFlowThread { -public: - RenderFlowThreadContainer(Node*); - virtual ~RenderFlowThreadContainer() { }; - - virtual void layout() OVERRIDE; - virtual bool isRenderFlowThreadContainer() const OVERRIDE { return true; } - -private: - virtual const char* renderName() const { return "RenderFlowThreadContainer"; } -}; - -} // namespace WebCore - -#endif // RenderFlowThread_h diff --git a/Source/WebCore/rendering/RenderFrameBase.cpp b/Source/WebCore/rendering/RenderFrameBase.cpp index aa82870d4..be92c0fa8 100644 --- a/Source/WebCore/rendering/RenderFrameBase.cpp +++ b/Source/WebCore/rendering/RenderFrameBase.cpp @@ -29,6 +29,8 @@ #include "Frame.h" #include "FrameView.h" #include "HTMLFrameElementBase.h" +#include "HitTestResult.h" +#include "RenderLayer.h" #include "RenderView.h" namespace WebCore { @@ -104,4 +106,33 @@ void RenderFrameBase::layoutWithFlattening(bool hasFixedWidth, bool hasFixedHeig setNeedsLayout(false); } +bool RenderFrameBase::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +{ + if (request.allowsChildFrameContent()) { + FrameView* childFrameView = static_cast<FrameView*>(widget()); + RenderView* childRoot = childFrameView ? static_cast<RenderView*>(childFrameView->frame()->contentRenderer()) : 0; + + if (childRoot) { + LayoutPoint adjustedLocation = accumulatedOffset + location(); + HitTestLocation newHitTestLocation(locationInContainer, -toLayoutSize(adjustedLocation)); + HitTestRequest newHitTestRequest(request.type() | HitTestRequest::ChildFrameHitTest); + + bool isInsideChildFrame = childRoot->layer()->hitTest(newHitTestRequest, newHitTestLocation, result); + if (isInsideChildFrame) + return true; + + if (request.shouldTestChildFrameScrollBars()) { + // ScrollView scrollbars are not the same as RenderLayer scrollbars tested by RenderLayer::hitTestOverflowControls, + // so we need to test ScrollView scrollbars separately here. + // FIXME: Consider if this test could be done unconditionally. + Scrollbar* frameScrollbar = childFrameView->scrollbarAtPoint(newHitTestLocation.roundedPoint()); + if (frameScrollbar) + result.setScrollbar(frameScrollbar); + } + } + } + + return RenderPart::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); +} + } diff --git a/Source/WebCore/rendering/RenderFrameBase.h b/Source/WebCore/rendering/RenderFrameBase.h index 4fad560c5..a7deedab1 100644 --- a/Source/WebCore/rendering/RenderFrameBase.h +++ b/Source/WebCore/rendering/RenderFrameBase.h @@ -36,6 +36,7 @@ protected: explicit RenderFrameBase(Element*); public: + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; void layoutWithFlattening(bool fixedWidth, bool fixedHeight); }; diff --git a/Source/WebCore/rendering/RenderFrameSet.cpp b/Source/WebCore/rendering/RenderFrameSet.cpp index c89547863..e6df40b9a 100644 --- a/Source/WebCore/rendering/RenderFrameSet.cpp +++ b/Source/WebCore/rendering/RenderFrameSet.cpp @@ -158,12 +158,12 @@ void RenderFrameSet::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) } bool RenderFrameSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, - const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) + const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (action != HitTestForeground) return false; - bool inside = RenderBox::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, action) + bool inside = RenderBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action) || m_isResizing; if (inside && frameSet()->noResize() diff --git a/Source/WebCore/rendering/RenderFrameSet.h b/Source/WebCore/rendering/RenderFrameSet.h index 7d69770e7..b670575c3 100644 --- a/Source/WebCore/rendering/RenderFrameSet.h +++ b/Source/WebCore/rendering/RenderFrameSet.h @@ -96,7 +96,7 @@ private: virtual bool isFrameSet() const { return true; } virtual void layout(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual void paint(PaintInfo&, const LayoutPoint&); virtual bool isChildAllowed(RenderObject*, RenderStyle*) const; virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const; diff --git a/Source/WebCore/rendering/RenderGeometryMap.h b/Source/WebCore/rendering/RenderGeometryMap.h index 98f44c633..495d0bf22 100644 --- a/Source/WebCore/rendering/RenderGeometryMap.h +++ b/Source/WebCore/rendering/RenderGeometryMap.h @@ -29,13 +29,17 @@ #include "FloatPoint.h" #include "FloatQuad.h" #include "IntSize.h" -#include "RenderObject.h" +#include "LayoutTypesInlineMethods.h" #include "TransformationMatrix.h" #include <wtf/OwnPtr.h> namespace WebCore { +class RenderBoxModelObject; class RenderLayer; +class RenderObject; +class RenderView; +class TransformState; // Stores data about how to map from one renderer to its container. struct RenderGeometryMapStep { diff --git a/Source/WebCore/rendering/RenderImage.cpp b/Source/WebCore/rendering/RenderImage.cpp index f399abc4d..1953f5331 100644 --- a/Source/WebCore/rendering/RenderImage.cpp +++ b/Source/WebCore/rendering/RenderImage.cpp @@ -499,16 +499,16 @@ HTMLMapElement* RenderImage::imageMap() const return i ? i->treeScope()->getImageMap(i->fastGetAttribute(usemapAttr)) : 0; } -bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderImage::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); - bool inside = RenderReplaced::nodeAtPoint(request, tempResult, pointInContainer, accumulatedOffset, hitTestAction); + HitTestResult tempResult(result.hitTestLocation()); + bool inside = RenderReplaced::nodeAtPoint(request, tempResult, locationInContainer, accumulatedOffset, hitTestAction); if (tempResult.innerNode() && node()) { if (HTMLMapElement* map = imageMap()) { LayoutRect contentBox = contentBoxRect(); float scaleFactor = 1 / style()->effectiveZoom(); - LayoutPoint mapLocation = pointInContainer.point() - toLayoutSize(accumulatedOffset) - locationOffset() - toLayoutSize(contentBox.location()); + LayoutPoint mapLocation = locationInContainer.point() - toLayoutSize(accumulatedOffset) - locationOffset() - toLayoutSize(contentBox.location()); mapLocation.scale(scaleFactor, scaleFactor); if (map->mapMouseEvent(mapLocation, contentBox.size(), tempResult)) diff --git a/Source/WebCore/rendering/RenderImage.h b/Source/WebCore/rendering/RenderImage.h index 6bddb0a58..2358fb2db 100644 --- a/Source/WebCore/rendering/RenderImage.h +++ b/Source/WebCore/rendering/RenderImage.h @@ -92,7 +92,7 @@ private: virtual int minimumReplacedHeight() const; virtual void notifyFinished(CachedResource*); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual bool boxShadowShouldBeAppliedToBackground(BackgroundBleedAvoidance, InlineFlowBox*) const OVERRIDE; diff --git a/Source/WebCore/rendering/RenderInline.cpp b/Source/WebCore/rendering/RenderInline.cpp index b139bcb44..941375509 100644 --- a/Source/WebCore/rendering/RenderInline.cpp +++ b/Source/WebCore/rendering/RenderInline.cpp @@ -750,6 +750,8 @@ const char* RenderInline::renderName() const { if (isRelPositioned()) return "RenderInline (relative positioned)"; + if (isStickyPositioned()) + return "RenderInline (sticky positioned)"; if (isAnonymous()) return "RenderInline (generated)"; if (isRunIn()) @@ -758,14 +760,14 @@ const char* RenderInline::renderName() const } bool RenderInline::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, - const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) + const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - return m_lineBoxes.hitTest(this, request, result, pointInContainer, accumulatedOffset, hitTestAction); + return m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction); } VisiblePosition RenderInline::positionForPoint(const LayoutPoint& point) { - // FIXME: Does not deal with relative positioned inlines (should it?) + // FIXME: Does not deal with relative or sticky positioned inlines (should it?) RenderBlock* cb = containingBlock(); if (firstLineBox()) { // This inline actually has a line box. We must have clicked in the border/padding of one of these boxes. We @@ -1064,7 +1066,7 @@ void RenderInline::computeRectForRepaint(RenderBoxModelObject* repaintContainer, if (style()->hasInFlowPosition() && layer()) { // Apply the in-flow position offset when invalidating a rectangle. The layer // is translated, but the render box isn't, so we need to do this to get the - // right dirty rect. Since this is called from RenderObject::setStyle, the relative position + // right dirty rect. Since this is called from RenderObject::setStyle, the relative or sticky position // flag on the RenderObject has been cleared, so use the one on the style(). topLeft += layer()->offsetForInFlowPosition(); } diff --git a/Source/WebCore/rendering/RenderInline.h b/Source/WebCore/rendering/RenderInline.h index 9adec42b0..4a5bb09dc 100644 --- a/Source/WebCore/rendering/RenderInline.h +++ b/Source/WebCore/rendering/RenderInline.h @@ -89,7 +89,7 @@ public: protected: virtual void willBeDestroyed(); - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) OVERRIDE; private: virtual RenderObjectChildList* virtualChildren() { return children(); } @@ -122,9 +122,9 @@ private: virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool requiresLayer() const { return isInFlowPositioned() || isTransparent() || hasMask() || hasFilter(); } + virtual bool requiresLayer() const { return isInFlowPositioned() || createsGroup() || hasClipPath(); } virtual LayoutUnit offsetLeft() const; virtual LayoutUnit offsetTop() const; @@ -140,6 +140,8 @@ private: virtual VisiblePosition positionForPoint(const LayoutPoint&); + virtual LayoutRect frameRectForStickyPositioning() const OVERRIDE { return linesBoundingBox(); } + virtual IntRect borderBoundingBox() const { IntRect boundingBox = linesBoundingBox(); diff --git a/Source/WebCore/rendering/RenderInputSpeech.h b/Source/WebCore/rendering/RenderInputSpeech.h index f37b836f4..6735961fb 100644 --- a/Source/WebCore/rendering/RenderInputSpeech.h +++ b/Source/WebCore/rendering/RenderInputSpeech.h @@ -31,12 +31,18 @@ #ifndef RenderInputSpeech_h #define RenderInputSpeech_h -#include "RenderObject.h" - #if ENABLE(INPUT_SPEECH) namespace WebCore { +struct PaintInfo; + +class Element; +class IntRect; +class RenderObject; +class RenderStyle; +class StyleResolver; + class RenderInputSpeech { public: static void adjustInputFieldSpeechButtonStyle(StyleResolver*, RenderStyle*, Element*); diff --git a/Source/WebCore/rendering/RenderLayer.cpp b/Source/WebCore/rendering/RenderLayer.cpp index edb3cf58d..271999385 100644 --- a/Source/WebCore/rendering/RenderLayer.cpp +++ b/Source/WebCore/rendering/RenderLayer.cpp @@ -126,9 +126,9 @@ using namespace HTMLNames; const int MinimumWidthWhileResizing = 100; const int MinimumHeightWhileResizing = 40; -bool ClipRect::intersects(const HitTestPoint& hitTestPoint) +bool ClipRect::intersects(const HitTestLocation& hitTestLocation) { - return hitTestPoint.intersects(m_rect); + return hitTestLocation.intersects(m_rect); } RenderLayer::RenderLayer(RenderBoxModelObject* renderer) @@ -161,6 +161,9 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer) #if ENABLE(CSS_FILTERS) , m_hasFilterInfo(false) #endif +#if ENABLE(CSS_COMPOSITING) + , m_blendMode(BlendModeNormal) +#endif , m_renderer(renderer) , m_parent(0) , m_previous(0) @@ -519,10 +522,10 @@ void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrol updateLayerPosition(); - if ((flags & HasSeenFixedPositionedAncestor) || renderer()->style()->position() == FixedPosition) { + if ((flags & HasSeenViewportConstrainedAncestor) || renderer()->style()->hasViewportConstrainedPosition()) { // FIXME: Is it worth passing the offsetFromRoot around like in updateLayerPositions? computeRepaintRects(); - flags |= HasSeenFixedPositionedAncestor; + flags |= HasSeenViewportConstrainedAncestor; } else if ((flags & HasSeenAncestorWithOverflowClip) && !m_canSkipRepaintRectsUpdateOnScroll) { // If we have seen an overflow clip, we should update our repaint rects as clippedOverflowRectForRepaint // intersects it with our ancestor overflow clip that may have moved. @@ -543,6 +546,18 @@ void RenderLayer::updateLayerPositionsAfterScroll(UpdateLayerPositionsAfterScrol m_marquee->updateMarqueePosition(); } +#if ENABLE(CSS_COMPOSITING) +void RenderLayer::updateBlendMode() +{ + BlendMode newBlendMode = renderer()->style()->blendMode(); + if (newBlendMode != m_blendMode) { + m_blendMode = newBlendMode; + if (backing()) + backing()->setBlendMode(newBlendMode); + } +} +#endif + void RenderLayer::updateTransform() { // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, @@ -933,7 +948,7 @@ RenderLayer* RenderLayer::stackingContext() const static inline bool isPositionedContainer(RenderLayer* layer) { RenderBoxModelObject* layerRenderer = layer->renderer(); - return layer->isRootLayer() || layerRenderer->isOutOfFlowPositioned() || layerRenderer->isInFlowPositioned() || layer->hasTransform(); + return layer->isRootLayer() || layerRenderer->isPositioned() || layer->hasTransform(); } static inline bool isFixedPositionedContainer(RenderLayer* layer) @@ -1552,6 +1567,20 @@ void RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, LayoutR rect.move(-delta.x(), -delta.y()); } +#if USE(ACCELERATED_COMPOSITING) +bool RenderLayer::usesCompositedScrolling() const +{ + if (!scrollsOverflow() || !allowsScrolling()) + return false; + +#if ENABLE(OVERFLOW_SCROLLING) + return renderer()->style()->useTouchOverflowScrolling(); +#else + return false; +#endif +} +#endif + static inline int adjustedScrollDelta(int beginningDelta) { // This implemention matches Firefox's. // http://mxr.mozilla.org/firefox/source/toolkit/content/widgets/browser.xml#856. @@ -1636,8 +1665,8 @@ IntSize RenderLayer::clampScrollOffset(const IntSize& scrollOffset) const int maxX = scrollWidth() - box->pixelSnappedClientWidth(); int maxY = scrollHeight() - box->pixelSnappedClientHeight(); - int x = min(max(scrollOffset.width(), 0), maxX); - int y = min(max(scrollOffset.height(), 0), maxY); + int x = max(min(scrollOffset.width(), maxX), 0); + int y = max(min(scrollOffset.height(), maxY), 0); return IntSize(x, y); } @@ -1703,7 +1732,7 @@ void RenderLayer::scrollTo(int x, int y) } // Just schedule a full repaint of our object. - if (view) + if (view && !usesCompositedScrolling()) renderer()->repaintUsingContainer(repaintContainer, m_repaintRect); // Schedule the scroll DOM event. @@ -2401,7 +2430,7 @@ bool RenderLayer::hasOverflowControls() const return m_hBar || m_vBar || m_scrollCorner || renderer()->style()->resize() != RESIZE_NONE; } -void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer) +void RenderLayer::positionOverflowControls(const IntSize& offsetFromRoot) { if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)) return; @@ -2412,7 +2441,7 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer) const IntRect borderBox = box->pixelSnappedBorderBoxRect(); const IntRect& scrollCorner = scrollCornerRect(); - IntRect absBounds(borderBox.location() + offsetFromLayer, borderBox.size()); + IntRect absBounds(borderBox.location() + offsetFromRoot, borderBox.size()); if (m_vBar) m_vBar->setFrameRect(IntRect(verticalScrollbarStart(absBounds.x(), absBounds.maxX()), absBounds.y() + box->borderTop(), @@ -2425,34 +2454,15 @@ void RenderLayer::positionOverflowControls(const IntSize& offsetFromLayer) absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(), m_hBar->height())); -#if USE(ACCELERATED_COMPOSITING) - if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { - if (m_hBar) { - layer->setPosition(m_hBar->frameRect().location() - offsetFromLayer); - layer->setSize(m_hBar->frameRect().size()); - } - layer->setDrawsContent(m_hBar); - } - if (GraphicsLayer* layer = layerForVerticalScrollbar()) { - if (m_vBar) { - layer->setPosition(m_vBar->frameRect().location() - offsetFromLayer); - layer->setSize(m_vBar->frameRect().size()); - } - layer->setDrawsContent(m_vBar); - } - - if (GraphicsLayer* layer = layerForScrollCorner()) { - const LayoutRect& scrollCornerAndResizer = scrollCornerAndResizerRect(); - layer->setPosition(scrollCornerAndResizer.location()); - layer->setSize(scrollCornerAndResizer.size()); - layer->setDrawsContent(!scrollCornerAndResizer.isEmpty()); - } -#endif - if (m_scrollCorner) m_scrollCorner->setFrameRect(scrollCorner); if (m_resizer) m_resizer->setFrameRect(resizerCornerRect(this, borderBox)); + +#if USE(ACCELERATED_COMPOSITING) + if (isComposited()) + backing()->positionOverflowControlsLayers(offsetFromRoot); +#endif } int RenderLayer::scrollWidth() const @@ -2626,6 +2636,12 @@ void RenderLayer::updateScrollInfoAfterLayout() if (originalScrollOffset != scrollOffset()) scrollToOffsetWithoutAnimation(toPoint(scrollOffset())); + +#if USE(ACCELERATED_COMPOSITING) + // Composited scrolling may need to be enabled or disabled if the amount of overflow changed. + if (renderer()->view() && compositor()->updateLayerCompositingState(this)) + compositor()->setCompositingLayersNeedRebuild(); +#endif } void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls) @@ -3009,7 +3025,8 @@ 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) ? TemporaryClipRects : PaintingClipRects); + clipRect = backgroundClipRect(rootLayer, region, (paintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, + IgnoreOverlayScrollbarSize, (paintFlags & PaintLayerPaintingOverflowContents) ? IgnoreOverflowClip : RespectOverflowClip); clipRect.intersect(paintDirtyRect); // Push the parent coordinate space's clip. @@ -3093,6 +3110,18 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co // Ensure our lists are up-to-date. updateLayerListsIfNeeded(); + // Apply clip-path to context. + RenderStyle* style = renderer()->style(); + if (renderer()->hasClipPath() && !context->paintingDisabled() && style) { + if (BasicShape* clipShape = style->clipPath()) { + // FIXME: Investigate if it is better to store and update a Path object in RenderStyle. + // https://bugs.webkit.org/show_bug.cgi?id=95619 + Path clipPath; + clipShape->path(clipPath, calculateLayerBounds(this, rootLayer, 0)); + transparencyLayerContext->clipPath(clipPath, clipShape->windRule()); + } + } + #if ENABLE(CSS_FILTERS) FilterEffectRendererHelper filterPainter(filterRenderer() && paintsWithFilters()); if (filterPainter.haveFilterEffect() && !context->paintingDisabled()) { @@ -3125,7 +3154,8 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co #endif if (shouldPaintContent || shouldPaintOutline || isPaintingOverlayScrollbars) { - calculateRects(rootLayer, region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect); + calculateRects(rootLayer, region, (localPaintFlags & PaintLayerTemporaryClipRects) ? TemporaryClipRects : PaintingClipRects, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, + IgnoreOverlayScrollbarSize, localPaintFlags & PaintLayerPaintingOverflowContents ? IgnoreOverflowClip : RespectOverflowClip); paintOffset = toPoint(layerBounds.location() - renderBoxLocation() + subPixelAccumulation); } @@ -3144,7 +3174,8 @@ void RenderLayer::paintLayerContents(RenderLayer* rootLayer, GraphicsContext* co performOverlapTests(*overlapTestRequests, rootLayer, this); // We want to paint our layer, but only if we intersect the damage rect. - shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); + if (this != rootLayer || !(localPaintFlags & PaintLayerPaintingOverflowContents)) + shouldPaintContent &= intersectsDamageRect(layerBounds, damageRect.rect(), rootLayer); if (localPaintFlags & PaintLayerPaintingCompositingBackgroundPhase) { if (shouldPaintContent && !selectionOnly) { @@ -3411,10 +3442,10 @@ static inline LayoutRect frameVisibleRect(RenderObject* renderer) bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result) { - return hitTest(request, result.hitTestPoint(), result); + return hitTest(request, result.hitTestLocation(), result); } -bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestPoint& hitTestPoint, HitTestResult& result) +bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestLocation& hitTestLocation, HitTestResult& result) { renderer()->document()->updateLayout(); @@ -3422,12 +3453,12 @@ bool RenderLayer::hitTest(const HitTestRequest& request, const HitTestPoint& hit if (!request.ignoreClipping()) hitTestArea.intersect(frameVisibleRect(renderer())); - RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestPoint, false); + RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, hitTestArea, hitTestLocation, false); if (!insideLayer) { // We didn't hit any layer. If we are the root layer and the mouse is -- or just was -- down, // return ourselves. We do this so mouse events continue getting delivered after a drag has // exited the WebView, and so hit testing over a scrollbar hits the content document. - if ((request.active() || request.release()) && isRootLayer()) { + if (!request.isChildFrameHitTest() && (request.active() || request.release()) && isRootLayer()) { renderer()->updateHitTestResult(result, toRenderView(renderer())->flipForWritingMode(result.point())); insideLayer = this; } @@ -3474,7 +3505,7 @@ static double computeZOffset(const HitTestingTransformState& transformState) } PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, - const LayoutRect& hitTestRect, const HitTestPoint& hitTestPoint, + const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* containerTransformState) const { RefPtr<HitTestingTransformState> transformState; @@ -3484,9 +3515,9 @@ PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(Rend transformState = HitTestingTransformState::create(*containerTransformState); convertToLayerCoords(containerLayer, offset); } else { - // If this is the first time we need to make transform state, then base it off of hitTestPoint, + // If this is the first time we need to make transform state, then base it off of hitTestLocation, // which is relative to rootLayer. - transformState = HitTestingTransformState::create(hitTestPoint.transformedPoint(), hitTestPoint.transformedRect(), FloatQuad(hitTestRect)); + transformState = HitTestingTransformState::create(hitTestLocation.transformedPoint(), hitTestLocation.transformedRect(), FloatQuad(hitTestRect)); convertToLayerCoords(rootLayer, offset); } @@ -3527,16 +3558,16 @@ static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, doubl return true; } -// hitTestPoint and hitTestRect are relative to rootLayer. +// hitTestLocation and hitTestRect are relative to rootLayer. // A 'flattening' layer is one preserves3D() == false. // transformState.m_accumulatedTransform holds the transform from the containing flattening layer. -// transformState.m_lastPlanarPoint is the hitTestPoint in the plane of the containing flattening layer. +// transformState.m_lastPlanarPoint is the hitTestLocation in the plane of the containing flattening layer. // transformState.m_lastPlanarQuad is the hitTestRect as a quad in the plane of the containing flattening layer. // // If zOffset is non-null (which indicates that the caller wants z offset information), // *zOffset on return is the z offset of the hit point relative to the containing flattening layer. RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint& hitTestPoint, bool appliedTransform, + const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, bool appliedTransform, const HitTestingTransformState* transformState, double* zOffset) { // The natural thing would be to keep HitTestingTransformState on the stack, but it's big, so we heap-allocate. @@ -3547,14 +3578,14 @@ 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, hitTestPoint.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, IncludeOverlayScrollbarSize); + ClipRect clipRect = backgroundClipRect(rootLayer, hitTestLocation.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, IncludeOverlayScrollbarSize); // Go ahead and test the enclosing clip now. - if (!clipRect.intersects(hitTestPoint)) + if (!clipRect.intersects(hitTestLocation)) return 0; } // Create a transform state to accumulate this transform. - RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); + RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState); // If the transform can't be inverted, then don't hit test this layer at all. if (!newTransformState->m_accumulatedTransform.isInvertible()) @@ -3564,19 +3595,19 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont // from the transformState, which store the point and quad in the coords of the last flattened // layer, and the accumulated transform which lets up map through preserve-3d layers. // - // We can't just map hitTestPoint and hitTestRect because they may have been flattened (losing z) + // We can't just map hitTestLocation and hitTestRect because they may have been flattened (losing z) // by our container. FloatPoint localPoint = newTransformState->mappedPoint(); FloatQuad localPointQuad = newTransformState->mappedQuad(); LayoutRect localHitTestRect = newTransformState->boundsOfMappedArea(); - HitTestPoint newHitTestPoint; - if (hitTestPoint.isRectBasedTest()) - newHitTestPoint = HitTestPoint(localPoint, localPointQuad); + HitTestLocation newHitTestLocation; + if (hitTestLocation.isRectBasedTest()) + newHitTestLocation = HitTestLocation(localPoint, localPointQuad); else - newHitTestPoint = HitTestPoint(localPoint); + newHitTestLocation = HitTestLocation(localPoint); // Now do a hit test with the root layer shifted to be us. - return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestPoint, true, newTransformState.get(), zOffset); + return hitTestLayer(this, containerLayer, request, result, localHitTestRect, newHitTestLocation, true, newTransformState.get(), zOffset); } // Ensure our lists and 3d status are up-to-date. @@ -3590,7 +3621,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont localTransformState = const_cast<HitTestingTransformState*>(transformState); } else if (transformState || m_has3DTransformedDescendant || preserves3D()) { // We need transform state for the first time, or to offset the container state, so create it here. - localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState); + localTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestLocation, transformState); } // Check for hit test on backface if backface-visibility is 'hidden' @@ -3614,7 +3645,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont ClipRect bgRect; ClipRect fgRect; ClipRect outlineRect; - calculateRects(rootLayer, hitTestPoint.region(), useTemporaryClipRects ? TemporaryClipRects : RootRelativeClipRects, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, IncludeOverlayScrollbarSize); + calculateRects(rootLayer, hitTestLocation.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. @@ -3643,7 +3674,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont RenderLayer* candidateLayer = 0; // Begin by walking our list of positive layers from highest z-index down to the lowest z-index. - RenderLayer* hitLayer = hitTestList(posZOrderList(), rootLayer, request, result, hitTestRect, hitTestPoint, + RenderLayer* hitLayer = hitTestList(posZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation, localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); if (hitLayer) { if (!depthSortDescendants) @@ -3652,7 +3683,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Now check our overflow objects. - hitLayer = hitTestList(m_normalFlowList, rootLayer, request, result, hitTestRect, hitTestPoint, + hitLayer = hitTestList(m_normalFlowList, rootLayer, request, result, hitTestRect, hitTestLocation, localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); if (hitLayer) { if (!depthSortDescendants) @@ -3661,11 +3692,11 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Next we want to see if the mouse pos is inside the child RenderObjects of the layer. - if (fgRect.intersects(hitTestPoint) && isSelfPaintingLayer()) { + if (fgRect.intersects(hitTestLocation) && isSelfPaintingLayer()) { // Hit test with a temporary HitTestResult, because we only want to commit to 'result' if we know we're frontmost. - HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); - if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) && - isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { + HitTestResult tempResult(result.hitTestLocation()); + if (hitTestContents(request, tempResult, layerBounds, hitTestLocation, HitTestDescendants) + && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) result.append(tempResult); else @@ -3679,7 +3710,7 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont } // Now check our negative z-index children. - hitLayer = hitTestList(negZOrderList(), rootLayer, request, result, hitTestRect, hitTestPoint, + hitLayer = hitTestList(negZOrderList(), rootLayer, request, result, hitTestRect, hitTestLocation, localTransformState.get(), zOffsetForDescendantsPtr, zOffset, unflattenedTransformState.get(), depthSortDescendants); if (hitLayer) { if (!depthSortDescendants) @@ -3691,25 +3722,26 @@ RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, RenderLayer* cont if (candidateLayer) return candidateLayer; - if (bgRect.intersects(hitTestPoint) && isSelfPaintingLayer()) { - HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); - if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) && - isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { + if (bgRect.intersects(hitTestLocation) && isSelfPaintingLayer()) { + HitTestResult tempResult(result.hitTestLocation()); + if (hitTestContents(request, tempResult, layerBounds, hitTestLocation, HitTestSelf) + && isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) { if (result.isRectBasedTest()) result.append(tempResult); else result = tempResult; return this; - } else if (result.isRectBasedTest()) + } + if (result.isRectBasedTest()) result.append(tempResult); } return 0; } -bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestPoint& hitTestPoint, HitTestFilter hitTestFilter) const +bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const LayoutRect& layerBounds, const HitTestLocation& hitTestLocation, HitTestFilter hitTestFilter) const { - if (!renderer()->hitTest(request, result, hitTestPoint, + if (!renderer()->hitTest(request, result, hitTestLocation, toLayoutPoint(layerBounds.location() - renderBoxLocation()), hitTestFilter)) { // It's wrong to set innerNode, but then claim that you didn't hit anything, unless it is @@ -3735,7 +3767,7 @@ bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint& hitTestPoint, + const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffsetForDescendants, double* zOffset, const HitTestingTransformState* unflattenedTransformState, @@ -3748,11 +3780,11 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r for (int i = list->size() - 1; i >= 0; --i) { RenderLayer* childLayer = list->at(i); RenderLayer* hitLayer = 0; - HitTestResult tempResult(result.hitTestPoint(), result.shadowContentFilterPolicy()); + HitTestResult tempResult(result.hitTestLocation()); if (childLayer->isPaginated()) - hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestPoint, transformState, zOffsetForDescendants); + hitLayer = hitTestPaginatedChildLayer(childLayer, rootLayer, request, tempResult, hitTestRect, hitTestLocation, transformState, zOffsetForDescendants); else - hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, transformState, zOffsetForDescendants); + hitLayer = childLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestLocation, false, transformState, zOffsetForDescendants); // If it a rect-based test, we can safely append the temporary result since it might had hit // nodes but not necesserily had hitLayer set. @@ -3772,7 +3804,7 @@ RenderLayer* RenderLayer::hitTestList(Vector<RenderLayer*>* list, RenderLayer* r } RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset) + const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset) { Vector<RenderLayer*> columnLayers; RenderLayer* ancestorLayer = isNormalFlowOnly() ? parent() : stackingContext(); @@ -3784,12 +3816,12 @@ RenderLayer* RenderLayer::hitTestPaginatedChildLayer(RenderLayer* childLayer, Re } ASSERT(columnLayers.size()); - return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestPoint, transformState, zOffset, + return hitTestChildLayerColumns(childLayer, rootLayer, request, result, hitTestRect, hitTestLocation, transformState, zOffset, columnLayers, columnLayers.size() - 1); } RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint& hitTestPoint, const HitTestingTransformState* transformState, double* zOffset, + const LayoutRect& hitTestRect, const HitTestLocation& hitTestLocation, const HitTestingTransformState* transformState, double* zOffset, const Vector<RenderLayer*>& columnLayers, size_t columnIndex) { RenderBlock* columnBlock = toRenderBlock(columnLayers[columnIndex]->renderer()); @@ -3846,7 +3878,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend LayoutRect localClipRect(hitTestRect); localClipRect.intersect(colRect); - if (!localClipRect.isEmpty() && hitTestPoint.intersects(localClipRect)) { + if (!localClipRect.isEmpty() && hitTestLocation.intersects(localClipRect)) { RenderLayer* hitLayer = 0; if (!columnIndex) { // Apply a translation transform to change where the layer paints. @@ -3858,7 +3890,7 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend newTransform.translateRight(offset.width(), offset.height()); childLayer->m_transform = adoptPtr(new TransformationMatrix(newTransform)); - hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestPoint, false, transformState, zOffset); + hitLayer = childLayer->hitTestLayer(rootLayer, columnLayers[0], request, result, localClipRect, hitTestLocation, false, transformState, zOffset); if (oldHasTransform) childLayer->m_transform = adoptPtr(new TransformationMatrix(oldTransform)); else @@ -3867,19 +3899,19 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend // Adjust the transform such that the renderer's upper left corner will be at (0,0) in user space. // This involves subtracting out the position of the layer in our current coordinate space. RenderLayer* nextLayer = columnLayers[columnIndex - 1]; - RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestPoint, transformState); + RefPtr<HitTestingTransformState> newTransformState = nextLayer->createLocalTransformState(rootLayer, nextLayer, localClipRect, hitTestLocation, transformState); newTransformState->translate(offset.width(), offset.height(), HitTestingTransformState::AccumulateTransform); FloatPoint localPoint = newTransformState->mappedPoint(); FloatQuad localPointQuad = newTransformState->mappedQuad(); LayoutRect localHitTestRect = newTransformState->mappedArea().enclosingBoundingBox(); - HitTestPoint newHitTestPoint; - if (hitTestPoint.isRectBasedTest()) - newHitTestPoint = HitTestPoint(localPoint, localPointQuad); + HitTestLocation newHitTestLocation; + if (hitTestLocation.isRectBasedTest()) + newHitTestLocation = HitTestLocation(localPoint, localPointQuad); else - newHitTestPoint = HitTestPoint(localPoint); + newHitTestLocation = HitTestLocation(localPoint); newTransformState->flatten(); - hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestPoint, + hitLayer = hitTestChildLayerColumns(childLayer, columnLayers[columnIndex - 1], request, result, localHitTestRect, newHitTestLocation, newTransformState.get(), zOffset, columnLayers, columnIndex - 1); } @@ -3891,11 +3923,12 @@ RenderLayer* RenderLayer::hitTestChildLayerColumns(RenderLayer* childLayer, Rend return 0; } -void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy) +void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) { ASSERT(clipRectsType < NumCachedClipRectsTypes); if (m_clipRectsCache && m_clipRectsCache->m_clipRects[clipRectsType]) { ASSERT(rootLayer == m_clipRectsCache->m_clipRectsRoot[clipRectsType]); + ASSERT(m_clipRectsCache->m_respectingOverflowClip[clipRectsType] == (respectOverflowClip == RespectOverflowClip)); return; // We have the correct cached value. } @@ -3903,10 +3936,10 @@ 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, clipRectsType, relevancy); + parentLayer->updateClipRects(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); ClipRects clipRects; - calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy); + calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy, respectOverflowClip); if (!m_clipRectsCache) m_clipRectsCache = adoptPtr(new ClipRectsCache); @@ -3918,10 +3951,11 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer, RenderRegion* re #ifndef NDEBUG m_clipRectsCache->m_clipRectsRoot[clipRectsType] = rootLayer; + m_clipRectsCache->m_respectingOverflowClip[clipRectsType] = respectOverflowClip == RespectOverflowClip; #endif } -void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const +void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const { if (!parent()) { // The root layer's clip rect is always infinite. @@ -3940,7 +3974,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* if (useCached && parentLayer->clipRects(clipRectsType)) clipRects = *parentLayer->clipRects(clipRectsType); else - parentLayer->calculateClipRects(rootLayer, region, clipRectsType, clipRects); + parentLayer->calculateClipRects(rootLayer, region, clipRectsType, clipRects, IgnoreOverlayScrollbarSize, respectOverflowClip); } else clipRects.reset(PaintInfo::infiniteRect()); @@ -3956,7 +3990,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* clipRects.setOverflowClipRect(clipRects.posClipRect()); // Update the clip rects that will be passed to child layers. - if (renderer()->hasClipOrOverflowClip()) { + if ((renderer()->hasOverflowClip() && (respectOverflowClip == RespectOverflowClip || this != rootLayer)) || renderer()->hasClip()) { // This layer establishes a clip of some kind. // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across @@ -3975,7 +4009,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* if (renderer()->style()->hasBorderRadius()) newOverflowClip.setHasRadius(true); clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); - if (renderer()->isOutOfFlowPositioned() || renderer()->isInFlowPositioned()) + if (renderer()->isPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); } if (renderer()->hasClip()) { @@ -3987,15 +4021,15 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, RenderRegion* } } -void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy) const +void RenderLayer::parentClipRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, ClipRects& clipRects, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const { ASSERT(parent()); if (clipRectsType == TemporaryClipRects) { - parent()->calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy); + parent()->calculateClipRects(rootLayer, region, clipRectsType, clipRects, relevancy, respectOverflowClip); return; } - parent()->updateClipRects(rootLayer, region, clipRectsType, relevancy); + parent()->updateClipRects(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); clipRects = *parent()->clipRects(clipRectsType); } @@ -4010,11 +4044,11 @@ static inline ClipRect backgroundClipRectForPosition(const ClipRects& parentRect return parentRects.overflowClipRect(); } -ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy) const +ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const { ASSERT(parent()); ClipRects parentRects; - parentClipRects(rootLayer, region, clipRectsType, parentRects, relevancy); + parentClipRects(rootLayer, region, clipRectsType, parentRects, relevancy, respectOverflowClip); ClipRect backgroundClipRect = backgroundClipRectForPosition(parentRects, renderer()->style()->position()); RenderView* view = renderer()->view(); ASSERT(view); @@ -4027,10 +4061,10 @@ ClipRect RenderLayer::backgroundClipRect(const RenderLayer* rootLayer, RenderReg } void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* region, ClipRectsType clipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, - ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, OverlayScrollbarSizeRelevancy relevancy) const + ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, OverlayScrollbarSizeRelevancy relevancy, ShouldRespectOverflowClip respectOverflowClip) const { if (rootLayer != this && parent()) { - backgroundRect = backgroundClipRect(rootLayer, region, clipRectsType, relevancy); + backgroundRect = backgroundClipRect(rootLayer, region, clipRectsType, relevancy, respectOverflowClip); backgroundRect.intersect(paintDirtyRect); } else backgroundRect = paintDirtyRect; @@ -4045,7 +4079,7 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* reg // Update the clip rects that will be passed to child layers. if (renderer()->hasClipOrOverflowClip()) { // This layer establishes a clip of some kind. - if (renderer()->hasOverflowClip()) { + if (renderer()->hasOverflowClip() && (this != rootLayer || respectOverflowClip == RespectOverflowClip)) { foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(offset, region, relevancy)); if (renderer()->style()->hasBorderRadius()) foregroundRect.setHasRadius(true); @@ -4068,12 +4102,14 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, RenderRegion* reg LayoutRect layerBoundsWithVisualOverflow = renderBox()->visualOverflowRect(); renderBox()->flipForWritingMode(layerBoundsWithVisualOverflow); // Layers are in physical coordinates, so the overflow has to be flipped. layerBoundsWithVisualOverflow.moveBy(offset); - backgroundRect.intersect(layerBoundsWithVisualOverflow); + if (this != rootLayer || respectOverflowClip == RespectOverflowClip) + backgroundRect.intersect(layerBoundsWithVisualOverflow); } else { // Shift the bounds to be for our region only. LayoutRect bounds = renderBox()->borderBoxRectInRegion(region); bounds.moveBy(offset); - backgroundRect.intersect(bounds); + if (this != rootLayer || respectOverflowClip == RespectOverflowClip) + backgroundRect.intersect(bounds); } } } @@ -4086,7 +4122,8 @@ LayoutRect RenderLayer::childrenClipRect() const RenderLayer* clippingRootLayer = clippingRootForPainting(); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect, outlineRect; - calculateRects(clippingRootLayer, 0, PaintingClipRects, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); + // Need to use temporary clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>). + calculateRects(clippingRootLayer, 0, TemporaryClipRects, renderView->unscaledDocumentRect(), layerBounds, backgroundRect, foregroundRect, outlineRect); return clippingRootLayer->renderer()->localToAbsoluteQuad(FloatQuad(foregroundRect.rect())).enclosingBoundingBox(); } @@ -4396,6 +4433,9 @@ RenderLayerBacking* RenderLayer::ensureBacking() #if ENABLE(CSS_FILTERS) updateOrRemoveFilterEffect(); #endif +#if ENABLE(CSS_COMPOSITING) + backing()->setBlendMode(m_blendMode); +#endif } return m_backing.get(); } @@ -4777,19 +4817,24 @@ bool RenderLayer::shouldBeNormalFlowOnly() const || renderer()->isEmbeddedObject() || renderer()->isRenderIFrame() || (renderer()->style()->specifiesColumns() && !isRootLayer())) - && !renderer()->isOutOfFlowPositioned() - && !renderer()->isInFlowPositioned() + && !renderer()->isPositioned() && !renderer()->hasTransform() + && !renderer()->hasClipPath() #if ENABLE(CSS_FILTERS) && !renderer()->hasFilter() #endif - && !isTransparent(); +#if ENABLE(CSS_COMPOSITING) + && !renderer()->hasBlendMode() +#endif + && !isTransparent() + && !usesCompositedScrolling(); } bool RenderLayer::shouldBeSelfPaintingLayer() const { return !isNormalFlowOnly() || hasOverlayScrollbars() + || usesCompositedScrolling() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow() @@ -4935,6 +4980,9 @@ void RenderLayer::styleChanged(StyleDifference, const RenderStyle* oldStyle) updateDescendantDependentFlags(); updateTransform(); +#if ENABLE(CSS_COMPOSITING) + updateBlendMode(); +#endif #if USE(ACCELERATED_COMPOSITING) if (compositor()->updateLayerCompositingState(this)) diff --git a/Source/WebCore/rendering/RenderLayer.h b/Source/WebCore/rendering/RenderLayer.h index e4f790e05..32d41e3ba 100644 --- a/Source/WebCore/rendering/RenderLayer.h +++ b/Source/WebCore/rendering/RenderLayer.h @@ -115,7 +115,7 @@ public: bool isEmpty() const { return m_rect.isEmpty(); } bool intersects(const LayoutRect& rect) { return m_rect.intersects(rect); } - bool intersects(const HitTestPoint&); + bool intersects(const HitTestLocation&); private: LayoutRect m_rect; @@ -230,14 +230,17 @@ struct ClipRectsCache { ClipRectsCache() { #ifndef NDEBUG - for (int i = 0; i < NumCachedClipRectsTypes; ++i) + for (int i = 0; i < NumCachedClipRectsTypes; ++i) { m_clipRectsRoot[i] = 0; + m_respectingOverflowClip[i] = false; + } #endif } RefPtr<ClipRects> m_clipRects[NumCachedClipRectsTypes]; #ifndef NDEBUG const RenderLayer* m_clipRectsRoot[NumCachedClipRectsTypes]; + bool m_respectingOverflowClip[NumCachedClipRectsTypes]; #endif }; @@ -504,6 +507,7 @@ public: PaintLayerPaintingCompositingBackgroundPhase = 1 << 5, PaintLayerPaintingCompositingForegroundPhase = 1 << 6, PaintLayerPaintingCompositingMaskPhase = 1 << 7, + PaintLayerPaintingOverflowContents = 1 << 8, PaintLayerPaintingCompositingAllPhases = (PaintLayerPaintingCompositingBackgroundPhase | PaintLayerPaintingCompositingForegroundPhase | PaintLayerPaintingCompositingMaskPhase) }; @@ -516,21 +520,23 @@ public: void paint(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior = PaintBehaviorNormal, RenderObject* paintingRoot = 0, RenderRegion* = 0, PaintLayerFlags = 0); bool hitTest(const HitTestRequest&, HitTestResult&); - bool hitTest(const HitTestRequest&, const HitTestPoint&, HitTestResult&); + bool hitTest(const HitTestRequest&, const HitTestLocation&, HitTestResult&); void paintOverlayScrollbars(GraphicsContext*, const LayoutRect& damageRect, PaintBehavior, RenderObject* paintingRoot); + enum ShouldRespectOverflowClip { IgnoreOverflowClip, RespectOverflowClip }; + // 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*, ClipRectsType, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds, ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, - OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; // Compute and cache clip rects computed with the given layer as the root - void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize); + void updateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip); // 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*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + void calculateClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; ClipRects* clipRects(ClipRectsType type) const { ASSERT(type < NumCachedClipRectsTypes); return m_clipRectsCache ? m_clipRectsCache->m_clipRects[type].get() : 0; } @@ -568,7 +574,7 @@ public: enum UpdateLayerPositionsAfterScrollFlag { NoFlag = 0, - HasSeenFixedPositionedAncestor = 1 << 0, + HasSeenViewportConstrainedAncestor = 1 << 0, HasSeenAncestorWithOverflowClip = 1 << 1 }; @@ -606,6 +612,12 @@ public: bool hasFilter() const { return false; } #endif +#if ENABLE(CSS_COMPOSITING) + bool hasBlendMode() const { return renderer()->hasBlendMode(); } +#else + bool hasBlendMode() const { return false; } +#endif + // Overloaded new operator. Derived classes must override operator new // in order to allocate out of the RenderArena. void* operator new(size_t, RenderArena*); @@ -622,9 +634,11 @@ public: virtual GraphicsLayer* layerForHorizontalScrollbar() const; virtual GraphicsLayer* layerForVerticalScrollbar() const; virtual GraphicsLayer* layerForScrollCorner() const; + virtual bool usesCompositedScrolling() const OVERRIDE; #else bool isComposited() const { return false; } bool hasCompositedMask() const { return false; } + bool usesCompositedScrolling() const { return false; } #endif bool paintsWithTransparency(PaintBehavior paintBehavior) const @@ -663,6 +677,8 @@ public: void setLayerListMutationAllowed(bool flag) { m_layerListMutationAllowed = flag; } #endif + Node* enclosingElement() const; + private: void updateZOrderLists(); void rebuildZOrderLists(); @@ -737,25 +753,25 @@ private: PaintLayerFlags, const Vector<RenderLayer*>& columnLayers, size_t columnIndex); RenderLayer* hitTestLayer(RenderLayer* rootLayer, RenderLayer* containerLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint&, bool appliedTransform, + const LayoutRect& hitTestRect, const HitTestLocation&, bool appliedTransform, const HitTestingTransformState* transformState = 0, double* zOffset = 0); RenderLayer* hitTestList(Vector<RenderLayer*>*, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint&, + const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* transformState, double* zOffsetForDescendants, double* zOffset, const HitTestingTransformState* unflattenedTransformState, bool depthSortDescendants); RenderLayer* hitTestPaginatedChildLayer(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint&, + const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* transformState, double* zOffset); RenderLayer* hitTestChildLayerColumns(RenderLayer* childLayer, RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result, - const LayoutRect& hitTestRect, const HitTestPoint&, + const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* transformState, double* zOffset, const Vector<RenderLayer*>& columnLayers, size_t columnIndex); PassRefPtr<HitTestingTransformState> createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer, - const LayoutRect& hitTestRect, const HitTestPoint&, + const LayoutRect& hitTestRect, const HitTestLocation&, const HitTestingTransformState* containerTransformState) const; - bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const HitTestPoint&, HitTestFilter) const; + bool hitTestContents(const HitTestRequest&, HitTestResult&, const LayoutRect& layerBounds, const HitTestLocation&, HitTestFilter) const; void computeScrollDimensions(); bool hasHorizontalOverflow() const; @@ -816,8 +832,6 @@ private: // Both updates the status, and returns true if descendants of this have 3d. bool update3DTransformedDescendantStatus(); - Node* enclosingElement() const; - void createReflection(); void removeReflection(); @@ -829,8 +843,8 @@ private: void updateOrRemoveFilterEffect(); #endif - void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; - ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize) const; + void parentClipRects(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, ClipRects&, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; + ClipRect backgroundClipRect(const RenderLayer* rootLayer, RenderRegion*, ClipRectsType, OverlayScrollbarSizeRelevancy = IgnoreOverlayScrollbarSize, ShouldRespectOverflowClip = RespectOverflowClip) const; LayoutRect paintingExtent(const RenderLayer* rootLayer, const LayoutRect& paintDirtyRect, PaintBehavior); RenderLayer* enclosingTransformedAncestor() const; diff --git a/Source/WebCore/rendering/RenderLayerBacking.cpp b/Source/WebCore/rendering/RenderLayerBacking.cpp index 6641bbc56..26cd50f50 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.cpp +++ b/Source/WebCore/rendering/RenderLayerBacking.cpp @@ -55,8 +55,8 @@ #include "Settings.h" #include "StyleResolver.h" #include "TiledBacking.h" - #include <wtf/CurrentTime.h> +#include <wtf/text/StringBuilder.h> #if ENABLE(CSS_FILTERS) #include "FilterEffectRenderer.h" @@ -138,6 +138,7 @@ RenderLayerBacking::~RenderLayerBacking() updateOverflowControlsLayers(false, false, false); updateForegroundLayer(false); updateMaskLayer(false); + updateScrollingLayers(false); destroyGraphicsLayers(); } @@ -218,6 +219,9 @@ void RenderLayerBacking::destroyGraphicsLayers() m_foregroundLayer = nullptr; m_containmentLayer = nullptr; m_maskLayer = nullptr; + + m_scrollingLayer = nullptr; + m_scrollingContentsLayer = nullptr; } void RenderLayerBacking::updateLayerOpacity(const RenderStyle* style) @@ -258,10 +262,10 @@ static bool hasNonZeroTransformOrigin(const RenderObject* renderer) || (style->transformOriginY().type() == Fixed && style->transformOriginY().value()); } -static bool layerOrAncestorIsTransformed(RenderLayer* layer) +static bool layerOrAncestorIsTransformedOrUsingCompositedScrolling(RenderLayer* layer) { for (RenderLayer* curr = layer; curr; curr = curr->parent()) { - if (curr->hasTransform()) + if (curr->hasTransform() || curr->usesCompositedScrolling()) return true; } @@ -280,7 +284,7 @@ bool RenderLayerBacking::shouldClipCompositedBounds() const if (!compositor()->compositingConsultsOverlap()) return false; - if (layerOrAncestorIsTransformed(m_owningLayer)) + if (layerOrAncestorIsTransformedOrUsingCompositedScrolling(m_owningLayer)) return false; return true; @@ -366,12 +370,21 @@ bool RenderLayerBacking::updateGraphicsLayerConfiguration() if (updateForegroundLayer(compositor->needsContentsCompositingLayer(m_owningLayer))) layerConfigChanged = true; - if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), compositor->clipsCompositingDescendants(m_owningLayer))) + bool needsDescendentsClippingLayer = compositor->clipsCompositingDescendants(m_owningLayer); + + // Our scrolling layer will clip. + if (m_owningLayer->usesCompositedScrolling()) + needsDescendentsClippingLayer = false; + + if (updateClippingLayers(compositor->clippedByAncestor(m_owningLayer), needsDescendentsClippingLayer)) layerConfigChanged = true; if (updateOverflowControlsLayers(requiresHorizontalScrollbarLayer(), requiresVerticalScrollbarLayer(), requiresScrollCornerLayer())) layerConfigChanged = true; + if (updateScrollingLayers(m_owningLayer->usesCompositedScrolling())) + layerConfigChanged = true; + if (layerConfigChanged) updateInternalHierarchy(); @@ -520,12 +533,19 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() graphicsLayerParentLocation = ancestorCompositingBounds.location(); else graphicsLayerParentLocation = renderer()->view()->documentRect().location(); + + if (compAncestor && compAncestor->usesCompositedScrolling()) { + RenderBox* renderBox = toRenderBox(compAncestor->renderer()); + IntSize scrollOffset = compAncestor->scrolledContentOffset(); + IntPoint scrollOrigin(renderBox->borderLeft(), renderBox->borderTop()); + graphicsLayerParentLocation = scrollOrigin - scrollOffset; + } if (compAncestor && m_ancestorClippingLayer) { // 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, TemporaryClipRects).rect()); // FIXME: Incorrect for CSS regions. + IntRect parentClipRect = pixelSnappedIntRect(m_owningLayer->backgroundClipRect(compAncestor, 0, TemporaryClipRects, IgnoreOverlayScrollbarSize, RenderLayer::IgnoreOverflowClip).rect()); // FIXME: Incorrect for CSS regions. ASSERT(parentClipRect != PaintInfo::infiniteRect()); m_ancestorClippingLayer->setPosition(FloatPoint() + (parentClipRect.location() - graphicsLayerParentLocation)); m_ancestorClippingLayer->setSize(parentClipRect.size()); @@ -633,6 +653,36 @@ void RenderLayerBacking::updateGraphicsLayerGeometry() reflectionBacking->graphicsLayer()->setReplicatedLayerPosition(FloatPoint() + (layerBounds.location() - reflectionLayerBounds.location())); } + if (m_scrollingLayer) { + ASSERT(m_scrollingContentsLayer); + RenderBox* renderBox = toRenderBox(renderer()); + IntRect paddingBox(renderBox->borderLeft(), renderBox->borderTop(), renderBox->width() - renderBox->borderLeft() - renderBox->borderRight(), renderBox->height() - renderBox->borderTop() - renderBox->borderBottom()); + IntSize scrollOffset = m_owningLayer->scrolledContentOffset(); + + m_scrollingLayer->setPosition(FloatPoint() + (paddingBox.location() - localCompositingBounds.location())); + + m_scrollingLayer->setSize(paddingBox.size()); + m_scrollingContentsLayer->setPosition(FloatPoint(-scrollOffset.width(), -scrollOffset.height())); + + IntSize oldScrollingLayerOffset = m_scrollingLayer->offsetFromRenderer(); + m_scrollingLayer->setOffsetFromRenderer(IntPoint() - paddingBox.location()); + + bool paddingBoxOffsetChanged = oldScrollingLayerOffset != m_scrollingLayer->offsetFromRenderer(); + + IntSize scrollSize(m_owningLayer->scrollWidth(), m_owningLayer->scrollHeight()); + if (scrollSize != m_scrollingContentsLayer->size() || paddingBoxOffsetChanged) + m_scrollingContentsLayer->setNeedsDisplay(); + + IntSize scrollingContentsOffset = paddingBox.location() - IntPoint() - scrollOffset; + if (scrollingContentsOffset != m_scrollingContentsLayer->offsetFromRenderer() || scrollSize != m_scrollingContentsLayer->size()) + compositor()->scrollingLayerDidChange(m_owningLayer); + + m_scrollingContentsLayer->setSize(scrollSize); + // FIXME: Scrolling the content layer does not need to trigger a repaint. The offset will be compensated away during painting. + // FIXME: The paint offset and the scroll offset should really be separate concepts. + m_scrollingContentsLayer->setOffsetFromRenderer(scrollingContentsOffset); + } + m_graphicsLayer->setContentsRect(contentsBox()); // If this layer was created just for clipping or to apply perspective, it doesn't need its own backing store. @@ -657,6 +707,12 @@ void RenderLayerBacking::updateInternalHierarchy() m_graphicsLayer->addChild(m_containmentLayer.get()); } + if (m_scrollingLayer) { + GraphicsLayer* superlayer = m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get(); + m_scrollingLayer->removeFromParent(); + superlayer->addChild(m_scrollingLayer.get()); + } + // The clip for child layers does not include space for overflow controls, so they exist as // siblings of the clipping layer if we have one. Normal children of this layer are set as // children of the clipping layer. @@ -676,6 +732,19 @@ void RenderLayerBacking::updateInternalHierarchy() void RenderLayerBacking::updateDrawsContent() { + if (m_scrollingLayer) { + // We don't have to consider overflow controls, because we know that the scrollbars are drawn elsewhere. + // m_graphicsLayer only needs backing store if the non-scrolling parts (background, outlines, borders, shadows etc) need to paint. + // m_scrollingLayer never has backing store. + // m_scrollingContentsLayer only needs backing store if the scrolled contents need to paint. + bool hasNonScrollingPaintedContent = m_owningLayer->hasVisibleContent() && hasBoxDecorationsOrBackground(renderer()); + m_graphicsLayer->setDrawsContent(hasNonScrollingPaintedContent); + + bool hasScrollingPaintedContent = m_owningLayer->hasVisibleContent() && (renderer()->hasBackground() || paintsChildren()); + m_scrollingContentsLayer->setDrawsContent(hasScrollingPaintedContent); + return; + } + bool hasPaintedContent = containsPaintedContent(); // FIXME: we could refine this to only allocate backing for one of these layers if possible. @@ -779,6 +848,35 @@ bool RenderLayerBacking::updateOverflowControlsLayers(bool needsHorizontalScroll return layersChanged; } +void RenderLayerBacking::positionOverflowControlsLayers(const IntSize& offsetFromRoot) +{ + IntSize offsetFromRenderer = m_graphicsLayer->offsetFromRenderer(); + if (GraphicsLayer* layer = layerForHorizontalScrollbar()) { + Scrollbar* hBar = m_owningLayer->horizontalScrollbar(); + if (hBar) { + layer->setPosition(hBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); + layer->setSize(hBar->frameRect().size()); + } + layer->setDrawsContent(hBar); + } + + if (GraphicsLayer* layer = layerForVerticalScrollbar()) { + Scrollbar* vBar = m_owningLayer->verticalScrollbar(); + if (vBar) { + layer->setPosition(vBar->frameRect().location() - offsetFromRoot - offsetFromRenderer); + layer->setSize(vBar->frameRect().size()); + } + layer->setDrawsContent(vBar); + } + + if (GraphicsLayer* layer = layerForScrollCorner()) { + const LayoutRect& scrollCornerAndResizer = m_owningLayer->scrollCornerAndResizerRect(); + layer->setPosition(scrollCornerAndResizer.location() - offsetFromRenderer); + layer->setSize(scrollCornerAndResizer.size()); + layer->setDrawsContent(!scrollCornerAndResizer.isEmpty()); + } +} + bool RenderLayerBacking::updateForegroundLayer(bool needsForegroundLayer) { bool layerChanged = false; @@ -826,6 +924,41 @@ bool RenderLayerBacking::updateMaskLayer(bool needsMaskLayer) return layerChanged; } +bool RenderLayerBacking::updateScrollingLayers(bool needsScrollingLayers) +{ + bool layerChanged = false; + if (needsScrollingLayers) { + if (!m_scrollingLayer) { + // Outer layer which corresponds with the scroll view. + m_scrollingLayer = createGraphicsLayer("Scrolling container"); + m_scrollingLayer->setDrawsContent(false); + m_scrollingLayer->setMasksToBounds(true); + + // Inner layer which renders the content that scrolls. + m_scrollingContentsLayer = createGraphicsLayer("Scrolled Contents"); + m_scrollingContentsLayer->setDrawsContent(true); + m_scrollingContentsLayer->setPaintingPhase(GraphicsLayerPaintForeground | GraphicsLayerPaintOverflowContents); + m_scrollingLayer->addChild(m_scrollingContentsLayer.get()); + + layerChanged = true; + } + } else if (m_scrollingLayer) { + m_scrollingLayer = nullptr; + m_scrollingContentsLayer = nullptr; + layerChanged = true; + } + + if (layerChanged) { + updateInternalHierarchy(); + m_graphicsLayer->setPaintingPhase(paintingPhaseForPrimaryLayer()); + m_graphicsLayer->setNeedsDisplay(); + if (renderer()->view()) + compositor()->scrollingLayerDidChange(m_owningLayer); + } + + return layerChanged; +} + GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() const { unsigned phase = GraphicsLayerPaintBackground; @@ -834,6 +967,9 @@ GraphicsLayerPaintingPhase RenderLayerBacking::paintingPhaseForPrimaryLayer() co if (!m_maskLayer) phase |= GraphicsLayerPaintMask; + if (m_scrollingContentsLayer) + phase &= ~GraphicsLayerPaintForeground; + return static_cast<GraphicsLayerPaintingPhase>(phase); } @@ -1166,6 +1302,14 @@ IntRect RenderLayerBacking::contentsBox() const return contentsRect; } +GraphicsLayer* RenderLayerBacking::parentForSublayers() const +{ + if (m_scrollingContentsLayer) + return m_scrollingContentsLayer.get(); + + return m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get(); +} + bool RenderLayerBacking::paintsIntoWindow() const { if (m_usingTiledCacheLayer) @@ -1214,6 +1358,9 @@ void RenderLayerBacking::setContentsNeedDisplay() if (m_maskLayer && m_maskLayer->drawsContent()) m_maskLayer->setNeedsDisplay(); + + if (m_scrollingContentsLayer && m_scrollingContentsLayer->drawsContent()) + m_scrollingContentsLayer->setNeedsDisplay(); } // r is in the coordinate space of the layer's render object @@ -1238,6 +1385,12 @@ void RenderLayerBacking::setContentsNeedDisplayInRect(const IntRect& r) layerDirtyRect.move(-m_maskLayer->offsetFromRenderer()); m_maskLayer->setNeedsDisplayInRect(layerDirtyRect); } + + if (m_scrollingContentsLayer && m_scrollingContentsLayer->drawsContent()) { + IntRect layerDirtyRect = r; + layerDirtyRect.move(-m_scrollingContentsLayer->offsetFromRenderer()); + m_scrollingContentsLayer->setNeedsDisplayInRect(layerDirtyRect); + } } void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* context, @@ -1259,7 +1412,9 @@ void RenderLayerBacking::paintIntoLayer(RenderLayer* rootLayer, GraphicsContext* paintFlags |= RenderLayer::PaintLayerPaintingCompositingForegroundPhase; if (paintingPhase & GraphicsLayerPaintMask) paintFlags |= RenderLayer::PaintLayerPaintingCompositingMaskPhase; - + if (paintingPhase & GraphicsLayerPaintOverflowContents) + paintFlags |= RenderLayer::PaintLayerPaintingOverflowContents; + // FIXME: GraphicsLayers need a way to split for RenderRegions. m_owningLayer->paintLayerContents(rootLayer, context, paintDirtyRect, LayoutSize(), paintBehavior, paintingRoot, 0, 0, paintFlags); @@ -1290,12 +1445,14 @@ void RenderLayerBacking::paintContents(const GraphicsLayer* graphicsLayer, Graph if (Page* page = renderer()->frame()->page()) page->setIsPainting(true); #endif - if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get()) { + + if (graphicsLayer == m_graphicsLayer.get() || graphicsLayer == m_foregroundLayer.get() || graphicsLayer == m_maskLayer.get() || graphicsLayer == m_scrollingContentsLayer.get()) { InspectorInstrumentationCookie cookie = InspectorInstrumentation::willPaint(m_owningLayer->renderer()->frame(), &context, clip); // The dirtyRect is in the coords of the painting root. - IntRect dirtyRect = compositedBounds(); - dirtyRect.intersect(clip); + IntRect dirtyRect = clip; + if (!(paintingPhase & GraphicsLayerPaintOverflowContents)) + dirtyRect.intersect(compositedBounds()); // We have to use the same root as for hit testing, because both methods can compute and cache clipRects. paintIntoLayer(m_owningLayer, &context, dirtyRect, PaintBehaviorNormal, paintingPhase, renderer()); @@ -1590,29 +1747,35 @@ AnimatedPropertyID RenderLayerBacking::cssToGraphicsLayerProperty(CSSPropertyID String RenderLayerBacking::nameForLayer() const { - String name = renderer()->renderName(); + StringBuilder name; + name.append(renderer()->renderName()); if (Node* node = renderer()->node()) { - if (node->isElementNode()) - name += " " + static_cast<Element*>(node)->tagName(); - if (node->hasID()) - name += " id=\'" + static_cast<Element*>(node)->getIdAttribute() + "\'"; + if (node->isElementNode()) { + name.append(' '); + name.append(static_cast<Element*>(node)->tagName()); + } + if (node->hasID()) { + name.appendLiteral(" id=\'"); + name.append(static_cast<Element*>(node)->getIdAttribute()); + name.append('\''); + } if (node->hasClass()) { + name.appendLiteral(" class=\'"); StyledElement* styledElement = static_cast<StyledElement*>(node); - String classes; for (size_t i = 0; i < styledElement->classNames().size(); ++i) { if (i > 0) - classes += " "; - classes += styledElement->classNames()[i]; + name.append(' '); + name.append(styledElement->classNames()[i]); } - name += " class=\'" + classes + "\'"; + name.append('\''); } } if (m_owningLayer->isReflection()) - name += " (reflection)"; + name.appendLiteral(" (reflection)"); - return name; + return name.toString(); } CompositingLayerType RenderLayerBacking::compositingLayerType() const @@ -1637,6 +1800,9 @@ double RenderLayerBacking::backingStoreMemoryEstimate() const if (m_maskLayer) backingMemory += m_maskLayer->backingStoreMemoryEstimate(); + if (m_scrollingContentsLayer) + backingMemory += m_scrollingContentsLayer->backingStoreMemoryEstimate(); + if (m_layerForHorizontalScrollbar) backingMemory += m_layerForHorizontalScrollbar->backingStoreMemoryEstimate(); diff --git a/Source/WebCore/rendering/RenderLayerBacking.h b/Source/WebCore/rendering/RenderLayerBacking.h index f107dc279..0508b52bb 100644 --- a/Source/WebCore/rendering/RenderLayerBacking.h +++ b/Source/WebCore/rendering/RenderLayerBacking.h @@ -83,10 +83,14 @@ public: bool hasContentsLayer() const { return m_foregroundLayer != 0; } GraphicsLayer* foregroundLayer() const { return m_foregroundLayer.get(); } + + bool hasScrollingLayer() const { return m_scrollingLayer; } + GraphicsLayer* scrollingLayer() const { return m_scrollingLayer.get(); } + GraphicsLayer* scrollingContentsLayer() const { return m_scrollingContentsLayer.get(); } bool hasMaskLayer() const { return m_maskLayer != 0; } - GraphicsLayer* parentForSublayers() const { return m_containmentLayer ? m_containmentLayer.get() : m_graphicsLayer.get(); } + GraphicsLayer* parentForSublayers() const; GraphicsLayer* childForSuperlayers() const { return m_ancestorClippingLayer ? m_ancestorClippingLayer.get() : m_graphicsLayer.get(); } // RenderLayers with backing normally short-circuit paintLayer() because @@ -127,6 +131,7 @@ public: void updateCompositedBounds(); void updateAfterWidgetResize(); + void positionOverflowControlsLayers(const IntSize& offsetFromRoot); // GraphicsLayerClient interface virtual bool shouldUseTileCache(const GraphicsLayer*) const; @@ -186,6 +191,7 @@ private: bool requiresHorizontalScrollbarLayer() const; bool requiresVerticalScrollbarLayer() const; bool requiresScrollCornerLayer() const; + bool updateScrollingLayers(bool scrollingLayers); GraphicsLayerPaintingPhase paintingPhaseForPrimaryLayer() const; @@ -247,6 +253,9 @@ private: OwnPtr<GraphicsLayer> m_layerForVerticalScrollbar; OwnPtr<GraphicsLayer> m_layerForScrollCorner; + OwnPtr<GraphicsLayer> m_scrollingLayer; // only used if the layer is using composited scrolling. + OwnPtr<GraphicsLayer> m_scrollingContentsLayer; // only used if the layer is using composited scrolling. + IntRect m_compositedBounds; bool m_artificiallyInflatedBounds; // bounds had to be made non-zero to make transform-origin work diff --git a/Source/WebCore/rendering/RenderLayerCompositor.cpp b/Source/WebCore/rendering/RenderLayerCompositor.cpp index 72ba4c2f8..f967233ef 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.cpp +++ b/Source/WebCore/rendering/RenderLayerCompositor.cpp @@ -1025,7 +1025,7 @@ void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vect // If the layer has a clipping layer the overflow controls layers will be siblings of the clipping layer. // Otherwise, the overflow control layers are normal children. - if (!layerBacking->hasClippingLayer()) { + if (!layerBacking->hasClippingLayer() && !layerBacking->hasScrollingLayer()) { if (GraphicsLayer* overflowControlLayer = layerBacking->layerForHorizontalScrollbar()) { overflowControlLayer->removeFromParent(); layerBacking->parentForSublayers()->addChild(overflowControlLayer); @@ -1092,6 +1092,13 @@ void RenderLayerCompositor::frameViewDidScroll() m_scrollLayer->setPosition(FloatPoint(-scrollPosition.x(), -scrollPosition.y())); } +void RenderLayerCompositor::scrollingLayerDidChange(RenderLayer* layer) +{ + RenderLayerBacking* backing = layer->backing(); + if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) + scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer, backing ? backing->scrollingContentsLayer() : 0); +} + String RenderLayerCompositor::layerTreeAsText(bool showDebugInfo) { updateCompositingLayers(CompositingUpdateAfterLayout); @@ -1444,7 +1451,9 @@ bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) c || clipsCompositingDescendants(layer) || requiresCompositingForAnimation(renderer) || requiresCompositingForFilters(renderer) - || requiresCompositingForPosition(renderer, layer); + || requiresCompositingForPosition(renderer, layer) + || requiresCompositingForOverflowScrolling(layer) + || requiresCompositingForBlending(renderer); } bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const @@ -1472,7 +1481,9 @@ bool RenderLayerCompositor::requiresOwnBackingStore(const RenderLayer* layer, co || (canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden) || requiresCompositingForAnimation(renderer) || requiresCompositingForFilters(renderer) + || requiresCompositingForBlending(renderer) || requiresCompositingForPosition(renderer, layer) + || requiresCompositingForOverflowScrolling(layer) || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection() @@ -1530,6 +1541,9 @@ const char* RenderLayerCompositor::reasonForCompositing(const RenderLayer* layer if (requiresCompositingForPosition(renderer, layer)) return "position: fixed"; + if (requiresCompositingForOverflowScrolling(layer)) + return "-webkit-overflow-scrolling: touch"; + if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForStacking) return "stacking"; @@ -1554,6 +1568,9 @@ const char* RenderLayerCompositor::reasonForCompositing(const RenderLayer* layer if (renderer->hasFilter()) return "filter with composited descendants"; + + if (renderer->hasBlendMode()) + return "blending with composited descendants"; } if (layer->indirectCompositingReason() == RenderLayer::IndirectCompositingForPerspective) @@ -1766,7 +1783,7 @@ bool RenderLayerCompositor::requiresCompositingForIndirectReason(RenderObject* r // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented // via compositing so that they also apply to those composited descdendants. - if (hasCompositedDescendants && (layer->transform() || renderer->isTransparent() || renderer->hasMask() || renderer->hasReflection() || renderer->hasFilter())) { + if (hasCompositedDescendants && (layer->transform() || renderer->createsGroup() || renderer->hasReflection())) { reason = RenderLayer::IndirectCompositingForGraphicalEffect; return true; } @@ -1802,6 +1819,16 @@ bool RenderLayerCompositor::requiresCompositingForFilters(RenderObject* renderer #endif } +bool RenderLayerCompositor::requiresCompositingForBlending(RenderObject* renderer) const +{ +#if ENABLE(CSS_COMPOSITING) + return renderer->hasBlendMode(); +#else + UNUSED_PARAM(renderer); + return false; +#endif +} + bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer) const { // position:fixed elements that create their own stacking context (e.g. have an explicit z-index, @@ -1834,6 +1861,11 @@ bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* rendere return true; } +bool RenderLayerCompositor::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const +{ + return layer->usesCompositedScrolling(); +} + bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const { if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) diff --git a/Source/WebCore/rendering/RenderLayerCompositor.h b/Source/WebCore/rendering/RenderLayerCompositor.h index 5b87e53c4..46a97a57f 100644 --- a/Source/WebCore/rendering/RenderLayerCompositor.h +++ b/Source/WebCore/rendering/RenderLayerCompositor.h @@ -192,6 +192,8 @@ public: void frameViewDidChangeSize(); void frameViewDidScroll(); + void scrollingLayerDidChange(RenderLayer*); + String layerTreeAsText(bool showDebugInfo = false); // These are named to avoid conflicts with the functions in GraphicsLayerClient @@ -290,8 +292,10 @@ private: bool requiresCompositingForPlugin(RenderObject*) const; bool requiresCompositingForFrame(RenderObject*) const; bool requiresCompositingForFilters(RenderObject*) const; + bool requiresCompositingForBlending(RenderObject* renderer) const; bool requiresCompositingForScrollableFrame() const; bool requiresCompositingForPosition(RenderObject*, const RenderLayer*) const; + bool requiresCompositingForOverflowScrolling(const RenderLayer*) const; bool requiresCompositingForIndirectReason(RenderObject*, bool hasCompositedDescendants, bool has3DTransformedDescendants, RenderLayer::IndirectCompositingReason&) const; bool requiresScrollLayer(RootLayerAttachment) const; diff --git a/Source/WebCore/rendering/RenderLayerFilterInfo.h b/Source/WebCore/rendering/RenderLayerFilterInfo.h index ab45a9fca..cf2be232e 100644 --- a/Source/WebCore/rendering/RenderLayerFilterInfo.h +++ b/Source/WebCore/rendering/RenderLayerFilterInfo.h @@ -36,6 +36,7 @@ #include "CachedSVGDocument.h" #endif #include "FilterOperation.h" +#include "FractionalLayoutRect.h" #include "LayoutTypes.h" #include <wtf/HashMap.h> #include <wtf/PassRefPtr.h> diff --git a/Source/WebCore/rendering/RenderLineBoxList.cpp b/Source/WebCore/rendering/RenderLineBoxList.cpp index 2739d4124..ea50d52e8 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.cpp +++ b/Source/WebCore/rendering/RenderLineBoxList.cpp @@ -273,7 +273,7 @@ void RenderLineBoxList::paint(RenderBoxModelObject* renderer, PaintInfo& paintIn } } -bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) const +bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) const { if (hitTestAction != HitTestForeground) return false; @@ -284,10 +284,10 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq if (!firstLineBox()) return false; - LayoutPoint point = pointInContainer.point(); + LayoutPoint point = locationInContainer.point(); LayoutRect rect = firstLineBox()->isHorizontal() ? - IntRect(point.x(), point.y() - pointInContainer.topPadding(), 1, pointInContainer.topPadding() + pointInContainer.bottomPadding() + 1) : - IntRect(point.x() - pointInContainer.leftPadding(), point.y(), pointInContainer.rightPadding() + pointInContainer.leftPadding() + 1, 1); + IntRect(point.x(), point.y() - locationInContainer.topPadding(), 1, locationInContainer.topPadding() + locationInContainer.bottomPadding() + 1) : + IntRect(point.x() - locationInContainer.leftPadding(), point.y(), locationInContainer.rightPadding() + locationInContainer.leftPadding() + 1, 1); if (!anyLineIntersectsRect(renderer, rect, accumulatedOffset)) return false; @@ -298,9 +298,9 @@ bool RenderLineBoxList::hitTest(RenderBoxModelObject* renderer, const HitTestReq for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevLineBox()) { RootInlineBox* root = curr->root(); if (rangeIntersectsRect(renderer, curr->logicalTopVisualOverflow(root->lineTop()), curr->logicalBottomVisualOverflow(root->lineBottom()), rect, accumulatedOffset)) { - bool inside = curr->nodeAtPoint(request, result, pointInContainer, accumulatedOffset, root->lineTop(), root->lineBottom()); + bool inside = curr->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, root->lineTop(), root->lineBottom()); if (inside) { - renderer->updateHitTestResult(result, pointInContainer.point() - toLayoutSize(accumulatedOffset)); + renderer->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } diff --git a/Source/WebCore/rendering/RenderLineBoxList.h b/Source/WebCore/rendering/RenderLineBoxList.h index 2c2038295..e5b085edf 100644 --- a/Source/WebCore/rendering/RenderLineBoxList.h +++ b/Source/WebCore/rendering/RenderLineBoxList.h @@ -30,7 +30,7 @@ #ifndef RenderLineBoxList_h #define RenderLineBoxList_h -#include "RenderBox.h" +#include "RenderObject.h" namespace WebCore { @@ -64,7 +64,7 @@ public: void dirtyLinesFromChangedChild(RenderObject* parent, RenderObject* child); void paint(RenderBoxModelObject*, PaintInfo&, const LayoutPoint&) const; - bool hitTest(RenderBoxModelObject*, const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) const; + bool hitTest(RenderBoxModelObject*, const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) const; private: bool anyLineIntersectsRect(RenderBoxModelObject*, const LayoutRect&, const LayoutPoint&, bool usePrintRect = false, LayoutUnit outlineSize = 0) const; diff --git a/Source/WebCore/rendering/RenderListBox.cpp b/Source/WebCore/rendering/RenderListBox.cpp index 6376b098b..db70b08a5 100644 --- a/Source/WebCore/rendering/RenderListBox.cpp +++ b/Source/WebCore/rendering/RenderListBox.cpp @@ -459,7 +459,7 @@ void RenderListBox::paintItemBackground(PaintInfo& paintInfo, const LayoutPoint& } } -bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) +bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) { if (!m_vBar || !m_vBar->shouldParticipateInHitTesting()) return false; @@ -469,7 +469,7 @@ bool RenderListBox::isPointInOverflowControl(HitTestResult& result, const Layout m_vBar->width(), height() - borderTop() - borderBottom()); - if (vertRect.contains(pointInContainer)) { + if (vertRect.contains(locationInContainer)) { result.setScrollbar(m_vBar.get()); return true; } @@ -689,21 +689,21 @@ void RenderListBox::setScrollTop(int newTop) scrollToOffsetWithoutAnimation(VerticalScrollbar, index); } -bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderListBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (!RenderBlock::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction)) + if (!RenderBlock::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; const Vector<HTMLElement*>& listItems = selectElement()->listItems(); int size = numItems(); LayoutPoint adjustedLocation = accumulatedOffset + location(); for (int i = 0; i < size; ++i) { - if (itemBoundingBoxRect(adjustedLocation, i).contains(pointInContainer.point())) { + if (itemBoundingBoxRect(adjustedLocation, i).contains(locationInContainer.point())) { if (Element* node = listItems[i]) { result.setInnerNode(node); if (!result.innerNonSharedNode()) result.setInnerNonSharedNode(node); - result.setLocalPoint(pointInContainer.point() - toLayoutSize(adjustedLocation)); + result.setLocalPoint(locationInContainer.point() - toLayoutSize(adjustedLocation)); break; } } diff --git a/Source/WebCore/rendering/RenderListBox.h b/Source/WebCore/rendering/RenderListBox.h index 496191206..9a0110efc 100644 --- a/Source/WebCore/rendering/RenderListBox.h +++ b/Source/WebCore/rendering/RenderListBox.h @@ -70,14 +70,14 @@ private: virtual void paintObject(PaintInfo&, const LayoutPoint&); virtual LayoutRect controlClipRect(const LayoutPoint&) const; - virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset); + virtual bool isPointInOverflowControl(HitTestResult&, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset); virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0); virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0); virtual void computePreferredLogicalWidths(); virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const; - virtual void computeLogicalHeight(); + virtual void computeLogicalHeight() OVERRIDE; virtual void layout(); @@ -98,7 +98,7 @@ private: virtual void setScrollLeft(int); virtual void setScrollTop(int); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; // ScrollableArea interface. virtual int scrollSize(ScrollbarOrientation) const OVERRIDE; diff --git a/Source/WebCore/rendering/RenderMediaControls.h b/Source/WebCore/rendering/RenderMediaControls.h index f9d3f3d78..8a16c2f78 100644 --- a/Source/WebCore/rendering/RenderMediaControls.h +++ b/Source/WebCore/rendering/RenderMediaControls.h @@ -28,12 +28,18 @@ #if ENABLE(VIDEO) -#include "RenderObject.h" #include "MediaControlElements.h" namespace WebCore { +struct PaintInfo; + class HTMLMediaElement; +class IntRect; +class IntSize; +class RenderBox; +class RenderObject; +class RenderStyle; class RenderMediaControls { public: diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp index d2954dc3a..38a4e5a3e 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.cpp +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.cpp @@ -327,6 +327,22 @@ static bool paintMediaFullscreenButton(RenderObject* object, const PaintInfo& pa return paintMediaButton(paintInfo.context, rect, mediaFullscreenButton); } +static bool paintMediaClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) +{ + HTMLMediaElement* mediaElement = toParentMediaElement(object); + if (!mediaElement) + return false; + + static Image* mediaClosedCaptionButton = platformResource("mediaplayerClosedCaption"); + static Image* mediaClosedCaptionButtonDisabled = platformResource("mediaplayerClosedCaptionDisabled"); + + if (mediaElement->webkitClosedCaptionsVisible()) + return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButton); + + return paintMediaButton(paintInfo.context, rect, mediaClosedCaptionButtonDisabled); +} + + bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType part, RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { switch (part) { @@ -336,6 +352,8 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType case MediaPauseButton: case MediaPlayButton: return paintMediaPlayButton(object, paintInfo, rect); + case MediaShowClosedCaptionsButton: + return paintMediaClosedCaptionsButton(object, paintInfo, rect); case MediaSlider: return paintMediaSlider(object, paintInfo, rect); case MediaSliderThumb: @@ -360,7 +378,6 @@ bool RenderMediaControlsChromium::paintMediaControlsPart(MediaControlElementType case MediaRewindButton: case MediaReturnToRealtimeButton: case MediaStatusDisplay: - case MediaShowClosedCaptionsButton: case MediaHideClosedCaptionsButton: case MediaTextTrackDisplayContainer: case MediaTextTrackDisplay: diff --git a/Source/WebCore/rendering/RenderMediaControlsChromium.h b/Source/WebCore/rendering/RenderMediaControlsChromium.h index c3b801bf0..6015cb1fc 100644 --- a/Source/WebCore/rendering/RenderMediaControlsChromium.h +++ b/Source/WebCore/rendering/RenderMediaControlsChromium.h @@ -28,12 +28,16 @@ #ifndef RenderMediaControlsChromium_h #define RenderMediaControlsChromium_h -#include "RenderObject.h" #include "MediaControlElements.h" namespace WebCore { +struct PaintInfo; + class HTMLMediaElement; +class IntRect; +class RenderObject; + class RenderMediaControlsChromium { public: static bool paintMediaControlsPart(MediaControlElementType, RenderObject*, const PaintInfo&, const IntRect&); diff --git a/Source/WebCore/rendering/RenderMenuList.cpp b/Source/WebCore/rendering/RenderMenuList.cpp index 5b79d6c90..06367c726 100644 --- a/Source/WebCore/rendering/RenderMenuList.cpp +++ b/Source/WebCore/rendering/RenderMenuList.cpp @@ -212,7 +212,7 @@ void RenderMenuList::setTextFromOption(int optionIndex) int size = listItems.size(); int i = select->optionToListIndex(optionIndex); - String text = ""; + String text = emptyString(); if (i >= 0 && i < size) { Element* element = listItems[i]; if (element->hasTagName(optionTag)) { diff --git a/Source/WebCore/rendering/RenderMeter.h b/Source/WebCore/rendering/RenderMeter.h index 34909eeb0..b73218598 100644 --- a/Source/WebCore/rendering/RenderMeter.h +++ b/Source/WebCore/rendering/RenderMeter.h @@ -39,8 +39,8 @@ public: virtual void updateFromElement(); private: - virtual void computeLogicalWidth(); - virtual void computeLogicalHeight(); + virtual void computeLogicalWidth() OVERRIDE; + virtual void computeLogicalHeight() OVERRIDE; virtual const char* renderName() const { return "RenderMeter"; } virtual bool isMeter() const { return true; } diff --git a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp index 9f6bdefb4..64271a329 100644 --- a/Source/WebCore/rendering/RenderMultiColumnBlock.cpp +++ b/Source/WebCore/rendering/RenderMultiColumnBlock.cpp @@ -78,23 +78,19 @@ bool RenderMultiColumnBlock::recomputeLogicalWidth() return relayoutChildren; } -void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) +void RenderMultiColumnBlock::checkForPaginationLogicalHeightChange(LayoutUnit& /*pageLogicalHeight*/, bool& /*pageLogicalHeightChanged*/, bool& /*hasSpecifiedPageLogicalHeight*/) { - // We need to go ahead and set our explicit page height if one exists, so that we can - // avoid doing multiple layout passes. + // We don't actually update any of the variables. We just subclassed to adjust our column height. computeLogicalHeight(); LayoutUnit newContentLogicalHeight = contentLogicalHeight(); if (newContentLogicalHeight > ZERO_LAYOUT_UNIT) { - pageLogicalHeight = newContentLogicalHeight; - hasSpecifiedPageLogicalHeight = true; + // The regions will be invalidated when we lay them out and they change size to + // the new column height. + if (columnHeight() != newContentLogicalHeight) + setColumnHeight(newContentLogicalHeight); } setLogicalHeight(ZERO_LAYOUT_UNIT); - if (columnHeight() != pageLogicalHeight && everHadLayout()) { - setColumnHeight(pageLogicalHeight); - pageLogicalHeightChanged = true; - } - // Set up our column sets. ensureColumnSets(); } diff --git a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h index 6f236d1f4..c69e65016 100644 --- a/Source/WebCore/rendering/RenderMultiColumnFlowThread.h +++ b/Source/WebCore/rendering/RenderMultiColumnFlowThread.h @@ -38,6 +38,8 @@ public: private: virtual const char* renderName() const OVERRIDE; + + virtual void computeLogicalHeight() OVERRIDE {}; // We simply remain at our intrinsic height. }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.cpp b/Source/WebCore/rendering/RenderMultiColumnSet.cpp index 3ac55cc9e..369011980 100644 --- a/Source/WebCore/rendering/RenderMultiColumnSet.cpp +++ b/Source/WebCore/rendering/RenderMultiColumnSet.cpp @@ -24,21 +24,33 @@ */ #include "config.h" +#include "RenderMultiColumnSet.h" + +#include "HitTestResult.h" #include "PaintInfo.h" #include "RenderMultiColumnFlowThread.h" -#include "RenderMultiColumnSet.h" #include "RenderMultiColumnBlock.h" +using std::min; +using std::max; + namespace WebCore { RenderMultiColumnSet::RenderMultiColumnSet(Node* node, RenderFlowThread* flowThread) : RenderRegionSet(node, flowThread) - , m_columnCount(1) - , m_columnWidth(ZERO_LAYOUT_UNIT) - , m_columnHeight(ZERO_LAYOUT_UNIT) + , m_computedColumnCount(1) + , m_computedColumnWidth(ZERO_LAYOUT_UNIT) + , m_computedColumnHeight(ZERO_LAYOUT_UNIT) { } +LayoutUnit RenderMultiColumnSet::pageLogicalTopForOffset(LayoutUnit offset) const +{ + LayoutUnit portionLogicalTop = (isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x()); + unsigned columnIndex = (offset - portionLogicalTop) / computedColumnHeight(); + return portionLogicalTop + columnIndex * computedColumnHeight(); +} + void RenderMultiColumnSet::computeLogicalWidth() { // Our logical width starts off matching the column block itself. @@ -49,17 +61,17 @@ void RenderMultiColumnSet::computeLogicalWidth() setLogicalWidth(parentBox()->contentLogicalWidth()); RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); - setColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->columnCount()); // FIXME: This will eventually vary if we are contained inside regions. + setComputedColumnWidthAndCount(parentBlock->columnWidth(), parentBlock->columnCount()); // FIXME: This will eventually vary if we are contained inside regions. } void RenderMultiColumnSet::computeLogicalHeight() { // Make sure our column height is up to date. RenderMultiColumnBlock* parentBlock = toRenderMultiColumnBlock(parent()); - setColumnHeight(parentBlock->columnHeight()); // FIXME: Once we make more than one column set, this will become variable. + setComputedColumnHeight(parentBlock->columnHeight()); // FIXME: Once we make more than one column set, this will become variable. // Our logical height is always just the height of our columns. - setLogicalHeight(columnHeight()); + setLogicalHeight(computedColumnHeight()); } LayoutUnit RenderMultiColumnSet::columnGap() const @@ -69,10 +81,20 @@ LayoutUnit RenderMultiColumnSet::columnGap() const return static_cast<int>(style()->columnGap()); } +unsigned RenderMultiColumnSet::columnCount() const +{ + if (!computedColumnHeight()) + return 0; + + // Our region rect determines our column count. We have as many columns as needed to fit all the content. + LayoutUnit logicalHeightInColumns = flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().height() : flowThreadPortionRect().width(); + return ceil(static_cast<float>(logicalHeightInColumns) / computedColumnHeight()); +} + LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const { - LayoutUnit colLogicalWidth = columnWidth(); - LayoutUnit colLogicalHeight = columnHeight(); + LayoutUnit colLogicalWidth = computedColumnWidth(); + LayoutUnit colLogicalHeight = computedColumnHeight(); LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); LayoutUnit colLogicalLeft = borderAndPaddingLogicalLeft(); int colGap = columnGap(); @@ -86,6 +108,81 @@ LayoutRect RenderMultiColumnSet::columnRectAt(unsigned index) const return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth); } +unsigned RenderMultiColumnSet::columnIndexAtOffset(LayoutUnit offset) const +{ + LayoutRect portionRect(flowThreadPortionRect()); + LayoutUnit flowThreadLogicalTop = isHorizontalWritingMode() ? portionRect.y() : portionRect.x(); + LayoutUnit flowThreadLogicalBottom = isHorizontalWritingMode() ? portionRect.maxY() : portionRect.maxX(); + + // Handle the offset being out of range. + if (offset < flowThreadLogicalTop) + return 0; + if (offset >= flowThreadLogicalBottom) + return columnCount() - 1; + + // Just divide by the column height to determine the correct column. + return static_cast<float>(offset - flowThreadLogicalTop) / computedColumnHeight(); +} + +LayoutRect RenderMultiColumnSet::flowThreadPortionRectAt(unsigned index) const +{ + LayoutRect portionRect = flowThreadPortionRect(); + if (isHorizontalWritingMode()) + portionRect = LayoutRect(portionRect.x(), portionRect.y() + index * computedColumnHeight(), portionRect.width(), computedColumnHeight()); + else + portionRect = LayoutRect(portionRect.x() + index * computedColumnHeight(), portionRect.y(), computedColumnHeight(), portionRect.height()); + return portionRect; +} + +LayoutRect RenderMultiColumnSet::flowThreadPortionOverflowRect(const LayoutRect& portionRect, unsigned index, unsigned colCount, int colGap) const +{ + // This function determines the portion of the flow thread that paints for the column. Along the inline axis, columns are + // unclipped at outside edges (i.e., the first and last column in the set), and they clip to half the column + // gap along interior edges. + // + // In the block direction, we will not clip overflow out of the top of the first column, or out of the bottom of + // the last column. This applies only to the true first column and last column across all column sets. + // + // FIXME: Eventually we will know overflow on a per-column basis, but we can't do this until we have a painting + // mode that understands not to paint contents from a previous column in the overflow area of a following column. + // This problem applies to regions and pages as well and is not unique to columns. + bool isFirstColumn = !index; + bool isLastColumn = index == colCount - 1; + LayoutRect overflowRect(portionRect); + if (isHorizontalWritingMode()) { + if (isFirstColumn) { + // Shift to the logical left overflow of the flow thread to make sure it's all covered. + overflowRect.shiftXEdgeTo(min(flowThread()->visualOverflowRect().x(), portionRect.x())); + } else { + // Expand into half of the logical left column gap. + overflowRect.shiftXEdgeTo(portionRect.x() - colGap / 2); + } + if (isLastColumn) { + // Shift to the logical right overflow of the flow thread to ensure content can spill out of the column. + overflowRect.shiftMaxXEdgeTo(max(flowThread()->visualOverflowRect().maxX(), portionRect.maxX())); + } else { + // Expand into half of the logical right column gap. + overflowRect.shiftMaxXEdgeTo(portionRect.maxX() + colGap / 2); + } + } else { + if (isFirstColumn) { + // Shift to the logical left overflow of the flow thread to make sure it's all covered. + overflowRect.shiftYEdgeTo(min(flowThread()->visualOverflowRect().y(), portionRect.y())); + } else { + // Expand into half of the logical left column gap. + overflowRect.shiftYEdgeTo(portionRect.y() - colGap / 2); + } + if (isLastColumn) { + // Shift to the logical right overflow of the flow thread to ensure content can spill out of the column. + overflowRect.shiftMaxYEdgeTo(max(flowThread()->visualOverflowRect().maxY(), portionRect.maxY())); + } else { + // Expand into half of the logical right column gap. + overflowRect.shiftMaxYEdgeTo(portionRect.maxY() + colGap / 2); + } + } + return overflowRectForFlowThreadPortion(overflowRect, isFirstRegion() && isFirstColumn, isLastRegion() && isLastColumn); +} + void RenderMultiColumnSet::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // FIXME: RenderRegions are replaced elements right now and so they only paint in the foreground phase. @@ -116,6 +213,8 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo return; unsigned colCount = columnCount(); + if (colCount <= 1) + return; bool antialias = shouldAntialiasLines(paintInfo.context); @@ -123,7 +222,7 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo LayoutUnit currLogicalLeftOffset = leftToRight ? ZERO_LAYOUT_UNIT : contentLogicalWidth(); LayoutUnit ruleAdd = borderAndPaddingLogicalLeft(); LayoutUnit ruleLogicalLeft = leftToRight ? ZERO_LAYOUT_UNIT : contentLogicalWidth(); - LayoutUnit inlineDirectionSize = columnWidth(); + LayoutUnit inlineDirectionSize = computedColumnWidth(); BoxSide boxSide = isHorizontalWritingMode() ? leftToRight ? BSLeft : BSRight : leftToRight ? BSTop : BSBottom; @@ -152,14 +251,112 @@ void RenderMultiColumnSet::paintColumnRules(PaintInfo& paintInfo, const LayoutPo } } -void RenderMultiColumnSet::paintColumnContents(PaintInfo& /* paintInfo */, const LayoutPoint& /* paintOffset */) +void RenderMultiColumnSet::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // For each rectangle, set it as the region rectangle and then let flow thread painting do the rest. - // We make multiple calls to paintIntoRegion, changing the rectangles each time. - if (!columnCount()) + // We make multiple calls to paintFlowThreadPortionInRegion, changing the rectangles each time. + unsigned colCount = columnCount(); + if (!colCount) return; + + LayoutUnit colGap = columnGap(); + for (unsigned i = 0; i < colCount; i++) { + // First we get the column rect, which is in our local coordinate space, and we make it physical and apply + // the paint offset to it. That gives us the physical location that we want to paint the column at. + LayoutRect colRect = columnRectAt(i); + flipForWritingMode(colRect); + colRect.moveBy(paintOffset); + + // Next we get the portion of the flow thread that corresponds to this column. + LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); + + // Now get the overflow rect that corresponds to the column. + LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); + + // Do the paint with the computed rects. + flowThread()->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortion, flowThreadOverflowPortion, colRect.location()); + } +} + +bool RenderMultiColumnSet::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +{ + LayoutPoint adjustedLocation = accumulatedOffset + location(); + + // Check our bounds next. For this purpose always assume that we can only be hit in the + // foreground phase (which is true for replaced elements like images). + // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect. + LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); + boundsRect.moveBy(adjustedLocation); + if (!visibleToHitTesting() || action != HitTestForeground || !locationInContainer.intersects(boundsRect)) + return false; + + // The point is in one specific column. Since columns can't overlap, we don't ever have to test + // multiple columns. Put the + + // FIXME: It would be nice to jump right to the specific column by just doing math on the point. Since columns + // can't overlap, we shouldn't have to walk every column like this. The old column code walked all the columns, though, + // so this is no worse. We'd have to watch out for rect-based hit testing, though, which actually could overlap + // multiple columns. + LayoutUnit colGap = columnGap(); + unsigned colCount = columnCount(); + for (unsigned i = 0; i < colCount; i++) { + // First we get the column rect, which is in our local coordinate space, and we make it physical and apply + // the hit test offset to it. That gives us the physical location that we want to paint the column at. + LayoutRect colRect = columnRectAt(i); + flipForWritingMode(colRect); + colRect.moveBy(adjustedLocation); + + // Next we get the portion of the flow thread that corresponds to this column. + LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); - // FIXME: Implement. + // Now get the overflow rect that corresponds to the column. + LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); + + // Do the hit test with the computed rects. + if (flowThread()->hitTestFlowThreadPortionInRegion(this, flowThreadPortion, flowThreadOverflowPortion, request, result, locationInContainer, colRect.location())) + return true; + } + + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); + return !result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect); +} + +void RenderMultiColumnSet::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const +{ + // Figure out the start and end columns and only check within that range so that we don't walk the + // entire column set. Put the repaint rect into flow thread coordinates by flipping it first. + LayoutRect flowThreadRepaintRect(repaintRect); + flowThread()->flipForWritingMode(flowThreadRepaintRect); + + // Now we can compare this rect with the flow thread portions owned by each column. First let's + // just see if the repaint rect intersects our flow thread portion at all. + LayoutRect clippedRect(flowThreadRepaintRect); + clippedRect.intersect(RenderRegion::flowThreadPortionOverflowRect()); + if (clippedRect.isEmpty()) + return; + + // Now we know we intersect at least one column. Let's figure out the logical top and logical + // bottom of the area we're repainting. + LayoutUnit repaintLogicalTop = isHorizontalWritingMode() ? flowThreadRepaintRect.y() : flowThreadRepaintRect.x(); + LayoutUnit repaintLogicalBottom = (isHorizontalWritingMode() ? flowThreadRepaintRect.maxY() : flowThreadRepaintRect.maxX()) - 1; + + unsigned startColumn = columnIndexAtOffset(repaintLogicalTop); + unsigned endColumn = columnIndexAtOffset(repaintLogicalBottom); + + LayoutUnit colGap = columnGap(); + unsigned colCount = columnCount(); + for (unsigned i = startColumn; i <= endColumn; i++) { + LayoutRect colRect = columnRectAt(i); + + // Get the portion of the flow thread that corresponds to this column. + LayoutRect flowThreadPortion = flowThreadPortionRectAt(i); + + // Now get the overflow rect that corresponds to the column. + LayoutRect flowThreadOverflowPortion = flowThreadPortionOverflowRect(flowThreadPortion, i, colCount, colGap); + + // Do a repaint for this specific column. + repaintFlowThreadContentRectangle(repaintRect, immediate, flowThreadPortion, flowThreadOverflowPortion, colRect.location()); + } } const char* RenderMultiColumnSet::renderName() const diff --git a/Source/WebCore/rendering/RenderMultiColumnSet.h b/Source/WebCore/rendering/RenderMultiColumnSet.h index b9a9da054..a0d1c4536 100644 --- a/Source/WebCore/rendering/RenderMultiColumnSet.h +++ b/Source/WebCore/rendering/RenderMultiColumnSet.h @@ -47,18 +47,18 @@ public: virtual bool isRenderMultiColumnSet() const OVERRIDE { return true; } - unsigned columnCount() const { return m_columnCount; } - LayoutUnit columnWidth() const { return m_columnWidth; } - LayoutUnit columnHeight() const { return m_columnHeight; } + unsigned computedColumnCount() const { return m_computedColumnCount; } + LayoutUnit computedColumnWidth() const { return m_computedColumnWidth; } + LayoutUnit computedColumnHeight() const { return m_computedColumnHeight; } - void setColumnWidthAndCount(LayoutUnit width, unsigned count) + void setComputedColumnWidthAndCount(LayoutUnit width, unsigned count) { - m_columnWidth = width; - m_columnCount = count; + m_computedColumnWidth = width; + m_computedColumnCount = count; } - void setColumnHeight(LayoutUnit height) + void setComputedColumnHeight(LayoutUnit height) { - m_columnHeight = height; + m_computedColumnHeight = height; } private: @@ -66,9 +66,17 @@ private: virtual void computeLogicalHeight() OVERRIDE; virtual void paintReplaced(PaintInfo&, const LayoutPoint& paintOffset) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual LayoutUnit logicalWidthForFlowThreadContent() const OVERRIDE { return m_columnWidth; } - virtual LayoutUnit logicalHeightForFlowThreadContent() const OVERRIDE { return m_columnHeight; } // FIXME: Will be wrong once we have multiple sets. + virtual LayoutUnit pageLogicalWidth() const OVERRIDE { return m_computedColumnWidth; } + virtual LayoutUnit pageLogicalHeight() const OVERRIDE { return m_computedColumnHeight; } + + virtual LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const OVERRIDE; + + // FIXME: This will change once we have column sets constrained by enclosing pages, etc. + virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const OVERRIDE { return m_computedColumnHeight; } + + virtual void repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const OVERRIDE; virtual const char* renderName() const; @@ -76,11 +84,17 @@ private: void paintColumnContents(PaintInfo&, const LayoutPoint& paintOffset); LayoutUnit columnGap() const; - LayoutRect columnRectAt( unsigned index) const; + LayoutRect columnRectAt(unsigned index) const; + unsigned columnCount() const; + + LayoutRect flowThreadPortionRectAt(unsigned index) const; + LayoutRect flowThreadPortionOverflowRect(const LayoutRect& flowThreadPortion, unsigned index, unsigned colCount, int colGap) const; + + unsigned columnIndexAtOffset(LayoutUnit) const; - unsigned m_columnCount; - LayoutUnit m_columnWidth; - LayoutUnit m_columnHeight; + unsigned m_computedColumnCount; + LayoutUnit m_computedColumnWidth; + LayoutUnit m_computedColumnHeight; }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.cpp b/Source/WebCore/rendering/RenderNamedFlowThread.cpp index 5b02453e4..4e83cca9e 100644 --- a/Source/WebCore/rendering/RenderNamedFlowThread.cpp +++ b/Source/WebCore/rendering/RenderNamedFlowThread.cpp @@ -38,18 +38,37 @@ RenderNamedFlowThread::RenderNamedFlowThread(Node* node, PassRefPtr<WebKitNamedF , m_namedFlow(namedFlow) , m_regionLayoutUpdateEventTimer(this, &RenderNamedFlowThread::regionLayoutUpdateEventTimerFired) { - m_namedFlow->setRenderer(this); } RenderNamedFlowThread::~RenderNamedFlowThread() { - m_namedFlow->setRenderer(0); + // The flow thread can be destroyed without unregistering the content nodes if the document is destroyed. + // This can lead to problems because the nodes are still marked as belonging to a flow thread. + clearContentNodes(); + + // Also leave the NamedFlow object in a consistent state by calling mark for destruction. + setMarkForDestruction(); } const char* RenderNamedFlowThread::renderName() const { return "RenderNamedFlowThread"; } + +void RenderNamedFlowThread::clearContentNodes() +{ + for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) { + Node* contentNode = *it; + + ASSERT(contentNode && contentNode->isElementNode()); + ASSERT(contentNode->inNamedFlow()); + ASSERT(contentNode->document() == document()); + + contentNode->clearInNamedFlow(); + } + + m_contentNodes.clear(); +} RenderObject* RenderNamedFlowThread::nextRendererForNode(Node* node) const { @@ -135,12 +154,45 @@ static bool compareRenderRegions(const RenderRegion* firstRegion, const RenderRe ASSERT(firstRegion); ASSERT(secondRegion); - // If the regions have the same region-index, compare their position in dom. - ASSERT(firstRegion->node()); - ASSERT(secondRegion->node()); + ASSERT(firstRegion->generatingNode()); + ASSERT(secondRegion->generatingNode()); + + // If the regions belong to different nodes, compare their position in the DOM. + if (firstRegion->generatingNode() != secondRegion->generatingNode()) { + unsigned short position = firstRegion->generatingNode()->compareDocumentPosition(secondRegion->generatingNode()); - unsigned short position = firstRegion->node()->compareDocumentPosition(secondRegion->node()); - return (position & Node::DOCUMENT_POSITION_FOLLOWING); + // If the second region is contained in the first one, the first region is "less" if it's :before. + if (position & Node::DOCUMENT_POSITION_CONTAINED_BY) { + ASSERT(secondRegion->style()->styleType() == NOPSEUDO); + return firstRegion->style()->styleType() == BEFORE; + } + + // If the second region contains the first region, the first region is "less" if the second is :after. + if (position & Node::DOCUMENT_POSITION_CONTAINS) { + ASSERT(firstRegion->style()->styleType() == NOPSEUDO); + return secondRegion->style()->styleType() == AFTER; + } + + return (position & Node::DOCUMENT_POSITION_FOLLOWING); + } + + // FIXME: Currently it's not possible for an element to be both a region and have pseudo-children. The case is covered anyway. + switch (firstRegion->style()->styleType()) { + case BEFORE: + // The second region can be the node or the after pseudo-element (before is smaller than any of those). + return true; + case AFTER: + // The second region can be the node or the before pseudo-element (after is greater than any of those). + return false; + case NOPSEUDO: + // The second region can either be the before or the after pseudo-element (the node is only smaller than the after pseudo-element). + return firstRegion->style()->styleType() == AFTER; + default: + break; + } + + ASSERT_NOT_REACHED(); + return true; } void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion) @@ -156,6 +208,8 @@ void RenderNamedFlowThread::addRegionToThread(RenderRegion* renderRegion) m_regionList.insertBefore(it, renderRegion); } + resetMarkForDestruction(); + ASSERT(!renderRegion->isValid()); if (renderRegion->parentNamedFlowThread()) { if (renderRegion->parentNamedFlowThread()->dependsOn(this)) { @@ -188,10 +242,8 @@ void RenderNamedFlowThread::removeRegionFromThread(RenderRegion* renderRegion) removeDependencyOnFlowThread(renderRegion->parentNamedFlowThread()); } - if (canBeDestroyed()) { - destroy(); - return; - } + if (canBeDestroyed()) + setMarkForDestruction(); // After removing all the regions in the flow the following layout needs to dispatch the regionLayoutUpdate event if (m_regionList.isEmpty()) @@ -265,9 +317,12 @@ void RenderNamedFlowThread::pushDependencies(RenderNamedFlowThreadList& list) void RenderNamedFlowThread::registerNamedFlowContentNode(Node* contentNode) { ASSERT(contentNode && contentNode->isElementNode()); + ASSERT(contentNode->document() == document()); contentNode->setInNamedFlow(); + resetMarkForDestruction(); + // Find the first content node following the new content node. for (NamedFlowContentNodes::iterator it = m_contentNodes.begin(); it != m_contentNodes.end(); ++it) { Node* node = *it; @@ -285,12 +340,13 @@ void RenderNamedFlowThread::unregisterNamedFlowContentNode(Node* contentNode) ASSERT(contentNode && contentNode->isElementNode()); ASSERT(m_contentNodes.contains(contentNode)); ASSERT(contentNode->inNamedFlow()); + ASSERT(contentNode->document() == document()); contentNode->clearInNamedFlow(); m_contentNodes.remove(contentNode); if (canBeDestroyed()) - destroy(); + setMarkForDestruction(); } const AtomicString& RenderNamedFlowThread::flowThreadName() const @@ -298,14 +354,6 @@ const AtomicString& RenderNamedFlowThread::flowThreadName() const return m_namedFlow->name(); } -void RenderNamedFlowThread::willBeDestroyed() -{ - if (!documentBeingDestroyed()) - view()->flowThreadController()->removeFlowThread(this); - - RenderFlowThread::willBeDestroyed(); -} - void RenderNamedFlowThread::dispatchRegionLayoutUpdateEvent() { RenderFlowThread::dispatchRegionLayoutUpdateEvent(); @@ -321,4 +369,28 @@ void RenderNamedFlowThread::regionLayoutUpdateEventTimerFired(Timer<RenderNamedF m_namedFlow->dispatchRegionLayoutUpdateEvent(); } +void RenderNamedFlowThread::setMarkForDestruction() +{ + if (m_namedFlow->flowState() == WebKitNamedFlow::FlowStateNull) + return; + + m_namedFlow->setRenderer(0); + // After this call ends, the renderer can be safely destroyed. + // The NamedFlow object may outlive its renderer if it's referenced from a script and may be reatached to one if the named flow is recreated in the stylesheet. +} + +void RenderNamedFlowThread::resetMarkForDestruction() +{ + if (m_namedFlow->flowState() == WebKitNamedFlow::FlowStateCreated) + return; + + m_namedFlow->setRenderer(this); +} + +bool RenderNamedFlowThread::isMarkedForDestruction() const +{ + // Flow threads in the "NULL" state can be destroyed. + return m_namedFlow->flowState() == WebKitNamedFlow::FlowStateNull; +} + } diff --git a/Source/WebCore/rendering/RenderNamedFlowThread.h b/Source/WebCore/rendering/RenderNamedFlowThread.h index 4101b771e..a8b8b5131 100644 --- a/Source/WebCore/rendering/RenderNamedFlowThread.h +++ b/Source/WebCore/rendering/RenderNamedFlowThread.h @@ -69,9 +69,11 @@ public: void unregisterNamedFlowContentNode(Node*); const NamedFlowContentNodes& contentNodes() const { return m_contentNodes; } bool hasContentNode(Node* contentNode) const { ASSERT(contentNode); return m_contentNodes.contains(contentNode); } + bool isMarkedForDestruction() const; protected: - virtual void willBeDestroyed() OVERRIDE; + void setMarkForDestruction(); + void resetMarkForDestruction(); private: virtual const char* renderName() const OVERRIDE; @@ -85,6 +87,7 @@ private: void checkInvalidRegions(); bool canBeDestroyed() const { return m_regionList.isEmpty() && m_contentNodes.isEmpty(); } void regionLayoutUpdateEventTimerFired(Timer<RenderNamedFlowThread>*); + void clearContentNodes(); private: // Observer flow threads have invalid regions that depend on the state of this thread diff --git a/Source/WebCore/rendering/RenderObject.cpp b/Source/WebCore/rendering/RenderObject.cpp index 933a559c4..8bfd9f74d 100755 --- a/Source/WebCore/rendering/RenderObject.cpp +++ b/Source/WebCore/rendering/RenderObject.cpp @@ -185,11 +185,9 @@ 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 case GRID: case INLINE_GRID: return new (arena) RenderGrid(node); @@ -640,9 +638,9 @@ void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderOb if (!container && !object->isRenderView()) return; if (!last->isText() && last->style()->hasOutOfFlowPosition()) { - bool willSkipRelativelyPositionedInlines = !object->isRenderBlock() || object->isAnonymousBlock() || object->isRenderFlowThreadContainer(); - // Skip relatively positioned inlines and anonymous blocks (and the flow threads container) to get to the enclosing RenderBlock. - while (object && (!object->isRenderBlock() || object->isAnonymousBlock() || object->isRenderFlowThreadContainer())) + bool willSkipRelativelyPositionedInlines = !object->isRenderBlock() || object->isAnonymousBlock(); + // Skip relatively positioned inlines and anonymous blocks to get to the enclosing RenderBlock. + while (object && (!object->isRenderBlock() || object->isAnonymousBlock())) object = object->container(); if (!object || object->posChildNeedsLayout()) return; @@ -1279,7 +1277,7 @@ RenderBoxModelObject* RenderObject::containerForRepaint() const return repaintContainer; } -void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, const LayoutRect& r, bool immediate) +void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, const LayoutRect& r, bool immediate) const { if (!repaintContainer) { view()->repaintViewRectangle(r, immediate); @@ -1322,7 +1320,7 @@ void RenderObject::repaintUsingContainer(RenderBoxModelObject* repaintContainer, #endif } -void RenderObject::repaint(bool immediate) +void RenderObject::repaint(bool immediate) const { // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) RenderView* view; @@ -1336,7 +1334,7 @@ void RenderObject::repaint(bool immediate) repaintUsingContainer(repaintContainer ? repaintContainer : view, clippedOverflowRectForRepaint(repaintContainer), immediate); } -void RenderObject::repaintRectangle(const LayoutRect& r, bool immediate) +void RenderObject::repaintRectangle(const LayoutRect& r, bool immediate) const { // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) RenderView* view; @@ -1853,7 +1851,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); s_affectsParentBlock = isFloatingOrOutOfFlowPositioned() - && (!newStyle->isFloating() && newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition) + && (!newStyle->isFloating() && !newStyle->hasOutOfFlowPosition()) && parent() && (parent()->isBlockFlow() || parent()->isRenderInline()); // reset style flags @@ -1861,6 +1859,7 @@ void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newS setFloating(false); setPositioned(false); setRelPositioned(false); + setStickyPositioned(false); } setHorizontalWritingMode(true); setPaintBackground(false); @@ -1966,9 +1965,9 @@ void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly) newStyle->setColumnSpan(ColumnSpanAll); } - // Preserve the position style of anonymous block continuations as they can have relative position when - // they contain block descendants of relative positioned inlines. - if (child->isRelPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation()) + // Preserve the position style of anonymous block continuations as they can have relative or sticky position when + // they contain block descendants of relative or sticky positioned inlines. + if (child->isInFlowPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation()) newStyle->setPosition(child->style()->position()); child->setStyle(newStyle.release()); @@ -2200,9 +2199,9 @@ LayoutRect RenderObject::localCaretRect(InlineBox*, int, LayoutUnit* extraWidthT return LayoutRect(); } -bool RenderObject::isRooted(RenderView** view) +bool RenderObject::isRooted(RenderView** view) const { - RenderObject* o = this; + const RenderObject* o = this; while (o->parent()) o = o->parent(); @@ -2210,7 +2209,7 @@ bool RenderObject::isRooted(RenderView** view) return false; if (view) - *view = toRenderView(o); + *view = const_cast<RenderView*>(toRenderView(o)); return true; } @@ -2534,25 +2533,25 @@ bool RenderObject::isComposited() const return hasLayer() && toRenderBoxModelObject(this)->layer()->isComposited(); } -bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter) +bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter) { bool inside = false; if (hitTestFilter != HitTestSelf) { // First test the foreground layer (lines and inlines). - inside = nodeAtPoint(request, result, pointInContainer, accumulatedOffset, HitTestForeground); + inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestForeground); // Test floats next. if (!inside) - inside = nodeAtPoint(request, result, pointInContainer, accumulatedOffset, HitTestFloat); + inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestFloat); // Finally test to see if the mouse is in the background (within a child block's background). if (!inside) - inside = nodeAtPoint(request, result, pointInContainer, accumulatedOffset, HitTestChildBlockBackgrounds); + inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestChildBlockBackgrounds); } // See if the mouse is inside us but not any of our descendants if (hitTestFilter != HitTestDescendants && !inside) - inside = nodeAtPoint(request, result, pointInContainer, accumulatedOffset, HitTestBlockBackground); + inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestBlockBackground); return inside; } @@ -2571,7 +2570,7 @@ void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint& } } -bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& /*pointInContainer*/, const LayoutPoint& /*accumulatedOffset*/, HitTestAction) +bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& /*locationInContainer*/, const LayoutPoint& /*accumulatedOffset*/, HitTestAction) { return false; } @@ -2898,10 +2897,10 @@ RenderBoxModelObject* RenderObject::offsetParent() const // is one of the following HTML elements: td, th, or table. // * Our own extension: if there is a difference in the effective zoom - bool skipTables = isOutOfFlowPositioned() || isRelPositioned(); + bool skipTables = isPositioned(); float currZoom = style()->effectiveZoom(); RenderObject* curr = parent(); - while (curr && (!curr->node() || (!curr->isOutOfFlowPositioned() && !curr->isRelPositioned() && !curr->isBody()))) { + while (curr && (!curr->node() || (!curr->isPositioned() && !curr->isBody()))) { Node* element = curr->node(); if (!skipTables && element && (element->hasTagName(tableTag) || element->hasTagName(tdTag) || element->hasTagName(thTag))) break; diff --git a/Source/WebCore/rendering/RenderObject.h b/Source/WebCore/rendering/RenderObject.h index 05ccea48d..b6aa16e19 100644 --- a/Source/WebCore/rendering/RenderObject.h +++ b/Source/WebCore/rendering/RenderObject.h @@ -46,7 +46,7 @@ class AffineTransform; class AnimationController; class Cursor; class Document; -class HitTestPoint; +class HitTestLocation; class HitTestResult; class InlineBox; class InlineFlowBox; @@ -311,6 +311,9 @@ public: virtual bool isBlockFlow() const { return false; } virtual bool isBoxModelObject() const { return false; } virtual bool isCounter() const { return false; } +#if ENABLE(DIALOG_ELEMENT) + virtual bool isDialog() const { return false; } +#endif virtual bool isQuote() const { return false; } #if ENABLE(DETAILS_ELEMENT) @@ -369,7 +372,6 @@ public: #endif virtual bool isRenderFlowThread() const { return false; } - virtual bool isRenderFlowThreadContainer() const { return false; } virtual bool isRenderNamedFlowThread() const { return false; } virtual bool isRenderMultiColumnBlock() const { return false; } @@ -513,8 +515,10 @@ public: bool isFloating() const { return m_bitfields.floating(); } bool isOutOfFlowPositioned() const { return m_bitfields.positioned(); } // absolute or fixed positioning - bool isInFlowPositioned() const { return m_bitfields.relPositioned(); } // relative positioning + bool isInFlowPositioned() const { return m_bitfields.relPositioned() || m_bitfields.stickyPositioned(); } // relative or sticky positioning bool isRelPositioned() const { return m_bitfields.relPositioned(); } // relative positioning + bool isStickyPositioned() const { return m_bitfields.stickyPositioned(); } + bool isPositioned() const { return m_bitfields.positioned() || m_bitfields.relPositioned() || m_bitfields.stickyPositioned(); } bool isText() const { return m_bitfields.isText(); } bool isBox() const { return m_bitfields.isBox(); } @@ -558,6 +562,7 @@ public: bool hasTransform() const { return m_bitfields.hasTransform(); } bool hasMask() const { return style() && style()->hasMask(); } + bool hasClipPath() const { return style() && style()->clipPath(); } bool hasHiddenBackface() const { return style() && style()->backfaceVisibility() == BackfaceVisibilityHidden; } #if ENABLE(CSS_FILTERS) @@ -566,6 +571,12 @@ public: bool hasFilter() const { return false; } #endif +#if ENABLE(CSS_COMPOSITING) + bool hasBlendMode() const { return style() && style()->hasBlendMode(); } +#else + bool hasBlendMode() const { return false; } +#endif + inline bool preservesNewline() const; // The pseudo element style can be cached or uncached. Use the cached method if the pseudo element doesn't respect @@ -579,7 +590,7 @@ public: RenderView* view() const; // Returns true if this renderer is rooted, and optionally returns the hosting view (the root of the hierarchy). - bool isRooted(RenderView** = 0); + bool isRooted(RenderView** = 0) const; Node* node() const { return isAnonymous() ? 0 : m_node; } @@ -621,6 +632,7 @@ public: void setPositioned(bool b = true) { m_bitfields.setPositioned(b); } void setRelPositioned(bool b = true) { m_bitfields.setRelPositioned(b); } + void setStickyPositioned(bool b = true) { m_bitfields.setStickyPositioned(b); } void setFloating(bool b = true) { m_bitfields.setFloating(b); } void setInline(bool b = true) { m_bitfields.setIsInline(b); } void setHasBoxDecorations(bool b = true) { m_bitfields.setPaintBackground(b); } @@ -657,9 +669,9 @@ public: bool isComposited() const; - bool hitTest(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter = HitTestAll); + bool hitTest(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter = HitTestAll); virtual void updateHitTestResult(HitTestResult&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction); virtual VisiblePosition positionForPoint(const LayoutPoint&); VisiblePosition createVisiblePosition(int offset, EAffinity); @@ -744,14 +756,14 @@ public: RenderBoxModelObject* containerForRepaint() const; // Actually do the repaint of rect r for this object which has been computed in the coordinate space // of repaintContainer. If repaintContainer is 0, repaint via the view. - void repaintUsingContainer(RenderBoxModelObject* repaintContainer, const LayoutRect&, bool immediate = false); + void repaintUsingContainer(RenderBoxModelObject* repaintContainer, const LayoutRect&, bool immediate = false) const; // Repaint the entire object. Called when, e.g., the color of a border changes, or when a border // style changes. - void repaint(bool immediate = false); + void repaint(bool immediate = false) const; // Repaint a specific subrectangle within a given object. The rect |r| is in the object's coordinate space. - void repaintRectangle(const LayoutRect&, bool immediate = false); + void repaintRectangle(const LayoutRect&, bool immediate = false) const; // Repaint only if our old bounds and new bounds are different. The caller may pass in newBounds and newOutlineBox if they are known. bool repaintAfterLayoutIfNeeded(RenderBoxModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr = 0, const LayoutRect* newOutlineBoxPtr = 0); @@ -903,6 +915,9 @@ public: bool shouldUseTransformFromContainer(const RenderObject* container) const; void getTransformFromContainer(const RenderObject* container, const LayoutSize& offsetInContainer, TransformationMatrix&) const; + // return true if this object requires a new stacking context + bool createsGroup() const { return isTransparent() || hasMask() || hasFilter() || hasBlendMode(); } + virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint&) { }; LayoutRect absoluteOutlineBounds() const @@ -930,7 +945,7 @@ protected: void paintFocusRing(GraphicsContext*, const LayoutPoint&, RenderStyle*); void paintOutline(GraphicsContext*, const LayoutRect&); void addPDFURLRect(GraphicsContext*, const LayoutRect&); - + virtual LayoutRect viewRect() const; void adjustRectForOutlineAndShadow(LayoutRect&) const; @@ -990,6 +1005,7 @@ private: , m_floating(false) , m_positioned(false) , m_relPositioned(false) + , m_stickyPositioned(false) , m_paintBackground(false) , m_isAnonymous(node == node->document()) , m_isText(false) @@ -1024,6 +1040,7 @@ private: ADD_BOOLEAN_BITFIELD(positioned, Positioned); ADD_BOOLEAN_BITFIELD(relPositioned, RelPositioned); + ADD_BOOLEAN_BITFIELD(stickyPositioned, StickyPositioned); ADD_BOOLEAN_BITFIELD(paintBackground, PaintBackground); // if the box has something to paint in the // background painting phase (background, border, etc) diff --git a/Source/WebCore/rendering/RenderObjectChildList.cpp b/Source/WebCore/rendering/RenderObjectChildList.cpp index 98a287627..247f7dda4 100644 --- a/Source/WebCore/rendering/RenderObjectChildList.cpp +++ b/Source/WebCore/rendering/RenderObjectChildList.cpp @@ -85,9 +85,6 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render if (oldChild->isBox()) toRenderBox(oldChild)->deleteLineBoxWrapper(); - if (!owner->documentBeingDestroyed() && notifyRenderer) - oldChild->willBeRemovedFromTree(); - // If oldChild is the start or end of the selection, then clear the selection to // avoid problems of invalid pointers. // FIXME: The FrameSelection should be responsible for this when it @@ -95,7 +92,13 @@ RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, Render if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder()) owner->view()->clearSelection(); - // remove the child + if (!owner->documentBeingDestroyed() && notifyRenderer) + oldChild->willBeRemovedFromTree(); + + // WARNING: There should be no code running between willBeRemovedFromTree and the actual removal below. + // This is needed to avoid race conditions where willBeRemovedFromTree would dirty the tree's structure + // and the code running here would force an untimely rebuilding, leaving |oldChild| dangling. + if (oldChild->previousSibling()) oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); if (oldChild->nextSibling()) @@ -337,6 +340,32 @@ static RenderObject* createRendererForBeforeAfterContent(RenderObject* owner, co return renderer; } +static RenderObject* ensureBeforeAfterContainer(RenderObject* owner, PseudoId type, RenderStyle* pseudoElementStyle, Node* generatingNode, RenderObject* insertBefore) +{ + // Make a generated box that might be any display type now that we are able to drill down into children + // to find the original content properly. + RenderObject* generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); + ASSERT(generatingNode); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements. + generatedContentContainer->setNode(generatingNode); // This allows access to the generatingNode. + generatedContentContainer->setStyle(pseudoElementStyle); + if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) { + // The generated content container is not allowed here -> abort. + generatedContentContainer->destroy(); + return 0; + } + + // When we don't have a first child and are part of a continuation chain, + // insertBefore is incorrectly set to zero above, which causes the :before + // child to end up at the end of continuation chain. + // See https://bugs.webkit.org/show_bug.cgi?id=78380. + if (!insertBefore && type == BEFORE && owner->virtualContinuation()) + owner->addChildIgnoringContinuation(generatedContentContainer, 0); + else + owner->addChild(generatedContentContainer, insertBefore); + + return generatedContentContainer; +} + void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject) { // Double check that the document did in fact use generated content rules. Otherwise we should not have been called. @@ -426,41 +455,30 @@ void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, Pseudo insertBefore = insertBefore->nextSibling(); // Generated content consists of a single container that houses multiple children (specified - // by the content property). This generated content container gets the pseudo-element style set on it. + // by the content property). This generated content container gets the pseudo-element style set on it. + // For pseudo-elements that are regions, the container is the RenderRegion. RenderObject* generatedContentContainer = 0; - // Walk our list of generated content and create render objects for each. - for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { - RenderObject* renderer = createRendererForBeforeAfterContent(owner, content, pseudoElementStyle); - - if (renderer) { - if (!generatedContentContainer) { - // Make a generated box that might be any display type now that we are able to drill down into children - // to find the original content properly. - generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle); - ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements. - generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode. - generatedContentContainer->setStyle(pseudoElementStyle); - if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) { - // The generated content container is not allowed here -> abort. - generatedContentContainer->destroy(); - renderer->destroy(); - return; + if (!pseudoElementStyle->regionThread().isEmpty()) + generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore); + else { + // Walk our list of generated content and create render objects for each. + for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) { + RenderObject* renderer = createRendererForBeforeAfterContent(owner, content, pseudoElementStyle); + + if (renderer) { + if (!generatedContentContainer) { + generatedContentContainer = ensureBeforeAfterContainer(owner, type, pseudoElementStyle, styledObject->node(), insertBefore); + if (!generatedContentContainer) { + renderer->destroy(); + return; + } } - - // When we don't have a first child and are part of a continuation chain, - // insertBefore is incorrectly set to zero above, which causes the :before - // child to end up at the end of continuation chain. - // See https://bugs.webkit.org/show_bug.cgi?id=78380. - if (!insertBefore && type == BEFORE && owner->virtualContinuation()) - owner->addChildIgnoringContinuation(generatedContentContainer, 0); + if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle)) + generatedContentContainer->addChild(renderer); else - owner->addChild(generatedContentContainer, insertBefore); + renderer->destroy(); } - if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle)) - generatedContentContainer->addChild(renderer); - else - renderer->destroy(); } } diff --git a/Source/WebCore/rendering/RenderQuote.cpp b/Source/WebCore/rendering/RenderQuote.cpp index 679e55ba4..da16df5aa 100644 --- a/Source/WebCore/rendering/RenderQuote.cpp +++ b/Source/WebCore/rendering/RenderQuote.cpp @@ -22,6 +22,7 @@ #include "config.h" #include "RenderQuote.h" +#include "RenderView.h" #include <wtf/text/AtomicString.h> #define U(x) ((const UChar*)L##x) @@ -242,6 +243,11 @@ PassRefPtr<StringImpl> RenderQuote::originalText() const return StringImpl::empty(); } +void RenderQuote::updateText() +{ + computePreferredLogicalWidths(0); +} + void RenderQuote::computePreferredLogicalWidths(float lead) { if (!m_attached) diff --git a/Source/WebCore/rendering/RenderQuote.h b/Source/WebCore/rendering/RenderQuote.h index 7917fc12b..947f3a6f5 100644 --- a/Source/WebCore/rendering/RenderQuote.h +++ b/Source/WebCore/rendering/RenderQuote.h @@ -22,7 +22,6 @@ #ifndef RenderQuote_h #define RenderQuote_h -#include "Document.h" #include "QuotesData.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" @@ -30,6 +29,8 @@ namespace WebCore { +class Document; + class RenderQuote : public RenderText { public: RenderQuote(Document*, const QuoteType); @@ -42,6 +43,8 @@ private: virtual const char* renderName() const OVERRIDE { return "RenderQuote"; }; virtual bool isQuote() const OVERRIDE { return true; }; virtual PassRefPtr<StringImpl> originalText() const OVERRIDE; + + virtual void updateText() OVERRIDE; virtual void computePreferredLogicalWidths(float leadWidth) OVERRIDE; // We don't override insertedIntoTree to call attachQuote() as it would be attached diff --git a/Source/WebCore/rendering/RenderRegion.cpp b/Source/WebCore/rendering/RenderRegion.cpp index dbdbe83f7..80c848bf4 100644 --- a/Source/WebCore/rendering/RenderRegion.cpp +++ b/Source/WebCore/rendering/RenderRegion.cpp @@ -52,25 +52,35 @@ RenderRegion::RenderRegion(Node* node, RenderFlowThread* flowThread) { } -LayoutUnit RenderRegion::logicalWidthForFlowThreadContent() const +LayoutUnit RenderRegion::pageLogicalWidth() const { return m_flowThread->isHorizontalWritingMode() ? contentWidth() : contentHeight(); } -LayoutUnit RenderRegion::logicalHeightForFlowThreadContent() const +LayoutUnit RenderRegion::pageLogicalHeight() const { return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth(); } -LayoutRect RenderRegion::regionOversetRect() const +LayoutUnit RenderRegion::logicalHeightOfAllFlowThreadContent() const +{ + return m_flowThread->isHorizontalWritingMode() ? contentHeight() : contentWidth(); +} + +LayoutRect RenderRegion::flowThreadPortionOverflowRect() const +{ + return overflowRectForFlowThreadPortion(flowThreadPortionRect(), isFirstRegion(), isLastRegion()); +} + +LayoutRect RenderRegion::overflowRectForFlowThreadPortion(LayoutRect flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const { // FIXME: Would like to just use hasOverflowClip() but we aren't a block yet. When RenderRegion is eliminated and // folded into RenderBlock, switch to hasOverflowClip(). bool clipX = style()->overflowX() != OVISIBLE; bool clipY = style()->overflowY() != OVISIBLE; - bool isLastRegionWithRegionOverflowBreak = (isLastRegion() && (style()->regionOverflow() == BreakRegionOverflow)); + bool isLastRegionWithRegionOverflowBreak = (isLastPortion && (style()->regionOverflow() == BreakRegionOverflow)); if ((clipX && clipY) || !isValid() || !m_flowThread || isLastRegionWithRegionOverflowBreak) - return regionRect(); + return flowThreadPortionRect; LayoutRect flowThreadOverflow = m_flowThread->visualOverflowRect(); @@ -78,22 +88,27 @@ LayoutRect RenderRegion::regionOversetRect() const LayoutUnit outlineSize = maximalOutlineSize(PaintPhaseOutline); LayoutRect clipRect; if (m_flowThread->isHorizontalWritingMode()) { - LayoutUnit minY = isFirstRegion() ? (flowThreadOverflow.y() - outlineSize) : regionRect().y(); - LayoutUnit maxY = isLastRegion() ? max(regionRect().maxY(), flowThreadOverflow.maxY()) + outlineSize : regionRect().maxY(); - LayoutUnit minX = clipX ? regionRect().x() : (flowThreadOverflow.x() - outlineSize); - LayoutUnit maxX = clipX ? regionRect().maxX() : (flowThreadOverflow.maxX() + outlineSize); + LayoutUnit minY = isFirstPortion ? (flowThreadOverflow.y() - outlineSize) : flowThreadPortionRect.y(); + LayoutUnit maxY = isLastPortion ? max(flowThreadPortionRect.maxY(), flowThreadOverflow.maxY()) + outlineSize : flowThreadPortionRect.maxY(); + LayoutUnit minX = clipX ? flowThreadPortionRect.x() : (flowThreadOverflow.x() - outlineSize); + LayoutUnit maxX = clipX ? flowThreadPortionRect.maxX() : (flowThreadOverflow.maxX() + outlineSize); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } else { - LayoutUnit minX = isFirstRegion() ? (flowThreadOverflow.x() - outlineSize) : regionRect().x(); - LayoutUnit maxX = isLastRegion() ? max(regionRect().maxX(), flowThreadOverflow.maxX()) + outlineSize : regionRect().maxX(); - LayoutUnit minY = clipY ? regionRect().y() : (flowThreadOverflow.y() - outlineSize); - LayoutUnit maxY = clipY ? regionRect().maxY() : (flowThreadOverflow.maxY() + outlineSize); + LayoutUnit minX = isFirstPortion ? (flowThreadOverflow.x() - outlineSize) : flowThreadPortionRect.x(); + LayoutUnit maxX = isLastPortion ? max(flowThreadPortionRect.maxX(), flowThreadOverflow.maxX()) + outlineSize : flowThreadPortionRect.maxX(); + LayoutUnit minY = clipY ? flowThreadPortionRect.y() : (flowThreadOverflow.y() - outlineSize); + LayoutUnit maxY = clipY ? flowThreadPortionRect.maxY() : (flowThreadOverflow.maxY() + outlineSize); clipRect = LayoutRect(minX, minY, maxX - minX, maxY - minY); } return clipRect; } +LayoutUnit RenderRegion::pageLogicalTopForOffset(LayoutUnit /* offset */) const +{ + return flowThread()->isHorizontalWritingMode() ? flowThreadPortionRect().y() : flowThreadPortionRect().x(); +} + bool RenderRegion::isFirstRegion() const { ASSERT(isValid() && m_flowThread); @@ -113,12 +128,12 @@ void RenderRegion::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintO return; setRegionObjectsRegionStyle(); - m_flowThread->paintIntoRegion(paintInfo, this, LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); + m_flowThread->paintFlowThreadPortionInRegion(paintInfo, this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), LayoutPoint(paintOffset.x() + borderLeft() + paddingLeft(), paintOffset.y() + borderTop() + paddingTop())); restoreRegionObjectsOriginalStyle(); } // Hit Testing -bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { if (!isValid()) return false; @@ -127,14 +142,15 @@ bool RenderRegion::nodeAtPoint(const HitTestRequest& request, HitTestResult& res // Check our bounds next. For this purpose always assume that we can only be hit in the // foreground phase (which is true for replaced elements like images). - LayoutRect boundsRect = borderBoxRectInRegion(pointInContainer.region()); + // FIXME: Once we support overflow, we need to intersect with that and not with the bounds rect. + LayoutRect boundsRect = borderBoxRectInRegion(locationInContainer.region()); boundsRect.moveBy(adjustedLocation); - if (visibleToHitTesting() && action == HitTestForeground && pointInContainer.intersects(boundsRect)) { + if (visibleToHitTesting() && action == HitTestForeground && locationInContainer.intersects(boundsRect)) { // Check the contents of the RenderFlowThread. - if (m_flowThread && m_flowThread->hitTestRegion(this, request, result, pointInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop()))) + if (m_flowThread && m_flowThread->hitTestFlowThreadPortionInRegion(this, flowThreadPortionRect(), flowThreadPortionOverflowRect(), request, result, locationInContainer, LayoutPoint(adjustedLocation.x() + borderLeft() + paddingLeft(), adjustedLocation.y() + borderTop() + paddingTop()))) return true; - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(adjustedLocation)); - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation)); + if (!result.addNodeToRectBasedTestResult(generatingNode(), request, locationInContainer, boundsRect)) return true; } @@ -145,6 +161,8 @@ void RenderRegion::checkRegionStyle() { ASSERT(m_flowThread); bool customRegionStyle = false; + + // FIXME: Region styling doesn't work for pseudo elements. if (node()) { Element* regionElement = static_cast<Element*>(node()); customRegionStyle = view()->document()->styleResolver()->checkRegionStyle(regionElement); @@ -172,10 +190,10 @@ void RenderRegion::layout() { RenderReplaced::layout(); if (m_flowThread && isValid()) { - LayoutRect oldRegionRect(regionRect()); + LayoutRect oldRegionRect(flowThreadPortionRect()); if (!isHorizontalWritingMode()) oldRegionRect = oldRegionRect.transposedRect(); - if (oldRegionRect.width() != logicalWidthForFlowThreadContent() || oldRegionRect.height() != logicalHeightForFlowThreadContent()) + if (oldRegionRect.width() != pageLogicalWidth() || oldRegionRect.height() != pageLogicalHeight()) m_flowThread->invalidateRegions(); } @@ -191,6 +209,34 @@ void RenderRegion::layout() // We'll need to expand RenderBoxRegionInfo to also hold left and right overflow values. } +void RenderRegion::repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const +{ + repaintFlowThreadContentRectangle(repaintRect, immediate, flowThreadPortionRect(), flowThreadPortionOverflowRect(), contentBoxRect().location()); +} + +void RenderRegion::repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, bool immediate, const LayoutRect& flowThreadPortionRect, const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const +{ + // We only have to issue a repaint in this region if the region rect intersects the repaint rect. + LayoutRect flippedFlowThreadPortionRect(flowThreadPortionRect); + LayoutRect flippedFlowThreadPortionOverflowRect(flowThreadPortionOverflowRect); + flowThread()->flipForWritingMode(flippedFlowThreadPortionRect); // Put the region rects into physical coordinates. + flowThread()->flipForWritingMode(flippedFlowThreadPortionOverflowRect); + + LayoutRect clippedRect(repaintRect); + clippedRect.intersect(flippedFlowThreadPortionOverflowRect); + if (clippedRect.isEmpty()) + return; + + // Put the region rect into the region's physical coordinate space. + clippedRect.setLocation(regionLocation + (clippedRect.location() - flippedFlowThreadPortionRect.location())); + + // Now switch to the region's writing mode coordinate space and let it repaint itself. + flipForWritingMode(clippedRect); + + // Issue the repaint. + repaintRectangle(clippedRect, immediate); +} + void RenderRegion::installFlowThread() { ASSERT(view()); @@ -287,8 +333,8 @@ LayoutUnit RenderRegion::offsetFromLogicalTopOfFirstPage() const if (!m_isValid || !m_flowThread) return 0; if (m_flowThread->isHorizontalWritingMode()) - return regionRect().y(); - return regionRect().x(); + return flowThreadPortionRect().y(); + return flowThreadPortionRect().x(); } void RenderRegion::setRegionObjectsRegionStyle() @@ -383,6 +429,7 @@ PassRefPtr<RenderStyle> RenderRegion::computeStyleInRegion(const RenderObject* o ASSERT(!object->isAnonymous()); ASSERT(object->node() && object->node()->isElementNode()); + // FIXME: Region styling fails for pseudo-elements because the renderers don't have a node. Element* element = toElement(object->node()); RefPtr<RenderStyle> renderObjectRegionStyle = object->view()->document()->styleResolver()->styleForElement(element, 0, DisallowStyleSharing, MatchAllRules, this); diff --git a/Source/WebCore/rendering/RenderRegion.h b/Source/WebCore/rendering/RenderRegion.h index 5f22a75a7..7c9b87fc0 100644 --- a/Source/WebCore/rendering/RenderRegion.h +++ b/Source/WebCore/rendering/RenderRegion.h @@ -47,13 +47,13 @@ public: virtual bool isRenderRegion() const { return true; } virtual void paintReplaced(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); - void setRegionRect(const LayoutRect& rect) { m_regionRect = rect; } - LayoutRect regionRect() const { return m_regionRect; } - LayoutRect regionOversetRect() const; + void setFlowThreadPortionRect(const LayoutRect& rect) { m_flowThreadPortionRect = rect; } + LayoutRect flowThreadPortionRect() const { return m_flowThreadPortionRect; } + LayoutRect flowThreadPortionOverflowRect() const; void attachRegion(); void detachRegion(); @@ -95,13 +95,37 @@ public: RegionState regionState() const { return isValid() ? m_regionState : RegionUndefined; } void setRegionState(RegionState regionState) { m_regionState = regionState; } - virtual LayoutUnit logicalWidthForFlowThreadContent() const; - virtual LayoutUnit logicalHeightForFlowThreadContent() const; + // These methods represent the width and height of a "page" and for a RenderRegion they are just the + // content width and content height of a region. For RenderRegionSets, however, they will be the width and + // height of a single column or page in the set. + virtual LayoutUnit pageLogicalWidth() const; + virtual LayoutUnit pageLogicalHeight() const; + + // This method represents the logical height of the entire flow thread portion used by the region or set. + // For RenderRegions it matches logicalPaginationHeight(), but for sets it is the height of all the pages + // or columns added together. + virtual LayoutUnit logicalHeightOfAllFlowThreadContent() const; + + // The top of the nearest page inside the region. For RenderRegions, this is just the logical top of the + // flow thread portion we contain. For sets, we have to figure out the top of the nearest column or + // page. + virtual LayoutUnit pageLogicalTopForOffset(LayoutUnit offset) const; + + virtual void expandToEncompassFlowThreadContentsIfNeeded() {}; + + // Whether or not this region is a set. + virtual bool isRenderRegionSet() const { return false; } + + virtual void repaintFlowThreadContent(const LayoutRect& repaintRect, bool immediate) const; protected: void setRegionObjectsRegionStyle(); void restoreRegionObjectsOriginalStyle(); - + + LayoutRect overflowRectForFlowThreadPortion(LayoutRect flowThreadPortionRect, bool isFirstPortion, bool isLastPortion) const; + void repaintFlowThreadContentRectangle(const LayoutRect& repaintRect, bool immediate, const LayoutRect& flowThreadPortionRect, + const LayoutRect& flowThreadPortionOverflowRect, const LayoutPoint& regionLocation) const; + private: virtual const char* renderName() const { return "RenderRegion"; } @@ -125,7 +149,7 @@ private: // we need to create a dependency tree, so that layout of the // regions is always done before the regions themselves. RenderNamedFlowThread* m_parentNamedFlowThread; - LayoutRect m_regionRect; + LayoutRect m_flowThreadPortionRect; // This map holds unique information about a block that is split across regions. // A RenderBoxRegionInfo* tells us about any layout information for a RenderBox that diff --git a/Source/WebCore/rendering/RenderRegionSet.cpp b/Source/WebCore/rendering/RenderRegionSet.cpp index e9dca62a3..25b5cfa9c 100644 --- a/Source/WebCore/rendering/RenderRegionSet.cpp +++ b/Source/WebCore/rendering/RenderRegionSet.cpp @@ -26,6 +26,8 @@ #include "config.h" #include "RenderRegionSet.h" +#include "RenderFlowThread.h" + namespace WebCore { RenderRegionSet::RenderRegionSet(Node* node, RenderFlowThread* flowThread) @@ -39,4 +41,23 @@ void RenderRegionSet::installFlowThread() // in the constructor. } +void RenderRegionSet::expandToEncompassFlowThreadContentsIfNeeded() +{ + // Whenever the last region is a set, it always expands its region rect to consume all + // of the flow thread content. This is because it is always capable of generating an + // infinite number of boxes in order to hold all of the remaining content. + LayoutRect rect(flowThreadPortionRect()); + + // Get the offset within the flow thread in its block progression direction. Then get the + // flow thread's remaining logical height including its overflow and expand our rect + // to encompass that remaining height and overflow. The idea is that we will generate + // additional columns and pages to hold that overflow, since people do write bad + // content like <body style="height:0px"> in multi-column layouts. + bool isHorizontal = flowThread()->isHorizontalWritingMode(); + LayoutUnit logicalTopOffset = isHorizontal ? rect.y() : rect.x(); + LayoutRect layoutRect = flowThread()->layoutOverflowRect(); + LayoutUnit logicalHeightWithOverflow = (isHorizontal ? layoutRect.maxY() : layoutRect.maxX()) - logicalTopOffset; + setFlowThreadPortionRect(LayoutRect(rect.x(), rect.y(), isHorizontal ? rect.width() : logicalHeightWithOverflow, isHorizontal ? logicalHeightWithOverflow : rect.height())); +} + } diff --git a/Source/WebCore/rendering/RenderRegionSet.h b/Source/WebCore/rendering/RenderRegionSet.h index 3771f004e..e91eceecc 100644 --- a/Source/WebCore/rendering/RenderRegionSet.h +++ b/Source/WebCore/rendering/RenderRegionSet.h @@ -52,7 +52,11 @@ public: private: virtual void installFlowThread() OVERRIDE; + virtual void expandToEncompassFlowThreadContentsIfNeeded() OVERRIDE; + virtual const char* renderName() const = 0; + + virtual bool isRenderRegionSet() const OVERRIDE { return true; } }; } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderScrollbar.h b/Source/WebCore/rendering/RenderScrollbar.h index 61d980347..918eee0a9 100644 --- a/Source/WebCore/rendering/RenderScrollbar.h +++ b/Source/WebCore/rendering/RenderScrollbar.h @@ -26,7 +26,6 @@ #ifndef RenderScrollbar_h #define RenderScrollbar_h -#include "Node.h" #include "RenderStyleConstants.h" #include "Scrollbar.h" #include <wtf/HashMap.h> @@ -34,6 +33,7 @@ namespace WebCore { class Frame; +class Node; class RenderBox; class RenderScrollbarPart; class RenderStyle; diff --git a/Source/WebCore/rendering/RenderScrollbarPart.cpp b/Source/WebCore/rendering/RenderScrollbarPart.cpp index 3d93fe828..f2ca8c640 100644 --- a/Source/WebCore/rendering/RenderScrollbarPart.cpp +++ b/Source/WebCore/rendering/RenderScrollbarPart.cpp @@ -91,7 +91,9 @@ void RenderScrollbarPart::computeScrollbarWidth() if (!m_scrollbar->owningRenderer()) return; RenderView* renderView = view(); - int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->borderLeft() - m_scrollbar->owningRenderer()->borderRight(); + // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. + // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. + int visibleSize = m_scrollbar->owningRenderer()->width() - m_scrollbar->owningRenderer()->style()->borderLeftWidth() - m_scrollbar->owningRenderer()->style()->borderRightWidth(); int w = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->width(), visibleSize, renderView); int minWidth = calcScrollbarThicknessUsing(MinSize, style()->minWidth(), visibleSize, renderView); int maxWidth = style()->maxWidth().isUndefined() ? w : calcScrollbarThicknessUsing(MaxSize, style()->maxWidth(), visibleSize, renderView); @@ -107,7 +109,9 @@ void RenderScrollbarPart::computeScrollbarHeight() if (!m_scrollbar->owningRenderer()) return; RenderView* renderView = view(); - int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->borderTop() - m_scrollbar->owningRenderer()->borderBottom(); + // FIXME: We are querying layout information but nothing guarantees that it's up-to-date, especially since we are called at style change. + // FIXME: Querying the style's border information doesn't work on table cells with collapsing borders. + int visibleSize = m_scrollbar->owningRenderer()->height() - m_scrollbar->owningRenderer()->style()->borderTopWidth() - m_scrollbar->owningRenderer()->style()->borderBottomWidth(); int h = calcScrollbarThicknessUsing(MainOrPreferredSize, style()->height(), visibleSize, renderView); int minHeight = calcScrollbarThicknessUsing(MinSize, style()->minHeight(), visibleSize, renderView); int maxHeight = style()->maxHeight().isUndefined() ? h : calcScrollbarThicknessUsing(MaxSize, style()->maxHeight(), visibleSize, renderView); diff --git a/Source/WebCore/rendering/RenderTable.cpp b/Source/WebCore/rendering/RenderTable.cpp index b5c308373..4f25944a6 100644 --- a/Source/WebCore/rendering/RenderTable.cpp +++ b/Source/WebCore/rendering/RenderTable.cpp @@ -117,10 +117,9 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) bool wrapInAnonymousSection = !child->isOutOfFlowPositioned(); - if (child->isTableCaption()) { - m_captions.append(toRenderTableCaption(child)); + if (child->isTableCaption()) wrapInAnonymousSection = false; - } else if (child->isRenderTableCol()) { + else if (child->isRenderTableCol()) { m_hasColElements = true; wrapInAnonymousSection = false; } else if (child->isTableSection()) { @@ -197,26 +196,34 @@ void RenderTable::addChild(RenderObject* child, RenderObject* beforeChild) section->addChild(child); } +void RenderTable::addCaption(const RenderTableCaption* caption) +{ + ASSERT(m_captions.find(caption) == notFound); + m_captions.append(const_cast<RenderTableCaption*>(caption)); +} + void RenderTable::removeCaption(const RenderTableCaption* oldCaption) { size_t index = m_captions.find(oldCaption); ASSERT(index != notFound); - m_captions.remove(index); - - // FIXME: The rest of this function is probably not needed since we have - // implemented proper multiple captions support (see bug 58249). - if (node()) - node()->setNeedsStyleRecalc(); + if (index == notFound) + return; - setNeedsSectionRecalc(); + m_captions.remove(index); } void RenderTable::computeLogicalWidth() { recalcSectionsIfNeeded(); - if (isOutOfFlowPositioned()) - computePositionedLogicalWidth(); + if (isOutOfFlowPositioned()) { + LogicalExtentComputedValues computedValues; + computePositionedLogicalWidth(computedValues); + setLogicalWidth(computedValues.m_extent); + setLogicalLeft(computedValues.m_position); + setMarginStart(computedValues.m_margins.m_start); + setMarginEnd(computedValues.m_margins.m_end); + } RenderBlock* cb = containingBlock(); RenderView* renderView = view(); @@ -260,7 +267,13 @@ void RenderTable::computeLogicalWidth() LayoutUnit containerLogicalWidthForAutoMargins = availableLogicalWidth; if (avoidsFloats() && cb->containsFloats()) containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(0, 0); // FIXME: Work with regions someday. - computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth()); + ComputedMarginValues marginValues; + bool hasInvertedDirection = cb->style()->isLeftToRightDirection() == style()->isLeftToRightDirection(); + computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, logicalWidth(), + hasInvertedDirection ? marginValues.m_start : marginValues.m_end, + hasInvertedDirection ? marginValues.m_end : marginValues.m_start); + setMarginStart(marginValues.m_start); + setMarginEnd(marginValues.m_end); } else { setMarginStart(minimumValueForLength(style()->marginStart(), availableLogicalWidth, renderView)); setMarginEnd(minimumValueForLength(style()->marginEnd(), availableLogicalWidth, renderView)); @@ -776,17 +789,12 @@ void RenderTable::recalcSections() const m_foot = 0; m_firstBody = 0; m_hasColElements = false; - m_captions.clear(); // We need to get valid pointers to caption, head, foot and first body again RenderObject* nextSibling; for (RenderObject* child = firstChild(); child; child = nextSibling) { nextSibling = child->nextSibling(); switch (child->style()->display()) { - case TABLE_CAPTION: - if (child->isTableCaption()) - m_captions.append(toRenderTableCaption(child)); - break; case TABLE_COLUMN: case TABLE_COLUMN_GROUP: m_hasColElements = true; @@ -1269,17 +1277,17 @@ LayoutRect RenderTable::overflowClipRect(const LayoutPoint& location, RenderRegi return rect; } -bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { LayoutPoint adjustedLocation = accumulatedOffset + location(); // Check kids first. - if (!hasOverflowClip() || pointInContainer.intersects(overflowClipRect(adjustedLocation, pointInContainer.region()))) { + if (!hasOverflowClip() || locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) { for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer() && (child->isTableSection() || child->isTableCaption())) { LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation); - if (child->nodeAtPoint(request, result, pointInContainer, childPoint, action)) { - updateHitTestResult(result, toLayoutPoint(pointInContainer.point() - childPoint)); + if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) { + updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint)); return true; } } @@ -1288,9 +1296,9 @@ bool RenderTable::nodeAtPoint(const HitTestRequest& request, HitTestResult& resu // Check our bounds next. LayoutRect boundsRect(adjustedLocation, size()); - if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && pointInContainer.intersects(boundsRect)) { - updateHitTestResult(result, flipForWritingMode(pointInContainer.point() - toLayoutSize(adjustedLocation))); - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) + if (visibleToHitTesting() && (action == HitTestBlockBackground || action == HitTestChildBlockBackground) && locationInContainer.intersects(boundsRect)) { + updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - toLayoutSize(adjustedLocation))); + if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect)) return true; } diff --git a/Source/WebCore/rendering/RenderTable.h b/Source/WebCore/rendering/RenderTable.h index bbafdb716..46073c539 100644 --- a/Source/WebCore/rendering/RenderTable.h +++ b/Source/WebCore/rendering/RenderTable.h @@ -231,6 +231,7 @@ public: const BorderValue& tableStartBorderAdjoiningCell(const RenderTableCell*) const; const BorderValue& tableEndBorderAdjoiningCell(const RenderTableCell*) const; + void addCaption(const RenderTableCaption*); void removeCaption(const RenderTableCaption*); protected: @@ -249,7 +250,7 @@ private: virtual void paintMask(PaintInfo&, const LayoutPoint&); virtual void layout(); virtual void computePreferredLogicalWidths(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual LayoutUnit baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const OVERRIDE; virtual LayoutUnit firstLineBoxBaseline() const OVERRIDE; @@ -260,7 +261,7 @@ private: virtual void setCellLogicalWidths(); - virtual void computeLogicalWidth(); + virtual void computeLogicalWidth() OVERRIDE; LayoutUnit convertStyleLogicalWidthToComputedWidth(const Length& styleLogicalWidth, LayoutUnit availableWidth); diff --git a/Source/WebCore/rendering/RenderTableCaption.cpp b/Source/WebCore/rendering/RenderTableCaption.cpp index 9785f372d..df5194c97 100644 --- a/Source/WebCore/rendering/RenderTableCaption.cpp +++ b/Source/WebCore/rendering/RenderTableCaption.cpp @@ -39,6 +39,13 @@ LayoutUnit RenderTableCaption::containingBlockLogicalWidthForContent() const return cb->logicalWidth(); } +void RenderTableCaption::insertedIntoTree() +{ + RenderBlock::insertedIntoTree(); + + table()->addCaption(this); +} + void RenderTableCaption::willBeRemovedFromTree() { RenderBlock::willBeRemovedFromTree(); diff --git a/Source/WebCore/rendering/RenderTableCaption.h b/Source/WebCore/rendering/RenderTableCaption.h index b505ebe10..91edb9f6e 100644 --- a/Source/WebCore/rendering/RenderTableCaption.h +++ b/Source/WebCore/rendering/RenderTableCaption.h @@ -35,6 +35,7 @@ public: private: virtual bool isTableCaption() const OVERRIDE { return true; } + virtual void insertedIntoTree() OVERRIDE; virtual void willBeRemovedFromTree() OVERRIDE; RenderTable* table() const; diff --git a/Source/WebCore/rendering/RenderTableCell.cpp b/Source/WebCore/rendering/RenderTableCell.cpp index 0cefc75a8..05d0ad19a 100644 --- a/Source/WebCore/rendering/RenderTableCell.cpp +++ b/Source/WebCore/rendering/RenderTableCell.cpp @@ -52,16 +52,12 @@ RenderTableCell::RenderTableCell(Node* node) { } -void RenderTableCell::willBeDestroyed() +void RenderTableCell::willBeRemovedFromTree() { - RenderTableSection* recalcSection = parent() ? section() : 0; + RenderBlock::willBeRemovedFromTree(); - RenderBlock::willBeDestroyed(); - - if (recalcSection) { - recalcSection->setNeedsCellRecalc(); - recalcSection->removeCachedCollapsedBorders(this); - } + section()->setNeedsCellRecalc(); + section()->removeCachedCollapsedBorders(this); } unsigned RenderTableCell::colSpan() const diff --git a/Source/WebCore/rendering/RenderTableCell.h b/Source/WebCore/rendering/RenderTableCell.h index 5d5b2764b..31ea56f59 100644 --- a/Source/WebCore/rendering/RenderTableCell.h +++ b/Source/WebCore/rendering/RenderTableCell.h @@ -173,9 +173,9 @@ private: virtual bool isTableCell() const { return true; } - virtual void willBeDestroyed(); + virtual void willBeRemovedFromTree() OVERRIDE; - virtual void computeLogicalWidth(); + virtual void computeLogicalWidth() OVERRIDE; virtual void paintBoxDecorations(PaintInfo&, const LayoutPoint&); virtual void paintMask(PaintInfo&, const LayoutPoint&); diff --git a/Source/WebCore/rendering/RenderTableRow.cpp b/Source/WebCore/rendering/RenderTableRow.cpp index 7dc05fa56..2b83faa5a 100644 --- a/Source/WebCore/rendering/RenderTableRow.cpp +++ b/Source/WebCore/rendering/RenderTableRow.cpp @@ -46,14 +46,11 @@ RenderTableRow::RenderTableRow(Node* node) setInline(false); // our object is not Inline } -void RenderTableRow::willBeDestroyed() +void RenderTableRow::willBeRemovedFromTree() { - RenderTableSection* recalcSection = section(); - - RenderBox::willBeDestroyed(); - - if (recalcSection) - recalcSection->setNeedsCellRecalc(); + RenderBox::willBeRemovedFromTree(); + + section()->setNeedsCellRecalc(); } void RenderTableRow::updateBeforeAndAfterContent() @@ -154,7 +151,7 @@ void RenderTableRow::layout() cell->setChildNeedsLayout(true, MarkOnlyThis); if (child->needsLayout()) { - cell->computeBlockDirectionMargins(table()); + cell->computeAndSetBlockDirectionMargins(table()); cell->layout(); } } @@ -195,7 +192,7 @@ LayoutRect RenderTableRow::clippedOverflowRectForRepaint(RenderBoxModelObject* r } // Hit Testing -bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { // Table rows cannot ever be hit tested. Effectively they do not exist. // Just forward to our children always. @@ -206,8 +203,8 @@ bool RenderTableRow::nodeAtPoint(const HitTestRequest& request, HitTestResult& r // then we can remove this check. if (child->isTableCell() && !toRenderBox(child)->hasSelfPaintingLayer()) { LayoutPoint cellPoint = flipForWritingModeForChild(toRenderTableCell(child), accumulatedOffset); - if (child->nodeAtPoint(request, result, pointInContainer, cellPoint, action)) { - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(cellPoint)); + if (child->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) { + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint)); return true; } } diff --git a/Source/WebCore/rendering/RenderTableRow.h b/Source/WebCore/rendering/RenderTableRow.h index afa838c12..0136c58a2 100644 --- a/Source/WebCore/rendering/RenderTableRow.h +++ b/Source/WebCore/rendering/RenderTableRow.h @@ -90,14 +90,14 @@ private: virtual bool isTableRow() const { return true; } - virtual void willBeDestroyed(); + virtual void willBeRemovedFromTree() OVERRIDE; virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); virtual void layout(); virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; - virtual bool requiresLayer() const OVERRIDE { return isTransparent() || hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasMask() || hasFilter(); } + virtual bool requiresLayer() const OVERRIDE { return hasOverflowClip() || hasTransform() || hasHiddenBackface() || hasClipPath() || createsGroup(); } virtual void paint(PaintInfo&, const LayoutPoint&); diff --git a/Source/WebCore/rendering/RenderTableSection.cpp b/Source/WebCore/rendering/RenderTableSection.cpp index a906a2ef8..62379085d 100644 --- a/Source/WebCore/rendering/RenderTableSection.cpp +++ b/Source/WebCore/rendering/RenderTableSection.cpp @@ -189,12 +189,6 @@ void RenderTableSection::addChild(RenderObject* child, RenderObject* beforeChild toRenderTableRow(child)->updateBeforeAndAfterContent(); } -void RenderTableSection::removeChild(RenderObject* oldChild) -{ - setNeedsCellRecalc(); - RenderBox::removeChild(oldChild); -} - void RenderTableSection::ensureRows(unsigned numRows) { if (numRows <= m_grid.size()) @@ -585,9 +579,9 @@ void RenderTableSection::layoutRows() } } - if (ListHashSet<RenderBox*>* percentHeightDescendants = cell->percentHeightDescendants()) { - ListHashSet<RenderBox*>::iterator end = percentHeightDescendants->end(); - for (ListHashSet<RenderBox*>::iterator it = percentHeightDescendants->begin(); it != end; ++it) { + if (TrackedRendererListHashSet* percentHeightDescendants = cell->percentHeightDescendants()) { + TrackedRendererListHashSet::iterator end = percentHeightDescendants->end(); + for (TrackedRendererListHashSet::iterator it = percentHeightDescendants->begin(); it != end; ++it) { RenderBox* box = *it; if (!box->isReplaced() && !box->scrollsOverflow() && !flexAllChildren) continue; @@ -1369,7 +1363,7 @@ void RenderTableSection::splitColumn(unsigned pos, unsigned first) } // Hit Testing -bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { // If we have no children then we have nothing to do. if (!firstChild()) @@ -1379,7 +1373,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul // Just forward to our children always. LayoutPoint adjustedLocation = accumulatedOffset + location(); - if (hasOverflowClip() && !pointInContainer.intersects(overflowClipRect(adjustedLocation, pointInContainer.region()))) + if (hasOverflowClip() && !locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region()))) return false; if (hasOverflowingCell()) { @@ -1390,8 +1384,8 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul // then we can remove this check. if (child->isBox() && !toRenderBox(child)->hasSelfPaintingLayer()) { LayoutPoint childPoint = flipForWritingModeForChild(toRenderBox(child), adjustedLocation); - if (child->nodeAtPoint(request, result, pointInContainer, childPoint, action)) { - updateHitTestResult(result, toLayoutPoint(pointInContainer.point() - childPoint)); + if (child->nodeAtPoint(request, result, locationInContainer, childPoint, action)) { + updateHitTestResult(result, toLayoutPoint(locationInContainer.point() - childPoint)); return true; } } @@ -1401,7 +1395,7 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul recalcCellsIfNeeded(); - LayoutRect hitTestRect = pointInContainer.boundingBox(); + LayoutRect hitTestRect = locationInContainer.boundingBox(); hitTestRect.moveBy(-adjustedLocation); LayoutRect tableAlignedRect = logicalRectForWritingModeAndDirection(hitTestRect); @@ -1421,8 +1415,8 @@ bool RenderTableSection::nodeAtPoint(const HitTestRequest& request, HitTestResul --i; RenderTableCell* cell = current.cells[i]; LayoutPoint cellPoint = flipForWritingModeForChild(cell, adjustedLocation); - if (static_cast<RenderObject*>(cell)->nodeAtPoint(request, result, pointInContainer, cellPoint, action)) { - updateHitTestResult(result, pointInContainer.point() - toLayoutSize(cellPoint)); + if (static_cast<RenderObject*>(cell)->nodeAtPoint(request, result, locationInContainer, cellPoint, action)) { + updateHitTestResult(result, locationInContainer.point() - toLayoutSize(cellPoint)); return true; } } diff --git a/Source/WebCore/rendering/RenderTableSection.h b/Source/WebCore/rendering/RenderTableSection.h index 89bff39a0..7054938e9 100644 --- a/Source/WebCore/rendering/RenderTableSection.h +++ b/Source/WebCore/rendering/RenderTableSection.h @@ -210,14 +210,12 @@ private: virtual void layout(); - virtual void removeChild(RenderObject* oldChild); - virtual void paintCell(RenderTableCell*, PaintInfo&, const LayoutPoint&); virtual void paintObject(PaintInfo&, const LayoutPoint&); virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; void ensureRows(unsigned); diff --git a/Source/WebCore/rendering/RenderText.cpp b/Source/WebCore/rendering/RenderText.cpp index 73e57754a..82b956993 100644 --- a/Source/WebCore/rendering/RenderText.cpp +++ b/Source/WebCore/rendering/RenderText.cpp @@ -1879,7 +1879,7 @@ int RenderText::nextOffset(int current) const bool RenderText::computeCanUseSimpleFontCodePath() const { - if (isAllASCII()) + if (isAllASCII() || m_text.is8Bit()) return true; return Font::characterRangeCodePath(characters(), length()) == Font::Simple; } diff --git a/Source/WebCore/rendering/RenderText.h b/Source/WebCore/rendering/RenderText.h index b96eca73f..6fc4c67a7 100644 --- a/Source/WebCore/rendering/RenderText.h +++ b/Source/WebCore/rendering/RenderText.h @@ -45,6 +45,12 @@ public: virtual PassRefPtr<StringImpl> originalText() const; + void updateTextIfNeeded() + { + if (preferredLogicalWidthsDirty()) + updateText(); + } + void extractTextBox(InlineTextBox*); void attachTextBox(InlineTextBox*); void removeTextBox(InlineTextBox*); @@ -139,6 +145,7 @@ protected: virtual void styleWillChange(StyleDifference, const RenderStyle*) { } virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + virtual void updateText() { } virtual void setTextInternal(PassRefPtr<StringImpl>); virtual UChar previousCharacter() const; @@ -156,7 +163,7 @@ private: virtual void paint(PaintInfo&, const LayoutPoint&) { ASSERT_NOT_REACHED(); } virtual void layout() { ASSERT_NOT_REACHED(); } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, HitTestAction) OVERRIDE { ASSERT_NOT_REACHED(); return false; } + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) OVERRIDE { ASSERT_NOT_REACHED(); return false; } void deleteTextBoxes(); bool containsOnlyWhitespace(unsigned from, unsigned len) const; diff --git a/Source/WebCore/rendering/RenderTextControl.cpp b/Source/WebCore/rendering/RenderTextControl.cpp index 3bc25b897..cb7637db3 100644 --- a/Source/WebCore/rendering/RenderTextControl.cpp +++ b/Source/WebCore/rendering/RenderTextControl.cpp @@ -110,13 +110,18 @@ int RenderTextControl::textBlockWidth() const { Element* innerText = innerTextElement(); ASSERT(innerText); - return width() - borderAndPaddingWidth() - innerText->renderBox()->paddingLeft() - innerText->renderBox()->paddingRight(); + + LayoutUnit unitWidth = width() - borderAndPaddingWidth(); + if (innerText->renderer()) + unitWidth -= innerText->renderBox()->paddingLeft() + innerText->renderBox()->paddingRight(); + + return unitWidth; } void RenderTextControl::updateFromElement() { Element* innerText = innerTextElement(); - if (innerText) + if (innerText && innerText->renderer()) updateUserModifyProperty(node(), innerText->renderer()->style()); } @@ -143,13 +148,14 @@ void RenderTextControl::computeLogicalHeight() { HTMLElement* innerText = innerTextElement(); ASSERT(innerText); - RenderBox* innerTextBox = innerText->renderBox(); - LayoutUnit nonContentHeight = innerTextBox->borderAndPaddingHeight() + innerTextBox->marginHeight(); - setHeight(computeControlHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight()); + if (RenderBox* innerTextBox = innerText->renderBox()) { + LayoutUnit nonContentHeight = innerTextBox->borderAndPaddingHeight() + innerTextBox->marginHeight(); + setHeight(computeControlHeight(innerTextBox->lineHeight(true, HorizontalLine, PositionOfInteriorLineBoxes), nonContentHeight) + borderAndPaddingHeight()); - // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. - if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->wordWrap() == NormalWordWrap)) - setHeight(height() + scrollbarThickness()); + // We are able to have a horizontal scrollbar if the overflow style is scroll, or if its auto and there's no word wrap. + if (style()->overflowX() == OSCROLL || (style()->overflowX() == OAUTO && innerText->renderer()->style()->overflowWrap() == NormalOverflowWrap)) + setHeight(height() + scrollbarThickness()); + } RenderBlock::computeLogicalHeight(); } @@ -157,6 +163,9 @@ void RenderTextControl::computeLogicalHeight() void RenderTextControl::hitInnerTextElement(HitTestResult& result, const LayoutPoint& pointInContainer, const LayoutPoint& accumulatedOffset) { HTMLElement* innerText = innerTextElement(); + if (!innerText->renderer()) + return; + LayoutPoint adjustedLocation = accumulatedOffset + location(); LayoutPoint localPoint = pointInContainer - toLayoutSize(adjustedLocation + innerText->renderBox()->location()); if (hasOverflowClip()) @@ -257,8 +266,9 @@ void RenderTextControl::computePreferredLogicalWidths() else { // Use average character width. Matches IE. AtomicString family = style()->font().family().family(); - RenderBox* innerTextRenderBox = innerTextElement()->renderBox(); - m_maxPreferredLogicalWidth = preferredContentWidth(getAvgCharWidth(family)) + innerTextRenderBox->paddingLeft() + innerTextRenderBox->paddingRight(); + m_maxPreferredLogicalWidth = preferredContentWidth(getAvgCharWidth(family)); + if (RenderBox* innerTextRenderBox = innerTextElement()->renderBox()) + m_maxPreferredLogicalWidth += innerTextRenderBox->paddingLeft() + innerTextRenderBox->paddingRight(); } if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { diff --git a/Source/WebCore/rendering/RenderTextControl.h b/Source/WebCore/rendering/RenderTextControl.h index b8f1f3025..6d0e43af1 100644 --- a/Source/WebCore/rendering/RenderTextControl.h +++ b/Source/WebCore/rendering/RenderTextControl.h @@ -62,7 +62,7 @@ protected: virtual RenderStyle* textBaseStyle() const = 0; virtual void updateFromElement(); - virtual void computeLogicalHeight(); + virtual void computeLogicalHeight() OVERRIDE; virtual RenderObject* layoutSpecialExcludedChild(bool relayoutChildren); private: diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp index 96997d0ed..be91de927 100644 --- a/Source/WebCore/rendering/RenderTextControlMultiLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlMultiLine.cpp @@ -43,13 +43,13 @@ RenderTextControlMultiLine::~RenderTextControlMultiLine() static_cast<HTMLTextAreaElement*>(node())->rendererWillBeDestroyed(); } -bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderTextControlMultiLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (!RenderTextControl::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction)) + if (!RenderTextControl::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; if (result.innerNode() == node() || result.innerNode() == innerTextElement()) - hitInnerTextElement(result, pointInContainer.point(), accumulatedOffset); + hitInnerTextElement(result, locationInContainer.point(), accumulatedOffset); return true; } diff --git a/Source/WebCore/rendering/RenderTextControlMultiLine.h b/Source/WebCore/rendering/RenderTextControlMultiLine.h index 5c84a5910..a4539959a 100644 --- a/Source/WebCore/rendering/RenderTextControlMultiLine.h +++ b/Source/WebCore/rendering/RenderTextControlMultiLine.h @@ -34,7 +34,7 @@ public: private: virtual bool isTextArea() const { return true; } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual float getAvgCharWidth(AtomicString family); virtual LayoutUnit preferredContentWidth(float charWidth) const; diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp index 665af32be..1484a2786 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.cpp +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.cpp @@ -192,9 +192,9 @@ void RenderTextControlSingleLine::layout() } } -bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - if (!RenderTextControl::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, hitTestAction)) + if (!RenderTextControl::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, hitTestAction)) return false; // Say that we hit the inner text element if @@ -203,7 +203,7 @@ bool RenderTextControlSingleLine::nodeAtPoint(const HitTestRequest& request, Hit // - we hit regions not in any decoration buttons. HTMLElement* container = containerElement(); if (result.innerNode()->isDescendantOf(innerTextElement()) || result.innerNode() == node() || (container && container == result.innerNode())) { - LayoutPoint pointInParent = pointInContainer.point(); + LayoutPoint pointInParent = locationInContainer.point(); if (container && innerBlockElement()) { if (innerBlockElement()->renderBox()) pointInParent -= toLayoutSize(innerBlockElement()->renderBox()->location()); @@ -342,7 +342,7 @@ PassRefPtr<RenderStyle> RenderTextControlSingleLine::createInnerTextStyle(const adjustInnerTextStyle(startStyle, textBlockStyle.get()); textBlockStyle->setWhiteSpace(PRE); - textBlockStyle->setWordWrap(NormalWordWrap); + textBlockStyle->setOverflowWrap(NormalOverflowWrap); textBlockStyle->setOverflowX(OHIDDEN); textBlockStyle->setOverflowY(OHIDDEN); textBlockStyle->setTextOverflow(textShouldBeTruncated() ? TextOverflowEllipsis : TextOverflowClip); diff --git a/Source/WebCore/rendering/RenderTextControlSingleLine.h b/Source/WebCore/rendering/RenderTextControlSingleLine.h index c79f3dfec..af27bf758 100644 --- a/Source/WebCore/rendering/RenderTextControlSingleLine.h +++ b/Source/WebCore/rendering/RenderTextControlSingleLine.h @@ -56,7 +56,7 @@ private: virtual void paint(PaintInfo&, const LayoutPoint&); virtual void layout(); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual void autoscroll(); diff --git a/Source/WebCore/rendering/RenderTheme.cpp b/Source/WebCore/rendering/RenderTheme.cpp index 934c4b2cf..66c37ec35 100644 --- a/Source/WebCore/rendering/RenderTheme.cpp +++ b/Source/WebCore/rendering/RenderTheme.cpp @@ -1004,21 +1004,34 @@ void RenderTheme::paintSliderTicks(RenderObject* o, const PaintInfo& paintInfo, IntSize tickSize = sliderTickSize(); float zoomFactor = o->style()->effectiveZoom(); FloatRect tickRect; - int tickRegionMargin = (thumbSize.width() - tickSize.width()) / 2.0; int tickRegionSideMargin = 0; int tickRegionWidth = 0; + IntRect trackBounds; + RenderObject* trackRenderer = input->sliderTrackElement()->renderer(); + // We can ignoring transforms because transform is handled by the graphics context. + if (trackRenderer) + trackBounds = trackRenderer->absoluteBoundingBoxRectIgnoringTransforms(); + IntRect sliderBounds = o->absoluteBoundingBoxRectIgnoringTransforms(); + + // Make position relative to the transformed ancestor element. + trackBounds.setX(trackBounds.x() - sliderBounds.x() + rect.x()); + trackBounds.setY(trackBounds.y() - sliderBounds.y() + rect.y()); + if (isHorizontal) { tickRect.setWidth(floor(tickSize.width() * zoomFactor)); tickRect.setHeight(floor(tickSize.height() * zoomFactor)); tickRect.setY(floor(rect.y() + rect.height() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); - tickRegionSideMargin = rect.x() + tickRegionMargin; - tickRegionWidth = rect.width() - tickRegionMargin * 2 - tickSize.width() * zoomFactor; + if (o->style()->isLeftToRightDirection()) + tickRegionSideMargin = trackBounds.x() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; + else + tickRegionSideMargin = trackBounds.x() - thumbSize.width() / 2.0; + tickRegionWidth = trackBounds.width(); } else { tickRect.setWidth(floor(tickSize.height() * zoomFactor)); tickRect.setHeight(floor(tickSize.width() * zoomFactor)); tickRect.setX(floor(rect.x() + rect.width() / 2.0 + sliderTickOffsetFromTrackCenter() * zoomFactor)); - tickRegionSideMargin = rect.y() + tickRegionMargin; - tickRegionWidth = rect.height() - tickRegionMargin * 2 - tickSize.width() * zoomFactor; + tickRegionSideMargin = trackBounds.y() + (thumbSize.width() - tickSize.width() * zoomFactor) / 2.0; + tickRegionWidth = trackBounds.height(); } RefPtr<HTMLCollection> options = dataList->options(); GraphicsContextStateSaver stateSaver(*paintInfo.context); diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.h b/Source/WebCore/rendering/RenderThemeChromiumMac.h index 5853a0661..cfd13df60 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.h +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.h @@ -58,6 +58,7 @@ protected: virtual String formatMediaControlsCurrentTime(float currentTime, float duration) const; virtual String formatMediaControlsRemainingTime(float currentTime, float duration) const; virtual bool paintMediaFullscreenButton(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); #endif virtual bool usesTestModeFocusRingColor() const; diff --git a/Source/WebCore/rendering/RenderThemeChromiumMac.mm b/Source/WebCore/rendering/RenderThemeChromiumMac.mm index 9af2dbc4c..efb6174ec 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumMac.mm +++ b/Source/WebCore/rendering/RenderThemeChromiumMac.mm @@ -233,6 +233,11 @@ bool RenderThemeChromiumMac::paintMediaFullscreenButton(RenderObject* object, co { return RenderMediaControlsChromium::paintMediaControlsPart(MediaEnterFullscreenButton, object, paintInfo, rect); } + +bool RenderThemeChromiumMac::paintMediaToggleClosedCaptionsButton(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) +{ + return RenderMediaControlsChromium::paintMediaControlsPart(MediaShowClosedCaptionsButton, object, paintInfo, rect); +} #endif } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp index 0a58af605..a38cf1be9 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.cpp @@ -81,7 +81,7 @@ static const float defaultSearchFieldResultsButtonWidth = 18; // sizes (e.g. 15px). So, for now we just use Arial. const String& RenderThemeChromiumSkia::defaultGUIFont() { - DEFINE_STATIC_LOCAL(String, fontFace, ("Arial")); + DEFINE_STATIC_LOCAL(String, fontFace, (ASCIILiteral("Arial"))); return fontFace; } @@ -131,6 +131,13 @@ bool RenderThemeChromiumSkia::supportsDataListUI(const AtomicString& type) const return RenderThemeChromiumCommon::supportsDataListUI(type); } +#if ENABLE(VIDEO_TRACK) +bool RenderThemeChromiumSkia::supportsClosedCaptioning() const +{ + return true; +} +#endif + Color RenderThemeChromiumSkia::platformActiveSelectionBackgroundColor() const { return Color(0x1e, 0x90, 0xff); @@ -427,6 +434,18 @@ bool RenderThemeChromiumSkia::paintMediaSliderThumb(RenderObject* object, const #endif } +bool RenderThemeChromiumSkia::paintMediaToggleClosedCaptionsButton(RenderObject* o, const PaintInfo& paintInfo, const IntRect& r) +{ +#if ENABLE(VIDEO_TRACK) + return RenderMediaControlsChromium::paintMediaControlsPart(MediaShowClosedCaptionsButton, o, paintInfo, r); +#else + UNUSED_PARAM(object); + UNUSED_PARAM(paintInfo); + UNUSED_PARAM(rect); + return false; +#endif +} + bool RenderThemeChromiumSkia::paintMediaVolumeSliderThumb(RenderObject* object, const PaintInfo& paintInfo, const IntRect& rect) { #if ENABLE(VIDEO) diff --git a/Source/WebCore/rendering/RenderThemeChromiumSkia.h b/Source/WebCore/rendering/RenderThemeChromiumSkia.h index ee9b11c37..10dc70b41 100644 --- a/Source/WebCore/rendering/RenderThemeChromiumSkia.h +++ b/Source/WebCore/rendering/RenderThemeChromiumSkia.h @@ -54,6 +54,9 @@ class RenderThemeChromiumSkia : public RenderTheme { virtual bool supportsDataListUI(const AtomicString& type) const OVERRIDE; +#if ENABLE(VIDEO_TRACK) + virtual bool supportsClosedCaptioning() const OVERRIDE; +#endif // The platform selection color. virtual Color platformActiveSelectionBackgroundColor() const; virtual Color platformInactiveSelectionBackgroundColor() const; @@ -95,6 +98,7 @@ class RenderThemeChromiumSkia : public RenderTheme { virtual bool paintMediaVolumeSliderTrack(RenderObject*, const PaintInfo&, const IntRect&); virtual void adjustSliderThumbSize(RenderStyle*, Element*) const; virtual bool paintMediaSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); + virtual bool paintMediaToggleClosedCaptionsButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaVolumeSliderThumb(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaPlayButton(RenderObject*, const PaintInfo&, const IntRect&); virtual bool paintMediaMuteButton(RenderObject*, const PaintInfo&, const IntRect&); diff --git a/Source/WebCore/rendering/RenderThemeWin.cpp b/Source/WebCore/rendering/RenderThemeWin.cpp index 403dd98b1..810a1fca4 100644 --- a/Source/WebCore/rendering/RenderThemeWin.cpp +++ b/Source/WebCore/rendering/RenderThemeWin.cpp @@ -24,6 +24,7 @@ #include "CSSValueKeywords.h" #include "Element.h" +#include "FontMetrics.h" #include "Frame.h" #include "GraphicsContext.h" #include "LocalWindowsContext.h" diff --git a/Source/WebCore/rendering/RenderTreeAsText.cpp b/Source/WebCore/rendering/RenderTreeAsText.cpp index 8af6a2765..276366c0b 100644 --- a/Source/WebCore/rendering/RenderTreeAsText.cpp +++ b/Source/WebCore/rendering/RenderTreeAsText.cpp @@ -315,19 +315,16 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, if (box.borderTop() || box.borderRight() || box.borderBottom() || box.borderLeft()) { ts << " [border:"; - BorderValue prevBorder; - if (o.style()->borderTop() != prevBorder) { - prevBorder = o.style()->borderTop(); - if (!box.borderTop()) - ts << " none"; - else { - ts << " (" << box.borderTop() << "px "; - printBorderStyle(ts, o.style()->borderTopStyle()); - Color col = o.style()->borderTopColor(); - if (!col.isValid()) - col = o.style()->color(); - ts << col.nameForRenderTreeAsText() << ")"; - } + BorderValue prevBorder = o.style()->borderTop(); + if (!box.borderTop()) + ts << " none"; + else { + ts << " (" << box.borderTop() << "px "; + printBorderStyle(ts, o.style()->borderTopStyle()); + Color col = o.style()->borderTopColor(); + if (!col.isValid()) + col = o.style()->color(); + ts << col.nameForRenderTreeAsText() << ")"; } if (o.style()->borderRight() != prevBorder) { @@ -448,14 +445,14 @@ void RenderTreeAsText::writeRenderObject(TextStream& ts, const RenderObject& o, ts << " id=\"" + static_cast<Element*>(node)->getIdAttribute() + "\""; if (node->hasClass()) { + ts << " class=\""; StyledElement* styledElement = static_cast<StyledElement*>(node); - String classes; for (size_t i = 0; i < styledElement->classNames().size(); ++i) { if (i > 0) - classes += " "; - classes += styledElement->classNames()[i]; + ts << " "; + ts << styledElement->classNames()[i]; } - ts << " class=\"" + classes + "\""; + ts << "\""; } } } @@ -702,12 +699,12 @@ static void writeRenderNamedFlowThreads(TextStream& ts, RenderView* renderView, RenderRegion* renderRegion = *itRR; writeIndent(ts, indent + 2); ts << "RenderRegion"; - if (renderRegion->node()) { - String tagName = getTagName(renderRegion->node()); + if (renderRegion->generatingNode()) { + String tagName = getTagName(renderRegion->generatingNode()); if (!tagName.isEmpty()) ts << " {" << tagName << "}"; - if (renderRegion->node()->isElementNode() && renderRegion->node()->hasID()) { - Element* element = static_cast<Element*>(renderRegion->node()); + if (renderRegion->generatingNode()->isElementNode() && renderRegion->generatingNode()->hasID()) { + Element* element = static_cast<Element*>(renderRegion->generatingNode()); ts << " #" << element->idForStyleResolution(); } if (renderRegion->hasCustomRegionStyle()) @@ -792,29 +789,36 @@ static void writeLayers(TextStream& ts, const RenderLayer* rootLayer, RenderLaye static String nodePosition(Node* node) { - String result; + StringBuilder result; Element* body = node->document()->body(); Node* parent; for (Node* n = node; n; n = parent) { parent = n->parentOrHostNode(); if (n != node) - result += " of "; + result.appendLiteral(" of "); if (parent) { if (body && n == body) { // We don't care what offset body may be in the document. - result += "body"; + result.appendLiteral("body"); break; } - if (n->isShadowRoot()) - result += "{" + getTagName(n) + "}"; - else - result += "child " + String::number(n->nodeIndex()) + " {" + getTagName(n) + "}"; + if (n->isShadowRoot()) { + result.append('{'); + result.append(getTagName(n)); + result.append('}'); + } else { + result.appendLiteral("child "); + result.appendNumber(n->nodeIndex()); + result.appendLiteral(" {"); + result.append(getTagName(n)); + result.append('}'); + } } else - result += "document"; + result.appendLiteral("document"); } - return result; + return result.toString(); } static void writeSelection(TextStream& ts, const RenderObject* o) diff --git a/Source/WebCore/rendering/RenderView.cpp b/Source/WebCore/rendering/RenderView.cpp index 8cc34a330..c79c66426 100644 --- a/Source/WebCore/rendering/RenderView.cpp +++ b/Source/WebCore/rendering/RenderView.cpp @@ -248,6 +248,11 @@ void RenderView::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) ASSERT(!needsLayout()); // RenderViews should never be called to paint with an offset not on device pixels. ASSERT(LayoutPoint(IntPoint(paintOffset.x(), paintOffset.y())) == paintOffset); + + // This avoids painting garbage between columns if there is a column gap. + if (m_frameView && m_frameView->pagination().mode != Pagination::Unpaginated) + paintInfo.context->fillRect(paintInfo.rect, m_frameView->baseBackgroundColor(), ColorSpaceDeviceRGB); + paintObject(paintInfo, paintOffset); } @@ -811,11 +816,6 @@ void RenderView::pushLayoutState(RenderObject* root) m_layoutState = new (renderArena()) LayoutState(root); } -void RenderView::pushLayoutState(RenderFlowThread* flowThread, bool regionsChanged) -{ - m_layoutState = new (renderArena()) LayoutState(m_layoutState, flowThread, regionsChanged); -} - bool RenderView::shouldDisableLayoutStateForSubtree(RenderObject* renderer) const { RenderObject* o = renderer; @@ -937,19 +937,4 @@ RenderBlock::IntervalArena* RenderView::intervalArena() return m_intervalArena.get(); } -void RenderView::setFixedPositionedObjectsNeedLayout() -{ - ASSERT(m_frameView); - - ListHashSet<RenderBox*>* positionedObjects = this->positionedObjects(); - if (!positionedObjects) - return; - - ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); - for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { - RenderBox* currBox = *it; - currBox->setNeedsLayout(true); - } -} - } // namespace WebCore diff --git a/Source/WebCore/rendering/RenderView.h b/Source/WebCore/rendering/RenderView.h index 296c629ec..4848ca9bb 100644 --- a/Source/WebCore/rendering/RenderView.h +++ b/Source/WebCore/rendering/RenderView.h @@ -193,8 +193,6 @@ public: IntSize viewportSize() const { return document()->viewportSize(); } - void setFixedPositionedObjectsNeedLayout(); - void setRenderQuoteHead(RenderQuote* head) { m_renderQuoteHead = head; } RenderQuote* renderQuoteHead() const { return m_renderQuoteHead; } @@ -351,17 +349,7 @@ public: , m_didCreateLayoutState(false) { } - - LayoutStateMaintainer(RenderView* view, RenderFlowThread* flowThread, bool regionsChanged) - : m_view(view) - , m_disabled(false) - , m_didStart(false) - , m_didEnd(false) - , m_didCreateLayoutState(false) - { - push(flowThread, regionsChanged); - } - + ~LayoutStateMaintainer() { ASSERT(m_didStart == m_didEnd); // if this fires, it means that someone did a push(), but forgot to pop(). @@ -376,14 +364,6 @@ public: m_view->disableLayoutState(); m_didStart = true; } - - void push(RenderFlowThread* flowThread, bool regionsChanged) - { - ASSERT(!m_didStart); - m_view->pushLayoutState(flowThread, regionsChanged); - m_didCreateLayoutState = true; - m_didStart = true; - } void pop() { diff --git a/Source/WebCore/rendering/RenderWidget.cpp b/Source/WebCore/rendering/RenderWidget.cpp index fc4f2f35a..9537edf5d 100644 --- a/Source/WebCore/rendering/RenderWidget.cpp +++ b/Source/WebCore/rendering/RenderWidget.cpp @@ -385,10 +385,10 @@ RenderWidget* RenderWidget::find(const Widget* widget) return widgetRendererMap().get(widget); } -bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) +bool RenderWidget::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action) { bool hadResult = result.innerNode(); - bool inside = RenderReplaced::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, action); + bool inside = RenderReplaced::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, action); // Check to see if we are really over the widget itself (and not just in the border/padding area). if ((inside || result.isRectBasedTest()) && !hadResult && result.innerNode() == node()) diff --git a/Source/WebCore/rendering/RenderWidget.h b/Source/WebCore/rendering/RenderWidget.h index b93ae7b5a..b7db3b809 100644 --- a/Source/WebCore/rendering/RenderWidget.h +++ b/Source/WebCore/rendering/RenderWidget.h @@ -60,7 +60,7 @@ protected: virtual void layout(); virtual void paint(PaintInfo&, const LayoutPoint&); virtual CursorDirective getCursor(const LayoutPoint&, Cursor&) const; - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; private: virtual bool isWidget() const { return true; } diff --git a/Source/WebCore/rendering/RenderingAllInOne.cpp b/Source/WebCore/rendering/RenderingAllInOne.cpp index 1f0a4a38e..03bdd3f8b 100644 --- a/Source/WebCore/rendering/RenderingAllInOne.cpp +++ b/Source/WebCore/rendering/RenderingAllInOne.cpp @@ -51,6 +51,7 @@ #include "RenderCounter.cpp" #include "RenderDeprecatedFlexibleBox.cpp" #include "RenderDetailsMarker.cpp" +#include "RenderDialog.cpp" #include "RenderEmbeddedObject.cpp" #include "RenderFieldset.cpp" #include "RenderFileUploadControl.cpp" diff --git a/Source/WebCore/rendering/RootInlineBox.cpp b/Source/WebCore/rendering/RootInlineBox.cpp index 4313fa735..928fe667e 100644 --- a/Source/WebCore/rendering/RootInlineBox.cpp +++ b/Source/WebCore/rendering/RootInlineBox.cpp @@ -217,15 +217,15 @@ void RootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, #endif } -bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) +bool RootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) { if (hasEllipsisBox() && visibleToHitTesting()) { - if (ellipsisBox()->nodeAtPoint(request, result, pointInContainer, accumulatedOffset, lineTop, lineBottom)) { - renderer()->updateHitTestResult(result, pointInContainer.point() - toLayoutSize(accumulatedOffset)); + if (ellipsisBox()->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom)) { + renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); return true; } } - return InlineFlowBox::nodeAtPoint(request, result, pointInContainer, accumulatedOffset, lineTop, lineBottom); + return InlineFlowBox::nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom); } void RootInlineBox::adjustPosition(float dx, float dy) diff --git a/Source/WebCore/rendering/RootInlineBox.h b/Source/WebCore/rendering/RootInlineBox.h index 27c1afcea..525b29503 100644 --- a/Source/WebCore/rendering/RootInlineBox.h +++ b/Source/WebCore/rendering/RootInlineBox.h @@ -118,7 +118,7 @@ public: #endif virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; using InlineBox::hasSelectedChildren; using InlineBox::setHasSelectedChildren; diff --git a/Source/WebCore/rendering/TextAutosizer.h b/Source/WebCore/rendering/TextAutosizer.h index c8ade00f7..ae9fd8363 100644 --- a/Source/WebCore/rendering/TextAutosizer.h +++ b/Source/WebCore/rendering/TextAutosizer.h @@ -28,7 +28,7 @@ #if ENABLE(TEXT_AUTOSIZING) -#include "LayoutTypes.h" +#include "IntSize.h" #include <wtf/Noncopyable.h> #include <wtf/PassOwnPtr.h> #include <wtf/PassRefPtr.h> diff --git a/Source/WebCore/rendering/WrapShapeInfo.cpp b/Source/WebCore/rendering/WrapShapeInfo.cpp new file mode 100644 index 000000000..8ef73c7fc --- /dev/null +++ b/Source/WebCore/rendering/WrapShapeInfo.cpp @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 THE COPYRIGHT HOLDER 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 "WrapShapeInfo.h" + +#if ENABLE(CSS_EXCLUSIONS) + +#include "NotImplemented.h" +#include "RenderBlock.h" +#include <wtf/HashMap.h> +#include <wtf/OwnPtr.h> + +namespace WebCore { + +typedef HashMap<const RenderBlock*, OwnPtr<WrapShapeInfo> > WrapShapeInfoMap; + +static WrapShapeInfoMap& wrapShapeInfoMap() +{ + DEFINE_STATIC_LOCAL(WrapShapeInfoMap, staticWrapShapeInfoMap, ()); + return staticWrapShapeInfoMap; +} + +WrapShapeInfo::WrapShapeInfo(RenderBlock* block) + : m_block(block) + , m_wrapShapeSizeDirty(true) +{ +} + +WrapShapeInfo::~WrapShapeInfo() +{ +} + +WrapShapeInfo* WrapShapeInfo::ensureWrapShapeInfoForRenderBlock(RenderBlock* block) +{ + WrapShapeInfoMap::AddResult result = wrapShapeInfoMap().add(block, create(block)); + return result.iterator->second.get(); +} + +WrapShapeInfo* WrapShapeInfo::wrapShapeInfoForRenderBlock(const RenderBlock* block) +{ + ASSERT(block->style()->wrapShapeInside()); + return wrapShapeInfoMap().get(block); +} + +bool WrapShapeInfo::isWrapShapeInfoEnabledForRenderBlock(const RenderBlock* block) +{ + // FIXME: Bug 89705: Enable shape inside for vertical writing modes + if (!block->isHorizontalWritingMode()) + return false; + + // FIXME: Bug 89707: Enable shape inside for non-rectangular shapes + BasicShape* shape = block->style()->wrapShapeInside(); + return (shape && shape->type() == BasicShape::BASIC_SHAPE_RECTANGLE); +} + +void WrapShapeInfo::removeWrapShapeInfoForRenderBlock(const RenderBlock* block) +{ + if (!block->style() || !block->style()->wrapShapeInside()) + return; + wrapShapeInfoMap().remove(block); +} + +bool WrapShapeInfo::hasSegments() const +{ + // All line positions within a shape should have at least one segment + ASSERT(lineState() != LINE_INSIDE_SHAPE || m_segments.size()); + return m_segments.size(); +} + +void WrapShapeInfo::computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight) +{ + if (!m_wrapShapeSizeDirty && logicalWidth == m_logicalWidth && logicalHeight == m_logicalHeight) + return; + + m_wrapShapeSizeDirty = false; + m_logicalWidth = logicalWidth; + m_logicalHeight = logicalHeight; + + // FIXME: Bug 89993: The wrap shape may come from the parent object + BasicShape* shape = m_block->style()->wrapShapeInside(); + + ASSERT(shape); + + switch (shape->type()) { + case BasicShape::BASIC_SHAPE_RECTANGLE: { + BasicShapeRectangle* rect = static_cast<BasicShapeRectangle *>(shape); + m_shapeLeft = valueForLength(rect->x(), m_logicalWidth); + m_shapeWidth = valueForLength(rect->width(), m_logicalWidth); + m_shapeTop = valueForLength(rect->y(), m_logicalHeight); + m_shapeHeight = valueForLength(rect->height(), m_logicalHeight); + break; + } + // FIXME: Bug 89707: Enable shape inside for non-rectangular shapes + case BasicShape::BASIC_SHAPE_CIRCLE: + case BasicShape::BASIC_SHAPE_ELLIPSE: + case BasicShape::BASIC_SHAPE_POLYGON: { + notImplemented(); + break; + } + } +} + +bool WrapShapeInfo::computeSegmentsForLine(LayoutUnit lineTop) +{ + m_lineTop = lineTop; + m_segments.clear(); + if (lineState() == LINE_INSIDE_SHAPE) { + LineSegment segment; + segment.logicalLeft = m_shapeLeft; + segment.logicalRight = m_shapeLeft + m_shapeWidth; + m_segments.append(segment); + } + return m_segments.size(); +} + +} +#endif diff --git a/Source/WebCore/rendering/WrapShapeInfo.h b/Source/WebCore/rendering/WrapShapeInfo.h new file mode 100644 index 000000000..a8036d0bb --- /dev/null +++ b/Source/WebCore/rendering/WrapShapeInfo.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER “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 THE COPYRIGHT HOLDER 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 WrapShapeInfo_h +#define WrapShapeInfo_h + +#if ENABLE(CSS_EXCLUSIONS) + +#include "LayoutTypesInlineMethods.h" +#include <wtf/PassOwnPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + +class RenderBlock; +class WrapShapeInfo; + +struct LineSegment { + LayoutUnit logicalLeft; + LayoutUnit logicalRight; +}; + +typedef Vector<LineSegment> SegmentList; + +class WrapShapeInfo { +public: + enum LineState { + LINE_BEFORE_SHAPE, + LINE_INSIDE_SHAPE, + LINE_AFTER_SHAPE + }; + + ~WrapShapeInfo(); + + static PassOwnPtr<WrapShapeInfo> create(RenderBlock* block) { return adoptPtr(new WrapShapeInfo(block)); } + static WrapShapeInfo* wrapShapeInfoForRenderBlock(const RenderBlock*); + static WrapShapeInfo* ensureWrapShapeInfoForRenderBlock(RenderBlock*); + static void removeWrapShapeInfoForRenderBlock(const RenderBlock*); + static bool isWrapShapeInfoEnabledForRenderBlock(const RenderBlock*); + + LayoutUnit shapeTop() const { return m_shapeTop; } + bool hasSegments() const; + const SegmentList& segments() const + { + ASSERT(hasSegments()); + return m_segments; + } + bool computeSegmentsForLine(LayoutUnit); + LineState lineState() const; + void computeShapeSize(LayoutUnit logicalWidth, LayoutUnit logicalHeight); + void dirtyWrapShapeSize() { m_wrapShapeSizeDirty = true; } + +private: + WrapShapeInfo(RenderBlock*); + + RenderBlock* m_block; + LayoutUnit m_shapeLeft; + LayoutUnit m_shapeTop; + LayoutUnit m_shapeWidth; + LayoutUnit m_shapeHeight; + + LayoutUnit m_lineTop; + LayoutUnit m_logicalWidth; + LayoutUnit m_logicalHeight; + + SegmentList m_segments; + bool m_wrapShapeSizeDirty; +}; + +inline WrapShapeInfo::LineState WrapShapeInfo::lineState() const +{ + if (m_lineTop < m_shapeTop) + return LINE_BEFORE_SHAPE; + if (m_lineTop < m_shapeTop + m_shapeHeight) + return LINE_INSIDE_SHAPE; + return LINE_AFTER_SHAPE; +} + +} +#endif +#endif diff --git a/Source/WebCore/rendering/break_lines.cpp b/Source/WebCore/rendering/break_lines.cpp index 4bba3ce7e..f1b5ca18f 100644 --- a/Source/WebCore/rendering/break_lines.cpp +++ b/Source/WebCore/rendering/break_lines.cpp @@ -38,7 +38,8 @@ namespace WebCore { -static inline bool isBreakableSpace(UChar ch, bool treatNoBreakSpaceAsBreak) +template<bool treatNoBreakSpaceAsBreak> +static inline bool isBreakableSpace(UChar ch) { switch (ch) { case ' ': @@ -138,12 +139,16 @@ static inline bool shouldBreakAfter(UChar lastCh, UChar ch, UChar nextCh) return false; } -static inline bool needsLineBreakIterator(UChar ch) +template<bool treatNoBreakSpaceAsBreak> +inline bool needsLineBreakIterator(UChar ch) { + if (treatNoBreakSpaceAsBreak) + return ch > asciiLineBreakTableLastChar; return ch > asciiLineBreakTableLastChar && ch != noBreakSpace; } -int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, bool treatNoBreakSpaceAsBreak) +template<bool treatNoBreakSpaceAsBreak> +static inline int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos) { const UChar* str = lazyBreakIterator.string(); int len = lazyBreakIterator.length(); @@ -154,16 +159,16 @@ int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, boo for (int i = pos; i < len; i++) { UChar ch = str[i]; - if (isBreakableSpace(ch, treatNoBreakSpaceAsBreak) || shouldBreakAfter(lastLastCh, lastCh, ch)) + if (isBreakableSpace<treatNoBreakSpaceAsBreak>(ch) || shouldBreakAfter(lastLastCh, lastCh, ch)) return i; - if (needsLineBreakIterator(ch) || needsLineBreakIterator(lastCh)) { + if (needsLineBreakIterator<treatNoBreakSpaceAsBreak>(ch) || needsLineBreakIterator<treatNoBreakSpaceAsBreak>(lastCh)) { if (nextBreak < i && i) { TextBreakIterator* breakIterator = lazyBreakIterator.get(); if (breakIterator) nextBreak = textBreakFollowing(breakIterator, i - 1); } - if (i == nextBreak && !isBreakableSpace(lastCh, treatNoBreakSpaceAsBreak)) + if (i == nextBreak && !isBreakableSpace<treatNoBreakSpaceAsBreak>(lastCh)) return i; } @@ -174,4 +179,14 @@ int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos, boo return len; } +int nextBreakablePositionIgnoringNBSP(LazyLineBreakIterator& lazyBreakIterator, int pos) +{ + return nextBreakablePosition<false>(lazyBreakIterator, pos); +} + +int nextBreakablePosition(LazyLineBreakIterator& lazyBreakIterator, int pos) +{ + return nextBreakablePosition<true>(lazyBreakIterator, pos); +} + } // namespace WebCore diff --git a/Source/WebCore/rendering/break_lines.h b/Source/WebCore/rendering/break_lines.h index 6600e524b..692363009 100644 --- a/Source/WebCore/rendering/break_lines.h +++ b/Source/WebCore/rendering/break_lines.h @@ -27,12 +27,17 @@ namespace WebCore { class LazyLineBreakIterator; -int nextBreakablePosition(LazyLineBreakIterator&, int pos, bool breakNBSP = false); +int nextBreakablePositionIgnoringNBSP(LazyLineBreakIterator&, int pos); +int nextBreakablePosition(LazyLineBreakIterator&, int pos); -inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP = false) +inline bool isBreakable(LazyLineBreakIterator& lazyBreakIterator, int pos, int& nextBreakable, bool breakNBSP) { - if (pos > nextBreakable) - nextBreakable = nextBreakablePosition(lazyBreakIterator, pos, breakNBSP); + if (pos > nextBreakable) { + if (breakNBSP) + nextBreakable = nextBreakablePosition(lazyBreakIterator, pos); + else + nextBreakable = nextBreakablePositionIgnoringNBSP(lazyBreakIterator, pos); + } return pos == nextBreakable; } diff --git a/Source/WebCore/rendering/style/BasicShapes.cpp b/Source/WebCore/rendering/style/BasicShapes.cpp new file mode 100644 index 000000000..9b1245f66 --- /dev/null +++ b/Source/WebCore/rendering/style/BasicShapes.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 "BasicShapes.h" +#include "FloatRect.h" +#include "LengthFunctions.h" +#include "Path.h" + +namespace WebCore { + +void BasicShapeRectangle::path(Path& path, const FloatRect& boundingBox) +{ + ASSERT(path.isEmpty()); + path.addRoundedRect(FloatRect(floatValueForLength(m_x, boundingBox.width()) + boundingBox.x(), + floatValueForLength(m_y, boundingBox.height()) + boundingBox.y(), + floatValueForLength(m_width, boundingBox.width()), + floatValueForLength(m_height, boundingBox.height())), + FloatSize(m_cornerRadiusX.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusX, boundingBox.width()), + m_cornerRadiusY.isUndefined() ? 0 : floatValueForLength(m_cornerRadiusY, boundingBox.height()))); +} + +void BasicShapeCircle::path(Path& path, const FloatRect& boundingBox) +{ + ASSERT(path.isEmpty()); + float diagonal = sqrtf((boundingBox.width() * boundingBox.width() + boundingBox.height() * boundingBox.height()) / 2); + float centerX = floatValueForLength(m_centerX, boundingBox.width()); + float centerY = floatValueForLength(m_centerY, boundingBox.height()); + float radius = floatValueForLength(m_radius, diagonal); + path.addEllipse(FloatRect(centerX - radius + boundingBox.x(), + centerY - radius + boundingBox.y(), + radius * 2, + radius * 2)); +} + +void BasicShapeEllipse::path(Path& path, const FloatRect& boundingBox) +{ + ASSERT(path.isEmpty()); + float centerX = floatValueForLength(m_centerX, boundingBox.width()); + float centerY = floatValueForLength(m_centerY, boundingBox.height()); + float radiusX = floatValueForLength(m_radiusX, boundingBox.width()); + float radiusY = floatValueForLength(m_radiusY, boundingBox.height()); + path.addEllipse(FloatRect(centerX - radiusX + boundingBox.x(), + centerY - radiusY + boundingBox.y(), + radiusX * 2, + radiusY * 2)); +} + +void BasicShapePolygon::path(Path& path, const FloatRect& boundingBox) +{ + ASSERT(path.isEmpty()); + ASSERT(!(m_values.size() % 2)); + size_t length = m_values.size(); + + if (!length) + return; + + path.moveTo(FloatPoint(floatValueForLength(m_values.at(0), boundingBox.width()) + boundingBox.x(), + floatValueForLength(m_values.at(1), boundingBox.width()) + boundingBox.y())); + for (size_t i = 2; i < length; i = i + 2) { + path.addLineTo(FloatPoint(floatValueForLength(m_values.at(i), boundingBox.width()) + boundingBox.x(), + floatValueForLength(m_values.at(i + 1), boundingBox.width()) + boundingBox.y())); + } + path.closeSubpath(); +} +} diff --git a/Source/WebCore/rendering/style/WrapShapes.h b/Source/WebCore/rendering/style/BasicShapes.h index 86928b68c..ad1182676 100644 --- a/Source/WebCore/rendering/style/WrapShapes.h +++ b/Source/WebCore/rendering/style/BasicShapes.h @@ -27,46 +27,42 @@ * SUCH DAMAGE. */ -#ifndef WrapShapes_h -#define WrapShapes_h +#ifndef BasicShapes_h +#define BasicShapes_h #include "Length.h" #include "WindRule.h" #include <wtf/RefCounted.h> #include <wtf/RefPtr.h> +#include <wtf/Vector.h> namespace WebCore { -class WrapShape : public WTF::RefCountedBase { +class FloatRect; +class Path; + +class BasicShape : public RefCounted<BasicShape> { public: + virtual ~BasicShape() { } + enum Type { - WRAP_SHAPE_RECTANGLE = 1, - WRAP_SHAPE_CIRCLE = 2, - WRAP_SHAPE_ELLIPSE = 3, - WRAP_SHAPE_POLYGON = 4 + BASIC_SHAPE_RECTANGLE = 1, + BASIC_SHAPE_CIRCLE = 2, + BASIC_SHAPE_ELLIPSE = 3, + BASIC_SHAPE_POLYGON = 4 }; - - void deref() - { - if (derefBase()) - destroy(); - } - Type type() const { return m_type; } + virtual void path(Path&, const FloatRect&) = 0; + virtual WindRule windRule() const { return RULE_NONZERO; } + virtual Type type() const = 0; protected: - WrapShape(Type type) - : m_type(type) - { } - -private: - void destroy(); - Type m_type; + BasicShape() { } }; -class WrapShapeRectangle : public WrapShape { +class BasicShapeRectangle : public BasicShape { public: - static PassRefPtr<WrapShapeRectangle> create() { return adoptRef(new WrapShapeRectangle); } + static PassRefPtr<BasicShapeRectangle> create() { return adoptRef(new BasicShapeRectangle); } Length x() const { return m_x; } Length y() const { return m_y; } @@ -81,11 +77,13 @@ public: void setHeight(Length height) { m_height = height; } void setCornerRadiusX(Length radiusX) { m_cornerRadiusX = radiusX; } void setCornerRadiusY(Length radiusY) { m_cornerRadiusY = radiusY; } - + + virtual void path(Path&, const FloatRect&); + + virtual Type type() const { return BASIC_SHAPE_RECTANGLE; } private: - WrapShapeRectangle() - : WrapShape(WRAP_SHAPE_RECTANGLE) - , m_cornerRadiusX(Undefined) + BasicShapeRectangle() + : m_cornerRadiusX(Undefined) , m_cornerRadiusY(Undefined) { } @@ -97,9 +95,9 @@ private: Length m_cornerRadiusY; }; -class WrapShapeCircle : public WrapShape { +class BasicShapeCircle : public BasicShape { public: - static PassRefPtr<WrapShapeCircle> create() { return adoptRef(new WrapShapeCircle); } + static PassRefPtr<BasicShapeCircle> create() { return adoptRef(new BasicShapeCircle); } Length centerX() const { return m_centerX; } Length centerY() const { return m_centerY; } @@ -109,19 +107,20 @@ public: void setCenterY(Length centerY) { m_centerY = centerY; } void setRadius(Length radius) { m_radius = radius; } + virtual void path(Path&, const FloatRect&); + + virtual Type type() const { return BASIC_SHAPE_CIRCLE; } private: - WrapShapeCircle() - : WrapShape(WRAP_SHAPE_CIRCLE) - { } + BasicShapeCircle() { } Length m_centerX; Length m_centerY; Length m_radius; }; -class WrapShapeEllipse : public WrapShape { +class BasicShapeEllipse : public BasicShape { public: - static PassRefPtr<WrapShapeEllipse> create() { return adoptRef(new WrapShapeEllipse); } + static PassRefPtr<BasicShapeEllipse> create() { return adoptRef(new BasicShapeEllipse); } Length centerX() const { return m_centerX; } Length centerY() const { return m_centerY; } @@ -133,10 +132,11 @@ public: void setRadiusX(Length radiusX) { m_radiusX = radiusX; } void setRadiusY(Length radiusY) { m_radiusY = radiusY; } + virtual void path(Path&, const FloatRect&); + + virtual Type type() const { return BASIC_SHAPE_ELLIPSE; } private: - WrapShapeEllipse() - : WrapShape(WRAP_SHAPE_ELLIPSE) - { } + BasicShapeEllipse() { } Length m_centerX; Length m_centerY; @@ -144,11 +144,10 @@ private: Length m_radiusY; }; -class WrapShapePolygon : public WrapShape { +class BasicShapePolygon : public BasicShape { public: - static PassRefPtr<WrapShapePolygon> create() { return adoptRef(new WrapShapePolygon); } + static PassRefPtr<BasicShapePolygon> create() { return adoptRef(new BasicShapePolygon); } - WindRule windRule() const { return m_windRule; } const Vector<Length>& values() const { return m_values; } Length getXAt(unsigned i) const { return m_values.at(2 * i); } Length getYAt(unsigned i) const { return m_values.at(2 * i + 1); } @@ -156,10 +155,13 @@ public: void setWindRule(WindRule windRule) { m_windRule = windRule; } void appendPoint(Length x, Length y) { m_values.append(x); m_values.append(y); } + virtual void path(Path&, const FloatRect&); + virtual WindRule windRule() const { return m_windRule; } + + virtual Type type() const { return BASIC_SHAPE_POLYGON; } private: - WrapShapePolygon() - : WrapShape(WRAP_SHAPE_POLYGON) - , m_windRule(RULE_NONZERO) + BasicShapePolygon() + : m_windRule(RULE_NONZERO) { } WindRule m_windRule; diff --git a/Source/WebCore/rendering/style/CounterDirectives.cpp b/Source/WebCore/rendering/style/CounterDirectives.cpp index 34becba98..06d44ddf6 100644 --- a/Source/WebCore/rendering/style/CounterDirectives.cpp +++ b/Source/WebCore/rendering/style/CounterDirectives.cpp @@ -27,13 +27,10 @@ namespace WebCore { bool operator==(const CounterDirectives& a, const CounterDirectives& b) { - if (a.m_reset != b.m_reset || a.m_increment != b.m_increment) - return false; - if (a.m_reset && a.m_resetValue != b.m_resetValue) - return false; - if (a.m_increment && a.m_incrementValue != b.m_incrementValue) - return false; - return true; + return a.isIncrement() == b.isIncrement() + && a.incrementValue() == b.incrementValue() + && a.isReset() == b.isReset() + && a.resetValue() == b.resetValue(); } PassOwnPtr<CounterDirectiveMap> clone(const CounterDirectiveMap& counterDirectives) diff --git a/Source/WebCore/rendering/style/CounterDirectives.h b/Source/WebCore/rendering/style/CounterDirectives.h index 1bdcb9061..cf793bb8f 100644 --- a/Source/WebCore/rendering/style/CounterDirectives.h +++ b/Source/WebCore/rendering/style/CounterDirectives.h @@ -26,20 +26,75 @@ #define CounterDirectives_h #include <wtf/HashMap.h> +#include <wtf/MathExtras.h> #include <wtf/RefPtr.h> -#include <wtf/text/AtomicStringImpl.h> +#include <wtf/text/AtomicString.h> +#include <wtf/text/AtomicStringHash.h> namespace WebCore { -struct CounterDirectives { +class CounterDirectives { +public: CounterDirectives() - : m_reset(false) - , m_increment(false) + : m_isResetSet(false) + , m_isIncrementSet(false) + , m_resetValue(0) + , m_incrementValue(0) { } - bool m_reset; - bool m_increment; + // FIXME: The code duplication here could possibly be replaced by using two + // maps, or by using a container that held two generic Directive objects. + + bool isReset() const { return m_isResetSet; } + int resetValue() const { return m_resetValue; } + void setResetValue(int value) + { + m_resetValue = value; + m_isResetSet = true; + } + void clearReset() + { + m_resetValue = 0; + m_isResetSet = false; + } + void inheritReset(CounterDirectives& parent) + { + m_resetValue = parent.m_resetValue; + m_isResetSet = parent.m_isResetSet; + } + + bool isIncrement() const { return m_isIncrementSet; } + int incrementValue() const { return m_incrementValue; } + void addIncrementValue(int value) + { + m_incrementValue = clampToInteger((double)m_incrementValue + value); + m_isIncrementSet = true; + } + void clearIncrement() + { + m_incrementValue = 0; + m_isIncrementSet = false; + } + void inheritIncrement(CounterDirectives& parent) + { + m_incrementValue = parent.m_incrementValue; + m_isIncrementSet = parent.m_isIncrementSet; + } + + bool isDefined() const { return isReset() || isIncrement(); } + + int combinedValue() const + { + ASSERT(m_isResetSet || !m_resetValue); + ASSERT(m_isIncrementSet || !m_incrementValue); + // FIXME: Shouldn't allow overflow here. + return m_resetValue + m_incrementValue; + } + +private: + bool m_isResetSet; + bool m_isIncrementSet; int m_resetValue; int m_incrementValue; }; @@ -47,7 +102,7 @@ struct CounterDirectives { bool operator==(const CounterDirectives&, const CounterDirectives&); inline bool operator!=(const CounterDirectives& a, const CounterDirectives& b) { return !(a == b); } -typedef HashMap<RefPtr<AtomicStringImpl>, CounterDirectives> CounterDirectiveMap; +typedef HashMap<AtomicString, CounterDirectives> CounterDirectiveMap; PassOwnPtr<CounterDirectiveMap> clone(const CounterDirectiveMap&); diff --git a/Source/WebCore/rendering/style/DataRef.h b/Source/WebCore/rendering/style/DataRef.h index c8d8072cb..91a78451d 100644 --- a/Source/WebCore/rendering/style/DataRef.h +++ b/Source/WebCore/rendering/style/DataRef.h @@ -62,6 +62,14 @@ public: return m_data != o.m_data && *m_data != *o.m_data; } + // Template helps us to write the implementation without MemoryInstrumentation.h include. + template<typename MemoryObjectInfo> + void reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const + { + typename MemoryObjectInfo::ClassInfo info(memoryObjectInfo, this); + info.addInstrumentedMember(m_data); + } + private: RefPtr<T> m_data; }; diff --git a/Source/WebCore/rendering/style/RenderStyle.cpp b/Source/WebCore/rendering/style/RenderStyle.cpp index b1b5faab0..f160d9ecc 100644 --- a/Source/WebCore/rendering/style/RenderStyle.cpp +++ b/Source/WebCore/rendering/style/RenderStyle.cpp @@ -28,7 +28,6 @@ #include "CSSPropertyNames.h" #include "Font.h" #include "FontSelector.h" -#include "MemoryInstrumentation.h" #include "QuotesData.h" #include "RenderArena.h" #include "RenderObject.h" @@ -40,6 +39,7 @@ #if ENABLE(TOUCH_EVENTS) #include "RenderTheme.h" #endif +#include "WebCoreMemoryInstrumentation.h" #include <wtf/StdLibExtras.h> #include <algorithm> @@ -455,6 +455,11 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon if (rareNonInheritedData->m_dashboardRegions != other->rareNonInheritedData->m_dashboardRegions) return StyleDifferenceLayout; #endif + +#if ENABLE(CSS_EXCLUSIONS) + if (rareNonInheritedData->m_wrapShapeInside != other->rareNonInheritedData->m_wrapShapeInside) + return StyleDifferenceLayout; +#endif } if (rareInheritedData.get() != other->rareInheritedData.get()) { @@ -463,7 +468,7 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon || rareInheritedData->m_effectiveZoom != other->rareInheritedData->m_effectiveZoom || rareInheritedData->textSizeAdjust != other->rareInheritedData->textSizeAdjust || rareInheritedData->wordBreak != other->rareInheritedData->wordBreak - || rareInheritedData->wordWrap != other->rareInheritedData->wordWrap + || rareInheritedData->overflowWrap != other->rareInheritedData->overflowWrap || rareInheritedData->nbspMode != other->rareInheritedData->nbspMode || rareInheritedData->khtmlLineBreak != other->rareInheritedData->khtmlLineBreak || rareInheritedData->textSecurity != other->rareInheritedData->textSecurity @@ -673,10 +678,13 @@ StyleDifference RenderStyle::diff(const RenderStyle* other, unsigned& changedCon // the parent container. For sure, I will have to revisit this code, but for now I've added this in order // to avoid having diff() == StyleDifferenceEqual where wrap-shapes actually differ. // Tracking bug: https://bugs.webkit.org/show_bug.cgi?id=62991 - if (rareNonInheritedData->m_wrapShapeInside != other->rareNonInheritedData->m_wrapShapeInside - || rareNonInheritedData->m_wrapShapeOutside != other->rareNonInheritedData->m_wrapShapeOutside) + if (rareNonInheritedData->m_wrapShapeOutside != other->rareNonInheritedData->m_wrapShapeOutside) + return StyleDifferenceRepaint; + + if (rareNonInheritedData->m_clipPath != other->rareNonInheritedData->m_clipPath) return StyleDifferenceRepaint; + #if USE(ACCELERATED_COMPOSITING) if (rareNonInheritedData.get() != other->rareNonInheritedData.get()) { if (rareNonInheritedData->m_transformStyle3D != other->rareNonInheritedData->m_transformStyle3D @@ -774,9 +782,7 @@ void RenderStyle::setContent(const String& string, bool add) // We attempt to merge with the last ContentData if possible. if (lastContent->isText()) { TextContentData* textContent = static_cast<TextContentData*>(lastContent); - String text = textContent->text(); - text += string; - textContent->setText(text); + textContent->setText(textContent->text() + string); } else lastContent->setNext(ContentData::create(string)); @@ -1030,6 +1036,13 @@ CounterDirectiveMap& RenderStyle::accessCounterDirectives() return *map; } +const CounterDirectives RenderStyle::getCounterDirectives(const AtomicString& identifier) const +{ + if (const CounterDirectiveMap* directives = counterDirectives()) + return directives->get(identifier); + return CounterDirectives(); +} + const AtomicString& RenderStyle::hyphenString() const { ASSERT(hyphens() != HyphensNone); @@ -1329,40 +1342,40 @@ Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) c EBorderStyle borderStyle = BNONE; switch (colorProperty) { case CSSPropertyBackgroundColor: - return visitedLink ? rareNonInheritedData->m_visitedLinkBackgroundColor : backgroundColor(); // Background color doesn't fall back. + return visitedLink ? visitedLinkBackgroundColor() : backgroundColor(); // Background color doesn't fall back. case CSSPropertyBorderLeftColor: - result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderLeftColor : borderLeftColor(); + result = visitedLink ? visitedLinkBorderLeftColor() : borderLeftColor(); borderStyle = borderLeftStyle(); break; case CSSPropertyBorderRightColor: - result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderRightColor : borderRightColor(); + result = visitedLink ? visitedLinkBorderRightColor() : borderRightColor(); borderStyle = borderRightStyle(); break; case CSSPropertyBorderTopColor: - result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderTopColor : borderTopColor(); + result = visitedLink ? visitedLinkBorderTopColor() : borderTopColor(); borderStyle = borderTopStyle(); break; case CSSPropertyBorderBottomColor: - result = visitedLink ? rareNonInheritedData->m_visitedLinkBorderBottomColor : borderBottomColor(); + result = visitedLink ? visitedLinkBorderBottomColor() : borderBottomColor(); borderStyle = borderBottomStyle(); break; case CSSPropertyColor: - result = visitedLink ? inherited->visitedLinkColor : color(); + result = visitedLink ? visitedLinkColor() : color(); break; case CSSPropertyOutlineColor: - result = visitedLink ? rareNonInheritedData->m_visitedLinkOutlineColor : outlineColor(); + result = visitedLink ? visitedLinkOutlineColor() : outlineColor(); break; case CSSPropertyWebkitColumnRuleColor: - result = visitedLink ? rareNonInheritedData->m_multiCol->m_visitedLinkColumnRuleColor : columnRuleColor(); + result = visitedLink ? visitedLinkColumnRuleColor() : columnRuleColor(); break; case CSSPropertyWebkitTextEmphasisColor: - result = visitedLink ? rareInheritedData->visitedLinkTextEmphasisColor : textEmphasisColor(); + result = visitedLink ? visitedLinkTextEmphasisColor() : textEmphasisColor(); break; case CSSPropertyWebkitTextFillColor: - result = visitedLink ? rareInheritedData->visitedLinkTextFillColor : textFillColor(); + result = visitedLink ? visitedLinkTextFillColor() : textFillColor(); break; case CSSPropertyWebkitTextStrokeColor: - result = visitedLink ? rareInheritedData->visitedLinkTextStrokeColor : textStrokeColor(); + result = visitedLink ? visitedLinkTextStrokeColor() : textStrokeColor(); break; default: ASSERT_NOT_REACHED(); @@ -1373,7 +1386,7 @@ Color RenderStyle::colorIncludingFallback(int colorProperty, bool visitedLink) c if (!visitedLink && (borderStyle == INSET || borderStyle == OUTSET || borderStyle == RIDGE || borderStyle == GROOVE)) result.setRGB(238, 238, 238); else - result = visitedLink ? inherited->visitedLinkColor : color(); + result = visitedLink ? visitedLinkColor() : color(); } return result; } @@ -1591,7 +1604,7 @@ LayoutBoxExtent RenderStyle::imageOutsets(const NinePieceImage& image) const void RenderStyle::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const { - MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::CSS); + MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS); info.addMember(m_box); info.addMember(visual); // FIXME: m_background contains RefPtr<StyleImage> that might need to be instrumented. diff --git a/Source/WebCore/rendering/style/RenderStyle.h b/Source/WebCore/rendering/style/RenderStyle.h index 2378c7a72..c50785295 100644 --- a/Source/WebCore/rendering/style/RenderStyle.h +++ b/Source/WebCore/rendering/style/RenderStyle.h @@ -34,10 +34,10 @@ #include "ColorSpace.h" #include "CounterDirectives.h" #include "DataRef.h" -#include "FillLayer.h" #include "FontBaseline.h" #include "FontDescription.h" #include "GraphicsTypes.h" +#include "LayoutTypesInlineMethods.h" #include "Length.h" #include "LengthBox.h" #include "LengthFunctions.h" @@ -74,7 +74,6 @@ #include <wtf/Vector.h> #if ENABLE(CSS_FILTERS) -#include "FilterOperations.h" #include "StyleFilterData.h" #endif @@ -101,6 +100,10 @@ namespace WebCore { using std::max; +#if ENABLE(CSS_FILTERS) +class FilterOperations; +#endif + class BorderData; class CounterContent; class CursorList; @@ -511,6 +514,7 @@ public: EPosition position() const { return static_cast<EPosition>(noninherited_flags._position); } bool hasOutOfFlowPosition() const { return position() == AbsolutePosition || position() == FixedPosition; } bool hasInFlowPosition() const { return position() == RelativePosition || position() == StickyPosition; } + bool hasViewportConstrainedPosition() const { return position() == FixedPosition || position() == StickyPosition; } EFloat floating() const { return static_cast<EFloat>(noninherited_flags._floating); } Length width() const { return m_box->width(); } @@ -683,7 +687,7 @@ public: bool breakWords() const { - return wordBreak() == BreakWordBreak || wordWrap() == BreakWordWrap; + return wordBreak() == BreakWordBreak || overflowWrap() == BreakOverflowWrap; } EFillRepeat backgroundRepeatX() const { return static_cast<EFillRepeat>(m_background->background().repeatX()); } @@ -838,7 +842,7 @@ public: EMarginCollapse marginBeforeCollapse() const { return static_cast<EMarginCollapse>(rareNonInheritedData->marginBeforeCollapse); } EMarginCollapse marginAfterCollapse() const { return static_cast<EMarginCollapse>(rareNonInheritedData->marginAfterCollapse); } EWordBreak wordBreak() const { return static_cast<EWordBreak>(rareInheritedData->wordBreak); } - EWordWrap wordWrap() const { return static_cast<EWordWrap>(rareInheritedData->wordWrap); } + EOverflowWrap overflowWrap() const { return static_cast<EOverflowWrap>(rareInheritedData->overflowWrap); } ENBSPMode nbspMode() const { return static_cast<ENBSPMode>(rareInheritedData->nbspMode); } EKHTMLLineBreak khtmlLineBreak() const { return static_cast<EKHTMLLineBreak>(rareInheritedData->khtmlLineBreak); } const AtomicString& highlight() const { return rareInheritedData->highlight; } @@ -988,7 +992,7 @@ public: #if ENABLE(CSS_COMPOSITING) BlendMode blendMode() const { return static_cast<BlendMode>(rareNonInheritedData->m_effectiveBlendMode); } void setBlendMode(BlendMode v) { rareNonInheritedData.access()->m_effectiveBlendMode = v; } - bool hasBlendMode() const { return static_cast<BlendMode>(rareNonInheritedData->m_effectiveBlendMode) == BlendModeNormal; } + bool hasBlendMode() const { return static_cast<BlendMode>(rareNonInheritedData->m_effectiveBlendMode) != BlendModeNormal; } #else bool hasBlendMode() const { return false; } #endif @@ -1301,7 +1305,7 @@ public: void setMarginBeforeCollapse(EMarginCollapse c) { SET_VAR(rareNonInheritedData, marginBeforeCollapse, c); } void setMarginAfterCollapse(EMarginCollapse c) { SET_VAR(rareNonInheritedData, marginAfterCollapse, c); } void setWordBreak(EWordBreak b) { SET_VAR(rareInheritedData, wordBreak, b); } - void setWordWrap(EWordWrap b) { SET_VAR(rareInheritedData, wordWrap, b); } + void setOverflowWrap(EOverflowWrap b) { SET_VAR(rareInheritedData, overflowWrap, b); } void setNBSPMode(ENBSPMode b) { SET_VAR(rareInheritedData, nbspMode, b); } void setKHTMLLineBreak(EKHTMLLineBreak b) { SET_VAR(rareInheritedData, khtmlLineBreak, b); } void setHighlight(const AtomicString& h) { SET_VAR(rareInheritedData, highlight, h); } @@ -1445,22 +1449,31 @@ public: void setKerning(SVGLength k) { accessSVGStyle()->setKerning(k); } #endif - void setWrapShapeInside(PassRefPtr<WrapShape> shape) + void setWrapShapeInside(PassRefPtr<BasicShape> shape) { if (rareNonInheritedData->m_wrapShapeInside != shape) rareNonInheritedData.access()->m_wrapShapeInside = shape; } - WrapShape* wrapShapeInside() const { return rareNonInheritedData->m_wrapShapeInside.get(); } + BasicShape* wrapShapeInside() const { return rareNonInheritedData->m_wrapShapeInside.get(); } - void setWrapShapeOutside(PassRefPtr<WrapShape> shape) + void setWrapShapeOutside(PassRefPtr<BasicShape> shape) { if (rareNonInheritedData->m_wrapShapeOutside != shape) rareNonInheritedData.access()->m_wrapShapeOutside = shape; } - WrapShape* wrapShapeOutside() const { return rareNonInheritedData->m_wrapShapeOutside.get(); } + BasicShape* wrapShapeOutside() const { return rareNonInheritedData->m_wrapShapeOutside.get(); } + + static BasicShape* initialWrapShapeInside() { return 0; } + static BasicShape* initialWrapShapeOutside() { return 0; } + + void setClipPath(PassRefPtr<BasicShape> shape) + { + if (rareNonInheritedData->m_clipPath != shape) + rareNonInheritedData.access()->m_clipPath = shape; + } + BasicShape* clipPath() const { return rareNonInheritedData->m_clipPath.get(); } - static WrapShape* initialWrapShapeInside() { return 0; } - static WrapShape* initialWrapShapeOutside() { return 0; } + static BasicShape* initialClipPath() { return 0; } Length wrapPadding() const { return rareNonInheritedData->m_wrapPadding; } void setWrapPadding(Length wrapPadding) { SET_VAR(rareNonInheritedData, m_wrapPadding, wrapPadding); } @@ -1481,6 +1494,7 @@ public: const CounterDirectiveMap* counterDirectives() const; CounterDirectiveMap& accessCounterDirectives(); + const CounterDirectives getCounterDirectives(const AtomicString& identifier) const; QuotesData* quotes() const { return rareInheritedData->quotes.get(); } void setQuotes(PassRefPtr<QuotesData>); @@ -1630,7 +1644,7 @@ public: static EMarginCollapse initialMarginBeforeCollapse() { return MCOLLAPSE; } static EMarginCollapse initialMarginAfterCollapse() { return MCOLLAPSE; } static EWordBreak initialWordBreak() { return NormalWordBreak; } - static EWordWrap initialWordWrap() { return NormalWordWrap; } + static EOverflowWrap initialOverflowWrap() { return NormalOverflowWrap; } static ENBSPMode initialNBSPMode() { return NBNORMAL; } static EKHTMLLineBreak initialKHTMLLineBreak() { return LBNORMAL; } static const AtomicString& initialHighlight() { return nullAtom; } @@ -1754,10 +1768,7 @@ private: bool isDisplayReplacedType(EDisplay display) const { - return display == INLINE_BLOCK || display == INLINE_BOX -#if ENABLE(CSS3_FLEXBOX) - || display == INLINE_FLEX -#endif + return display == INLINE_BLOCK || display == INLINE_BOX || display == INLINE_FLEX || display == INLINE_TABLE || display == INLINE_GRID; } diff --git a/Source/WebCore/rendering/style/RenderStyleConstants.h b/Source/WebCore/rendering/style/RenderStyleConstants.h index 6d967cba3..3cdfd59d0 100644 --- a/Source/WebCore/rendering/style/RenderStyleConstants.h +++ b/Source/WebCore/rendering/style/RenderStyleConstants.h @@ -202,8 +202,8 @@ enum EWordBreak { NormalWordBreak, BreakAllWordBreak, BreakWordBreak }; -enum EWordWrap { - NormalWordWrap, BreakWordWrap +enum EOverflowWrap { + NormalOverflowWrap, BreakOverflowWrap }; enum ENBSPMode { @@ -415,9 +415,7 @@ enum EDisplay { TABLE_HEADER_GROUP, TABLE_FOOTER_GROUP, TABLE_ROW, TABLE_COLUMN_GROUP, TABLE_COLUMN, TABLE_CELL, TABLE_CAPTION, BOX, INLINE_BOX, -#if ENABLE(CSS3_FLEXBOX) FLEX, INLINE_FLEX, -#endif GRID, INLINE_GRID, NONE }; diff --git a/Source/WebCore/rendering/style/ShadowData.cpp b/Source/WebCore/rendering/style/ShadowData.cpp index f30d87f2b..d2a1cd270 100644 --- a/Source/WebCore/rendering/style/ShadowData.cpp +++ b/Source/WebCore/rendering/style/ShadowData.cpp @@ -22,6 +22,8 @@ #include "config.h" #include "ShadowData.h" +#include "LayoutTypesInlineMethods.h" + using namespace std; namespace WebCore { diff --git a/Source/WebCore/rendering/style/ShadowData.h b/Source/WebCore/rendering/style/ShadowData.h index b8df95d88..1518edd93 100644 --- a/Source/WebCore/rendering/style/ShadowData.h +++ b/Source/WebCore/rendering/style/ShadowData.h @@ -26,6 +26,7 @@ #define ShadowData_h #include "Color.h" +#include "FloatRect.h" #include "LayoutTypes.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> diff --git a/Source/WebCore/rendering/style/StyleDashboardRegion.h b/Source/WebCore/rendering/style/StyleDashboardRegion.h index 552fdeb82..e591154e6 100644 --- a/Source/WebCore/rendering/style/StyleDashboardRegion.h +++ b/Source/WebCore/rendering/style/StyleDashboardRegion.h @@ -27,7 +27,7 @@ #if ENABLE(DASHBOARD_SUPPORT) || ENABLE(WIDGET_REGION) #include "LengthBox.h" -#include "PlatformString.h" +#include <wtf/text/WTFString.h> namespace WebCore { diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp index 62fe5b89f..ea666d589 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.cpp @@ -23,11 +23,11 @@ #include "StyleRareInheritedData.h" #include "CursorList.h" -#include "MemoryInstrumentation.h" #include "QuotesData.h" #include "RenderStyle.h" #include "RenderStyleConstants.h" #include "ShadowData.h" +#include "WebCoreMemoryInstrumentation.h" namespace WebCore { @@ -69,7 +69,7 @@ StyleRareInheritedData::StyleRareInheritedData() , textSecurity(RenderStyle::initialTextSecurity()) , userModify(READ_ONLY) , wordBreak(RenderStyle::initialWordBreak()) - , wordWrap(RenderStyle::initialWordWrap()) + , overflowWrap(RenderStyle::initialOverflowWrap()) , nbspMode(NBNORMAL) , khtmlLineBreak(LBNORMAL) , textSizeAdjust(RenderStyle::initialTextSizeAdjust()) @@ -131,7 +131,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o) , textSecurity(o.textSecurity) , userModify(o.userModify) , wordBreak(o.wordBreak) - , wordWrap(o.wordWrap) + , overflowWrap(o.overflowWrap) , nbspMode(o.nbspMode) , khtmlLineBreak(o.khtmlLineBreak) , textSizeAdjust(o.textSizeAdjust) @@ -212,7 +212,7 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const && textSecurity == o.textSecurity && userModify == o.userModify && wordBreak == o.wordBreak - && wordWrap == o.wordWrap + && overflowWrap == o.overflowWrap && nbspMode == o.nbspMode && khtmlLineBreak == o.khtmlLineBreak #if ENABLE(OVERFLOW_SCROLLING) @@ -264,7 +264,7 @@ bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& void StyleRareInheritedData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const { - MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::CSS); + MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS); info.addMember(textShadow); info.addInstrumentedMember(highlight); info.addMember(cursorData); diff --git a/Source/WebCore/rendering/style/StyleRareInheritedData.h b/Source/WebCore/rendering/style/StyleRareInheritedData.h index 39e096ea4..60b4ff6d9 100644 --- a/Source/WebCore/rendering/style/StyleRareInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareInheritedData.h @@ -84,7 +84,7 @@ public: unsigned textSecurity : 2; // ETextSecurity unsigned userModify : 2; // EUserModify (editing) unsigned wordBreak : 2; // EWordBreak - unsigned wordWrap : 1; // EWordWrap + unsigned overflowWrap : 1; // EOverflowWrap unsigned nbspMode : 1; // ENBSPMode unsigned khtmlLineBreak : 1; // EKHTMLLineBreak unsigned textSizeAdjust : 1; // An Apple extension. diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp index 5b800d0ac..811bfa1fe 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.cpp @@ -23,7 +23,6 @@ #include "StyleRareNonInheritedData.h" #include "ContentData.h" -#include "MemoryInstrumentation.h" #include "RenderCounter.h" #include "RenderStyle.h" #include "ShadowData.h" @@ -31,6 +30,7 @@ #include "StyleTransformData.h" #include "StyleImage.h" #include "StyleResolver.h" +#include "WebCoreMemoryInstrumentation.h" namespace WebCore { @@ -48,6 +48,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData() , m_wrapShapeOutside(RenderStyle::initialWrapShapeOutside()) , m_wrapMargin(RenderStyle::initialWrapMargin()) , m_wrapPadding(RenderStyle::initialWrapPadding()) + , m_clipPath(RenderStyle::initialClipPath()) , m_visitedLinkBackgroundColor(RenderStyle::initialBackgroundColor()) , m_order(RenderStyle::initialOrder()) , m_flowThread(RenderStyle::initialFlowThread()) @@ -118,6 +119,7 @@ StyleRareNonInheritedData::StyleRareNonInheritedData(const StyleRareNonInherited , m_wrapShapeOutside(o.m_wrapShapeOutside) , m_wrapMargin(o.m_wrapMargin) , m_wrapPadding(o.m_wrapPadding) + , m_clipPath(o.m_clipPath) , m_visitedLinkBackgroundColor(o.m_visitedLinkBackgroundColor) , m_visitedLinkOutlineColor(o.m_visitedLinkOutlineColor) , m_visitedLinkBorderLeftColor(o.m_visitedLinkBorderLeftColor) @@ -199,6 +201,7 @@ bool StyleRareNonInheritedData::operator==(const StyleRareNonInheritedData& o) c && m_wrapShapeOutside == o.m_wrapShapeOutside && m_wrapMargin == o.m_wrapMargin && m_wrapPadding == o.m_wrapPadding + && m_clipPath == o.m_clipPath && m_visitedLinkBackgroundColor == o.m_visitedLinkBackgroundColor && m_visitedLinkOutlineColor == o.m_visitedLinkOutlineColor && m_visitedLinkBorderLeftColor == o.m_visitedLinkBorderLeftColor @@ -301,7 +304,7 @@ bool StyleRareNonInheritedData::transitionDataEquivalent(const StyleRareNonInher void StyleRareNonInheritedData::reportMemoryUsage(MemoryObjectInfo* memoryObjectInfo) const { - MemoryClassInfo info(memoryObjectInfo, this, MemoryInstrumentation::CSS); + MemoryClassInfo info(memoryObjectInfo, this, WebCoreMemoryTypes::CSS); #if ENABLE(DASHBOARD_SUPPORT) info.addVector(m_dashboardRegions); #endif @@ -323,6 +326,7 @@ void StyleRareNonInheritedData::reportMemoryUsage(MemoryObjectInfo* memoryObject info.addMember(m_transitions); info.addMember(m_wrapShapeInside); info.addMember(m_wrapShapeOutside); + info.addMember(m_clipPath); info.addInstrumentedMember(m_flowThread); info.addInstrumentedMember(m_regionThread); } diff --git a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h index e6f4a18be..251ffa319 100644 --- a/Source/WebCore/rendering/style/StyleRareNonInheritedData.h +++ b/Source/WebCore/rendering/style/StyleRareNonInheritedData.h @@ -25,13 +25,13 @@ #ifndef StyleRareNonInheritedData_h #define StyleRareNonInheritedData_h +#include "BasicShapes.h" #include "CounterDirectives.h" #include "CursorData.h" #include "DataRef.h" #include "FillLayer.h" #include "LineClampValue.h" #include "NinePieceImage.h" -#include "WrapShapes.h" #include <wtf/OwnPtr.h> #include <wtf/PassRefPtr.h> #include <wtf/Vector.h> @@ -134,11 +134,13 @@ public: LengthSize m_pageSize; - RefPtr<WrapShape> m_wrapShapeInside; - RefPtr<WrapShape> m_wrapShapeOutside; + RefPtr<BasicShape> m_wrapShapeInside; + RefPtr<BasicShape> m_wrapShapeOutside; Length m_wrapMargin; Length m_wrapPadding; - + + RefPtr<BasicShape> m_clipPath; + Color m_visitedLinkBackgroundColor; Color m_visitedLinkOutlineColor; Color m_visitedLinkBorderLeftColor; diff --git a/Source/WebCore/rendering/style/WrapShapes.cpp b/Source/WebCore/rendering/style/WrapShapes.cpp deleted file mode 100644 index 61a2c9fbf..000000000 --- a/Source/WebCore/rendering/style/WrapShapes.cpp +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (C) 2012 Adobe Systems Incorporated. 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 THE COPYRIGHT HOLDER "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 THE COPYRIGHT HOLDER 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 "WrapShapes.h" - -namespace WebCore { - -void WrapShape::destroy() -{ - switch (m_type) { - case WRAP_SHAPE_RECTANGLE: - delete static_cast<WrapShapeRectangle*>(this); - return; - case WRAP_SHAPE_CIRCLE: - delete static_cast<WrapShapeCircle*>(this); - return; - case WRAP_SHAPE_ELLIPSE: - delete static_cast<WrapShapeEllipse*>(this); - return; - case WRAP_SHAPE_POLYGON: - delete static_cast<WrapShapePolygon*>(this); - return; - } - ASSERT_NOT_REACHED(); -} - -} diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp index 8f842ee21..acc0c6d36 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp @@ -178,13 +178,13 @@ bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, Hit return false; // FOs establish a stacking context, so we need to hit-test all layers. - HitTestPoint hitTestPoint(roundedLayoutPoint(localPoint)); - return RenderBlock::nodeAtPoint(request, result, hitTestPoint, LayoutPoint(), HitTestForeground) - || RenderBlock::nodeAtPoint(request, result, hitTestPoint, LayoutPoint(), HitTestFloat) - || RenderBlock::nodeAtPoint(request, result, hitTestPoint, LayoutPoint(), HitTestChildBlockBackgrounds); + HitTestLocation hitTestLocation(roundedLayoutPoint(localPoint)); + return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestForeground) + || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestFloat) + || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds); } -bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, HitTestAction) +bool RenderSVGForeignObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) { ASSERT_NOT_REACHED(); return false; diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h index 7e52e00c2..0d65d5741 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h @@ -51,7 +51,7 @@ public: virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(FloatPoint(), m_viewport.size()); } virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual bool isSVGForeignObject() const { return true; } virtual void mapLocalToContainer(RenderBoxModelObject* repaintContainer, TransformState&, MapLocalToContainerFlags mode = ApplyContainerFlip | SnapOffsetForTransforms, bool* wasFixed = 0) const OVERRIDE; @@ -59,8 +59,8 @@ public: virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } private: - virtual void computeLogicalWidth(); - virtual void computeLogicalHeight(); + virtual void computeLogicalWidth() OVERRIDE; + virtual void computeLogicalHeight() OVERRIDE; virtual const AffineTransform& localToParentTransform() const; virtual AffineTransform localTransform() const { return m_localTransform; } diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index 082bf487e..d44a93da4 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -111,7 +111,7 @@ void RenderSVGModelObject::styleDidChange(StyleDifference diff, const RenderStyl SVGResourcesCache::clientStyleChanged(this, diff, style()); } -bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, HitTestAction) +bool RenderSVGModelObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) { ASSERT_NOT_REACHED(); return false; diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index a28376625..a99dd9da7 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -71,7 +71,7 @@ protected: private: // This method should never be called, SVG uses a different nodeAtPoint method - bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; }; } diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h index faa225892..26fbc6f93 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h @@ -22,7 +22,6 @@ #if ENABLE(SVG) #include "FloatRect.h" -#include "RenderObject.h" #include "RenderSVGResourceContainer.h" #include "SVGMarkerElement.h" #include "SVGStyledElement.h" @@ -32,6 +31,7 @@ namespace WebCore { class AffineTransform; +class RenderObject; class RenderSVGResourceMarker : public RenderSVGResourceContainer { public: diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index 5d56b5ce7..f7115d926 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -415,9 +415,9 @@ void RenderSVGRoot::updateCachedBoundaries() m_repaintBoundingBox.inflate(borderAndPaddingWidth()); } -bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) +bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) { - LayoutPoint pointInParent = pointInContainer.point() - toLayoutSize(accumulatedOffset); + LayoutPoint pointInParent = locationInContainer.point() - toLayoutSize(accumulatedOffset); LayoutPoint pointInBorderBox = pointInParent - toLayoutSize(location()); // Only test SVG content if the point is in our content box. @@ -429,7 +429,7 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { updateHitTestResult(result, pointInBorderBox); - if (!result.addNodeToRectBasedTestResult(child->node(), pointInContainer)) + if (!result.addNodeToRectBasedTestResult(child->node(), request, locationInContainer)) return true; } } @@ -442,9 +442,9 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able // to detect these hits anymore. LayoutRect boundsRect(accumulatedOffset + location(), size()); - if (pointInContainer.intersects(boundsRect)) { + if (locationInContainer.intersects(boundsRect)) { updateHitTestResult(result, pointInBorderBox); - if (!result.addNodeToRectBasedTestResult(node(), pointInContainer, boundsRect)) + if (!result.addNodeToRectBasedTestResult(node(), request, locationInContainer, boundsRect)) return true; } } diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h index a0566b134..cddd311fd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.h +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h @@ -90,7 +90,7 @@ private: virtual FloatRect strokeBoundingBox() const { return m_strokeBoundingBox; } virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual LayoutRect clippedOverflowRectForRepaint(RenderBoxModelObject* repaintContainer) const; virtual void computeFloatRectForRepaint(RenderBoxModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const; diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index de2f0165c..2945fe48b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -451,15 +451,15 @@ bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResul if (!SVGRenderSupport::pointInClippingArea(this, localPoint)) return false; - HitTestPoint hitTestPoint(LayoutPoint(flooredIntPoint(localPoint))); - return RenderBlock::nodeAtPoint(request, result, hitTestPoint, LayoutPoint(), hitTestAction); + HitTestLocation hitTestLocation(LayoutPoint(flooredIntPoint(localPoint))); + return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), hitTestAction); } } return false; } -bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint&, const LayoutPoint&, HitTestAction) +bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation&, const LayoutPoint&, HitTestAction) { ASSERT_NOT_REACHED(); return false; diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 0a0c2856b..cd2e38f79 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -62,7 +62,7 @@ private: virtual bool isSVGText() const { return true; } virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) OVERRIDE; virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); virtual VisiblePosition positionForPoint(const LayoutPoint&); diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index 47bb63de2..7864d4ee8 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -701,7 +701,7 @@ FloatRect SVGInlineTextBox::calculateBoundaries() const return textRect; } -bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) +bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); @@ -714,9 +714,9 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& FloatPoint boxOrigin(x(), y()); boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); - if (pointInContainer.intersects(rect)) { - renderer()->updateHitTestResult(result, pointInContainer.point() - toLayoutSize(accumulatedOffset)); - if (!result.addNodeToRectBasedTestResult(renderer()->node(), pointInContainer, rect)) + if (locationInContainer.intersects(rect)) { + renderer()->updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + if (!result.addNodeToRectBasedTestResult(renderer()->node(), request, locationInContainer, rect)) return true; } } diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index a4e03d828..ef399c724 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -79,7 +79,7 @@ private: void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition); void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestPoint& pointInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; + virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) OVERRIDE; private: float m_logicalHeight; diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp index e2adb3063..6e3cd2dcb 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp @@ -27,6 +27,7 @@ #if ENABLE(SVG) #include "SVGRenderingContext.h" +#include "BasicShapes.h" #include "Frame.h" #include "FrameView.h" #include "RenderSVGResource.h" @@ -122,6 +123,15 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI } } + BasicShape* clipShape = style->clipPath(); + if (clipShape) { + // FIXME: Investigate if it is better to store and update a Path object in RenderStyle. + // https://bugs.webkit.org/show_bug.cgi?id=95619 + Path clipPath; + clipShape->path(clipPath, object->objectBoundingBox()); + m_paintInfo->context->clipPath(clipPath, clipShape->windRule()); + } + SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(m_object); if (!resources) { #if ENABLE(FILTERS) @@ -139,7 +149,8 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderObject* object, PaintI } } - if (RenderSVGResourceClipper* clipper = resources->clipper()) { + RenderSVGResourceClipper* clipper = resources->clipper(); + if (!clipShape && clipper) { if (!clipper->applyResource(m_object, style, m_paintInfo->context, ApplyToDefaultMode)) return; } @@ -205,14 +216,10 @@ bool SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const A GraphicsContext* imageContext = image->context(); ASSERT(imageContext); - // This is done in absolute coordinates. - imageContext->translate(-paintRect.x(), -paintRect.y()); - - imageContext->concatCTM(absoluteTransform); - - // This happens in local coordinates. imageContext->scale(FloatSize(static_cast<float>(clampedSize.width()) / paintRect.width(), static_cast<float>(clampedSize.height()) / paintRect.height())); + imageContext->translate(-paintRect.x(), -paintRect.y()); + imageContext->concatCTM(absoluteTransform); imageBuffer = image.release(); return true; diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.h b/Source/WebCore/rendering/svg/SVGRenderingContext.h index 5d38ce495..c88168968 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.h +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.h @@ -27,7 +27,6 @@ #if ENABLE(SVG) #include "ImageBuffer.h" -#include "LayoutTypes.h" #include "PaintInfo.h" namespace WebCore { diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp index d6cbe4c50..99bfbd4d3 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp @@ -56,7 +56,7 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& m_width = scaledFont.width(run, length, m_glyph.name) / scalingFactor; m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; - m_glyph.unicodeString = String(run.characters(), length); + m_glyph.unicodeString = run.is8Bit() ? String(run.characters8(), length) : String(run.characters16(), length); m_glyph.isValid = true; ASSERT(length >= 0); diff --git a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp index 5ac85cbbe..ff9ca3073 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp @@ -30,7 +30,7 @@ namespace WebCore { SVGTextMetricsBuilder::SVGTextMetricsBuilder() : m_text(0) - , m_run(0, 0) + , m_run(static_cast<const UChar*>(0), 0) , m_textPosition(0) , m_isComplexText(false) , m_totalWidth(0) @@ -148,7 +148,7 @@ void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, Measu int surrogatePairCharacters = 0; while (advance()) { - const UChar* currentCharacter = m_run.data(m_textPosition); + const UChar* currentCharacter = m_run.data16(m_textPosition); if (*currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || *data->lastCharacter == ' ')) { if (data->processRenderer) textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); |