summaryrefslogtreecommitdiffstats
path: root/WebCore/rendering/RenderLayer.cpp
diff options
context:
space:
mode:
authorFeng Qian <>2009-04-10 18:11:29 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-10 18:11:29 -0700
commit8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch)
tree181bf9a400c30a1bf34ea6d72560e8d00111d549 /WebCore/rendering/RenderLayer.cpp
parent7ed56f225e0ade046e1c2178977f72b2d896f196 (diff)
downloadexternal_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip
external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz
external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'WebCore/rendering/RenderLayer.cpp')
-rw-r--r--WebCore/rendering/RenderLayer.cpp1214
1 files changed, 880 insertions, 334 deletions
diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp
index 1a538c6..fd88120 100644
--- a/WebCore/rendering/RenderLayer.cpp
+++ b/WebCore/rendering/RenderLayer.cpp
@@ -44,10 +44,13 @@
#include "config.h"
#include "RenderLayer.h"
+#include "CString.h"
#include "CSSPropertyNames.h"
+#include "CSSStyleSelector.h"
#include "Document.h"
#include "EventHandler.h"
#include "EventNames.h"
+#include "FloatPoint3D.h"
#include "FloatRect.h"
#include "FocusController.h"
#include "Frame.h"
@@ -73,8 +76,16 @@
#include "Scrollbar.h"
#include "ScrollbarTheme.h"
#include "SelectionController.h"
+#include "TransformationMatrix.h"
+#include "TransformState.h"
#include "TranslateTransformOperation.h"
#include <wtf/StdLibExtras.h>
+#include <wtf/UnusedParam.h>
+
+#if USE(ACCELERATED_COMPOSITING)
+#include "RenderLayerBacking.h"
+#include "RenderLayerCompositor.h"
+#endif
#if ENABLE(SVG)
#include "SVGNames.h"
@@ -88,12 +99,6 @@ namespace WebCore {
using namespace HTMLNames;
-const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterIfNeeded = { RenderLayer::noScroll, RenderLayer::alignCenter, RenderLayer::alignToClosestEdge };
-const RenderLayer::ScrollAlignment RenderLayer::gAlignToEdgeIfNeeded = { RenderLayer::noScroll, RenderLayer::alignToClosestEdge, RenderLayer::alignToClosestEdge };
-const RenderLayer::ScrollAlignment RenderLayer::gAlignCenterAlways = { RenderLayer::alignCenter, RenderLayer::alignCenter, RenderLayer::alignCenter };
-const RenderLayer::ScrollAlignment RenderLayer::gAlignTopAlways = { RenderLayer::alignTop, RenderLayer::alignTop, RenderLayer::alignTop };
-const RenderLayer::ScrollAlignment RenderLayer::gAlignBottomAlways = { RenderLayer::alignBottom, RenderLayer::alignBottom, RenderLayer::alignBottom };
-
const int MinimumWidthWhileResizing = 100;
const int MinimumHeightWhileResizing = 40;
@@ -116,7 +121,7 @@ void ClipRects::destroy(RenderArena* renderArena)
renderArena->free(*(size_t *)this, this);
}
-RenderLayer::RenderLayer(RenderBox* renderer)
+RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
: m_renderer(renderer)
, m_parent(0)
, m_previous(0)
@@ -138,15 +143,15 @@ RenderLayer::RenderLayer(RenderBox* renderer)
, m_inResizeMode(false)
, m_posZOrderList(0)
, m_negZOrderList(0)
- , m_overflowList(0)
+ , m_normalFlowList(0)
, m_clipRects(0)
#ifndef NDEBUG
, m_clipRectsRoot(0)
#endif
, m_scrollDimensionsDirty(true)
, m_zOrderListsDirty(true)
- , m_overflowListDirty(true)
- , m_isOverflowOnly(shouldBeOverflowOnly())
+ , m_normalFlowListDirty(true)
+ , m_isNormalFlowOnly(shouldBeNormalFlowOnly())
, m_usedTransparency(false)
, m_paintingInsideReflection(false)
, m_inOverflowRelayout(false)
@@ -156,10 +161,15 @@ RenderLayer::RenderLayer(RenderBox* renderer)
, m_hasVisibleContent(false)
, m_visibleDescendantStatusDirty(false)
, m_hasVisibleDescendant(false)
+ , m_3DTransformedDescendantStatusDirty(true)
+ , m_has3DTransformedDescendant(false)
+#if USE(ACCELERATED_COMPOSITING)
+ , m_hasCompositingDescendant(false)
+ , m_mustOverlayCompositedLayers(false)
+#endif
, m_marquee(0)
, m_staticX(0)
, m_staticY(0)
- , m_transform(0)
, m_reflection(0)
, m_scrollCorner(0)
, m_resizer(0)
@@ -185,9 +195,13 @@ RenderLayer::~RenderLayer()
delete m_posZOrderList;
delete m_negZOrderList;
- delete m_overflowList;
+ delete m_normalFlowList;
delete m_marquee;
+#if USE(ACCELERATED_COMPOSITING)
+ clearBacking();
+#endif
+
// Make sure we have no lingering clip rects.
ASSERT(!m_clipRects);
@@ -204,11 +218,40 @@ RenderLayer::~RenderLayer()
m_resizer->destroy();
}
+#if USE(ACCELERATED_COMPOSITING)
+RenderLayerCompositor* RenderLayer::compositor() const
+{
+ ASSERT(renderer()->view());
+ return renderer()->view()->compositor();
+}
+
+void RenderLayer::rendererContentChanged()
+{
+ if (m_backing)
+ m_backing->rendererContentChanged();
+}
+#endif // USE(ACCELERATED_COMPOSITING)
+
+void RenderLayer::setStaticY(int staticY)
+{
+ if (m_staticY == staticY)
+ return;
+ m_staticY = staticY;
+ renderer()->setChildNeedsLayout(true, false);
+}
+
void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
{
if (doFullRepaint) {
renderer()->repaint();
+#if USE(ACCELERATED_COMPOSITING)
+ checkForRepaint = false;
+ // We need the full repaint to propagate to child layers if we are hardware compositing.
+ if (!compositor()->inCompositingMode())
+ doFullRepaint = false;
+#else
checkForRepaint = doFullRepaint = false;
+#endif
}
updateLayerPosition(); // For relpositioned layers or non-positioned layers,
@@ -231,16 +274,17 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
// from updateScrollInfoAfterLayout().
ASSERT(!view->layoutStateEnabled());
- IntRect newRect = renderer()->absoluteClippedOverflowRect();
- IntRect newOutlineBox = renderer()->absoluteOutlineBounds();
+ RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
+ IntRect newRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
+ IntRect newOutlineBox = renderer()->outlineBoundsForRepaint(repaintContainer);
if (checkForRepaint) {
if (view && !view->printing()) {
if (m_needsFullRepaint) {
- view->repaintViewRectangle(m_repaintRect);
+ renderer()->repaintUsingContainer(repaintContainer, m_repaintRect);
if (newRect != m_repaintRect)
- view->repaintViewRectangle(newRect);
+ renderer()->repaintUsingContainer(repaintContainer, newRect);
} else
- renderer()->repaintAfterLayoutIfNeeded(m_repaintRect, m_outlineBox);
+ renderer()->repaintAfterLayoutIfNeeded(repaintContainer, m_repaintRect, m_outlineBox);
}
}
m_repaintRect = newRect;
@@ -258,6 +302,14 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(doFullRepaint, checkForRepaint);
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (!parent())
+ compositor()->updateRootLayerPosition();
+
+ if (isComposited())
+ backing()->updateAfterLayout();
+#endif
// With all our children positioned, now update our marquee if we need to.
if (m_marquee)
@@ -266,7 +318,11 @@ void RenderLayer::updateLayerPositions(bool doFullRepaint, bool checkForRepaint)
void RenderLayer::updateTransform()
{
- bool hasTransform = renderer()->hasTransform();
+ // hasTransform() on the renderer is also true when there is transform-style: preserve-3d or perspective set,
+ // so check style too.
+ bool hasTransform = renderer()->hasTransform() && renderer()->style()->hasTransform();
+ bool had3DTransform = has3DTransform();
+
bool hadTransform = m_transform;
if (hasTransform != hadTransform) {
if (hasTransform)
@@ -276,9 +332,33 @@ void RenderLayer::updateTransform()
}
if (hasTransform) {
- m_transform->reset();
- renderer()->style()->applyTransform(*m_transform, renderer()->borderBoxRect().size());
+ RenderBox* box = renderBox();
+ ASSERT(box);
+ m_transform->makeIdentity();
+ box->style()->applyTransform(*m_transform, box->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+ makeMatrixRenderable(*m_transform);
}
+
+ if (had3DTransform != has3DTransform())
+ dirty3DTransformedDescendantStatus();
+}
+
+TransformationMatrix RenderLayer::currentTransform() const
+{
+ if (!m_transform)
+ return TransformationMatrix();
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (renderer()->style()->isRunningAcceleratedAnimation()) {
+ TransformationMatrix currTransform;
+ RefPtr<RenderStyle> style = renderer()->animation()->getAnimatedStyleForRenderer(renderer());
+ style->applyTransform(currTransform, renderBox()->borderBoxRect().size(), RenderStyle::IncludeTransformOrigin);
+ makeMatrixRenderable(currTransform);
+ return currTransform;
+ }
+#endif
+
+ return *m_transform;
}
void RenderLayer::setHasVisibleContent(bool b)
@@ -288,9 +368,10 @@ void RenderLayer::setHasVisibleContent(bool b)
m_visibleContentStatusDirty = false;
m_hasVisibleContent = b;
if (m_hasVisibleContent) {
- m_repaintRect = renderer()->absoluteClippedOverflowRect();
- m_outlineBox = renderer()->absoluteOutlineBounds();
- if (!isOverflowOnly())
+ RenderBoxModelObject* repaintContainer = renderer()->containerForRepaint();
+ m_repaintRect = renderer()->clippedOverflowRectForRepaint(repaintContainer);
+ m_outlineBox = renderer()->outlineBoundsForRepaint(repaintContainer);
+ if (!isNormalFlowOnly())
dirtyStackingContextZOrderLists();
}
if (parent())
@@ -372,38 +453,84 @@ void RenderLayer::updateVisibilityStatus()
}
}
+void RenderLayer::dirty3DTransformedDescendantStatus()
+{
+ RenderLayer* curr = stackingContext();
+ if (curr)
+ curr->m_3DTransformedDescendantStatusDirty = true;
+
+ // This propagates up through preserve-3d hierarchies to the enclosing flattening layer.
+ // Note that preserves3D() creates stacking context, so we can just run up the stacking contexts.
+ while (curr && curr->preserves3D()) {
+ curr->m_3DTransformedDescendantStatusDirty = true;
+ curr = curr->stackingContext();
+ }
+}
+
+// Return true if this layer or any preserve-3d descendants have 3d.
+bool RenderLayer::update3DTransformedDescendantStatus()
+{
+ if (m_3DTransformedDescendantStatusDirty) {
+ m_has3DTransformedDescendant = false;
+
+ // Transformed or preserve-3d descendants can only be in the z-order lists, not
+ // in the normal flow list, so we only need to check those.
+ if (m_posZOrderList) {
+ for (unsigned i = 0; i < m_posZOrderList->size(); ++i)
+ m_has3DTransformedDescendant |= m_posZOrderList->at(i)->update3DTransformedDescendantStatus();
+ }
+
+ // Now check our negative z-index children.
+ if (m_negZOrderList) {
+ for (unsigned i = 0; i < m_negZOrderList->size(); ++i)
+ m_has3DTransformedDescendant |= m_negZOrderList->at(i)->update3DTransformedDescendantStatus();
+ }
+ }
+
+ // If we live in a 3d hierarchy, then the layer at the root of that hierarchy needs
+ // the m_has3DTransformedDescendant set.
+ if (preserves3D())
+ return has3DTransform() || m_has3DTransformedDescendant;
+
+ return has3DTransform();
+}
+
void RenderLayer::updateLayerPosition()
{
// Clear our cached clip rect information.
clearClipRects();
- int x = renderer()->x();
- int y = renderer()->y();
+ RenderBox* rendererBox = renderBox();
+
+ int x = rendererBox ? rendererBox->x() : 0;
+ int y = rendererBox ? rendererBox->y() : 0;
if (!renderer()->isPositioned() && renderer()->parent()) {
// We must adjust our position by walking up the render tree looking for the
// nearest enclosing object with a layer.
- RenderBox* curr = renderer()->parentBox();
+ RenderObject* curr = renderer()->parent();
while (curr && !curr->hasLayer()) {
- if (!curr->isTableRow()) {
+ if (curr->isBox() && !curr->isTableRow()) {
// Rows and cells share the same coordinate space (that of the section).
// Omit them when computing our xpos/ypos.
- x += curr->x();
- y += curr->y();
+ RenderBox* currBox = toRenderBox(curr);
+ x += currBox->x();
+ y += currBox->y();
}
- curr = curr->parentBox();
+ curr = curr->parent();
}
- if (curr->isTableRow()) {
+ if (curr->isBox() && curr->isTableRow()) {
// Put ourselves into the row coordinate space.
- x -= curr->x();
- y -= curr->y();
+ RenderBox* currBox = toRenderBox(curr);
+ x -= currBox->x();
+ y -= currBox->y();
}
}
m_relX = m_relY = 0;
if (renderer()->isRelPositioned()) {
- m_relX = toRenderBox(renderer())->relativePositionOffsetX();
- m_relY = toRenderBox(renderer())->relativePositionOffsetY();
+ m_relX = renderer()->relativePositionOffsetX();
+ m_relY = renderer()->relativePositionOffsetY();
x += m_relX; y += m_relY;
}
@@ -414,8 +541,8 @@ void RenderLayer::updateLayerPosition()
// For positioned layers, we subtract out the enclosing positioned layer's scroll offset.
positionedParent->subtractScrolledContentOffset(x, y);
- if (renderer()->isPositioned()) {
- IntSize offset = toRenderBox(renderer())->offsetForPositionedInContainer(positionedParent->renderer());
+ if (renderer()->isPositioned() && positionedParent->renderer()->isRelPositioned() && positionedParent->renderer()->isRenderInline()) {
+ IntSize offset = toRenderInline(positionedParent->renderer())->relativePositionedInlineOffset(toRenderBox(renderer()));
x += offset.width();
y += offset.height();
}
@@ -424,33 +551,74 @@ void RenderLayer::updateLayerPosition()
// FIXME: We'd really like to just get rid of the concept of a layer rectangle and rely on the renderers.
- setPos(x, y);
+ setLocation(x, y);
if (renderer()->isRenderInline()) {
- RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
+ RenderInline* inlineFlow = toRenderInline(renderer());
IntRect lineBox = inlineFlow->linesBoundingBox();
setWidth(lineBox.width());
setHeight(lineBox.height());
- } else {
- setWidth(renderer()->width());
- setHeight(renderer()->height());
-
- if (!renderer()->hasOverflowClip()) {
- if (renderer()->overflowWidth() > renderer()->width())
- setWidth(renderer()->overflowWidth());
- if (renderer()->overflowHeight() > renderer()->height())
- setHeight(renderer()->overflowHeight());
+ } else if (RenderBox* box = renderBox()) {
+ setWidth(box->width());
+ setHeight(box->height());
+
+ if (!box->hasOverflowClip()) {
+ if (box->overflowWidth() > box->width())
+ setWidth(box->overflowWidth());
+ if (box->overflowHeight() > box->height())
+ setHeight(box->overflowHeight());
}
}
}
-RenderLayer *RenderLayer::stackingContext() const
+TransformationMatrix RenderLayer::perspectiveTransform() const
{
- RenderLayer* curr = parent();
- for ( ; curr && !curr->renderer()->isRenderView() && !curr->renderer()->isRoot() &&
- curr->renderer()->style()->hasAutoZIndex();
- curr = curr->parent()) { }
- return curr;
+ if (!renderer()->hasTransform())
+ return TransformationMatrix();
+
+ RenderStyle* style = renderer()->style();
+ if (!style->hasPerspective())
+ return TransformationMatrix();
+
+ // Maybe fetch the perspective from the backing?
+ const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
+ const float boxWidth = borderBox.width();
+ const float boxHeight = borderBox.height();
+
+ float perspectiveOriginX = style->perspectiveOriginX().calcFloatValue(boxWidth);
+ float perspectiveOriginY = style->perspectiveOriginY().calcFloatValue(boxHeight);
+
+ // A perspective origin of 0,0 makes the vanishing point in the center of the element.
+ // We want it to be in the top-left, so subtract half the height and width.
+ perspectiveOriginX -= boxWidth / 2.0f;
+ perspectiveOriginY -= boxHeight / 2.0f;
+
+ TransformationMatrix t;
+ t.translate(perspectiveOriginX, perspectiveOriginY);
+ t.applyPerspective(style->perspective());
+ t.translate(-perspectiveOriginX, -perspectiveOriginY);
+
+ return t;
+}
+
+FloatPoint RenderLayer::perspectiveOrigin() const
+{
+ if (!renderer()->hasTransform())
+ return FloatPoint();
+
+ const IntRect borderBox = toRenderBox(renderer())->borderBoxRect();
+ RenderStyle* style = renderer()->style();
+
+ return FloatPoint(style->perspectiveOriginX().calcFloatValue(borderBox.width()),
+ style->perspectiveOriginY().calcFloatValue(borderBox.height()));
+}
+
+RenderLayer* RenderLayer::stackingContext() const
+{
+ RenderLayer* layer = parent();
+ while (layer && !layer->renderer()->isRenderView() && !layer->renderer()->isRoot() && layer->renderer()->style()->hasAutoZIndex())
+ layer = layer->parent();
+ return layer;
}
RenderLayer* RenderLayer::enclosingPositionedAncestor() const
@@ -469,6 +637,27 @@ RenderLayer* RenderLayer::enclosingTransformedAncestor() const
return curr;
}
+#if USE(ACCELERATED_COMPOSITING)
+RenderLayer* RenderLayer::enclosingCompositingLayer(bool includeSelf) const
+{
+ if (includeSelf && isComposited())
+ return const_cast<RenderLayer*>(this);
+
+ // Compositing layers are parented according to stacking order and overflow list,
+ // so we have to check whether the parent is a stacking context, or whether
+ // the child is overflow-only.
+ bool inNormalFlowList = isNormalFlowOnly();
+ for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
+ if (curr->isComposited() && (inNormalFlowList || curr->isStackingContext()))
+ return curr;
+
+ inNormalFlowList = curr->isNormalFlowOnly();
+ }
+
+ return 0;
+}
+#endif
+
IntPoint RenderLayer::absoluteToContents(const IntPoint& absolutePoint) const
{
// We don't use convertToLayerCoords because it doesn't know about transforms
@@ -487,18 +676,24 @@ bool RenderLayer::requiresSlowRepaints() const
bool RenderLayer::isTransparent() const
{
#if ENABLE(SVG)
- if (renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
+ if (renderer()->node() && renderer()->node()->namespaceURI() == SVGNames::svgNamespaceURI)
return false;
#endif
return renderer()->isTransparent() || renderer()->hasMask();
}
-RenderLayer*
-RenderLayer::transparentAncestor()
+RenderLayer* RenderLayer::transparentPaintingAncestor()
{
- RenderLayer* curr = parent();
- for ( ; curr && !curr->isTransparent(); curr = curr->parent()) { }
- return curr;
+ if (isComposited())
+ return 0;
+
+ for (RenderLayer* curr = parent(); curr; curr = curr->parent()) {
+ if (curr->isComposited())
+ return 0;
+ if (curr->isTransparent())
+ return curr;
+ }
+ return 0;
}
static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransform, const RenderLayer* l, const RenderLayer* rootLayer)
@@ -507,16 +702,16 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor
// paintDirtyRect, and that should cut down on the amount we have to paint. Still it
// would be better to respect clips.
- TransformationMatrix* t = l->transform();
- if (t && rootLayer != l) {
+ if (rootLayer != l && l->paintsWithTransform()) {
// The best we can do here is to use enclosed bounding boxes to establish a "fuzzy" enough clip to encompass
// the transformed layer and all of its children.
int x = 0;
int y = 0;
l->convertToLayerCoords(rootLayer, x, y);
+
TransformationMatrix transform;
transform.translate(x, y);
- transform = *t * transform;
+ transform = *l->transform() * transform;
transform = transform * enclosingTransform;
// We now have a transform that will produce a rectangle in our view's space.
@@ -550,14 +745,14 @@ static IntRect transparencyClipBox(const TransformationMatrix& enclosingTransfor
void RenderLayer::beginTransparencyLayers(GraphicsContext* p, const RenderLayer* rootLayer)
{
- if (p->paintingDisabled() || (isTransparent() && m_usedTransparency))
+ if (p->paintingDisabled() || (paintsWithTransparency() && m_usedTransparency))
return;
- RenderLayer* ancestor = transparentAncestor();
+ RenderLayer* ancestor = transparentPaintingAncestor();
if (ancestor)
ancestor->beginTransparencyLayers(p, rootLayer);
- if (isTransparent()) {
+ if (paintsWithTransparency()) {
m_usedTransparency = true;
p->save();
p->clip(transparencyClipBox(TransformationMatrix(), this, rootLayer));
@@ -577,7 +772,7 @@ void RenderLayer::operator delete(void* ptr, size_t sz)
}
void RenderLayer::destroy(RenderArena* renderArena)
-{
+{
delete this;
// Recover the size left there for us by operator delete and free the memory.
@@ -601,10 +796,10 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
child->setParent(this);
- if (child->isOverflowOnly())
- dirtyOverflowList();
+ if (child->isNormalFlowOnly())
+ dirtyNormalFlowList();
- if (!child->isOverflowOnly() || child->firstChild()) {
+ if (!child->isNormalFlowOnly() || child->firstChild()) {
// Dirty the z-order list in which we are contained. The stackingContext() can be null in the
// case where we're building up generated content layers. This is ok, since the lists will start
// off dirty in that case anyway.
@@ -614,10 +809,19 @@ void RenderLayer::addChild(RenderLayer* child, RenderLayer* beforeChild)
child->updateVisibilityStatus();
if (child->m_hasVisibleContent || child->m_hasVisibleDescendant)
childVisibilityChanged(true);
+
+#if USE(ACCELERATED_COMPOSITING)
+ compositor()->layerWasAdded(this, child);
+#endif
}
RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
{
+#if USE(ACCELERATED_COMPOSITING)
+ if (!renderer()->documentBeingDestroyed())
+ compositor()->layerWillBeRemoved(this, oldChild);
+#endif
+
// remove the child
if (oldChild->previousSibling())
oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
@@ -629,9 +833,9 @@ RenderLayer* RenderLayer::removeChild(RenderLayer* oldChild)
if (m_last == oldChild)
m_last = oldChild->previousSibling();
- if (oldChild->isOverflowOnly())
- dirtyOverflowList();
- if (!oldChild->isOverflowOnly() || oldChild->firstChild()) {
+ if (oldChild->isNormalFlowOnly())
+ dirtyNormalFlowList();
+ if (!oldChild->isNormalFlowOnly() || oldChild->firstChild()) {
// Dirty the z-order list in which we are contained. When called via the
// reattachment process in removeOnlyThisLayer, the layer may already be disconnected
// from the main layer tree, so we need to null-check the |stackingContext| value.
@@ -654,6 +858,10 @@ void RenderLayer::removeOnlyThisLayer()
if (!m_parent)
return;
+#if USE(ACCELERATED_COMPOSITING)
+ compositor()->layerWillBeRemoved(m_parent, this);
+#endif
+
// Dirty the clip rects.
clearClipRectsIncludingDescendants();
@@ -674,8 +882,8 @@ void RenderLayer::removeOnlyThisLayer()
current->updateLayerPositions();
current = next;
}
-
- destroy(renderer()->renderArena());
+
+ m_renderer->destroyLayer();
}
void RenderLayer::insertOnlyThisLayer()
@@ -684,21 +892,21 @@ void RenderLayer::insertOnlyThisLayer()
// We need to connect ourselves when our renderer() has a parent.
// Find our enclosingLayer and add ourselves.
RenderLayer* parentLayer = renderer()->parent()->enclosingLayer();
+ ASSERT(parentLayer);
RenderLayer* beforeChild = parentLayer->reflectionLayer() != this ? renderer()->parent()->findNextLayer(parentLayer, renderer()) : 0;
- if (parentLayer)
- parentLayer->addChild(this, beforeChild);
+ parentLayer->addChild(this, beforeChild);
}
-
+
// Remove all descendant layers from the hierarchy and add them to the new position.
for (RenderObject* curr = renderer()->firstChild(); curr; curr = curr->nextSibling())
curr->moveLayers(m_parent, this);
-
+
// Clear out all the clip rects.
clearClipRectsIncludingDescendants();
}
void
-RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int& y) const
+RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& xPos, int& yPos) const
{
if (ancestorLayer == this)
return;
@@ -707,8 +915,8 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int&
// Add in the offset of the view. We can obtain this by calling
// localToAbsolute() on the RenderView.
FloatPoint absPos = renderer()->localToAbsolute(FloatPoint(), true);
- x += absPos.x();
- y += absPos.y();
+ xPos += absPos.x();
+ yPos += absPos.y();
return;
}
@@ -720,10 +928,10 @@ RenderLayer::convertToLayerCoords(const RenderLayer* ancestorLayer, int& x, int&
if (!parentLayer) return;
- parentLayer->convertToLayerCoords(ancestorLayer, x, y);
+ parentLayer->convertToLayerCoords(ancestorLayer, xPos, yPos);
- x += xPos();
- y += yPos();
+ xPos += x();
+ yPos += y();
}
void RenderLayer::panScrollFromPoint(const IntPoint& sourcePoint)
@@ -804,14 +1012,18 @@ RenderLayer::subtractScrolledContentOffset(int& x, int& y) const
void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repaint)
{
- if (renderer()->style()->overflowX() != OMARQUEE) {
+ RenderBox* box = renderBox();
+ if (!box)
+ return;
+
+ if (box->style()->overflowX() != OMARQUEE) {
if (x < 0) x = 0;
if (y < 0) y = 0;
// Call the scrollWidth/Height functions so that the dimensions will be computed if they need
// to be (for overflow:hidden blocks).
- int maxX = scrollWidth() - renderer()->clientWidth();
- int maxY = scrollHeight() - renderer()->clientHeight();
+ int maxX = scrollWidth() - box->clientWidth();
+ int maxY = scrollHeight() - box->clientHeight();
if (x > maxX) x = maxX;
if (y > maxY) y = maxY;
@@ -831,6 +1043,11 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai
// Update the positions of our child layers.
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
child->updateLayerPositions(false, false);
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (isComposited())
+ m_backing->updateGraphicsLayerGeometry();
+#endif
RenderView* view = renderer()->view();
@@ -865,7 +1082,7 @@ void RenderLayer::scrollToOffset(int x, int y, bool updateScrollbars, bool repai
// Schedule the scroll DOM event.
if (view) {
if (FrameView* frameView = view->frameView())
- frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), EventTargetNodeCast(renderer()->element()));
+ frameView->scheduleEvent(Event::create(eventNames().scrollEvent, false, false), renderer()->node());
}
}
@@ -890,10 +1107,12 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor,
if (renderer()->hasOverflowClip() && !restrictedByLineClamp) {
// Don't scroll to reveal an overflow layer that is restricted by the -webkit-line-clamp property.
// This will prevent us from revealing text hidden by the slider in Safari RSS.
- FloatPoint absPos = renderer()->localToAbsolute();
- absPos.move(renderer()->borderLeft(), renderer()->borderTop());
+ RenderBox* box = renderBox();
+ ASSERT(box);
+ FloatPoint absPos = box->localToAbsolute();
+ absPos.move(box->borderLeft(), box->borderTop());
- IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), renderer()->clientWidth(), renderer()->clientHeight());
+ IntRect layerBounds = IntRect(absPos.x() + scrollXOffset(), absPos.y() + scrollYOffset(), box->clientWidth(), box->clientHeight());
IntRect exposeRect = IntRect(rect.x() + scrollXOffset(), rect.y() + scrollYOffset(), rect.width(), rect.height());
IntRect r = getRectToExpose(layerBounds, exposeRect, alignX, alignY);
@@ -912,7 +1131,7 @@ void RenderLayer::scrollRectToVisible(const IntRect &rect, bool scrollToAnchor,
newRect.setX(rect.x() - diffX);
newRect.setY(rect.y() - diffY);
}
- } else if (!parentLayer && renderer()->canBeProgramaticallyScrolled(scrollToAnchor)) {
+ } else if (!parentLayer && renderer()->isBox() && renderBox()->canBeProgramaticallyScrolled(scrollToAnchor)) {
if (frameView) {
if (renderer()->document() && renderer()->document()->ownerElement() && renderer()->document()->ownerElement()->renderer()) {
IntRect viewRect = frameView->visibleContentRect();
@@ -956,17 +1175,17 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &
// If the rectangle is fully visible, use the specified visible behavior.
// If the rectangle is partially visible, but over a certain threshold,
// then treat it as fully visible to avoid unnecessary horizontal scrolling
- scrollX = getVisibleBehavior(alignX);
+ scrollX = ScrollAlignment::getVisibleBehavior(alignX);
else if (intersectWidth == visibleRect.width()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
- scrollX = getVisibleBehavior(alignX);
+ scrollX = ScrollAlignment::getVisibleBehavior(alignX);
if (scrollX == alignCenter)
scrollX = noScroll;
} else if (intersectWidth > 0)
// If the rectangle is partially visible, but not above the minimum threshold, use the specified partial behavior
- scrollX = getPartialBehavior(alignX);
+ scrollX = ScrollAlignment::getPartialBehavior(alignX);
else
- scrollX = getHiddenBehavior(alignX);
+ scrollX = ScrollAlignment::getHiddenBehavior(alignX);
// If we're trying to align to the closest edge, and the exposeRect is further right
// than the visibleRect, and not bigger than the visible area, then align with the right.
if (scrollX == alignToClosestEdge && exposeRect.right() > visibleRect.right() && exposeRect.width() < visibleRect.width())
@@ -989,17 +1208,17 @@ IntRect RenderLayer::getRectToExpose(const IntRect &visibleRect, const IntRect &
int intersectHeight = intersection(visibleRect, exposeRectY).height();
if (intersectHeight == exposeRect.height())
// If the rectangle is fully visible, use the specified visible behavior.
- scrollY = getVisibleBehavior(alignY);
+ scrollY = ScrollAlignment::getVisibleBehavior(alignY);
else if (intersectHeight == visibleRect.height()) {
// If the rect is bigger than the visible area, don't bother trying to center. Other alignments will work.
- scrollY = getVisibleBehavior(alignY);
+ scrollY = ScrollAlignment::getVisibleBehavior(alignY);
if (scrollY == alignCenter)
scrollY = noScroll;
} else if (intersectHeight > 0)
// If the rectangle is partially visible, use the specified partial behavior
- scrollY = getPartialBehavior(alignY);
+ scrollY = ScrollAlignment::getPartialBehavior(alignY);
else
- scrollY = getHiddenBehavior(alignY);
+ scrollY = ScrollAlignment::getHiddenBehavior(alignY);
// If we're trying to align to the closest edge, and the exposeRect is further down
// than the visibleRect, and not bigger than the visible area, then align with the bottom.
if (scrollY == alignToClosestEdge && exposeRect.bottom() > visibleRect.bottom() && exposeRect.height() < visibleRect.height())
@@ -1032,12 +1251,13 @@ void RenderLayer::autoscroll()
frame->eventHandler()->updateSelectionForMouseDrag();
IntPoint currentDocumentPosition = frameView->windowToContents(frame->eventHandler()->currentMousePosition());
- scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, gAlignToEdgeIfNeeded, gAlignToEdgeIfNeeded);
+ scrollRectToVisible(IntRect(currentDocumentPosition, IntSize(1, 1)), false, ScrollAlignment::alignToEdgeIfNeeded, ScrollAlignment::alignToEdgeIfNeeded);
}
void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset)
{
- if (!inResizeMode() || !renderer()->hasOverflowClip())
+ // FIXME: This should be possible on generated content but is not right now.
+ if (!inResizeMode() || !renderer()->hasOverflowClip() || !renderer()->node())
return;
// Set the width and height of the shadow ancestor node if there is one.
@@ -1073,7 +1293,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset
ExceptionCode ec;
if (difference.width()) {
- if (element && element->isControl()) {
+ if (element->isFormControlElement()) {
// Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
style->setProperty(CSSPropertyMarginLeft, String::number(renderer->marginLeft() / zoomFactor) + "px", false, ec);
style->setProperty(CSSPropertyMarginRight, String::number(renderer->marginRight() / zoomFactor) + "px", false, ec);
@@ -1085,7 +1305,7 @@ void RenderLayer::resize(const PlatformMouseEvent& evt, const IntSize& oldOffset
}
if (difference.height()) {
- if (element && element->isControl()) {
+ if (element->isFormControlElement()) {
// Make implicit margins from the theme explicit (see <http://bugs.webkit.org/show_bug.cgi?id=9547>).
style->setProperty(CSSPropertyMarginTop, String::number(renderer->marginTop() / zoomFactor) + "px", false, ec);
style->setProperty(CSSPropertyMarginBottom, String::number(renderer->marginBottom() / zoomFactor) + "px", false, ec);
@@ -1172,6 +1392,7 @@ static IntRect scrollCornerRect(const RenderLayer* layer, const IntRect& bounds)
static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds)
{
+ ASSERT(layer->renderer()->isBox());
if (layer->renderer()->style()->resize() == RESIZE_NONE)
return IntRect();
return cornerRect(layer, bounds);
@@ -1179,25 +1400,29 @@ static IntRect resizerCornerRect(const RenderLayer* layer, const IntRect& bounds
bool RenderLayer::scrollbarCornerPresent() const
{
- return !scrollCornerRect(this, renderer()->borderBoxRect()).isEmpty();
+ ASSERT(renderer()->isBox());
+ return !scrollCornerRect(this, renderBox()->borderBoxRect()).isEmpty();
}
void RenderLayer::invalidateScrollbarRect(Scrollbar* scrollbar, const IntRect& rect)
{
IntRect scrollRect = rect;
+ RenderBox* box = renderBox();
+ ASSERT(box);
if (scrollbar == m_vBar.get())
- scrollRect.move(renderer()->width() - renderer()->borderRight() - scrollbar->width(), renderer()->borderTop());
+ scrollRect.move(box->width() - box->borderRight() - scrollbar->width(), box->borderTop());
else
- scrollRect.move(renderer()->borderLeft(), renderer()->height() - renderer()->borderBottom() - scrollbar->height());
+ scrollRect.move(box->borderLeft(), box->height() - box->borderBottom() - scrollbar->height());
renderer()->repaintRectangle(scrollRect);
}
PassRefPtr<Scrollbar> RenderLayer::createScrollbar(ScrollbarOrientation orientation)
{
RefPtr<Scrollbar> widget;
- bool hasCustomScrollbarStyle = renderer()->node()->shadowAncestorNode()->renderer()->style()->hasPseudoStyle(RenderStyle::SCROLLBAR);
+ RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
+ bool hasCustomScrollbarStyle = actualRenderer->isBox() && actualRenderer->style()->hasPseudoStyle(SCROLLBAR);
if (hasCustomScrollbarStyle)
- widget = RenderScrollbar::createCustomScrollbar(this, orientation, renderer()->node()->shadowAncestorNode()->renderBox());
+ widget = RenderScrollbar::createCustomScrollbar(this, orientation, toRenderBox(actualRenderer));
else
widget = Scrollbar::createNativeScrollbar(this, orientation, RegularScrollbar);
renderer()->document()->view()->addChild(widget.get());
@@ -1287,19 +1512,23 @@ void RenderLayer::positionOverflowControls(int tx, int ty)
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
return;
- IntRect borderBox = renderer()->borderBoxRect();
+ RenderBox* box = renderBox();
+ if (!box)
+ return;
+
+ IntRect borderBox = box->borderBoxRect();
IntRect scrollCorner(scrollCornerRect(this, borderBox));
IntRect absBounds(borderBox.x() + tx, borderBox.y() + ty, borderBox.width(), borderBox.height());
if (m_vBar)
- m_vBar->setFrameRect(IntRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(),
- absBounds.y() + renderer()->borderTop(),
+ m_vBar->setFrameRect(IntRect(absBounds.right() - box->borderRight() - m_vBar->width(),
+ absBounds.y() + box->borderTop(),
m_vBar->width(),
- absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - scrollCorner.height()));
+ absBounds.height() - (box->borderTop() + box->borderBottom()) - scrollCorner.height()));
if (m_hBar)
- m_hBar->setFrameRect(IntRect(absBounds.x() + renderer()->borderLeft(),
- absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(),
- absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - scrollCorner.width(),
+ m_hBar->setFrameRect(IntRect(absBounds.x() + box->borderLeft(),
+ absBounds.bottom() - box->borderBottom() - m_hBar->height(),
+ absBounds.width() - (box->borderLeft() + box->borderRight()) - scrollCorner.width(),
m_hBar->height()));
if (m_scrollCorner)
@@ -1324,19 +1553,22 @@ int RenderLayer::scrollHeight()
void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
{
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
m_scrollDimensionsDirty = false;
bool ltr = renderer()->style()->direction() == LTR;
- int clientWidth = renderer()->clientWidth();
- int clientHeight = renderer()->clientHeight();
+ int clientWidth = box->clientWidth();
+ int clientHeight = box->clientHeight();
- m_scrollLeftOverflow = ltr ? 0 : min(0, renderer()->leftmostPosition(true, false) - renderer()->borderLeft());
+ m_scrollLeftOverflow = ltr ? 0 : min(0, box->leftmostPosition(true, false) - box->borderLeft());
int rightPos = ltr ?
- renderer()->rightmostPosition(true, false) - renderer()->borderLeft() :
+ box->rightmostPosition(true, false) - box->borderLeft() :
clientWidth - m_scrollLeftOverflow;
- int bottomPos = renderer()->lowestPosition(true, false) - renderer()->borderTop();
+ int bottomPos = box->lowestPosition(true, false) - box->borderTop();
m_scrollWidth = max(rightPos, clientWidth);
m_scrollHeight = max(bottomPos, clientHeight);
@@ -1368,7 +1600,7 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve
if (FrameView* frameView = renderer()->document()->view()) {
frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
- EventTargetNodeCast(renderer()->element()));
+ renderer()->node());
}
}
}
@@ -1376,16 +1608,20 @@ void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOve
void
RenderLayer::updateScrollInfoAfterLayout()
{
+ RenderBox* box = renderBox();
+ if (!box)
+ return;
+
m_scrollDimensionsDirty = true;
bool horizontalOverflow, verticalOverflow;
computeScrollDimensions(&horizontalOverflow, &verticalOverflow);
- if (renderer()->style()->overflowX() != OMARQUEE) {
+ if (box->style()->overflowX() != OMARQUEE) {
// Layout may cause us to be in an invalid scroll position. In this case we need
// to pull our scroll offsets back to the max (or push them up to the min).
- int newX = max(0, min(scrollXOffset(), scrollWidth() - renderer()->clientWidth()));
- int newY = max(0, min(m_scrollY, scrollHeight() - renderer()->clientHeight()));
+ int newX = max(0, min(scrollXOffset(), scrollWidth() - box->clientWidth()));
+ int newY = max(0, min(m_scrollY, scrollHeight() - box->clientHeight()));
if (newX != scrollXOffset() || newY != m_scrollY) {
RenderView* view = renderer()->view();
ASSERT(view);
@@ -1417,12 +1653,12 @@ RenderLayer::updateScrollInfoAfterLayout()
setHasVerticalScrollbar(false);
// overflow:auto may need to lay out again if scrollbars got added/removed.
- bool scrollbarsChanged = (renderer()->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
- (renderer()->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
+ bool scrollbarsChanged = (box->hasAutoHorizontalScrollbar() && haveHorizontalBar != horizontalOverflow) ||
+ (box->hasAutoVerticalScrollbar() && haveVerticalBar != verticalOverflow);
if (scrollbarsChanged) {
- if (renderer()->hasAutoHorizontalScrollbar())
+ if (box->hasAutoHorizontalScrollbar())
setHasHorizontalScrollbar(horizontalOverflow);
- if (renderer()->hasAutoVerticalScrollbar())
+ if (box->hasAutoVerticalScrollbar())
setHasVerticalScrollbar(verticalOverflow);
#if ENABLE(DASHBOARD_SUPPORT)
@@ -1439,7 +1675,7 @@ RenderLayer::updateScrollInfoAfterLayout()
m_inOverflowRelayout = true;
renderer()->setNeedsLayout(true, false);
if (renderer()->isRenderBlock())
- static_cast<RenderBlock*>(renderer())->layoutBlock(true);
+ toRenderBlock(renderer())->layoutBlock(true);
else
renderer()->layout();
m_inOverflowRelayout = false;
@@ -1448,14 +1684,14 @@ RenderLayer::updateScrollInfoAfterLayout()
}
// If overflow:scroll is turned into overflow:auto a bar might still be disabled (Bug 11985).
- if (m_hBar && renderer()->hasAutoHorizontalScrollbar())
+ if (m_hBar && box->hasAutoHorizontalScrollbar())
m_hBar->setEnabled(true);
- if (m_vBar && renderer()->hasAutoVerticalScrollbar())
+ if (m_vBar && box->hasAutoVerticalScrollbar())
m_vBar->setEnabled(true);
// Set up the range (and page step/line step).
if (m_hBar) {
- int clientWidth = renderer()->clientWidth();
+ int clientWidth = box->clientWidth();
int pageStep = (clientWidth - cAmountToKeepWhenPaging);
if (pageStep < 0) pageStep = clientWidth;
m_hBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
@@ -1463,14 +1699,14 @@ RenderLayer::updateScrollInfoAfterLayout()
m_hBar->setValue(scrollXOffset());
}
if (m_vBar) {
- int clientHeight = renderer()->clientHeight();
+ int clientHeight = box->clientHeight();
int pageStep = (clientHeight - cAmountToKeepWhenPaging);
if (pageStep < 0) pageStep = clientHeight;
m_vBar->setSteps(cScrollbarPixelsPerLineStep, pageStep);
m_vBar->setProportion(clientHeight, m_scrollHeight);
}
- if (renderer()->element() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
+ if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
updateOverflowStatus(horizontalOverflow, verticalOverflow);
}
@@ -1501,7 +1737,10 @@ void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty
void RenderLayer::paintScrollCorner(GraphicsContext* context, int tx, int ty, const IntRect& damageRect)
{
- IntRect cornerRect = scrollCornerRect(this, renderer()->borderBoxRect());
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
+ IntRect cornerRect = scrollCornerRect(this, box->borderBoxRect());
IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
if (!absRect.intersects(damageRect))
return;
@@ -1524,7 +1763,10 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
if (renderer()->style()->resize() == RESIZE_NONE)
return;
- IntRect cornerRect = resizerCornerRect(this, renderer()->borderBoxRect());
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
+ IntRect cornerRect = resizerCornerRect(this, box->borderBoxRect());
IntRect absRect = IntRect(cornerRect.x() + tx, cornerRect.y() + ty, cornerRect.width(), cornerRect.height());
if (!absRect.intersects(damageRect))
return;
@@ -1548,6 +1790,7 @@ void RenderLayer::paintResizer(GraphicsContext* context, int tx, int ty, const I
// Clipping will exclude the right and bottom edges of this frame.
if (m_hBar || m_vBar) {
context->save();
+ context->clip(absRect);
IntRect largerCorner = absRect;
largerCorner.setSize(IntSize(largerCorner.width() + 1, largerCorner.height() + 1));
context->setStrokeColor(Color(makeRGB(217, 217, 217)));
@@ -1563,9 +1806,12 @@ bool RenderLayer::isPointInResizeControl(const IntPoint& absolutePoint) const
if (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE)
return false;
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
IntPoint localPoint = absoluteToContents(absolutePoint);
- IntRect localBounds(0, 0, renderer()->width(), renderer()->height());
+ IntRect localBounds(0, 0, box->width(), box->height());
return resizerCornerRect(this, localBounds).contains(localPoint);
}
@@ -1574,10 +1820,13 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
if (!m_hBar && !m_vBar && (!renderer()->hasOverflowClip() || renderer()->style()->resize() == RESIZE_NONE))
return false;
+ RenderBox* box = renderBox();
+ ASSERT(box);
+
int x = 0;
int y = 0;
convertToLayerCoords(root(), x, y);
- IntRect absBounds(x, y, renderer()->width(), renderer()->height());
+ IntRect absBounds(x, y, box->width(), box->height());
IntRect resizeControlRect;
if (renderer()->style()->resize() != RESIZE_NONE) {
@@ -1589,7 +1838,10 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
int resizeControlSize = max(resizeControlRect.height(), 0);
if (m_vBar) {
- IntRect vBarRect(absBounds.right() - renderer()->borderRight() - m_vBar->width(), absBounds.y() + renderer()->borderTop(), m_vBar->width(), absBounds.height() - (renderer()->borderTop() + renderer()->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
+ IntRect vBarRect(absBounds.right() - box->borderRight() - m_vBar->width(),
+ absBounds.y() + box->borderTop(),
+ m_vBar->width(),
+ absBounds.height() - (box->borderTop() + box->borderBottom()) - (m_hBar ? m_hBar->height() : resizeControlSize));
if (vBarRect.contains(result.point())) {
result.setScrollbar(m_vBar.get());
return true;
@@ -1598,7 +1850,10 @@ bool RenderLayer::hitTestOverflowControls(HitTestResult& result)
resizeControlSize = max(resizeControlRect.width(), 0);
if (m_hBar) {
- IntRect hBarRect(absBounds.x() + renderer()->borderLeft(), absBounds.bottom() - renderer()->borderBottom() - m_hBar->height(), absBounds.width() - (renderer()->borderLeft() + renderer()->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize), m_hBar->height());
+ IntRect hBarRect(absBounds.x() + box->borderLeft(),
+ absBounds.bottom() - box->borderBottom() - m_hBar->height(),
+ absBounds.width() - (box->borderLeft() + box->borderRight()) - (m_vBar ? m_vBar->width() : resizeControlSize),
+ m_hBar->height());
if (hBarRect.contains(result.point())) {
result.setScrollbar(m_hBar.get());
return true;
@@ -1654,6 +1909,12 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
const IntRect& paintDirtyRect, bool haveTransparency, PaintRestriction paintRestriction,
RenderObject* paintingRoot, bool appliedTransform, bool temporaryClipRects)
{
+#if USE(ACCELERATED_COMPOSITING)
+ // Composited RenderLayers are painted via the backing's paintIntoLayer().
+ if (isComposited() && !backing()->paintingGoesToWindow())
+ return;
+#endif
+
// Avoid painting layers when stylesheets haven't loaded. This eliminates FOUC.
// It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
// will do a full repaint().
@@ -1664,11 +1925,11 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
if (!renderer()->opacity())
return;
- if (isTransparent())
+ if (paintsWithTransparency())
haveTransparency = true;
// Apply a transform if we have one. A reflection is considered to be a transform, since it is a flip and a translate.
- if (m_transform && !appliedTransform) {
+ if (paintsWithTransform() && !appliedTransform) {
// If the transform can't be inverted, then don't paint anything.
if (!m_transform->isInvertible())
return;
@@ -1681,14 +1942,9 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Make sure the parent's clip rects have been calculated.
IntRect clipRect = paintDirtyRect;
if (parent()) {
- if (temporaryClipRects) {
- ClipRects parentClipRects;
- parent()->calculateClipRects(rootLayer, parentClipRects);
- clipRect = parentClipRects.overflowClipRect();
- } else {
- parent()->updateClipRects(rootLayer);
- clipRect = parent()->clipRects()->overflowClipRect();
- }
+ ClipRects parentRects;
+ parentClipRects(rootLayer, parentRects, temporaryClipRects);
+ clipRect = parentRects.overflowClipRect();
clipRect.intersect(paintDirtyRect);
}
@@ -1710,7 +1966,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
// Now do a paint with the root layer shifted to be us.
paintLayer(this, p, transform.inverse().mapRect(paintDirtyRect), haveTransparency, paintRestriction, paintingRoot, true, temporaryClipRects);
-
+
p->restore();
// Restore the clip.
@@ -1732,12 +1988,11 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
calculateRects(rootLayer, paintDirtyRect, layerBounds, damageRect, clipRectToApply, outlineRect, temporaryClipRects);
int x = layerBounds.x();
int y = layerBounds.y();
- int tx = x - renderer()->x();
- int ty = y - renderer()->y();
+ int tx = x - renderBoxX();
+ int ty = y - renderBoxY();
// Ensure our lists are up-to-date.
- updateZOrderLists();
- updateOverflowList();
+ updateLayerListsIfNeeded();
bool selectionOnly = paintRestriction == PaintRestrictionSelectionOnly || paintRestriction == PaintRestrictionSelectionOnlyBlackText;
bool forceBlackText = paintRestriction == PaintRestrictionSelectionOnlyBlackText;
@@ -1765,11 +2020,6 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
RenderObject::PaintInfo paintInfo(p, damageRect, PaintPhaseBlockBackground, false, paintingRootForRenderer, 0);
renderer()->paint(paintInfo, tx, ty);
- // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
- // z-index. We paint after we painted the background/border, so that the scrollbars will
- // sit above the background/border.
- paintOverflowControls(p, x, y, damageRect);
-
// Restore the clip.
restoreClip(p, paintDirtyRect, damageRect);
}
@@ -1813,10 +2063,12 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
}
// Paint any child layers that have overflow.
- if (m_overflowList)
- for (Vector<RenderLayer*>::iterator it = m_overflowList->begin(); it != m_overflowList->end(); ++it)
- it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
-
+ if (m_normalFlowList)
+ for (Vector<RenderLayer*>::iterator it = m_normalFlowList->begin(); it != m_normalFlowList->end(); ++it) {
+ if (it[0]->isSelfPaintingLayer())
+ it[0]->paintLayer(rootLayer, p, paintDirtyRect, haveTransparency, paintRestriction, paintingRoot, false, temporaryClipRects);
+ }
+
// Now walk the sorted list of children with positive z-indices.
if (m_posZOrderList)
for (Vector<RenderLayer*>::iterator it = m_posZOrderList->begin(); it != m_posZOrderList->end(); ++it)
@@ -1834,7 +2086,7 @@ RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
}
// End our transparency layer
- if (isTransparent() && m_usedTransparency) {
+ if (haveTransparency && m_usedTransparency && !m_paintingInsideReflection) {
p->endTransparencyLayer();
p->restore();
m_usedTransparency = false;
@@ -1855,9 +2107,19 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
renderer()->document()->updateLayout();
IntRect boundsRect(m_x, m_y, width(), height());
- boundsRect.intersect(frameVisibleRect(renderer()));
-
- RenderLayer* insideLayer = hitTestLayer(this, request, result, boundsRect, result.point());
+ if (!request.ignoreClipping())
+ boundsRect.intersect(frameVisibleRect(renderer()));
+
+ RenderLayer* insideLayer = hitTestLayer(this, 0, request, result, boundsRect, result.point(), 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.mouseUp()) && renderer()->isRenderView()) {
+ renderer()->updateHitTestResult(result, result.point());
+ insideLayer = this;
+ }
+ }
// Now determine if the result is inside an anchor; make sure an image map wins if
// it already set URLElement and only use the innermost.
@@ -1880,135 +2142,302 @@ bool RenderLayer::hitTest(const HitTestRequest& request, HitTestResult& result)
Node* RenderLayer::enclosingElement() const
{
for (RenderObject* r = renderer(); r; r = r->parent()) {
- if (Node* e = r->element())
+ if (Node* e = r->node())
return e;
}
ASSERT_NOT_REACHED();
return 0;
}
-RenderLayer* RenderLayer::hitTestLayer(RenderLayer* rootLayer, const HitTestRequest& request, HitTestResult& result,
- const IntRect& hitTestRect, const IntPoint& hitTestPoint, bool appliedTransform)
+// Compute the z-offset of the point in the transformState.
+// This is effectively projecting a ray normal to the plane of ancestor, finding where that
+// ray intersects target, and computing the z delta between those two points.
+static double computeZOffset(const HitTestingTransformState& transformState)
+{
+ // We got an affine transform, so no z-offset
+ if (transformState.m_accumulatedTransform.isAffine())
+ return 0;
+
+ // Flatten the point into the target plane
+ FloatPoint targetPoint = transformState.mappedPoint();
+
+ // Now map the point back through the transform, which computes Z.
+ FloatPoint3D backmappedPoint = transformState.m_accumulatedTransform.mapPoint(FloatPoint3D(targetPoint));
+ return backmappedPoint.z();
+}
+
+PassRefPtr<HitTestingTransformState> RenderLayer::createLocalTransformState(RenderLayer* rootLayer, RenderLayer* containerLayer,
+ const IntRect& hitTestRect, const IntPoint& hitTestPoint,
+ const HitTestingTransformState* containerTransformState) const
+{
+ RefPtr<HitTestingTransformState> transformState;
+ int offsetX = 0;
+ int offsetY = 0;
+ if (containerTransformState) {
+ // If we're already computing transform state, then it's relative to the container (which we know is non-null).
+ transformState = HitTestingTransformState::create(*containerTransformState);
+ convertToLayerCoords(containerLayer, offsetX, offsetY);
+ } else {
+ // If this is the first time we need to make transform state, then base it off of hitTestPoint,
+ // which is relative to rootLayer.
+ transformState = HitTestingTransformState::create(hitTestPoint, FloatQuad(hitTestRect));
+ convertToLayerCoords(rootLayer, offsetX, offsetY);
+ }
+
+ TransformationMatrix containerTransform = renderer()->transformFromContainer(containerLayer ? containerLayer->renderer() : 0, IntSize(offsetX, offsetY));
+ transformState->applyTransform(containerTransform, true);
+ return transformState;
+}
+
+
+static bool isHitCandidate(const RenderLayer* hitLayer, bool canDepthSort, double* zOffset, const HitTestingTransformState* transformState)
+{
+ if (!hitLayer)
+ return false;
+
+ // The hit layer is depth-sorting with other layers, so just say that it was hit.
+ if (canDepthSort)
+ return true;
+
+ // We need to look at z-depth to decide if this layer was hit.
+ if (zOffset) {
+ ASSERT(transformState);
+ // This is actually computing our z, but that's OK because the hitLayer is coplanar with us.
+ double childZOffset = computeZOffset(*transformState);
+ if (childZOffset > *zOffset) {
+ *zOffset = childZOffset;
+ return true;
+ }
+ return false;
+ }
+
+ return true;
+}
+
+// hitTestPoint 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_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 IntRect& hitTestRect, const IntPoint& hitTestPoint, 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.
+
+ bool useTemporaryClipRects = false;
+#if USE(ACCELERATED_COMPOSITING)
+ useTemporaryClipRects = compositor()->inCompositingMode();
+#endif
+
// Apply a transform if we have one.
- if (m_transform && !appliedTransform) {
- // If the transform can't be inverted, then don't hit test this layer at all.
- if (!m_transform->isInvertible())
- return 0;
-
+ if (transform() && !appliedTransform) {
// Make sure the parent's clip rects have been calculated.
if (parent()) {
- parent()->updateClipRects(rootLayer);
-
+ ClipRects parentRects;
+ parentClipRects(rootLayer, parentRects, useTemporaryClipRects);
+ IntRect clipRect = parentRects.overflowClipRect();
// Go ahead and test the enclosing clip now.
- IntRect clipRect = parent()->clipRects()->overflowClipRect();
if (!clipRect.contains(hitTestPoint))
return 0;
}
- // Adjust the transform such that the renderer's upper left corner is at (0,0) in user space.
- // This involves subtracting out the position of the layer in our current coordinate space.
- int x = 0;
- int y = 0;
- convertToLayerCoords(rootLayer, x, y);
- TransformationMatrix transform;
- transform.translate(x, y);
- transform = *m_transform * transform;
-
- // Map the hit test point into the transformed space and then do a hit test with the root layer shifted to be us.
- return hitTestLayer(this, request, result, transform.inverse().mapRect(hitTestRect), transform.inverse().mapPoint(hitTestPoint), true);
+ // Create a transform state to accumulate this transform.
+ RefPtr<HitTestingTransformState> newTransformState = createLocalTransformState(rootLayer, containerLayer, hitTestRect, hitTestPoint, transformState);
+
+ // If the transform can't be inverted, then don't hit test this layer at all.
+ if (!newTransformState->m_accumulatedTransform.isInvertible())
+ return 0;
+
+ // Compute the point and the hit test rect in the coords of this layer by using the values
+ // 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)
+ // by our container.
+ IntPoint localPoint = roundedIntPoint(newTransformState->mappedPoint());
+ IntRect localHitTestRect;
+#if USE(ACCELERATED_COMPOSITING)
+ if (isComposited()) {
+ // It doesn't make sense to project hitTestRect into the plane of this layer, so use the same bounds we use for painting.
+ localHitTestRect = compositor()->calculateCompositedBounds(this, this);
+ } else
+#endif
+ localHitTestRect = newTransformState->mappedQuad().enclosingBoundingBox();
+
+ // Now do a hit test with the root layer shifted to be us.
+ return hitTestLayer(this, containerLayer, request, result, localHitTestRect, localPoint, true, newTransformState.get(), zOffset);
}
+ // Ensure our lists and 3d status are up-to-date.
+ updateLayerListsIfNeeded();
+ update3DTransformedDescendantStatus();
+
+ RefPtr<HitTestingTransformState> localTransformState;
+ if (appliedTransform) {
+ // We computed the correct state in the caller (above code), so just reference it.
+ ASSERT(transformState);
+ 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);
+ }
+
+ // Check for hit test on backface if backface-visibility is 'hidden'
+ if (localTransformState && renderer()->style()->backfaceVisibility() == BackfaceVisibilityHidden) {
+ TransformationMatrix invertedMatrix = localTransformState->m_accumulatedTransform.inverse();
+ // If the z-vector of the matrix is negative, the back is facing towards the viewer.
+ if (invertedMatrix.m33() < 0)
+ return 0;
+ }
+
+ RefPtr<HitTestingTransformState> unflattenedTransformState = localTransformState;
+ if (localTransformState && !preserves3D()) {
+ // Keep a copy of the pre-flattening state, for computing z-offsets for the container
+ unflattenedTransformState = HitTestingTransformState::create(*localTransformState);
+ // This layer is flattening, so flatten the state passed to descendants.
+ localTransformState->flatten();
+ }
+
// Calculate the clip rects we should use.
IntRect layerBounds;
IntRect bgRect;
IntRect fgRect;
IntRect outlineRect;
- calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect);
-
- // Ensure our lists are up-to-date.
- updateZOrderLists();
- updateOverflowList();
-
- // This variable tracks which layer the mouse ends up being inside. The minute we find an insideLayer,
- // we are done and can return it.
- RenderLayer* insideLayer = 0;
-
- // Begin by walking our list of positive layers from highest z-index down to the lowest
- // z-index.
+ calculateRects(rootLayer, hitTestRect, layerBounds, bgRect, fgRect, outlineRect, useTemporaryClipRects);
+
+ // The following are used for keeping track of the z-depth of the hit point of 3d-transformed
+ // descendants.
+ double localZOffset = -numeric_limits<double>::infinity();
+ double* zOffsetForDescendantsPtr = 0;
+ double* zOffsetForContentsPtr = 0;
+
+ bool depthSortDescendants = false;
+ if (preserves3D()) {
+ depthSortDescendants = true;
+ // Our layers can depth-test with our container, so share the z depth pointer with the container, if it passed one down.
+ zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
+ zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
+ } else if (m_has3DTransformedDescendant) {
+ // Flattening layer with 3d children; use a local zOffset pointer to depth-test children and foreground.
+ depthSortDescendants = true;
+ zOffsetForDescendantsPtr = zOffset ? zOffset : &localZOffset;
+ zOffsetForContentsPtr = zOffset ? zOffset : &localZOffset;
+ } else if (zOffset) {
+ zOffsetForDescendantsPtr = 0;
+ // Container needs us to give back a z offset for the hit layer.
+ zOffsetForContentsPtr = zOffset;
+ }
+
+ // This variable tracks which layer the mouse ends up being inside.
+ RenderLayer* candidateLayer = 0;
+
+ // Begin by walking our list of positive layers from highest z-index down to the lowest z-index.
if (m_posZOrderList) {
for (int i = m_posZOrderList->size() - 1; i >= 0; --i) {
- insideLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
- if (insideLayer)
- return insideLayer;
+ HitTestResult tempResult(result.point());
+ RenderLayer* hitLayer = m_posZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr);
+ if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) {
+ result = tempResult;
+ if (!depthSortDescendants)
+ return hitLayer;
+
+ candidateLayer = hitLayer;
+ }
}
}
// Now check our overflow objects.
- if (m_overflowList) {
- for (int i = m_overflowList->size() - 1; i >= 0; --i) {
- insideLayer = m_overflowList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
- if (insideLayer)
- return insideLayer;
+ if (m_normalFlowList) {
+ for (int i = m_normalFlowList->size() - 1; i >= 0; --i) {
+ RenderLayer* currLayer = m_normalFlowList->at(i);
+ if (!currLayer->isSelfPaintingLayer())
+ continue;
+
+ HitTestResult tempResult(result.point());
+ RenderLayer* hitLayer = currLayer->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr);
+ if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) {
+ result = tempResult;
+ if (!depthSortDescendants)
+ return hitLayer;
+
+ candidateLayer = hitLayer;
+ }
}
}
// Next we want to see if the mouse pos is inside the child RenderObjects of the layer.
- if (fgRect.contains(hitTestPoint) &&
- renderer()->hitTest(request, result, hitTestPoint,
- layerBounds.x() - renderer()->x(),
- layerBounds.y() - renderer()->y(),
- HitTestDescendants)) {
- // For positioned generated content, we might still not have a
- // node by the time we get to the layer level, since none of
- // the content in the layer has an element. So just walk up
- // the tree.
- if (!result.innerNode() || !result.innerNonSharedNode()) {
- Node* e = enclosingElement();
- if (!result.innerNode())
- result.setInnerNode(e);
- if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(e);
+ if (fgRect.contains(hitTestPoint)) {
+ // Hit test with a temporary HitTestResult, because we onlyl want to commit to 'result' if we know we're frontmost.
+ HitTestResult tempResult(result.point());
+ if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestDescendants) &&
+ isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
+ result = tempResult;
+ if (!depthSortDescendants)
+ return this;
+ // Foreground can depth-sort with descendant layers, so keep this as a candidate.
+ candidateLayer = this;
}
-
- return this;
}
-
+
// Now check our negative z-index children.
if (m_negZOrderList) {
for (int i = m_negZOrderList->size() - 1; i >= 0; --i) {
- insideLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, request, result, hitTestRect, hitTestPoint);
- if (insideLayer)
- return insideLayer;
+ HitTestResult tempResult(result.point());
+ RenderLayer* hitLayer = m_negZOrderList->at(i)->hitTestLayer(rootLayer, this, request, tempResult, hitTestRect, hitTestPoint, false, localTransformState.get(), zOffsetForDescendantsPtr);
+ if (isHitCandidate(hitLayer, depthSortDescendants, zOffset, unflattenedTransformState.get())) {
+ result = tempResult;
+ if (!depthSortDescendants)
+ return hitLayer;
+
+ candidateLayer = hitLayer;
+ }
}
}
+
+ // If we found a layer, return. Child layers, and foreground always render in front of background.
+ if (candidateLayer)
+ return candidateLayer;
- // Next we want to see if the mouse is inside this layer but not any of its children.
- if (bgRect.contains(hitTestPoint) &&
- renderer()->hitTest(request, result, hitTestPoint,
- layerBounds.x() - renderer()->x(),
- layerBounds.y() - renderer()->y(),
- HitTestSelf)) {
- if (!result.innerNode() || !result.innerNonSharedNode()) {
- Node* e = enclosingElement();
- if (!result.innerNode())
- result.setInnerNode(e);
- if (!result.innerNonSharedNode())
- result.setInnerNonSharedNode(e);
+ if (bgRect.contains(hitTestPoint)) {
+ HitTestResult tempResult(result.point());
+ if (hitTestContents(request, tempResult, layerBounds, hitTestPoint, HitTestSelf) &&
+ isHitCandidate(this, false, zOffsetForContentsPtr, unflattenedTransformState.get())) {
+ result = tempResult;
+ return this;
}
-
- return this;
}
+
+ return 0;
+}
- // 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.mouseUp) && renderer()->isRenderView()) {
- renderer()->updateHitTestResult(result, hitTestPoint);
- return this;
+bool RenderLayer::hitTestContents(const HitTestRequest& request, HitTestResult& result, const IntRect& layerBounds, const IntPoint& hitTestPoint, HitTestFilter hitTestFilter) const
+{
+ if (!renderer()->hitTest(request, result, hitTestPoint,
+ layerBounds.x() - renderBoxX(),
+ layerBounds.y() - renderBoxY(),
+ hitTestFilter)) {
+ // It's wrong to set innerNode, but then claim that you didn't hit anything.
+ ASSERT(!result.innerNode());
+ return false;
}
- return 0;
+ // For positioned generated content, we might still not have a
+ // node by the time we get to the layer level, since none of
+ // the content in the layer has an element. So just walk up
+ // the tree.
+ if (!result.innerNode() || !result.innerNonSharedNode()) {
+ Node* e = enclosingElement();
+ if (!result.innerNode())
+ result.setInnerNode(e);
+ if (!result.innerNonSharedNode())
+ result.setInnerNonSharedNode(e);
+ }
+
+ return true;
}
void RenderLayer::updateClipRects(const RenderLayer* rootLayer)
@@ -2039,10 +2468,9 @@ void RenderLayer::updateClipRects(const RenderLayer* rootLayer)
void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool useCached) const
{
- IntRect infiniteRect(INT_MIN/2, INT_MIN/2, INT_MAX, INT_MAX);
if (!parent()) {
// The root layer's clip rect is always infinite.
- clipRects.reset(infiniteRect);
+ clipRects.reset(ClipRects::infiniteRect());
return;
}
@@ -2058,7 +2486,7 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl
parentLayer->calculateClipRects(rootLayer, clipRects);
}
else
- clipRects.reset(infiniteRect);
+ clipRects.reset(ClipRects::infiniteRect());
// A fixed object is essentially the root of its containing block hierarchy, so when
// we encounter such an object, we reset our clip rects to the fixedClipRect.
@@ -2086,13 +2514,13 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl
}
if (renderer()->hasOverflowClip()) {
- IntRect newOverflowClip = renderer()->getOverflowClipRect(x,y);
+ IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x,y);
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
if (renderer()->isPositioned() || renderer()->isRelPositioned())
clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
}
if (renderer()->hasClip()) {
- IntRect newPosClip = renderer()->getClipRect(x,y);
+ IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y);
clipRects.setPosClipRect(intersection(newPosClip, clipRects.posClipRect()));
clipRects.setOverflowClipRect(intersection(newPosClip, clipRects.overflowClipRect()));
clipRects.setFixedClipRect(intersection(newPosClip, clipRects.fixedClipRect()));
@@ -2100,24 +2528,30 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl
}
}
+void RenderLayer::parentClipRects(const RenderLayer* rootLayer, ClipRects& clipRects, bool temporaryClipRects) const
+{
+ ASSERT(parent());
+ if (temporaryClipRects) {
+ parent()->calculateClipRects(rootLayer, clipRects);
+ return;
+ }
+
+ parent()->updateClipRects(rootLayer);
+ clipRects = *parent()->clipRects();
+}
+
void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& paintDirtyRect, IntRect& layerBounds,
IntRect& backgroundRect, IntRect& foregroundRect, IntRect& outlineRect, bool temporaryClipRects) const
{
if (rootLayer != this && parent()) {
- ClipRects parentClipRects;
- if (temporaryClipRects)
- parent()->calculateClipRects(rootLayer, parentClipRects);
- else {
- parent()->updateClipRects(rootLayer);
- parentClipRects = *parent()->clipRects();
- }
-
- backgroundRect = renderer()->style()->position() == FixedPosition ? parentClipRects.fixedClipRect() :
- (renderer()->isPositioned() ? parentClipRects.posClipRect() :
- parentClipRects.overflowClipRect());
+ ClipRects parentRects;
+ parentClipRects(rootLayer, parentRects, temporaryClipRects);
+ backgroundRect = renderer()->style()->position() == FixedPosition ? parentRects.fixedClipRect() :
+ (renderer()->isPositioned() ? parentRects.posClipRect() :
+ parentRects.overflowClipRect());
RenderView* view = renderer()->view();
ASSERT(view);
- if (view && parentClipRects.fixed() && rootLayer->renderer() == view)
+ if (view && parentRects.fixed() && rootLayer->renderer() == view)
backgroundRect.move(view->frameView()->scrollX(), view->frameView()->scrollY());
backgroundRect.intersect(paintDirtyRect);
@@ -2136,10 +2570,10 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa
if (renderer()->hasOverflowClip() || renderer()->hasClip()) {
// This layer establishes a clip of some kind.
if (renderer()->hasOverflowClip())
- foregroundRect.intersect(renderer()->getOverflowClipRect(x,y));
+ foregroundRect.intersect(toRenderBox(renderer())->overflowClipRect(x,y));
if (renderer()->hasClip()) {
// Clip applies to *us* as well, so go ahead and update the damageRect.
- IntRect newPosClip = renderer()->getClipRect(x,y);
+ IntRect newPosClip = toRenderBox(renderer())->clipRect(x,y);
backgroundRect.intersect(newPosClip);
foregroundRect.intersect(newPosClip);
outlineRect.intersect(newPosClip);
@@ -2202,7 +2636,7 @@ bool RenderLayer::intersectsDamageRect(const IntRect& layerBounds, const IntRect
return boundingBox(rootLayer).intersects(damageRect);
}
-IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const
+IntRect RenderLayer::localBoundingBox() const
{
// There are three special cases we need to consider.
// (1) Inline Flows. For inline flows we will create a bounding box that fully encompasses all of the lines occupied by the
@@ -2216,56 +2650,64 @@ IntRect RenderLayer::boundingBox(const RenderLayer* rootLayer) const
IntRect result;
if (renderer()->isRenderInline()) {
// Go from our first line box to our last line box.
- RenderInline* inlineFlow = static_cast<RenderInline*>(renderer());
+ RenderInline* inlineFlow = toRenderInline(renderer());
InlineFlowBox* firstBox = inlineFlow->firstLineBox();
if (!firstBox)
return result;
int top = firstBox->root()->topOverflow();
int bottom = inlineFlow->lastLineBox()->root()->bottomOverflow();
- int left = firstBox->xPos();
+ int left = firstBox->x();
for (InlineRunBox* curr = firstBox->nextLineBox(); curr; curr = curr->nextLineBox())
- left = min(left, curr->xPos());
- result = IntRect(m_x + left, m_y + (top - renderer()->y()), width(), bottom - top);
+ left = min(left, curr->x());
+ result = IntRect(left, top, width(), bottom - top);
} else if (renderer()->isTableRow()) {
// Our bounding box is just the union of all of our cells' border/overflow rects.
for (RenderObject* child = renderer()->firstChild(); child; child = child->nextSibling()) {
if (child->isTableCell()) {
IntRect bbox = toRenderBox(child)->borderBoxRect();
result.unite(bbox);
- IntRect overflowRect = renderer()->overflowRect(false);
+ IntRect overflowRect = renderBox()->overflowRect(false);
if (bbox != overflowRect)
result.unite(overflowRect);
}
}
- result.move(m_x, m_y);
} else {
- if (renderer()->hasMask())
- result = renderer()->maskClipRect();
+ RenderBox* box = renderBox();
+ ASSERT(box);
+ if (box->hasMask())
+ result = box->maskClipRect();
else {
- IntRect bbox = renderer()->borderBoxRect();
+ IntRect bbox = box->borderBoxRect();
result = bbox;
- IntRect overflowRect = renderer()->overflowRect(false);
+ IntRect overflowRect = box->overflowRect(false);
if (bbox != overflowRect)
result.unite(overflowRect);
}
-
- // We have to adjust the x/y of this result so that it is in the coordinate space of the layer.
- result.move(m_x, m_y);
}
-
- // Convert the bounding box to an absolute position. We can do this easily by looking at the delta
- // between the bounding box's xpos and our layer's xpos and then applying that to the absolute layerBounds
- // passed in.
- int absX = 0, absY = 0;
- convertToLayerCoords(rootLayer, absX, absY);
- result.move(absX - m_x, absY - m_y);
+
RenderView* view = renderer()->view();
ASSERT(view);
if (view)
- result.inflate(view->maximalOutlineSize());
+ result.inflate(view->maximalOutlineSize()); // Used to apply a fudge factor to dirty-rect checks on blocks/tables.
+
return result;
}
+IntRect RenderLayer::boundingBox(const RenderLayer* ancestorLayer) const
+{
+ IntRect result = localBoundingBox();
+
+ int deltaX = 0, deltaY = 0;
+ convertToLayerCoords(ancestorLayer, deltaX, deltaY);
+ result.move(deltaX, deltaY);
+ return result;
+}
+
+IntRect RenderLayer::absoluteBoundingBox() const
+{
+ return boundingBox(root());
+}
+
void RenderLayer::clearClipRectsIncludingDescendants()
{
if (!m_clipRects)
@@ -2288,6 +2730,38 @@ void RenderLayer::clearClipRects()
}
}
+#if USE(ACCELERATED_COMPOSITING)
+RenderLayerBacking* RenderLayer::ensureBacking()
+{
+ if (!m_backing)
+ m_backing.set(new RenderLayerBacking(this));
+ return m_backing.get();
+}
+
+void RenderLayer::clearBacking()
+{
+ m_backing.clear();
+}
+#endif
+
+void RenderLayer::setParent(RenderLayer* parent)
+{
+ if (parent == m_parent)
+ return;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_parent && !renderer()->documentBeingDestroyed())
+ compositor()->layerWillBeRemoved(m_parent, this);
+#endif
+
+ m_parent = parent;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (m_parent && !renderer()->documentBeingDestroyed())
+ compositor()->layerWasAdded(m_parent, this);
+#endif
+}
+
static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
{
if (!obj1 || !obj2)
@@ -2303,28 +2777,28 @@ static RenderObject* commonAncestor(RenderObject* obj1, RenderObject* obj2)
void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestResult& result)
{
- // We don't update :hover/:active state when the result is marked as readonly.
- if (request.readonly)
+ // We don't update :hover/:active state when the result is marked as readOnly.
+ if (request.readOnly())
return;
Document* doc = renderer()->document();
Node* activeNode = doc->activeNode();
- if (activeNode && !request.active) {
+ if (activeNode && !request.active()) {
// We are clearing the :active chain because the mouse has been released.
for (RenderObject* curr = activeNode->renderer(); curr; curr = curr->parent()) {
- if (curr->element() && !curr->isText())
- curr->element()->setInActiveChain(false);
+ if (curr->node() && !curr->isText())
+ curr->node()->setInActiveChain(false);
}
doc->setActiveNode(0);
} else {
Node* newActiveNode = result.innerNode();
- if (!activeNode && newActiveNode && request.active) {
+ if (!activeNode && newActiveNode && request.active()) {
// We are setting the :active chain and freezing it. If future moves happen, they
// will need to reference this chain.
for (RenderObject* curr = newActiveNode->renderer(); curr; curr = curr->parent()) {
- if (curr->element() && !curr->isText()) {
- curr->element()->setInActiveChain(true);
+ if (curr->node() && !curr->isText()) {
+ curr->node()->setInActiveChain(true);
}
}
doc->setActiveNode(newActiveNode);
@@ -2334,7 +2808,7 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR
// If the mouse is down and if this is a mouse move event, we want to restrict changes in
// :hover/:active to only apply to elements that are in the :active chain that we froze
// at the time the mouse went down.
- bool mustBeInActiveChain = request.active && request.mouseMove;
+ bool mustBeInActiveChain = request.active() && request.mouseMove();
// Check to see if the hovered node has changed. If not, then we don't need to
// do anything.
@@ -2354,18 +2828,18 @@ void RenderLayer::updateHoverActiveState(const HitTestRequest& request, HitTestR
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->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
- curr->element()->setActive(false);
- curr->element()->setHovered(false);
+ if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) {
+ curr->node()->setActive(false);
+ curr->node()->setHovered(false);
}
}
}
// Now set the hover state for our new object up to the root.
for (RenderObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
- if (curr->element() && !curr->isText() && (!mustBeInActiveChain || curr->element()->inActiveChain())) {
- curr->element()->setActive(request.active);
- curr->element()->setHovered(true);
+ if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain())) {
+ curr->node()->setActive(request.active());
+ curr->node()->setHovered(true);
}
}
}
@@ -2383,6 +2857,11 @@ void RenderLayer::dirtyZOrderLists()
if (m_negZOrderList)
m_negZOrderList->clear();
m_zOrderListsDirty = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (!renderer()->documentBeingDestroyed())
+ compositor()->setCompositingLayersNeedUpdate();
+#endif
}
void RenderLayer::dirtyStackingContextZOrderLists()
@@ -2392,18 +2871,23 @@ void RenderLayer::dirtyStackingContextZOrderLists()
sc->dirtyZOrderLists();
}
-void RenderLayer::dirtyOverflowList()
+void RenderLayer::dirtyNormalFlowList()
{
- if (m_overflowList)
- m_overflowList->clear();
- m_overflowListDirty = true;
+ if (m_normalFlowList)
+ m_normalFlowList->clear();
+ m_normalFlowListDirty = true;
+
+#if USE(ACCELERATED_COMPOSITING)
+ if (!renderer()->documentBeingDestroyed())
+ compositor()->setCompositingLayersNeedUpdate();
+#endif
}
void RenderLayer::updateZOrderLists()
{
if (!isStackingContext() || !m_zOrderListsDirty)
return;
-
+
for (RenderLayer* child = firstChild(); child; child = child->nextSibling())
if (!m_reflection || reflectionLayer() != child)
child->collectLayers(m_posZOrderList, m_negZOrderList);
@@ -2411,27 +2895,28 @@ void RenderLayer::updateZOrderLists()
// Sort the two lists.
if (m_posZOrderList)
std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex);
+
if (m_negZOrderList)
std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex);
m_zOrderListsDirty = false;
}
-void RenderLayer::updateOverflowList()
+void RenderLayer::updateNormalFlowList()
{
- if (!m_overflowListDirty)
+ if (!m_normalFlowListDirty)
return;
for (RenderLayer* child = firstChild(); child; child = child->nextSibling()) {
// Ignore non-overflow layers and reflections.
- if (child->isOverflowOnly() && (!m_reflection || reflectionLayer() != child)) {
- if (!m_overflowList)
- m_overflowList = new Vector<RenderLayer*>;
- m_overflowList->append(child);
+ if (child->isNormalFlowOnly() && (!m_reflection || reflectionLayer() != child)) {
+ if (!m_normalFlowList)
+ m_normalFlowList = new Vector<RenderLayer*>;
+ m_normalFlowList->append(child);
}
}
- m_overflowListDirty = false;
+ m_normalFlowListDirty = false;
}
void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderLayer*>*& negBuffer)
@@ -2439,7 +2924,7 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL
updateVisibilityStatus();
// Overflow layers are just painted by their enclosing layers, so they don't get put in zorder lists.
- if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isOverflowOnly()) {
+ if ((m_hasVisibleContent || (m_hasVisibleDescendant && isStackingContext())) && !isNormalFlowOnly()) {
// Determine which buffer the child should be in.
Vector<RenderLayer*>*& buffer = (zIndex() >= 0) ? posBuffer : negBuffer;
@@ -2462,6 +2947,19 @@ void RenderLayer::collectLayers(Vector<RenderLayer*>*& posBuffer, Vector<RenderL
}
}
+void RenderLayer::updateLayerListsIfNeeded()
+{
+#if USE(ACCELERATED_COMPOSITING)
+ if (compositor()->inCompositingMode()) {
+ if ((isStackingContext() && m_zOrderListsDirty) || m_normalFlowListDirty)
+ compositor()->updateCompositingLayers(this);
+ return;
+ }
+#endif
+ updateZOrderLists();
+ updateNormalFlowList();
+}
+
void RenderLayer::repaintIncludingDescendants()
{
renderer()->repaint();
@@ -2469,23 +2967,62 @@ void RenderLayer::repaintIncludingDescendants()
curr->repaintIncludingDescendants();
}
-bool RenderLayer::shouldBeOverflowOnly() const
+#if USE(ACCELERATED_COMPOSITING)
+void RenderLayer::setBackingNeedsRepaint()
+{
+ ASSERT(isComposited());
+ if (backing()->paintingGoesToWindow()) {
+ // If we're trying to repaint the placeholder document layer, propagate the
+ // repaint to the native view system.
+ RenderView* view = renderer()->view();
+ if (view)
+ view->repaintViewRectangle(absoluteBoundingBox());
+ } else
+ backing()->setContentsNeedDisplay();
+}
+
+void RenderLayer::setBackingNeedsRepaintInRect(const IntRect& r)
{
- return (renderer()->hasOverflowClip() || renderer()->hasReflection()) &&
+ ASSERT(isComposited());
+ if (backing()->paintingGoesToWindow()) {
+ // If we're trying to repaint the placeholder document layer, propagate the
+ // repaint to the native view system.
+ IntRect absRect(r);
+ int x = 0;
+ int y = 0;
+ convertToLayerCoords(root(), x, y);
+ absRect.move(x, y);
+
+ RenderView* view = renderer()->view();
+ if (view)
+ view->repaintViewRectangle(absRect);
+ } else
+ backing()->setContentsNeedDisplayInRect(r);
+}
+#endif
+
+bool RenderLayer::shouldBeNormalFlowOnly() const
+{
+ return (renderer()->hasOverflowClip() || renderer()->hasReflection() || renderer()->hasMask()) &&
!renderer()->isPositioned() &&
!renderer()->isRelPositioned() &&
!renderer()->hasTransform() &&
!isTransparent();
}
-void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
+bool RenderLayer::isSelfPaintingLayer() const
+{
+ return !isNormalFlowOnly() || renderer()->hasReflection() || renderer()->hasMask() || renderer()->isTableRow();
+}
+
+void RenderLayer::styleChanged(StyleDifference diff, const RenderStyle*)
{
- bool isOverflowOnly = shouldBeOverflowOnly();
- if (isOverflowOnly != m_isOverflowOnly) {
- m_isOverflowOnly = isOverflowOnly;
+ bool isNormalFlowOnly = shouldBeNormalFlowOnly();
+ if (isNormalFlowOnly != m_isNormalFlowOnly) {
+ m_isNormalFlowOnly = isNormalFlowOnly;
RenderLayer* p = parent();
if (p)
- p->dirtyOverflowList();
+ p->dirtyNormalFlowList();
dirtyStackingContextZOrderLists();
}
@@ -2516,12 +3053,21 @@ void RenderLayer::styleChanged(RenderStyle::Diff, const RenderStyle*)
updateScrollCornerStyle();
updateResizerStyle();
+
+#if USE(ACCELERATED_COMPOSITING)
+ updateTransform();
+
+ if (compositor()->updateLayerCompositingState(this, diff))
+ compositor()->setCompositingLayersNeedUpdate();
+#else
+ UNUSED_PARAM(diff);
+#endif
}
void RenderLayer::updateScrollCornerStyle()
{
- RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::SCROLLBAR_CORNER, actualRenderer->style()) : 0;
+ RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
+ RefPtr<RenderStyle> corner = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(SCROLLBAR_CORNER, actualRenderer->style()) : 0;
if (corner) {
if (!m_scrollCorner) {
m_scrollCorner = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());
@@ -2536,8 +3082,8 @@ void RenderLayer::updateScrollCornerStyle()
void RenderLayer::updateResizerStyle()
{
- RenderObject* actualRenderer = renderer()->node()->isElementNode() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
- RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RenderStyle::RESIZER, actualRenderer->style()) : 0;
+ RenderObject* actualRenderer = renderer()->node() ? renderer()->node()->shadowAncestorNode()->renderer() : renderer();
+ RefPtr<RenderStyle> resizer = renderer()->hasOverflowClip() ? actualRenderer->getUncachedPseudoStyle(RESIZER, actualRenderer->style()) : 0;
if (resizer) {
if (!m_resizer) {
m_resizer = new (renderer()->renderArena()) RenderScrollbarPart(renderer()->document());