diff options
Diffstat (limited to 'WebCore/rendering/RenderLayer.cpp')
| -rw-r--r-- | WebCore/rendering/RenderLayer.cpp | 164 |
1 files changed, 119 insertions, 45 deletions
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 03a1e75..7994325 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. * * Portions are Copyright (C) 1998 Netscape Communications Corporation. * @@ -44,7 +44,6 @@ #include "config.h" #include "RenderLayer.h" -#include "CString.h" #include "CSSPropertyNames.h" #include "CSSStyleDeclaration.h" #include "CSSStyleSelector.h" @@ -83,6 +82,7 @@ #include "TransformationMatrix.h" #include "TransformState.h" #include "TranslateTransformOperation.h" +#include <wtf/text/CString.h> #include <wtf/StdLibExtras.h> #include <wtf/UnusedParam.h> @@ -245,7 +245,7 @@ bool RenderLayer::hasAcceleratedCompositing() const #endif } -void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) +void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags, IntPoint* cachedOffset) { if (flags & DoFullRepaint) { renderer()->repaint(); @@ -259,13 +259,49 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) #endif } + updateLayerPosition(); // For relpositioned layers or non-positioned layers, // we need to keep in sync, since we may have shifted relative // to our parent layer. + IntPoint oldCachedOffset; + if (cachedOffset) { + // We can't cache our offset to the repaint container if the mapping is anything more complex than a simple translation + bool disableOffsetCache = renderer()->hasColumns() || renderer()->hasTransform() || isComposited(); +#if ENABLE(SVG) + disableOffsetCache = disableOffsetCache || renderer()->isSVGRoot(); +#endif + if (disableOffsetCache) + cachedOffset = 0; // If our cached offset is invalid make sure it's not passed to any of our children + else { + oldCachedOffset = *cachedOffset; + // Frequently our parent layer's renderer will be the same as our renderer's containing block. In that case, + // we just update the cache using our offset to our parent (which is m_x / m_y). Otherwise, regenerated cached + // offsets to the root from the render tree. + if (!m_parent || m_parent->renderer() == renderer()->containingBlock()) + cachedOffset->move(m_x, m_y); // Fast case + else { + int x = 0; + int y = 0; + convertToLayerCoords(root(), x, y); + *cachedOffset = IntPoint(x, y); + } + } + } int x = 0; int y = 0; - convertToLayerCoords(root(), x, y); + if (cachedOffset) { + x += cachedOffset->x(); + y += cachedOffset->y(); +#ifndef NDEBUG + int nonCachedX = 0; + int nonCachedY = 0; + convertToLayerCoords(root(), nonCachedX, nonCachedY); + ASSERT(x == nonCachedX); + ASSERT(y == nonCachedY); +#endif + } else + convertToLayerCoords(root(), x, y); positionOverflowControls(x, y); updateVisibilityStatus(); @@ -281,7 +317,9 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer); - IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); + IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer, cachedOffset); + // FIXME: Should ASSERT that value calculated for newOutlineBox using the cached offset is the same + // as the value not using the cached offset, but we can't due to https://bugs.webkit.org/show_bug.cgi?id=37048 if (flags & CheckForRepaint) { if (view && !view->printing()) { if (m_needsFullRepaint) { @@ -289,7 +327,7 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) if (newRect != m_repaintRect) renderer()->repaintUsingContainer(repaintContainer, newRect); } else - renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox); + renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox, &newRect, &newOutlineBox); } } m_repaintRect = newRect; @@ -313,7 +351,7 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) #endif for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) - child->updateLayerPositions(flags); + child->updateLayerPositions(flags, cachedOffset); #if USE(ACCELERATED_COMPOSITING) if ((flags & UpdateCompositingLayers) && isComposited()) @@ -323,6 +361,9 @@ void RenderLayer::updateLayerPositions(UpdateLayerPositionsFlags flags) // With all our children positioned, now update our marquee if we need to. if (m_marquee) m_marquee->updateMarqueePosition(); + + if (cachedOffset) + *cachedOffset = oldCachedOffset; } void RenderLayer::computeRepaintRects() @@ -332,6 +373,22 @@ void RenderLayer::computeRepaintRects() m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer); } +void RenderLayer::updateRepaintRectsAfterScroll(bool fixed) +{ + if (fixed || renderer()->style()->position() == FixedPosition) { + computeRepaintRects(); + fixed = true; + } else if (renderer()->hasTransform()) { + // Transforms act as fixed position containers, so nothing inside a + // transformed element can be fixed relative to the viewport if the + // transformed element is not fixed itself or child of a fixed element. + return; + } + + for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) + child->updateRepaintRectsAfterScroll(fixed); +} + void RenderLayer::updateTransform() { // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set, @@ -571,15 +628,20 @@ void RenderLayer::updateLayerPosition() RenderLayer* positionedParent = enclosingPositionedAncestor(); // For positioned layers, we subtract out the enclosing positioned layer's scroll offset. - positionedParent->subtractScrolledContentOffset(x, y); + IntSize offset = positionedParent->scrolledContentOffset(); + x -= offset.width(); + y -= offset.height(); if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) { IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer())); x += offset.width(); y += offset.height(); } - } else if (parent()) - parent()->subtractScrolledContentOffset(x, y); + } else if (parent()) { + IntSize offset = parent()->scrolledContentOffset(); + x -= offset.width(); + y -= offset.height(); + } // FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers. @@ -714,6 +776,11 @@ RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const RenderLayer* RenderLayer::clippingRoot() const { +#if USE(ACCELERATED_COMPOSITING) + if (isComposited()) + return const_cast<RenderLayer*>(this); +#endif + const RenderLayer* current = this; while (current) { if (current->renderer()->isRenderView()) @@ -1175,21 +1242,6 @@ void RenderLayer::scrollByRecursively(int xDelta, int yDelta) } } - -void -RenderLayer::addScrolledContentOffset(int& x, int& y) const -{ - x += scrollXOffset() + m_scrollLeftOverflow; - y += scrollYOffset(); -} - -void -RenderLayer::subtractScrolledContentOffset(int& x, int& y) const -{ - x -= scrollXOffset() + m_scrollLeftOverflow; - y -= scrollYOffset(); -} - void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint) { RenderBox* box = renderBox(); @@ -1250,15 +1302,24 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai view->updateWidgetPositions(); } - // The caret rect needs to be invalidated after scrolling + RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint(); + IntRect rectForRepaint = renderer()->clippedOverflowRectForRepaint(repaintContainer); + Frame* frame = renderer()->document()->frame(); - if (frame) + if (frame) { + // The caret rect needs to be invalidated after scrolling frame->selection()->setNeedsLayout(); + FloatQuad quadForFakeMouseMoveEvent = FloatQuad(rectForRepaint); + if (repaintContainer) + quadForFakeMouseMoveEvent = repaintContainer->localToAbsoluteQuad(quadForFakeMouseMoveEvent); + frame->eventHandler()->dispatchFakeMouseMoveEventSoonInQuad(quadForFakeMouseMoveEvent); + } + // Just schedule a full repaint of our object. - if (repaint) - renderer()->repaint(); - + if (view && repaint) + renderer()->repaintUsingContainer(repaintContainer, rectForRepaint); + if (updateScrollbars) { if (m_hBar) m_hBar->setValue(scrollXOffset()); @@ -2876,17 +2937,19 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa // If we establish a clip at all, then go ahead and make sure our background // rect is intersected with our layer's bounds. - if (ShadowData* boxShadow = renderer()->style()->boxShadow()) { + // FIXME: This could be changed to just use generic visual overflow. + // See https://bugs.webkit.org/show_bug.cgi?id=37467 for more information. + if (const ShadowData* boxShadow = renderer()->style()->boxShadow()) { IntRect overflow = layerBounds; do { - if (boxShadow->style == Normal) { + if (boxShadow->style() == Normal) { IntRect shadowRect = layerBounds; - shadowRect.move(boxShadow->x, boxShadow->y); - shadowRect.inflate(boxShadow->blur + boxShadow->spread); + shadowRect.move(boxShadow->x(), boxShadow->y()); + shadowRect.inflate(boxShadow->blur() + boxShadow->spread()); overflow.unite(shadowRect); } - boxShadow = boxShadow->next; + boxShadow = boxShadow->next(); } while (boxShadow); backgroundRect.intersect(overflow); } else @@ -2987,7 +3050,7 @@ IntRect RenderLayer::localBoundingBox() const int top = firstBox->topVisibleOverflow(); int bottom = inlineFlow->lastLineBox()->bottomVisibleOverflow(); int left = firstBox->x(); - for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) + for (InlineFlowBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox()) left = min(left, curr->x()); result = IntRect(left, top, width(), bottom - top); } else if (renderer()->isTableRow()) { @@ -3160,22 +3223,33 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR // Locate the common ancestor render object for the two renderers. RenderObject* ancestor = commonAncestor(oldHoverObj, newHoverObj); + Vector<RefPtr<Node>, 32> nodesToRemoveFromChain; + Vector<RefPtr<Node>, 32> nodesToAddToChain; + if (oldHoverObj != newHoverObj) { // The old hover path only needs to be cleared up to (and not including) the common ancestor; for (RenderObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) { - if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { - curr->node()->setActive(false); - curr->node()->setHovered(false); - } + if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) + nodesToRemoveFromChain.append(curr->node()); } } // Now set the hover state for our new object up to the root. for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) { - if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) { - curr->node()->setActive(request.active()); - curr->node()->setHovered(true); - } + if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) + nodesToAddToChain.append(curr->node()); + } + + size_t removeCount = nodesToRemoveFromChain.size(); + for (size_t i = 0; i < removeCount; ++i) { + nodesToRemoveFromChain[i]->setActive(false); + nodesToRemoveFromChain[i]->setHovered(false); + } + + size_t addCount = nodesToAddToChain.size(); + for (size_t i = 0; i < addCount; ++i) { + nodesToAddToChain[i]->setActive(request.active()); + nodesToAddToChain[i]->setHovered(true); } } @@ -3519,7 +3593,7 @@ void showLayerTree(const WebCore::RenderLayer* layer) return; if (WebCore::Frame* frame = layer->renderer()->document()->frame()) { - WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers); + WebCore::String output = externalRepresentation(frame, WebCore::RenderAsTextShowAllLayers | WebCore::RenderAsTextShowLayerNesting | WebCore::RenderAsTextShowCompositedLayers | WebCore::RenderAsTextShowAddresses); fprintf(stderr, "%s\n", output.utf8().data()); } } |
