diff options
author | Patrick Scott <phanna@android.com> | 2010-11-04 10:11:34 -0400 |
---|---|---|
committer | Patrick Scott <phanna@android.com> | 2010-12-03 09:15:36 -0500 |
commit | 82f247bdbb98dd80c44209d87692c650c3704617 (patch) | |
tree | d8e9cb36f483b1e50d099563759d868aa6fef175 | |
parent | 50114931eb31b3ee57480bf3d0068891aa62571f (diff) | |
download | external_webkit-82f247bdbb98dd80c44209d87692c650c3704617.zip external_webkit-82f247bdbb98dd80c44209d87692c650c3704617.tar.gz external_webkit-82f247bdbb98dd80c44209d87692c650c3704617.tar.bz2 |
Rewrite scrollable layers using multiple layers.
Remove PlatformBridge::updateLayers and instead call layersDraw from
ChromeClientAndroid during a requested sync.
Instead of LayerAndroid having knowledge of scrolling pictures, use multiple
layers (background, mask, foreground).
Update navigation to use the new structure. Always record nodes in absolute,
unscrolled coordinates. Do not track layers unless the node has a composited
layer and a last child. Check for composited parents when adding to tracked
layers as well.
TODO:
* developer.android.com doesn't completely work with navigation due to some
nodes being clipped out.
* BaseLayerAndroid needs to be able to operate with a matrix other than
identity.
* nested fixed position elements do not draw correctly.
* nested overflow layers haven't been tested.
Change-Id: I0e2bd37612341e8884d68153ab36194cb2dc1eeb
20 files changed, 345 insertions, 361 deletions
diff --git a/WebCore/platform/android/PlatformBridge.h b/WebCore/platform/android/PlatformBridge.h index 2019d1a..2d6451a 100644 --- a/WebCore/platform/android/PlatformBridge.h +++ b/WebCore/platform/android/PlatformBridge.h @@ -137,8 +137,6 @@ public: static void updateTextfield(FrameView*, Node*, bool changeToPassword, const WTF::String& text); - // Updates the layers on the UI - static void updateLayers(FrameView* view); // Language static String computeDefaultLanguage(); // Memory details for V8 GC diff --git a/WebCore/platform/graphics/GraphicsLayer.h b/WebCore/platform/graphics/GraphicsLayer.h index 991ca32..81aa6d0 100644 --- a/WebCore/platform/graphics/GraphicsLayer.h +++ b/WebCore/platform/graphics/GraphicsLayer.h @@ -82,6 +82,12 @@ class LayerChromium; typedef LayerChromium PlatformLayer; typedef void* NativeLayer; } +#elif PLATFORM(ANDROID) +namespace WebCore { +class LayerAndroid; +typedef LayerAndroid PlatformLayer; +typedef void* NativeLayer; +} #else typedef void* PlatformLayer; typedef void* NativeLayer; diff --git a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index f139eeb..996b272 100644 --- a/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -92,7 +92,10 @@ void BaseLayerAndroid::setContent(const PictureSet& src) android::Mutex::Autolock lock(m_drawLock); #endif m_content.set(src); - setSize(src.width(), src.height()); + // FIXME: We cannot set the size of the base layer because it will screw up + // the matrix used. We need to fix matrix computation for the base layer + // and then we can set the size. + // setSize(src.width(), src.height()); } void BaseLayerAndroid::setExtra(SkPicture& src) diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp index 593c896..fe7b132 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.cpp @@ -120,7 +120,9 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : m_translateY(0), m_currentTranslateX(0), m_currentTranslateY(0), - m_currentPosition(0, 0) + m_currentPosition(0, 0), + m_foregroundLayer(0), + m_foregroundClipLayer(0) { m_contentLayer = new LayerAndroid(true); RenderLayer* renderLayer = renderLayerFromClient(m_client); @@ -134,6 +136,8 @@ GraphicsLayerAndroid::GraphicsLayerAndroid(GraphicsLayerClient* client) : GraphicsLayerAndroid::~GraphicsLayerAndroid() { m_contentLayer->unref(); + SkSafeUnref(m_foregroundLayer); + SkSafeUnref(m_foregroundClipLayer); gDebugGraphicsLayerAndroidInstances--; } @@ -162,8 +166,8 @@ bool GraphicsLayerAndroid::setChildren(const Vector<GraphicsLayer*>& children) void GraphicsLayerAndroid::addChild(GraphicsLayer* childLayer) { #ifndef NDEBUG - const char* n = (static_cast<GraphicsLayerAndroid*>(childLayer))->m_name.latin1().data(); - LOG("(%x) addChild: %x (%s)", this, childLayer, n); + const String& name = childLayer->name(); + LOG("(%x) addChild: %x (%s)", this, childLayer, name.latin1().data()); #endif GraphicsLayer::addChild(childLayer); m_needsSyncChildren = true; @@ -206,19 +210,11 @@ bool GraphicsLayerAndroid::replaceChild(GraphicsLayer* oldChild, GraphicsLayer* void GraphicsLayerAndroid::removeFromParent() { LOG("(%x) removeFromParent()", this); - if (m_parent) - static_cast<GraphicsLayerAndroid*>(m_parent)->needsSyncChildren(); GraphicsLayer::removeFromParent(); m_needsSyncChildren = true; askForSync(); } -void GraphicsLayerAndroid::needsSyncChildren() -{ - m_needsSyncChildren = true; - askForSync(); -} - void GraphicsLayerAndroid::updateFixedPosition() { if (!m_client) @@ -353,6 +349,19 @@ void GraphicsLayerAndroid::setDrawsContent(bool drawsContent) if (m_contentLayer->isRootLayer()) return; if (m_drawsContent) { +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + RenderLayer* layer = renderLayerFromClient(m_client); + if (layer && layer->hasOverflowScroll() && !m_foregroundLayer) { + m_foregroundLayer = new LayerAndroid(false); + m_foregroundLayer->setContentScrollable(true); + m_foregroundClipLayer = new LayerAndroid(false); + m_foregroundClipLayer->setMasksToBounds(true); + + m_foregroundClipLayer->addChild(m_foregroundLayer); + m_contentLayer->addChild(m_foregroundClipLayer); + } +#endif + m_haveContents = true; setNeedsDisplay(); } @@ -440,18 +449,42 @@ bool GraphicsLayerAndroid::repaint() // with SkPicture, we request the entire layer's content. IntRect layerBounds(0, 0, m_size.width(), m_size.height()); - if (m_contentsRect.width() > m_size.width() || - m_contentsRect.height() > m_size.height()) { + if (m_foregroundLayer) { PaintingPhase phase(this); // Paint the background into a separate context. phase.set(GraphicsLayerPaintBackground); if (!paintContext(m_contentLayer->recordContext(), layerBounds)) return false; + + RenderLayer* layer = renderLayerFromClient(m_client); + // Construct the foreground layer and draw. + RenderBox* box = layer->renderBox(); + int outline = box->view()->maximalOutlineSize(); + IntRect contentsRect(0, 0, + box->borderLeft() + box->borderRight() + layer->scrollWidth(), + box->borderTop() + box->borderBottom() + layer->scrollHeight()); + contentsRect.inflate(outline); + // Update the foreground layer size. + m_foregroundLayer->setSize(contentsRect.width(), contentsRect.height()); // Paint everything else into the main recording canvas. phase.clear(GraphicsLayerPaintBackground); - if (!paintContext(m_contentLayer->foregroundContext(), - m_contentsRect)) + if (!paintContext(m_foregroundLayer->recordContext(), contentsRect)) return false; + + // Construct the clip layer for masking the contents. + IntRect clip = layer->renderer()->absoluteBoundingBoxRect(); + // absoluteBoundingBoxRect does not include the outline so we need + // to offset the position. + int x = box->borderLeft() + outline; + int y = box->borderTop() + outline; + int width = clip.width() - box->borderLeft() - box->borderRight(); + int height = clip.height() - box->borderTop() - box->borderBottom(); + m_foregroundClipLayer->setPosition(x, y); + m_foregroundClipLayer->setSize(width, height); + + // Need to offset the foreground layer by the clip layer in order + // for the contents to be in the correct position. + m_foregroundLayer->setPosition(-x, -y); } else { // If there is no contents clip, we can draw everything into one // picture. @@ -469,24 +502,6 @@ bool GraphicsLayerAndroid::repaint() m_needsRepaint = false; m_invalidatedRects.clear(); - RenderLayer* layer = renderLayerFromClient(m_client); - // Use the absolute bounds of the renderer instead of the layer's - // bounds because the layer will add in the outline. What we want - // is the content bounds inside the outline. - FloatRect clip = layer->renderer()->absoluteBoundingBoxRect(); - // Move the clip local to the layer position. - clip.setLocation(FloatPoint(0, 0)); -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (layer->hasOverflowScroll()) { - // If this is a scrollable layer, inset the clip by the border. - RenderBox* box = layer->renderBox(); - clip.move(box->borderLeft(), box->borderTop()); - clip.setWidth(clip.width() - box->borderLeft() - box->borderRight()); - clip.setHeight(clip.height() - box->borderTop() - box->borderBottom()); - } -#endif - m_contentLayer->setForegroundClip(clip); - return true; } return false; @@ -511,7 +526,7 @@ bool GraphicsLayerAndroid::paintContext(SkPicture* context, void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) { for (unsigned int i = 0; i < m_children.size(); i++) { - GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); + GraphicsLayer* layer = m_children[i]; if (layer) { FloatRect childrenRect(m_position.x() + m_translateX + rect.x(), m_position.y() + m_translateY + rect.y(), @@ -548,16 +563,6 @@ void GraphicsLayerAndroid::setNeedsDisplayInRect(const FloatRect& rect) m_needsRepaint = true; askForSync(); - - if (!m_client) - return; - - // Update the layers on the UI - RenderLayer* renderLayer = renderLayerFromClient(m_client); - if (renderLayer) { - FrameView* frameView = renderLayer->root()->renderer()->view()->frameView(); - PlatformBridge::updateLayers(frameView); - } } void GraphicsLayerAndroid::pauseDisplay(bool state) @@ -862,7 +867,7 @@ void GraphicsLayerAndroid::setContentsToImage(Image* image) PlatformLayer* GraphicsLayerAndroid::platformLayer() const { LOG("platformLayer"); - return (PlatformLayer*) m_contentLayer; + return m_contentLayer; } #ifndef NDEBUG @@ -884,6 +889,9 @@ void GraphicsLayerAndroid::setZPosition(float position) void GraphicsLayerAndroid::askForSync() { + if (!m_client) + return; + if (m_client) m_client->notifySyncRequired(this); } @@ -892,10 +900,10 @@ void GraphicsLayerAndroid::syncChildren() { if (m_needsSyncChildren) { m_contentLayer->removeChildren(); - for (unsigned int i = 0; i < m_children.size(); i++) { - m_contentLayer->addChild( - (static_cast<GraphicsLayerAndroid*>(m_children[i]))->contentLayer()); - } + if (m_foregroundClipLayer) + m_contentLayer->addChild(m_foregroundClipLayer); + for (unsigned int i = 0; i < m_children.size(); i++) + m_contentLayer->addChild(m_children[i]->platformLayer()); m_needsSyncChildren = false; } } @@ -904,8 +912,7 @@ void GraphicsLayerAndroid::syncMask() { if (m_needsSyncMask) { if (m_maskLayer) { - GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_maskLayer); - LayerAndroid* mask = reinterpret_cast<LayerAndroid*>(layer->platformLayer()); + LayerAndroid* mask = m_maskLayer->platformLayer(); m_contentLayer->setMaskLayer(mask); } else m_contentLayer->setMaskLayer(0); @@ -929,10 +936,8 @@ void GraphicsLayerAndroid::syncPositionState() void GraphicsLayerAndroid::syncCompositingState() { - for (unsigned int i = 0; i < m_children.size(); i++) { - GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); - layer->syncCompositingState(); - } + for (unsigned int i = 0; i < m_children.size(); i++) + m_children[i]->syncCompositingState(); syncChildren(); syncMask(); @@ -944,10 +949,8 @@ void GraphicsLayerAndroid::syncCompositingState() void GraphicsLayerAndroid::notifyClientAnimationStarted() { - for (unsigned int i = 0; i < m_children.size(); i++) { - GraphicsLayerAndroid* layer = static_cast<GraphicsLayerAndroid*>(m_children[i]); - layer->notifyClientAnimationStarted(); - } + for (unsigned int i = 0; i < m_children.size(); i++) + static_cast<GraphicsLayerAndroid*>(m_children[i])->notifyClientAnimationStarted(); if (m_needsNotifyClient) { if (client()) diff --git a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h index 80c92f3..098ad37 100644 --- a/WebCore/platform/graphics/android/GraphicsLayerAndroid.h +++ b/WebCore/platform/graphics/android/GraphicsLayerAndroid.h @@ -119,7 +119,6 @@ private: void askForSync(); void syncPositionState(); - void needsSyncChildren(); void syncChildren(); void syncMask(); @@ -150,6 +149,8 @@ private: Vector<FloatRect> m_invalidatedRects; LayerAndroid* m_contentLayer; + LayerAndroid* m_foregroundLayer; + LayerAndroid* m_foregroundClipLayer; }; } // namespace WebCore diff --git a/WebCore/platform/graphics/android/LayerAndroid.cpp b/WebCore/platform/graphics/android/LayerAndroid.cpp index 0a6d3e2..68bdec0 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -13,7 +13,6 @@ #include "SkPicture.h" #include <wtf/CurrentTime.h> - #define LAYER_DEBUG // Add diagonals for debugging #undef LAYER_DEBUG @@ -52,8 +51,8 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_haveClip(false), m_doRotation(false), m_isFixed(false), + m_contentScrollable(false), m_recordingPicture(0), - m_foregroundPicture(0), m_contentsImage(0), m_extra(0), m_uniqueId(++gUniqueId) @@ -62,8 +61,6 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), m_translation.set(0, 0); m_scale.set(1, 1); m_backgroundColor = 0; - m_foregroundClip.setEmpty(); - m_foregroundLocation.set(0, 0); gDebugLayerAndroidInstances++; } @@ -71,6 +68,7 @@ LayerAndroid::LayerAndroid(bool isRootLayer) : SkLayer(), LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_isRootLayer(layer.m_isRootLayer), m_haveClip(layer.m_haveClip), + m_contentScrollable(layer.m_contentScrollable), m_extra(0), // deliberately not copied m_uniqueId(layer.m_uniqueId) { @@ -95,12 +93,7 @@ LayerAndroid::LayerAndroid(const LayerAndroid& layer) : SkLayer(layer), m_fixedRect = layer.m_fixedRect; m_recordingPicture = layer.m_recordingPicture; - m_foregroundPicture = layer.m_foregroundPicture; SkSafeRef(m_recordingPicture); - SkSafeRef(m_foregroundPicture); - - m_foregroundClip = layer.m_foregroundClip; - m_foregroundLocation = layer.m_foregroundLocation; for (int i = 0; i < layer.countChildren(); i++) addChild(new LayerAndroid(*layer.getChild(i)))->unref(); @@ -117,8 +110,8 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_haveClip(false), m_doRotation(false), m_isFixed(false), + m_contentScrollable(false), m_recordingPicture(picture), - m_foregroundPicture(0), m_contentsImage(0), m_extra(0), m_uniqueId(-1) @@ -127,8 +120,6 @@ LayerAndroid::LayerAndroid(SkPicture* picture) : SkLayer(), m_translation.set(0, 0); m_scale.set(1, 1); m_backgroundColor = 0; - m_foregroundClip.setEmpty(); - m_foregroundLocation.set(0, 0); SkSafeRef(m_recordingPicture); gDebugLayerAndroidInstances++; } @@ -138,7 +129,6 @@ LayerAndroid::~LayerAndroid() removeChildren(); m_contentsImage->safeUnref(); m_recordingPicture->safeUnref(); - m_foregroundPicture->safeUnref(); m_animations.clear(); gDebugLayerAndroidInstances--; } @@ -198,11 +188,6 @@ void LayerAndroid::setMaskLayer(LayerAndroid* layer) m_haveClip = true; } -void LayerAndroid::setMasksToBounds(bool masksToBounds) -{ - m_haveClip = masksToBounds; -} - void LayerAndroid::setBackgroundColor(SkColor color) { m_backgroundColor = color; @@ -323,6 +308,11 @@ public: int x() const { return m_x; } int y() const { return m_y; } + void setLocation(int x, int y) { + m_x = x; + m_y = y; + } + protected: int m_x; int m_y; @@ -336,18 +326,20 @@ void LayerAndroid::findInner(LayerAndroid::FindState& state) const { int x = state.x(); int y = state.y(); - for (int i = 0; i < countChildren(); i++) - getChild(i)->findInner(state); SkRect localBounds; bounds(&localBounds); if (!localBounds.contains(x, y)) return; - if (!m_foregroundPicture) { - if (!m_recordingPicture) - return; - if (!state.drew(m_recordingPicture, localBounds)) - return; - } + // Move into local coordinates. + state.setLocation(x - localBounds.fLeft, y - localBounds.fTop); + for (int i = 0; i < countChildren(); i++) + getChild(i)->findInner(state); + // Move back into the parent coordinates. + state.setLocation(x + localBounds.fLeft, y + localBounds.fTop); + if (!m_recordingPicture) + return; + if (!state.drew(m_recordingPicture, localBounds)) + return; state.setBest(this); // set last match (presumably on top) } @@ -450,14 +442,6 @@ void LayerAndroid::onDraw(SkCanvas* canvas, SkScalar opacity) { canvas->drawBitmapRect(m_contentsImage->bitmap(), 0, dest); } else { canvas->drawPicture(*m_recordingPicture); - if (m_foregroundPicture) { - canvas->save(); - canvas->clipRect(m_foregroundClip); - canvas->translate(-m_foregroundLocation.fX, - -m_foregroundLocation.fY); - canvas->drawPicture(*m_foregroundPicture); - canvas->restore(); - } } if (m_extra) { IntRect dummy; // inval area, unused for now @@ -492,38 +476,48 @@ SkPicture* LayerAndroid::recordContext() return 0; } -SkPicture* LayerAndroid::foregroundContext() -{ - // Always create a new picture since this method is called only when - // recording the foreground picture. - m_foregroundPicture = new SkPicture(); - return m_foregroundPicture; -} - -bool LayerAndroid::contentIsScrollable() const { - return m_foregroundPicture != 0 && - (getWidth() < SkIntToScalar(m_foregroundPicture->width()) || - getHeight() < SkIntToScalar(m_foregroundPicture->height())); -} - bool LayerAndroid::scrollBy(int dx, int dy) { - if (m_foregroundPicture == 0) + if (!contentIsScrollable()) return false; - SkScalar maxScrollX = SkIntToScalar(m_foregroundPicture->width()) - getWidth(); - SkScalar maxScrollY = SkIntToScalar(m_foregroundPicture->height()) - getHeight(); - SkScalar x = m_foregroundLocation.fX + dx; - SkScalar y = m_foregroundLocation.fY + dy; - x = SkScalarClampMax(x, maxScrollX); - y = SkScalarClampMax(y, maxScrollY); - if (x != m_foregroundLocation.fX || y != m_foregroundLocation.fY) { - m_foregroundLocation.set(x, y); - return true; - } - return false; + + // Scrollable layers have a mask layer and then the actual main layer. + if (getParent() == 0 || getParent()->getParent() == 0) + return false; + LayerAndroid* realLayer = static_cast<LayerAndroid*>(getParent()->getParent()); + + SkRect scrollBounds; + realLayer->bounds(&scrollBounds); + + const SkPoint& maskLayerPosition = getParent()->getPosition(); + // Our original position is the offset of the mask layer's position. + SkScalar maxX = -maskLayerPosition.fX; + SkScalar maxY = -maskLayerPosition.fY; + SkScalar minX = maxX - (getSize().width() - scrollBounds.width()); + SkScalar minY = maxY - (getSize().height() - scrollBounds.height()); + + // Move the layer's position by the difference and pin the result to within + // the scrollable range. + SkPoint diff; + diff.iset(dx, dy); + SkPoint pos = getPosition() - diff; + pos.fX = SkScalarPin(pos.fX, minX, maxX); + pos.fY = SkScalarPin(pos.fY, minY, maxY); + + // Update the difference to reflect the changes. + diff = getPosition() - pos; + if (diff.equals(0, 0)) + // no change + return false; + + setPosition(pos.fX, pos.fY); + return true; } bool LayerAndroid::prepareContext(bool force) { + if (masksToBounds()) + return false; + if (!m_isRootLayer) { if (force || !m_recordingPicture || (m_recordingPicture @@ -696,17 +690,6 @@ void LayerAndroid::dumpLayers(FILE* file, int indentLevel) const writeIntVal(file, indentLevel + 1, "m_recordingPicture.height", m_recordingPicture->height()); } - if (m_foregroundPicture) { - writeIntVal(file, indentLevel + 1, "m_foregroundPicture.width", m_foregroundPicture->width()); - writeIntVal(file, indentLevel + 1, "m_foregroundPicture.height", m_foregroundPicture->height()); - writeFloatVal(file, indentLevel + 1, "m_foregroundClip.fLeft", m_foregroundClip.fLeft); - writeFloatVal(file, indentLevel + 1, "m_foregroundClip.fTop", m_foregroundClip.fTop); - writeFloatVal(file, indentLevel + 1, "m_foregroundClip.fRight", m_foregroundClip.fRight); - writeFloatVal(file, indentLevel + 1, "m_foregroundClip.fBottom", m_foregroundClip.fBottom); - writeFloatVal(file, indentLevel + 1, "m_foregroundLocation.fX", m_foregroundLocation.fX); - writeFloatVal(file, indentLevel + 1, "m_foregroundLocation.fY", m_foregroundLocation.fY); - } - if (countChildren()) { writeln(file, indentLevel + 1, "children = ["); for (int i = 0; i < countChildren(); i++) { @@ -732,12 +715,12 @@ void LayerAndroid::dumpToLog() const fclose(file); } -const LayerAndroid* LayerAndroid::findById(int match) const +LayerAndroid* LayerAndroid::findById(int match) { if (m_uniqueId == match) return this; for (int i = 0; i < countChildren(); i++) { - const LayerAndroid* result = getChild(i)->findById(match); + LayerAndroid* result = getChild(i)->findById(match); if (result) return result; } diff --git a/WebCore/platform/graphics/android/LayerAndroid.h b/WebCore/platform/graphics/android/LayerAndroid.h index 939c95c..a9a9c69 100644 --- a/WebCore/platform/graphics/android/LayerAndroid.h +++ b/WebCore/platform/graphics/android/LayerAndroid.h @@ -121,31 +121,18 @@ public: void setBackgroundColor(SkColor color); void setMaskLayer(LayerAndroid*); - void setMasksToBounds(bool); + void setMasksToBounds(bool masksToBounds) { + m_haveClip = masksToBounds; + } + bool masksToBounds() const { return m_haveClip; } void setIsRootLayer(bool isRootLayer) { m_isRootLayer = isRootLayer; } bool isRootLayer() const { return m_isRootLayer; } SkPicture* recordContext(); - // The foreground context is used to draw overflow scroll content. - SkPicture* foregroundContext(); - - // The foreground clip is set when there is content within the node that - // can be scrolled (i.e. a div with overflow:scroll). - void setForegroundClip(const SkRect& clip) { - m_foregroundClip = clip; - } - - // Return the foreground clip offset by the position of the layer. - SkRect foregroundClip() const { return m_foregroundClip; } - - bool contentIsScrollable() const; - // Returns true if the content position has changed. bool scrollBy(int dx, int dy); - const SkPoint& scrollPosition() const { return m_foregroundLocation; } - void setScrollPosition(const SkPoint& pos) { m_foregroundLocation = pos; } void addAnimation(PassRefPtr<AndroidAnimation> anim); void removeAnimation(const String& name); @@ -180,7 +167,10 @@ public: void clipArea(SkTDArray<SkRect>* region) const; const LayerAndroid* find(int x, int y, SkPicture* root) const; - const LayerAndroid* findById(int uniqueID) const; + const LayerAndroid* findById(int uniqueID) const { + return const_cast<LayerAndroid*>(this)->findById(uniqueID); + } + LayerAndroid* findById(int uniqueID); LayerAndroid* getChild(int index) const { return static_cast<LayerAndroid*>(this->INHERITED::getChild(index)); } @@ -196,6 +186,14 @@ public: void setContentsImage(SkBitmapRef* img); void bounds(SkRect* ) const; + + bool contentIsScrollable() const { return m_contentScrollable; } + + // Set when building the layer hierarchy for scrollable elements. + void setContentScrollable(bool scrollable) { + m_contentScrollable = scrollable; + } + protected: virtual void onDraw(SkCanvas*, SkScalar opacity); @@ -215,6 +213,7 @@ private: bool m_doRotation; bool m_isFixed; bool m_backgroundColorSet; + bool m_contentScrollable; SkLength m_fixedLeft; SkLength m_fixedTop; @@ -239,15 +238,6 @@ private: // it is a much faster method than using m_recordingPicture. SkPicture* m_recordingPicture; - // m_foregroundPicture is set only when compositing a scrollable div. It - // contains the contents minus the background and border which is drawn - // first by the rendering tree. When we draw the layer, we draw - // m_recordingPicture (containing the background + border) first and then - // clip to m_foregroundClip and draw m_foregroundPicture. - SkPicture* m_foregroundPicture; - SkRect m_foregroundClip; - SkPoint m_foregroundLocation; - SkBitmapRef* m_contentsImage; typedef HashMap<String, RefPtr<AndroidAnimation> > KeyframesMap; diff --git a/WebCore/rendering/RenderLayer.cpp b/WebCore/rendering/RenderLayer.cpp index 12360c8..4221816 100644 --- a/WebCore/rendering/RenderLayer.cpp +++ b/WebCore/rendering/RenderLayer.cpp @@ -1938,6 +1938,14 @@ bool RenderLayer::hasOverflowScroll() const return true; return false; } + +bool RenderLayer::hasOverflowParent() const +{ + const RenderLayer* layer = this; + while (layer && !layer->hasOverflowScroll()) + layer = layer->parent(); + return layer; +} #endif void RenderLayer::positionOverflowControls(int tx, int ty) @@ -2012,13 +2020,6 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar) *needHBar = rightPos > clientWidth; if (needVBar) *needVBar = bottomPos > clientHeight; -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (hasOverflowScroll()) { - compositor()->setCompositingLayersNeedRebuild(true); - compositor()->enableCompositingMode(true); - compositor()->updateCompositingLayers(CompositingUpdateAfterLayoutOrStyleChange, this); - } -#endif } void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow) @@ -2154,6 +2155,14 @@ RenderLayer::updateScrollInfoAfterLayout() if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER)) updateOverflowStatus(horizontalOverflow, verticalOverflow); + +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (hasOverflowScroll()) { + rendererContentChanged(); + dirtyStackingContextZOrderLists(); + dirtyZOrderLists(); + } +#endif } void RenderLayer::paintOverflowControls(GraphicsContext* context, int tx, int ty, const IntRect& damageRect) @@ -3213,6 +3222,15 @@ void RenderLayer::calculateClipRects(const RenderLayer* rootLayer, ClipRects& cl if (renderer()->hasOverflowClip()) { IntRect newOverflowClip = toRenderBox(renderer())->overflowClipRect(x, y); +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (hasOverflowScroll()) { + RenderBox* box = toRenderBox(renderer()); + newOverflowClip = + IntRect(x, y, + box->borderLeft() + box->borderRight() + m_scrollWidth, + box->borderTop() + box->borderBottom() + m_scrollHeight); + } +#endif clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect())); if (renderer()->isPositioned() || renderer()->isRelPositioned()) clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect())); @@ -3277,6 +3295,7 @@ void RenderLayer::calculateRects(const RenderLayer* rootLayer, const IntRect& pa // This layer establishes a clip of some kind. #if ENABLE(ANDROID_OVERFLOW_SCROLL) if (hasOverflowScroll()) { + // Use the entire foreground rectangle to record the contents. RenderBox* box = toRenderBox(renderer()); foregroundRect = IntRect(x, y, diff --git a/WebCore/rendering/RenderLayer.h b/WebCore/rendering/RenderLayer.h index 27d2b31..6b60fe1 100644 --- a/WebCore/rendering/RenderLayer.h +++ b/WebCore/rendering/RenderLayer.h @@ -260,6 +260,7 @@ public: bool hasOverflowControls() const; #if ENABLE(ANDROID_OVERFLOW_SCROLL) bool hasOverflowScroll() const; + bool hasOverflowParent() const; #endif void positionOverflowControls(int tx, int ty); bool isPointInResizeControl(const IntPoint& absolutePoint) const; @@ -323,11 +324,19 @@ public: bool isFixed() const { return renderer()->isPositioned() && renderer()->style()->position() == FixedPosition; } // If fixed elements are composited, they will be containing children bool isStackingContext() const { +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + if (hasOverflowScroll()) + return true; +#endif return !hasAutoZIndex() || renderer()->isRenderView() || (isComposited() && isFixed()); } #else +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isRenderView() || hasOverflowScroll(); } +#else bool isStackingContext() const { return !hasAutoZIndex() || renderer()->isRenderView() ; } #endif +#endif void dirtyZOrderLists(); void dirtyStackingContextZOrderLists(); diff --git a/WebCore/rendering/RenderLayerBacking.cpp b/WebCore/rendering/RenderLayerBacking.cpp index 517a6d2..215b41f 100644 --- a/WebCore/rendering/RenderLayerBacking.cpp +++ b/WebCore/rendering/RenderLayerBacking.cpp @@ -57,10 +57,6 @@ #include "Settings.h" #include "WebGLRenderingContext.h" -#if ENABLE(ANDROID_OVERFLOW_SCROLL) -#include "GraphicsLayerAndroid.h" -#endif - using namespace std; namespace WebCore { @@ -883,20 +879,6 @@ IntRect RenderLayerBacking::contentsBox() const } else #endif contentsRect = toRenderBox(renderer())->contentBoxRect(); -#if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (m_owningLayer->hasOverflowScroll()) { - // Update the contents rect to have the width and height of the entire - // contents. This rect is only used by the platform GraphicsLayer and - // the position of the rectangle is ignored. Use the layer's scroll - // width/height (which contain the padding). - RenderBox* box = toRenderBox(renderer()); - int outline = box->view()->maximalOutlineSize() << 1; - contentsRect.setWidth(box->borderLeft() + box->borderRight() + - m_owningLayer->scrollWidth() + outline); - contentsRect.setHeight(box->borderTop() + box->borderBottom() + - m_owningLayer->scrollHeight() + outline); - } -#endif IntSize contentOffset = contentOffsetInCompostingLayer(); contentsRect.move(contentOffset); @@ -1116,10 +1098,10 @@ void RenderLayerBacking::paintContents(const GraphicsLayer*, GraphicsContext& co // can compute and cache clipRects. IntRect enclosingBBox = compositedBounds(); #if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (m_owningLayer->hasOverflowScroll()) { - enclosingBBox.setSize(contentsBox().size()); - enclosingBBox.setLocation(m_compositedBounds.location()); - } + // If we encounter a scrollable layer, layers inside the scrollable layer + // will need their entire content recorded. + if (m_owningLayer->hasOverflowParent()) + enclosingBBox.setSize(clip.size()); #endif IntRect clipRect(clip); diff --git a/WebCore/rendering/RenderLayerCompositor.cpp b/WebCore/rendering/RenderLayerCompositor.cpp index da804dd..cf75a2a 100644 --- a/WebCore/rendering/RenderLayerCompositor.cpp +++ b/WebCore/rendering/RenderLayerCompositor.cpp @@ -286,6 +286,13 @@ bool RenderLayerCompositor::updateBacking(RenderLayer* layer, CompositingChangeR // 3D transforms turn off the testing of overlap. if (requiresCompositingForTransform(layer->renderer())) setCompositingConsultsOverlap(false); +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + // If we are a child of a scrollable layer, ignore the overlap from the + // scrollable layer as it can cause child layers to become composited + // siblings and will not scroll with the main content layer. + if (layer->hasOverflowParent()) + setCompositingConsultsOverlap(false); +#endif if (!layer->backing()) { diff --git a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp index f1e6279..80a90fe 100644 --- a/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp +++ b/WebKit/android/WebCoreSupport/ChromeClientAndroid.cpp @@ -71,7 +71,12 @@ WebCore::GraphicsLayer* ChromeClientAndroid::layersSync() void ChromeClientAndroid::scheduleCompositingLayerSync() { - m_needsLayerSync = true; + if (m_needsLayerSync) + return; + m_needsLayerSync = true; + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_webFrame->page()->mainFrame()->view()); + if (webViewCore) + webViewCore->layersDraw(); } void ChromeClientAndroid::setNeedsOneShotDrawingSynchronization() diff --git a/WebKit/android/WebCoreSupport/PlatformBridge.cpp b/WebKit/android/WebCoreSupport/PlatformBridge.cpp index 89af00a..2c238b2 100644 --- a/WebKit/android/WebCoreSupport/PlatformBridge.cpp +++ b/WebKit/android/WebCoreSupport/PlatformBridge.cpp @@ -184,12 +184,6 @@ void PlatformBridge::updateTextfield(FrameView* frameView, Node* nodePtr, bool c webViewCore->updateTextfield(nodePtr, changeToPassword, text); } -void PlatformBridge::updateLayers(FrameView* frameView) -{ - android::WebViewCore* webViewCore = android::WebViewCore::getWebViewCore(frameView); - webViewCore->layersDraw(); -} - int PlatformBridge::lowMemoryUsageMB() { return MemoryUsage::lowMemoryUsageMb(); diff --git a/WebKit/android/jni/WebViewCore.cpp b/WebKit/android/jni/WebViewCore.cpp index 1fdc3d5..5f5bb53 100644 --- a/WebKit/android/jni/WebViewCore.cpp +++ b/WebKit/android/jni/WebViewCore.cpp @@ -1176,14 +1176,6 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, WebCoreViewBridge* window = m_mainFrame->view()->platformWidget(); int ow = window->width(); int oh = window->height(); - window->setSize(width, height); - window->setVisibleSize(screenWidth, screenHeight); - if (width != screenWidth) { - m_mainFrame->view()->setUseFixedLayout(true); - m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); - } else { - m_mainFrame->view()->setUseFixedLayout(false); - } int osw = m_screenWidth; int osh = m_screenHeight; int otw = m_textWrapWidth; @@ -1210,7 +1202,7 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, // orientation change. Try to keep the anchor at the same place. if (otw && textWrapWidth && otw != textWrapWidth) { WebCore::HitTestResult hitTestResult = - m_mainFrame->eventHandler()-> hitTestResultAtPoint( + m_mainFrame->eventHandler()->hitTestResultAtPoint( anchorPoint, false); node = hitTestResult.innerNode(); } @@ -1230,8 +1222,20 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, } } } + + // Set the size after finding the old anchor point as + // hitTestResultAtPoint causes a layout. + window->setSize(width, height); + window->setVisibleSize(screenWidth, screenHeight); + if (width != screenWidth) { + m_mainFrame->view()->setUseFixedLayout(true); + m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); + } else { + m_mainFrame->view()->setUseFixedLayout(false); + } r->setNeedsLayoutAndPrefWidthsRecalc(); m_mainFrame->view()->forceLayout(); + // scroll to restore current screen center if (node) { const WebCore::IntRect& newBounds = node->getRect(); @@ -1261,6 +1265,16 @@ void WebViewCore::setSizeScreenWidthAndScale(int width, int height, } } } + } else { + window->setSize(width, height); + window->setVisibleSize(screenWidth, screenHeight); + m_mainFrame->view()->resize(width, height); + if (width != screenWidth) { + m_mainFrame->view()->setUseFixedLayout(true); + m_mainFrame->view()->setFixedLayoutSize(IntSize(width, height)); + } else { + m_mainFrame->view()->setUseFixedLayout(false); + } } // update the currently visible screen as perceived by the plugin @@ -2792,33 +2806,35 @@ void WebViewCore::touchUp(int touchGeneration, // Return the RenderLayer for the given RenderObject only if the layer is // composited and it contains a scrollable content layer. -static WebCore::RenderLayer* getLayerFromRenderer( - WebCore::RenderObject* renderer, LayerAndroid** aLayer) +static WebCore::RenderLayer* getScrollingLayerFromRenderer( + WebCore::RenderObject* renderer) { +#if ENABLE(ANDROID_OVERFLOW_SCROLL) if (!renderer) return 0; WebCore::RenderLayer* layer = renderer->enclosingSelfPaintingLayer(); - if (!layer || !layer->backing()) - return 0; - GraphicsLayerAndroid* graphicsLayer = - static_cast<GraphicsLayerAndroid*>(layer->backing()->graphicsLayer()); - if (!graphicsLayer) - return 0; - LayerAndroid* layerAndroid = graphicsLayer->contentLayer(); - if (!layerAndroid || !layerAndroid->contentIsScrollable()) + if (!layer) return 0; - *aLayer = layerAndroid; + // Find the layer that actually has overflow scroll in case this renderer is + // inside a child layer. + while (layer && !layer->hasOverflowScroll()) + layer = layer->parent(); return layer; +#endif + return 0; } // Scroll the RenderLayer associated with a scrollable div element. This is // done so that the node is visible when it is clicked. static void scrollLayer(WebCore::RenderObject* renderer, WebCore::IntPoint* pos) { - LayerAndroid* aLayer; - WebCore::RenderLayer* layer = getLayerFromRenderer(renderer, &aLayer); + WebCore::RenderLayer* layer = getScrollingLayerFromRenderer(renderer); if (!layer) return; + // The cache uses absolute coordinates when clicking on nodes and it assumes + // the layer is not scrolled. + layer->scrollToOffset(0, 0, false, false); + WebCore::IntRect absBounds = renderer->absoluteBoundingBoxRect(); // Do not include the outline when moving the node's bounds. WebCore::IntRect layerBounds = layer->renderer()->absoluteBoundingBoxRect(); @@ -2826,16 +2842,11 @@ static void scrollLayer(WebCore::RenderObject* renderer, WebCore::IntPoint* pos) // Move the node's bounds into the layer's coordinates. absBounds.move(-layerBounds.x(), -layerBounds.y()); - int diffX = layer->scrollXOffset(); - int diffY = layer->scrollYOffset(); - // Scroll the layer to the node's position. The false parameters tell the - // layer not to invalidate. + // Scroll the layer to the node's position. layer->scrollToOffset(absBounds.x(), absBounds.y(), false, true); - diffX = layer->scrollXOffset() - diffX; - diffY = layer->scrollYOffset() - diffY; // Update the mouse position to the layer offset. - pos->move(-diffX, -diffY); + pos->move(-layer->scrollXOffset(), -layer->scrollYOffset()); } // Common code for both clicking with the trackball and touchUp diff --git a/WebKit/android/nav/CacheBuilder.cpp b/WebKit/android/nav/CacheBuilder.cpp index 449b9e2..f0333f2 100644 --- a/WebKit/android/nav/CacheBuilder.cpp +++ b/WebKit/android/nav/CacheBuilder.cpp @@ -93,6 +93,12 @@ Frame* CacheBuilder::FrameAnd(const CacheBuilder* cacheBuilder) { return loader->getFrame(); } +CacheBuilder::LayerTracker::~LayerTracker() { + if (mRenderLayer) + // Restore the scroll position of the layer. Does not affect layers + // without overflow scroll as the layer will not be scrolled. + mRenderLayer->scrollToOffset(mScroll.x(), mScroll.y(), false, false); +} #if DUMP_NAV_CACHE @@ -919,8 +925,7 @@ static bool checkForPluginViewThatWantsFocus(RenderObject* renderer) { } #if USE(ACCELERATED_COMPOSITING) -static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, - const IntPoint& scroll, int id) +static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, int id) { DBG_NAV_LOGD("frame=%p index=%d loc=(%d,%d) id=%d", frame, index, location.x(), location.y(), id); @@ -928,7 +933,6 @@ static void AddLayer(CachedFrame* frame, size_t index, const IntPoint& location, cachedLayer.reset(); cachedLayer.setCachedNodeIndex(index); cachedLayer.setOffset(location); - cachedLayer.setScrollOffset(scroll); cachedLayer.setUniqueId(id); frame->add(cachedLayer); } @@ -1099,7 +1103,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, hasCursorRing = style->tapHighlightColor().alpha() > 0; #endif #if USE(ACCELERATED_COMPOSITING) - if (nodeRenderer->hasLayer()) { + // If this renderer has its own layer and the layer is composited, + // start tracking it. + if (lastChild && nodeRenderer->hasLayer() && toRenderBox(nodeRenderer)->layer()->backing()) { TrackLayer(layerTracker, nodeRenderer, lastChild, globalOffsetX, globalOffsetY); size_t size = tracker.size(); @@ -1108,11 +1114,9 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, int id = layer->uniqueId(); const RenderLayer* renderLayer = layerTracker.last().mRenderLayer; - IntPoint loc(SkScalarRound(layer->getPosition().fX), - SkScalarRound(layer->getPosition().fY)); + // Global location + IntPoint loc = renderLayer->absoluteBoundingBox().location(); loc.move(globalOffsetX, globalOffsetY); - IntPoint scroll(renderLayer->scrollXOffset(), - renderLayer->scrollYOffset()); // if this is a child of a CachedNode, add a layer size_t limit = cachedFrame->layerCount() == 0 ? 0 : cachedFrame->lastLayer()->cachedNodeIndex(); @@ -1128,7 +1132,7 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, CachedNode* trackedNode = cachedFrame->getIndex(index); trackedNode->setIsInLayer(true); trackedNode->setIsUnclipped(true); - AddLayer(cachedFrame, index, loc, scroll, id); + AddLayer(cachedFrame, index, loc, id); } } } @@ -1174,11 +1178,8 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, absBounds.move(globalOffsetX, globalOffsetY); hasClip = nodeRenderer->hasOverflowClip(); #if ENABLE(ANDROID_OVERFLOW_SCROLL) - if (nodeRenderer->hasLayer()) { - const LayerAndroid* layer = layerTracker.last().mLayer; - if (layer && layer->contentIsScrollable()) - hasClip = false; - } + if (nodeRenderer->enclosingLayer() && nodeRenderer->enclosingLayer()->hasOverflowParent()) + hasClip = false; #endif if (node->hasTagName(HTMLNames::canvasTag)) @@ -1399,22 +1400,23 @@ void CacheBuilder::BuildFrame(Frame* root, Frame* frame, } bool isInLayer = false; #if USE(ACCELERATED_COMPOSITING) + // If this renderer has a composited parent layer (including itself), + // add the node to the cached layer. // FIXME: does not work for area rects - LayerAndroid* layer = layerTracker.last().mLayer; - if (layer) { - const IntRect& layerClip = layerTracker.last().mBounds; - const RenderLayer* renderLayer = layerTracker.last().mRenderLayer; - if (!layer->contentIsScrollable() && !layerClip.isEmpty() && - !cachedNode.clip(layerClip)) { - DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex); - continue; // skip this node if outside of the clip + RenderLayer* enclosingLayer = nodeRenderer->enclosingLayer(); + if (enclosingLayer && enclosingLayer->enclosingCompositingLayer()) { + LayerAndroid* layer = layerTracker.last().mLayer; + if (layer) { + const IntRect& layerClip = layerTracker.last().mBounds; + if (!layerClip.isEmpty() && !cachedNode.clip(layerClip)) { + DBG_NAV_LOGD("skipped on layer clip %d", cacheIndex); + continue; // skip this node if outside of the clip + } + isInLayer = true; + isUnclipped = true; // assume that layers do not have occluded nodes + AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(), + layer->uniqueId()); } - isInLayer = true; - isUnclipped = true; // assume that layers do not have occluded nodes - IntPoint scroll(renderLayer->scrollXOffset(), - renderLayer->scrollYOffset()); - AddLayer(cachedFrame, cachedFrame->size(), layerClip.location(), - scroll, layer->uniqueId()); } #endif cachedNode.setNavableRects(); @@ -2919,7 +2921,7 @@ bool CacheBuilder::setData(CachedFrame* cachedFrame) void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker, RenderObject* nodeRenderer, Node* lastChild, int offsetX, int offsetY) { - RenderLayer* layer = toRenderBoxModelObject(nodeRenderer)->layer(); + RenderLayer* layer = nodeRenderer->enclosingLayer(); RenderLayerBacking* back = layer->backing(); if (!back) return; @@ -2930,13 +2932,28 @@ void CacheBuilder::TrackLayer(WTF::Vector<LayerTracker>& layerTracker, LayerAndroid* aLayer = grLayer->contentLayer(); if (!aLayer) return; + IntPoint scroll(layer->scrollXOffset(), layer->scrollYOffset()); +#if ENABLE(ANDROID_OVERFLOW_SCROLL) + // If this is an overflow element, track the content layer. + if (layer->hasOverflowParent() && aLayer->getChild(0)) + aLayer = aLayer->getChild(0)->getChild(0); + if (!aLayer) + return; + layer->scrollToOffset(0, 0, false, false); +#endif layerTracker.grow(layerTracker.size() + 1); LayerTracker& indexTracker = layerTracker.last(); indexTracker.mLayer = aLayer; indexTracker.mRenderLayer = layer; indexTracker.mBounds = IntRect(FloatRect(aLayer->bounds())); + // Use the absolute location of the layer as the bounds location. This + // provides the original offset of nodes in the layer so that we can + // translate nodes between their original location and the layer's new + // location. + indexTracker.mBounds.setLocation(layer->absoluteBoundingBox().location()); indexTracker.mBounds.move(offsetX, offsetY); - indexTracker.mLastChild = lastChild ? OneAfter(lastChild) : 0; + indexTracker.mScroll = scroll; + indexTracker.mLastChild = OneAfter(lastChild); DBG_NAV_LOGD("layer=%p [%d] bounds=(%d,%d,w=%d,h=%d)", aLayer, aLayer->uniqueId(), indexTracker.mBounds.x(), indexTracker.mBounds.y(), indexTracker.mBounds.width(), indexTracker.mBounds.height()); diff --git a/WebKit/android/nav/CacheBuilder.h b/WebKit/android/nav/CacheBuilder.h index 9832865..d229df0 100644 --- a/WebKit/android/nav/CacheBuilder.h +++ b/WebKit/android/nav/CacheBuilder.h @@ -202,6 +202,8 @@ private: LayerAndroid* mLayer; RenderLayer* mRenderLayer; IntRect mBounds; + IntPoint mScroll; + ~LayerTracker(); }; struct TabIndexTracker : Tracker { int mTabIndex; diff --git a/WebKit/android/nav/CachedFrame.cpp b/WebKit/android/nav/CachedFrame.cpp index 4f9ec06..55a7c0e 100644 --- a/WebKit/android/nav/CachedFrame.cpp +++ b/WebKit/android/nav/CachedFrame.cpp @@ -53,12 +53,8 @@ WebCore::IntRect CachedFrame::adjustBounds(const CachedNode* node, const CachedLayer* cachedLayer = layer(node); const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer(); const LayerAndroid* aLayer = cachedLayer->layer(rootLayer); - if (aLayer) { - IntRect rrect = cachedLayer->adjustBounds(rootLayer, rect); - if (!aLayer->contentIsScrollable()) - rrect.move(-mViewBounds.x(), -mViewBounds.y()); - return rrect; - } + if (aLayer) + return cachedLayer->adjustBounds(rootLayer, rect); #endif return rect; } @@ -74,12 +70,8 @@ WebCore::IntRect CachedFrame::unadjustBounds(const CachedNode* node, const CachedLayer* cachedLayer = layer(node); const WebCore::LayerAndroid* rootLayer = mRoot->rootLayer(); const LayerAndroid* aLayer = cachedLayer->layer(rootLayer); - if (aLayer) { - IntRect rrect = cachedLayer->unadjustBounds(rootLayer, rect); - if (!aLayer->contentIsScrollable()) - rrect.move(mViewBounds.x(), mViewBounds.y()); - return rrect; - } + if (aLayer) + return cachedLayer->unadjustBounds(rootLayer, rect); } #endif return rect; diff --git a/WebKit/android/nav/CachedLayer.cpp b/WebKit/android/nav/CachedLayer.cpp index 5ad5c8b..0c53da2 100644 --- a/WebKit/android/nav/CachedLayer.cpp +++ b/WebKit/android/nav/CachedLayer.cpp @@ -49,10 +49,6 @@ IntRect CachedLayer::adjustBounds(const LayerAndroid* root, // First, remove the original offset from the bounds. temp.move(-mOffset.x(), -mOffset.y()); - // Now, add in the original scroll position. This moves the node to the - // original location within the layer. - temp.move(mScrollOffset.x(), mScrollOffset.y()); - // Next, add in the new position of the layer (could be different due to a // fixed position layer). FloatPoint position = getGlobalPosition(aLayer); @@ -62,32 +58,16 @@ IntRect CachedLayer::adjustBounds(const LayerAndroid* root, const FloatPoint& translation = aLayer->translation(); temp.move(translation.x(), translation.y()); - // Move the bounds by the layer's internal scroll position. - const SkPoint& scroll = aLayer->scrollPosition(); - temp.move(SkScalarToFloat(-scroll.fX), SkScalarToFloat(-scroll.fY)); - IntRect result = enclosingIntRect(temp); - // Finally, clip the result to the foreground (this includes the object's - // border which does not scroll). - IntRect clip(aLayer->foregroundClip()); - if (!clip.isEmpty()) { - clip.move(position.x(), position.y()); - result.intersect(clip); - } - DBG_NAV_LOGV("root=%p aLayer=%p [%d]" " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g) pos=(%f,%f)" - " offset=(%d,%d) clip=(%d,%d,w=%d,h=%d)" - " scroll=(%d,%d) origScroll=(%d,%d)" + " offset=(%d,%d)" " result=(%d,%d,w=%d,h=%d)", root, aLayer, aLayer->uniqueId(), bounds.x(), bounds.y(), bounds.width(), bounds.height(), translation.x(), translation.y(), position.x(), position.y(), mOffset.x(), mOffset.y(), - clip.x(), clip.y(), clip.width(), clip.height(), - SkScalarRound(scroll.fX), SkScalarRound(scroll.fY), - mScrollOffset.x(), mScrollOffset.y(), result.x(), result.y(), result.width(), result.height()); return result; } @@ -109,26 +89,17 @@ IntRect CachedLayer::unadjustBounds(const LayerAndroid* root, const FloatPoint& translation = aLayer->translation(); temp.move(-translation.x(), -translation.y()); - // Move the bounds by the internal scroll position. - const SkPoint& scroll = aLayer->scrollPosition(); - temp.move(SkScalarRound(scroll.fX), SkScalarRound(scroll.fY)); - // Move it back to the original offset. temp.move(mOffset.x(), mOffset.y()); - // Move the bounds by the original scroll. - temp.move(-mScrollOffset.x(), -mScrollOffset.y()); DBG_NAV_LOGD("root=%p aLayer=%p [%d]" " bounds=(%d,%d,w=%d,h=%d) trans=(%g,%g) pos=(%f,%f)" " offset=(%d,%d)" - " scroll=(%d,%d) origScroll=(%d,%d)" " result=(%d,%d,w=%d,h=%d)", root, aLayer, aLayer->uniqueId(), bounds.x(), bounds.y(), bounds.width(), bounds.height(), translation.x(), translation.y(), position.x(), position.y(), mOffset.x(), mOffset.y(), - SkScalarRound(scroll.fX), SkScalarRound(scroll.fY), - mScrollOffset.x(), mScrollOffset.y(), temp.x(), temp.y(), temp.width(), temp.height()); return temp; } @@ -153,7 +124,7 @@ const LayerAndroid* CachedLayer::layer(const LayerAndroid* root) const return mLayer = root->findById(mUniqueId); } -// return bounds relative to enclosing layer as recorded when walking the dom +// return bounds relative to the layer as recorded when walking the dom IntRect CachedLayer::localBounds(const LayerAndroid* root, const IntRect& bounds) const { @@ -161,45 +132,14 @@ IntRect CachedLayer::localBounds(const LayerAndroid* root, // Remove the original offset from the bounds. temp.move(-mOffset.x(), -mOffset.y()); - // We add in the original scroll position in order to position the node - // relative to the current internal scroll position. - temp.move(mScrollOffset.x(), mScrollOffset.y()); - - const LayerAndroid* aLayer = layer(root); - FloatPoint position; - if (aLayer) { - const LayerAndroid* parent = static_cast<const LayerAndroid*> - (aLayer->getParent()); - if (parent) { - position = getGlobalPosition(parent); - temp.move(-position.x(), -position.y()); - } - // Move the bounds by the scroll position of the layer. - const SkPoint& scroll = aLayer->scrollPosition(); - temp.move(SkScalarToFloat(-scroll.fX), SkScalarToFloat(-scroll.fY)); - - // Clip by the layer's foreground bounds. Since the bounds have - // already be moved local to the layer, no need to move the foreground - // clip. - IntRect foregroundClip(aLayer->foregroundClip()); - if (!foregroundClip.isEmpty()) - temp.intersect(foregroundClip); - } - #if DEBUG_NAV_UI - const FloatPoint& translation = aLayer->translation(); - SkPoint scroll = SkPoint::Make(0,0); - if (aLayer) scroll = aLayer->scrollPosition(); + const LayerAndroid* aLayer = layer(root); DBG_NAV_LOGD("aLayer=%p [%d] bounds=(%d,%d,w=%d,h=%d) offset=(%d,%d)" - " scrollOffset=(%d,%d) position=(%g,%g) result=(%d,%d,w=%d,h=%d)" - " scroll=(%d,%d) trans=(%g,%g)", + " result=(%d,%d,w=%d,h=%d)", aLayer, aLayer ? aLayer->uniqueId() : 0, bounds.x(), bounds.y(), bounds.width(), bounds.height(), mOffset.x(), mOffset.y(), - mScrollOffset.x(), mScrollOffset.y(), position.x(), position.y(), - temp.x(), temp.y(), temp.width(), temp.height(), - scroll.fX, scroll.fY, - translation.x(), translation.y()); + temp.x(), temp.y(), temp.width(), temp.height()); #endif return temp; @@ -240,8 +180,6 @@ void CachedLayer::Debug::print() const DUMP_NAV_LOGD(" // LayerAndroid* mLayer=%p;\n", b->mLayer); DUMP_NAV_LOGD(" // int mOffset=(%d, %d);\n", b->mOffset.x(), b->mOffset.y()); - DUMP_NAV_LOGD(" // int mScrollOffset=(%d, %d);\n", - b->mScrollOffset.x(), b->mScrollOffset.y()); DUMP_NAV_LOGD(" // int mUniqueId=%p;\n", b->mUniqueId); DUMP_NAV_LOGD("%s\n", ""); } @@ -257,11 +195,10 @@ void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer) ++spaces; SkRect bounds; layer->bounds(&bounds); - DUMP_NAV_LOGD("%.*s layer=%p [%d] (%g,%g,%g,%g)" - " position=(%g,%g) translation=(%g,%g) anchor=(%g,%g)" - " matrix=(%g,%g) childMatrix=(%g,%g)" - " foregroundLocation=(%g,%g)" - " picture=%p clipped=%s\n", + DBG_NAV_LOGD("%.*s layer=%p [%d] (%g,%g,%g,%g)" + " position=(%g,%g) translation=(%g,%g) anchor=(%g,%g)" + " matrix=(%g,%g) childMatrix=(%g,%g) picture=%p clipped=%s" + " scrollable=%s\n", spaces, " ", layer, layer->uniqueId(), bounds.fLeft, bounds.fTop, bounds.width(), bounds.height(), layer->getPosition().fX, layer->getPosition().fY, @@ -270,8 +207,8 @@ void CachedLayer::Debug::printLayerAndroid(const LayerAndroid* layer) layer->getMatrix().getTranslateX(), layer->getMatrix().getTranslateY(), layer->getChildrenMatrix().getTranslateX(), layer->getChildrenMatrix().getTranslateY(), - layer->scrollPosition().fX, layer->scrollPosition().fY, - layer->picture(), layer->m_haveClip ? "true" : "false"); + layer->picture(), layer->m_haveClip ? "true" : "false", + layer->contentIsScrollable() ? "true" : "false"); for (int i = 0; i < layer->countChildren(); i++) printLayerAndroid(layer->getChild(i)); --spaces; diff --git a/WebKit/android/nav/CachedLayer.h b/WebKit/android/nav/CachedLayer.h index fd5f4a0..db7bfb1 100644 --- a/WebKit/android/nav/CachedLayer.h +++ b/WebKit/android/nav/CachedLayer.h @@ -48,7 +48,7 @@ public: } // FIXME: adjustBounds should be renamed globalBounds or toGlobal IntRect adjustBounds(const LayerAndroid* root, const IntRect& bounds) const; - // Moves the bounds by the layer's scroll position. Assumes the incoming + // Moves the bounds by the layer's position. Assumes the incoming // bounds have been adjusted by adjustBounds. IntRect unadjustBounds(const LayerAndroid* root, const IntRect& bounds) const; @@ -60,19 +60,17 @@ public: void toLocal(const LayerAndroid* root, int* xPtr, int* yPtr) const; void reset() { mLayer = 0; } void setCachedNodeIndex(int index) { mCachedNodeIndex = index; } + // Set the global position of the layer. This is recorded by the nav cache + // and corresponds to RenderLayer::absoluteBoundingBox() which is in + // document coordinates. This can be different from the global position of + // the layer if the layer is fixed positioned or scrollable. void setOffset(const IntPoint& offset) { mOffset = offset; } - void setScrollOffset(const IntPoint& scrollOffset) { - mScrollOffset = scrollOffset; - } void setUniqueId(int uniqueId) { mUniqueId = uniqueId; } int uniqueId() const { return mUniqueId; } private: int mCachedNodeIndex; mutable const LayerAndroid* mLayer; - // mOffset and mScrollOffset are the position and scroll offset of the - // layer when recorded by the nav cache. IntPoint mOffset; - IntPoint mScrollOffset; int mUniqueId; #if DUMP_NAV_CACHE diff --git a/WebKit/android/nav/WebView.cpp b/WebKit/android/nav/WebView.cpp index 6370021..4d92ce8 100644 --- a/WebKit/android/nav/WebView.cpp +++ b/WebKit/android/nav/WebView.cpp @@ -971,15 +971,38 @@ bool motionUp(int x, int y, int slop) return pageScrolled; } +#if USE(ACCELERATED_COMPOSITING) +static const LayerAndroid* findScrollableLayer(const LayerAndroid* parent, int x, int y) { + SkRect bounds; + parent->bounds(&bounds); + // Check the parent bounds first; this will clip to within a masking layer's + // bounds. + if (!bounds.contains(x, y)) + return 0; + // Move the hit test local to parent. + x -= bounds.fLeft; + y -= bounds.fTop; + int count = parent->countChildren(); + for (int i = 0; i < count; i++) { + const LayerAndroid* child = parent->getChild(i); + const LayerAndroid* result = findScrollableLayer(child, x, y); + if (result) + return result; + } + if (parent->contentIsScrollable()) + return parent; + return 0; +} +#endif + const LayerAndroid* scrollableLayer(int x, int y) { -#if ENABLE(ANDROID_OVERFLOW_SCROLL) && USE(ACCELERATED_COMPOSITING) +#if USE(ACCELERATED_COMPOSITING) const LayerAndroid* layerRoot = compositeRoot(); if (!layerRoot) return 0; - const LayerAndroid* result = layerRoot->find(x, y, 0); - if (result != 0 && result->contentIsScrollable()) - return result; + const LayerAndroid* result = findScrollableLayer(layerRoot, x, y); + return result; #endif return 0; } @@ -1269,6 +1292,7 @@ LayerAndroid* compositeRoot() const return 0; } +#if ENABLE(ANDROID_OVERFLOW_SCROLL) static void copyScrollPositionRecursive(const LayerAndroid* from, LayerAndroid* root) { @@ -1277,14 +1301,15 @@ static void copyScrollPositionRecursive(const LayerAndroid* from, for (int i = 0; i < from->countChildren(); i++) { const LayerAndroid* l = from->getChild(i); if (l->contentIsScrollable()) { - LayerAndroid* match = - const_cast<LayerAndroid*>(root->findById(l->uniqueId())); - if (match != 0) - match->setScrollPosition(l->scrollPosition()); + const SkPoint& pos = l->getPosition(); + LayerAndroid* match = root->findById(l->uniqueId()); + if (match && match->contentIsScrollable()) + match->setPosition(pos.fX, pos.fY); } copyScrollPositionRecursive(l, root); } } +#endif void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect) { @@ -1293,10 +1318,12 @@ void setBaseLayer(BaseLayerAndroid* layer, WebCore::IntRect& rect) m_glWebViewState->setBaseLayer(layer, rect); #endif +#if ENABLE(ANDROID_OVERFLOW_SCROLL) if (layer) { - copyScrollPositionRecursive(compositeRoot(), - static_cast<LayerAndroid*>(layer->getChild(0))); + LayerAndroid* newCompositeRoot = static_cast<LayerAndroid*>(layer->getChild(0)); + copyScrollPositionRecursive(compositeRoot(), newCompositeRoot); } +#endif delete m_baseLayer; m_baseLayer = layer; CachedRoot* root = getFrameCache(DontAllowNewer); |