From 8782ca1236bac0bb13e08a6b63f8743e0b01e75a Mon Sep 17 00:00:00 2001 From: Steve Block Date: Wed, 21 Sep 2011 15:43:37 +0100 Subject: Fix find-in-page to scroll scrollable layers This requires the addition of the following methods ... - Layer::contentIsScrollable() - Layer::localToParent() - ScrollableLayerAndroid::scrollRectIntoView() Bug: 5262656 Change-Id: I2f1cf3342f73890f98a172f1b4e3f440c02dd9f4 --- Source/WebCore/platform/graphics/android/Layer.cpp | 31 ++++++++++++++++++---- Source/WebCore/platform/graphics/android/Layer.h | 20 +++++++++++++- .../platform/graphics/android/LayerAndroid.h | 1 - .../graphics/android/ScrollableLayerAndroid.cpp | 29 ++++++++++++++++++++ .../graphics/android/ScrollableLayerAndroid.h | 7 +++++ 5 files changed, 81 insertions(+), 7 deletions(-) (limited to 'Source/WebCore/platform') diff --git a/Source/WebCore/platform/graphics/android/Layer.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index 361cb4e..f650c52 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -124,23 +124,34 @@ void Layer::getLocalTransform(SkMatrix* matrix) const { matrix->preTranslate(-tx, -ty); } -void Layer::localToGlobal(SkMatrix* matrix) const { +void Layer::localToAncestor(const Layer* ancestor, SkMatrix* matrix) const { + if (this == ancestor) { + matrix->setIdentity(); + return; + } + getLocalTransform(matrix); + // Fixed position layers simply use the root layer's transform. if (shouldInheritFromRootTransform()) { + ASSERT(!ancestor); matrix->postConcat(getRootLayer()->getMatrix()); return; } - const Layer* layer = this; - while (layer->fParent != NULL) { - layer = layer->fParent; - + // Apply the local and child transforms for every layer between this layer + // and ancestor. + ASSERT(isAncestor(ancestor)); + for (const Layer* layer = this->fParent; layer != ancestor; layer = layer->fParent) { SkMatrix tmp; layer->getLocalTransform(&tmp); tmp.preConcat(layer->getChildrenMatrix()); matrix->postConcat(tmp); } + + // If ancestor is not the root layer, apply its child transformation too. + if (ancestor) + matrix->postConcat(ancestor->getChildrenMatrix()); } /////////////////////////////////////////////////////////////////////////////// @@ -204,3 +215,13 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) { } } } + +bool Layer::isAncestor(const Layer* possibleAncestor) const { + if (!possibleAncestor) + return true; + for (const Layer* layer = getParent(); layer; layer = layer->getParent()) { + if (layer == possibleAncestor) + return true; + } + return false; +} diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 7b27349..24302ce 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -104,7 +104,21 @@ public: from this layer's root parent to the layer itself. This is the matrix that is applied to the layer during drawing. */ - void localToGlobal(SkMatrix* matrix) const; + void localToGlobal(SkMatrix* matrix) const { localToAncestor(0, matrix); } + + /** Return, as a matrix, the transform that converts from this layer's local + space to the space of the given ancestor layer. Use NULL for ancestor to + represent the root layer. Note that this method must not be called on a + fixed position layer with ancestor != NULL. + + For non-fixed position layers, the following holds (in pseudo-code for + brevity) ... + SkMatrix localToAncestor = layer->localToAncestor(ancestor); + SkMatrix ancestorToGlobal = ancestor->localToAncestor(NULL); + SkMatrix localToGlobal = layer->localToGlobal(); + ASSERT(localToAncestor * ancestorToGlobal == localToGlobal); + */ + void localToAncestor(const Layer* ancestor, SkMatrix* matrix) const; // paint method @@ -115,12 +129,16 @@ public: void setHasOverflowChildren(bool value) { m_hasOverflowChildren = value; } + virtual bool contentIsScrollable() const { return false; } + protected: virtual void onDraw(SkCanvas*, SkScalar opacity); bool m_hasOverflowChildren; private: + bool isAncestor(const Layer*) const; + Layer* fParent; SkScalar m_opacity; SkSize m_size; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 31bb185..5bed7e5 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -243,7 +243,6 @@ public: void bounds(SkRect*) const; - virtual bool contentIsScrollable() const { return false; } virtual LayerAndroid* copy() const { return new LayerAndroid(*this); } void needsRepaint() { m_pictureUsed++; } diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index 2bb8b5c..bca2fd4 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -31,6 +31,35 @@ void ScrollableLayerAndroid::getScrollRect(SkIRect* out) const out->fBottom = getSize().height() - m_scrollLimits.height(); } +bool ScrollableLayerAndroid::scrollRectIntoView(const SkIRect& rect) +{ + // Apply the local transform to the rect to get it relative to the parent + // layer. + SkMatrix localTransform; + getLocalTransform(&localTransform); + SkRect transformedRect; + transformedRect.set(rect); + localTransform.mapRect(&transformedRect); + + // Test left before right to prioritize left alignment if transformedRect is wider than + // visible area. + int x = m_scrollLimits.fLeft; + if (transformedRect.fLeft < m_scrollLimits.fLeft) + x = transformedRect.fLeft; + else if (transformedRect.fRight > m_scrollLimits.fRight) + x = transformedRect.fRight - std::max(m_scrollLimits.width(), transformedRect.width()); + + // Test top before bottom to prioritize top alignment if transformedRect is taller than + // visible area. + int y = m_scrollLimits.fTop; + if (transformedRect.fTop < m_scrollLimits.fTop) + y = transformedRect.fTop; + else if (transformedRect.fBottom > m_scrollLimits.fBottom) + y = transformedRect.fBottom - std::max(m_scrollLimits.height(), transformedRect.height()); + + return scrollTo(x - getPosition().fX, y - getPosition().fY); +} + } // namespace WebCore #endif // USE(ACCELERATED_COMPOSITING) diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index b59b4e1..a2486a5 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -58,6 +58,13 @@ public: m_scrollLimits.set(x, y, x + width, y + height); } + // Given a rect in the layer, scrolls to bring the rect into view. Uses a + // lazy approach, whereby we scroll as little as possible to bring the + // entire rect into view. If the size of the rect exceeds that of the + // visible area of the layer, we favor the top and left of the rect. + // Returns whether or not any scrolling was required. + bool scrollRectIntoView(const SkIRect&); + friend void android::serializeLayer(LayerAndroid* layer, SkWStream* stream); friend LayerAndroid* android::deserializeLayer(SkStream* stream); -- cgit v1.1