summaryrefslogtreecommitdiffstats
path: root/WebCore/platform
diff options
context:
space:
mode:
authorNicolas Roard <nicolas@android.com>2010-03-05 14:41:28 +0000
committerNicolas Roard <nicolas@android.com>2010-03-09 19:13:10 +0000
commitfa26a8dd531dff44d6cad0700ff32c0bb949392c (patch)
tree2984a63001721ee4143e4ad88797fa0dbd1a4b1d /WebCore/platform
parent7332bc6f7a4d9ccd11185104fb0aa1a0c9b84ac0 (diff)
downloadexternal_webkit-fa26a8dd531dff44d6cad0700ff32c0bb949392c.zip
external_webkit-fa26a8dd531dff44d6cad0700ff32c0bb949392c.tar.gz
external_webkit-fa26a8dd531dff44d6cad0700ff32c0bb949392c.tar.bz2
Fix bug 'Children of fixed elements do not always remain fixed themselves'
The problem was twofold: - webkit didn't create composited layers of the children div unless they were intersecting with the fixed layer - the children divs layers are siblings, not children of the fixed layer The solution is to: 1/ mark layers as needed to be composited if their ancestor is a fixed element (in RenderLayerCompositor) 2/ as the GraphicsLayer/LayerAndroid hierarchy is based on the RenderLayer hierarchy (z-order..) and not the display hierarchy, we need to a way of updating the position of the contained layers when a fixed layer move. We do that by: - marking layers contained in a fixed layer as being linked to the fixed layer (GraphicsLayerAndroid::syncFixedDescendants), and set the offset between the layer and the fixed layer. - when pushing the layers tree to the UI side, we ensure that such layers are linked to their corresponding fixed layer (LayerAndroid::ensureFixedLayersForDescendants) - when we draw, we do a first pass to update the fixed layers position (LayerAndroid::updateFixedLayersPositions) then update the rest of the layers (LayerAndroid::updatePositions). The layers that are linked to the fixed layers will then update their position relative to it, using the original offset between the fixed layer and the layer. Bug:2470701 Change-Id: I512966df94de6a5f84aff335c5d09b3f027bc2c3
Diffstat (limited to 'WebCore/platform')
-rw-r--r--WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp75
-rw-r--r--WebCore/platform/graphics/android/GraphicsLayerAndroid.h1
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.cpp69
-rw-r--r--WebCore/platform/graphics/android/LayerAndroid.h38
4 files changed, 151 insertions, 32 deletions
diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
index fd1c91a..b48ef49 100644
--- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp
@@ -218,26 +218,63 @@ void GraphicsLayerAndroid::needsSyncChildren()
askForSync();
}
+void GraphicsLayerAndroid::syncFixedDescendants()
+{
+ for (unsigned int i = 0; i < m_children.size(); i++)
+ (static_cast<GraphicsLayerAndroid*>(m_children[i]))->syncFixedDescendants();
+
+ if (!m_client)
+ return;
+
+ RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_client);
+ RenderLayer* renderLayer = backing->owningLayer();
+ RenderView* view = static_cast<RenderView*>(renderLayer->renderer());
+
+ // If we have an ancestor that is a fixed position layer, we need to
+ // mark ourselve as a child of it, as the RenderLayer hierarchy only
+ // keeps track of the z-order.
+ // By calling setRelativeTo() we ensure that we will keep track of
+ // the fixed layer we are relative to, and will be able to update
+ // our position accordingly.
+ RenderLayer* positionedParent = renderLayer->parent();
+ while (positionedParent &&
+ !(positionedParent->renderer()->isPositioned() &&
+ positionedParent->renderer()->style()->position() == FixedPosition))
+ positionedParent = positionedParent->parent();
+
+ if (positionedParent && positionedParent->isComposited()) {
+ RenderLayerBacking* positionedParentBacking = positionedParent->backing();
+ GraphicsLayerAndroid* positionedParentLayer =
+ static_cast<GraphicsLayerAndroid*>(positionedParentBacking->graphicsLayer());
+ LayerAndroid* parentLayer = positionedParentLayer->contentLayer();
+ m_contentLayer->setRelativeTo(parentLayer);
+ }
+}
+
void GraphicsLayerAndroid::updateFixedPosition()
{
- if (m_client) {
- RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_client);
- RenderLayer* renderLayer = backing->owningLayer();
- RenderView* view = static_cast<RenderView*>(renderLayer->renderer());
- if (view->isPositioned() && view->style()->position() == FixedPosition) {
- SkLength left, top, right, bottom;
- left = convertLength(view->style()->left());
- top = convertLength(view->style()->top());
- right = convertLength(view->style()->right());
- bottom = convertLength(view->style()->bottom());
- // We need to pass the size of the element to compute the final fixed
- // position -- we can't use the layer's size as it could possibly differs.
- // We also have to use the visible overflow and not just the size,
- // as some child elements could be overflowing.
- int w = view->rightVisibleOverflow() - view->leftVisibleOverflow();
- int h = view->bottomVisibleOverflow() - view->topVisibleOverflow();
- m_contentLayer->setFixedPosition(left, top, right, bottom, w, h);
- }
+ if (!m_client)
+ return;
+
+ RenderLayerBacking* backing = static_cast<RenderLayerBacking*>(m_client);
+ RenderLayer* renderLayer = backing->owningLayer();
+ RenderView* view = static_cast<RenderView*>(renderLayer->renderer());
+
+ // If we are a fixed position layer, just set it
+ if (view->isPositioned() && view->style()->position() == FixedPosition) {
+ SkLength left, top, right, bottom;
+ left = convertLength(view->style()->left());
+ top = convertLength(view->style()->top());
+ right = convertLength(view->style()->right());
+ bottom = convertLength(view->style()->bottom());
+ // We need to pass the size of the element to compute the final fixed
+ // position -- we can't use the layer's size as it could possibly differs.
+ // We also have to use the visible overflow and not just the size,
+ // as some child elements could be overflowing.
+ int w = view->rightVisibleOverflow() - view->leftVisibleOverflow();
+ int h = view->bottomVisibleOverflow() - view->topVisibleOverflow();
+
+ m_contentLayer->setFixedPosition(left, top, right, bottom, w, h);
}
}
@@ -419,6 +456,7 @@ void GraphicsLayerAndroid::sendImmediateRepaint()
if (rootGraphicsLayer->m_frame
&& rootGraphicsLayer->m_frame->view()) {
LayerAndroid* copyLayer = new LayerAndroid(*m_contentLayer);
+ copyLayer->ensureFixedLayersForDescendants(copyLayer);
TLOG("(%x) sendImmediateRepaint, copy the layer, (%.2f,%.2f => %.2f,%.2f)",
this, m_contentLayer->getSize().width(), m_contentLayer->getSize().height(),
copyLayer->getSize().width(), copyLayer->getSize().height());
@@ -882,6 +920,7 @@ void GraphicsLayerAndroid::syncCompositingState()
syncChildren();
syncMask();
syncPositionState();
+ syncFixedDescendants();
if (!gPaused || WTF::currentTime() >= gPausedDelay)
repaintAll();
diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
index 25f70b4..09f4181 100644
--- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
+++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h
@@ -110,6 +110,7 @@ public:
virtual void setZPosition(float);
void askForSync();
+ void syncFixedDescendants();
void syncPositionState();
void needsSyncChildren();
void syncChildren();
diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp
index b0c2629..26372f0 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.cpp
+++ b/WebCore/platform/graphics/android/LayerAndroid.cpp
@@ -49,10 +49,14 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(),
m_haveClip(false),
m_doRotation(false),
m_isFixed(false),
+ m_isRelativeTo(false),
+ m_relativeFixedLayerID(0),
m_recordingPicture(0),
m_extra(0),
- m_uniqueId(++gUniqueId)
+ m_uniqueId(++gUniqueId),
+ m_relativeFixedLayer(0)
{
+ m_deltaPosition.set(0, 0);
m_angleTransform = 0;
m_translation.set(0, 0);
m_scale.set(1, 1);
@@ -65,10 +69,14 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer),
m_isRootLayer(layer.m_isRootLayer),
m_haveClip(layer.m_haveClip),
m_extra(0), // deliberately not copied
- m_uniqueId(layer.m_uniqueId)
+ m_uniqueId(layer.m_uniqueId),
+ m_relativeFixedLayer(0)
{
m_doRotation = layer.m_doRotation;
m_isFixed = layer.m_isFixed;
+ m_isRelativeTo = layer.m_isRelativeTo;
+ m_relativeFixedLayerID = layer.m_relativeFixedLayerID;
+ m_deltaPosition = layer.m_deltaPosition;
m_angleTransform = layer.m_angleTransform;
m_translation = layer.m_translation;
@@ -100,10 +108,14 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(),
m_haveClip(false),
m_doRotation(false),
m_isFixed(false),
+ m_isRelativeTo(false),
+ m_relativeFixedLayerID(0),
m_recordingPicture(picture),
m_extra(0),
- m_uniqueId(-1)
+ m_uniqueId(-1),
+ m_relativeFixedLayer(0)
{
+ m_deltaPosition.set(0, 0);
m_angleTransform = 0;
m_translation.set(0, 0);
m_scale.set(1, 1);
@@ -245,9 +257,29 @@ const LayerAndroid* LayerAndroid::find(int x, int y) const
///////////////////////////////////////////////////////////////////////////////
-void LayerAndroid::updatePositions(const SkRect& viewport) {
- // apply the viewport to us
- SkMatrix matrix;
+void LayerAndroid::setRelativeTo(LayerAndroid* container) {
+ ASSERT(container->m_isFixed);
+ m_relativeFixedLayerID = container->m_uniqueId;
+ m_isRelativeTo = true;
+ m_deltaPosition = getPosition() - container->getPosition();
+}
+
+void LayerAndroid::ensureFixedLayersForDescendants(const LayerAndroid* rootLayer) {
+ if (m_isRelativeTo && !m_relativeFixedLayer) {
+ LayerAndroid* containerLayer = const_cast<LayerAndroid*>(
+ rootLayer->findById(m_relativeFixedLayerID));
+ if (containerLayer)
+ m_relativeFixedLayer = containerLayer;
+ }
+
+ int count = countChildren();
+ for (int i = 0; i < count; i++) {
+ getChild(i)->ensureFixedLayersForDescendants(rootLayer);
+ }
+}
+
+void LayerAndroid::updateFixedLayersPositions(const SkRect& viewport) {
+
if (m_isFixed) {
float x = 0;
float y = 0;
@@ -267,8 +299,25 @@ void LayerAndroid::updatePositions(const SkRect& viewport) {
y = dy + h - m_fixedBottom.calcFloatValue(h) - m_fixedHeight;
this->setPosition(x, y);
- matrix.reset();
- } else {
+ }
+
+ int count = this->countChildren();
+ for (int i = 0; i < count; i++) {
+ this->getChild(i)->updateFixedLayersPositions(viewport);
+ }
+}
+
+void LayerAndroid::updatePositions() {
+ // apply the viewport to us
+ SkMatrix matrix;
+ if (!m_isFixed) {
+ // If we are defined as being relative to a fixed
+ // layer, we need to update our position...
+ if (m_isRelativeTo && m_relativeFixedLayer) {
+ this->setPosition(m_relativeFixedLayer->getPosition().fX + m_deltaPosition.fX,
+ m_relativeFixedLayer->getPosition().fY + m_deltaPosition.fY);
+ }
+
// turn our fields into a matrix.
//
// TODO: this should happen in the caller, and we should remove these
@@ -278,13 +327,13 @@ void LayerAndroid::updatePositions(const SkRect& viewport) {
matrix.preRotate(m_angleTransform);
}
matrix.preScale(m_scale.fX, m_scale.fY);
+ this->setMatrix(matrix);
}
- this->setMatrix(matrix);
// now apply it to our children
int count = this->countChildren();
for (int i = 0; i < count; i++) {
- this->getChild(i)->updatePositions(viewport);
+ this->getChild(i)->updatePositions();
}
}
diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h
index 2554fb9..005ef3d 100644
--- a/WebCore/platform/graphics/android/LayerAndroid.h
+++ b/WebCore/platform/graphics/android/LayerAndroid.h
@@ -103,6 +103,14 @@ public:
m_isFixed = true;
}
+ /** Call that method to position the layer relative to another one.
+ We can only be set relative to a fixed layer.
+ The parameter is not refcounted -- we only save its ID as we
+ need to reconnect with the correct layer once we copy the tree
+ to the UI.
+ */
+ void setRelativeTo(LayerAndroid* container);
+
void setBackgroundColor(SkColor color);
void setMaskLayer(LayerAndroid*);
void setMasksToBounds(bool);
@@ -126,14 +134,31 @@ public:
void dumpLayers(FILE*, int indentLevel) const;
void dumpToLog() const;
- /** Call this with the current viewport (scrolling, zoom) to update its
- position attribute, so that later calls like bounds() will report the
- corrected position (assuming the layer had fixed-positioning).
+ /** Call this to be sure all fixed descendants correctly have
+ a pointer to their container layer before we try
+ to update the positions. The fixed layer we point to is
+ not refcounted (no need, it's already in the layers' tree).
+
+ This call is recursive, so it should be called on the root of the
+ hierarchy.
+ */
+ void ensureFixedLayersForDescendants(const LayerAndroid* rootLayer);
+
+ /** Call this with the current viewport (scrolling, zoom) to update
+ the position of the fixed layers.
+
+ This call is recursive, so it should be called on the root of the
+ hierarchy.
+ */
+ void updateFixedLayersPositions(const SkRect& viewPort);
+
+ /** Call this to update the position attribute, so that later calls
+ like bounds() will report the corrected position.
This call is recursive, so it should be called on the root of the
hierarchy.
*/
- void updatePositions(const SkRect& viewPort);
+ void updatePositions();
void clipArea(SkTDArray<SkRect>* region) const;
const LayerAndroid* find(int x, int y) const;
@@ -160,6 +185,7 @@ private:
bool m_haveClip;
bool m_doRotation;
bool m_isFixed;
+ bool m_isRelativeTo;
bool m_backgroundColorSet;
SkLength m_fixedLeft;
@@ -168,6 +194,8 @@ private:
SkLength m_fixedBottom;
int m_fixedWidth;
int m_fixedHeight;
+ int m_relativeFixedLayerID;
+ SkPoint m_deltaPosition;
SkPoint m_translation;
SkPoint m_scale;
@@ -181,6 +209,8 @@ private:
DrawExtra* m_extra;
int m_uniqueId;
+ LayerAndroid* m_relativeFixedLayer;
+
typedef SkLayer INHERITED;
};