summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/WebCore/platform/graphics/android/GLWebViewState.cpp2
-rw-r--r--Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp9
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.cpp31
-rw-r--r--Source/WebCore/platform/graphics/android/Layer.h20
-rw-r--r--Source/WebCore/platform/graphics/android/LayerAndroid.h1
-rw-r--r--Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp29
-rw-r--r--Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h7
-rw-r--r--Source/WebKit/android/nav/CachedRoot.h2
-rw-r--r--Source/WebKit/android/nav/WebView.cpp47
9 files changed, 130 insertions, 18 deletions
diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
index 55419f4..0b2d058 100644
--- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
+++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp
@@ -511,8 +511,6 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect,
IntRect& webViewRect, int titleBarHeight,
IntRect& clip, float scale, bool* buffersSwappedPtr)
{
- glFinish();
-
TilesManager::instance()->getProfiler()->nextFrame(viewport.fLeft,
viewport.fTop,
viewport.fRight,
diff --git a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
index e015f5a..86e1f63 100644
--- a/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
+++ b/Source/WebCore/platform/graphics/android/GraphicsContextAndroid.cpp
@@ -380,12 +380,13 @@ public:
m_state->antiAliasClipPaths.append(clipPath);
if (!haveLayerOutstanding) {
SkRect bounds = clipPath.getBounds();
- if (m_platformGfxCtx && m_platformGfxCtx->mCanvas)
+ if (m_platformGfxCtx && m_platformGfxCtx->mCanvas) {
m_platformGfxCtx->mCanvas->saveLayerAlpha(&bounds, 255,
static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag
| SkCanvas::kFullColorLayer_SaveFlag
| SkCanvas::kClipToLayer_SaveFlag));
- else
+ m_platformGfxCtx->mCanvas->save();
+ } else
ASSERT(0);
}
}
@@ -395,6 +396,10 @@ public:
// Anti-aliased clipping:
//
// Refer to PlatformContextSkia.cpp's applyAntiAliasedClipPaths() for more details
+
+ if (m_platformGfxCtx && m_platformGfxCtx->mCanvas)
+ m_platformGfxCtx->mCanvas->restore();
+
SkPaint paint;
paint.setXfermodeMode(SkXfermode::kClear_Mode);
paint.setAntiAlias(true);
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);
diff --git a/Source/WebKit/android/nav/CachedRoot.h b/Source/WebKit/android/nav/CachedRoot.h
index 45fc27a..65c6062 100644
--- a/Source/WebKit/android/nav/CachedRoot.h
+++ b/Source/WebKit/android/nav/CachedRoot.h
@@ -89,7 +89,7 @@ public:
return pictureAt(xPtr, yPtr, 0); }
void reset();
CachedHistory* rootHistory() const { return mHistory; }
- const WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
+ WebCore::LayerAndroid* rootLayer() const { return mRootLayer; }
bool scrollDelta(WebCore::IntRect& cursorRingBounds, Direction , int* delta);
const WebCore::IntRect& scrolledBounds() const { return mScrolledBounds; }
void setCursor(CachedFrame* , CachedNode* );
diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp
index 101e206..39a370c 100644
--- a/Source/WebKit/android/nav/WebView.cpp
+++ b/Source/WebKit/android/nav/WebView.cpp
@@ -339,13 +339,48 @@ void scrollToCurrentMatch()
}
SkRect matchBounds = m_findOnPage.currentMatchBounds();
- const LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
- const Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
+ LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer();
+ Layer* layerContainingMatch = rootLayer->findById(m_findOnPage.currentMatchLayerId());
ASSERT(layerContainingMatch);
- // FIXME: If the match is in a scrollable layer or a child of such a layer,
- // we may need to scroll these layers to make sure the match is visible.
- // See http://b/5262656.
+ // If the match is in a fixed position layer, there's nothing to do.
+ if (layerContainingMatch->shouldInheritFromRootTransform())
+ return;
+
+ // If the match is in a scrollable layer or a descendant of such a layer,
+ // there may be a range of of scroll configurations that will make the
+ // current match visible. Our approach is the simplest possible. Starting at
+ // the layer in which the match is found, we move up the layer tree,
+ // scrolling any scrollable layers as little as possible to make sure that
+ // the current match is in view. This approach has the disadvantage that we
+ // may end up scrolling a larger number of elements than is necessary, which
+ // may be visually jarring. However, minimising the number of layers
+ // scrolled would complicate the code significantly.
+
+ bool didScrollLayer = false;
+ for (Layer* layer = layerContainingMatch; layer; layer = layer->getParent()) {
+ ASSERT(layer->getParent() || layer == rootLayer);
+
+ if (layer->contentIsScrollable()) {
+ // Convert the match location to layer's local space and scroll it.
+ // Repeatedly calling Layer::localToAncestor() is inefficient as
+ // each call repeats part of the calculation. It would be more
+ // efficient to maintain the transform here and update it on each
+ // iteration, but that would mean duplicating logic from
+ // Layer::localToAncestor() and would complicate things.
+ SkMatrix transform;
+ layerContainingMatch->localToAncestor(layer, &transform);
+ SkRect transformedMatchBounds;
+ transform.mapRect(&transformedMatchBounds, matchBounds);
+ SkIRect roundedTransformedMatchBounds;
+ transformedMatchBounds.roundOut(&roundedTransformedMatchBounds);
+ // Only ScrollableLayerAndroid returns true for contentIsScrollable().
+ didScrollLayer |= static_cast<ScrollableLayerAndroid*>(layer)->scrollRectIntoView(roundedTransformedMatchBounds);
+ }
+ }
+ // Invalidate, as the call below to scroll the main page may be a no-op.
+ if (didScrollLayer)
+ viewInvalidate();
// Convert matchBounds to the global space so we can scroll the main page.
SkMatrix transform;
@@ -429,7 +464,7 @@ bool drawCursorPreamble(CachedRoot* root)
}
#if USE(ACCELERATED_COMPOSITING)
if (node->isInLayer() && root->rootLayer()) {
- LayerAndroid* layer = const_cast<LayerAndroid*>(root->rootLayer());
+ LayerAndroid* layer = root->rootLayer();
SkRect visible;
calcOurContentVisibleRect(&visible);
layer->updateFixedLayersPositions(visible);