diff options
17 files changed, 244 insertions, 139 deletions
diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 1fa69f8..0ab28d7 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -239,7 +239,6 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, tiledPage->draw(transparency, preZoomBounds); - m_glWebViewState->paintExtras(); return needsRedraw; } #endif // USE(ACCELERATED_COMPOSITING) @@ -281,12 +280,14 @@ bool BaseLayerAndroid::drawGL(double currentTime, LayerAndroid* compositedRoot, // Clean up GL textures for video layer. TilesManager::instance()->videoLayerManager()->deleteUnusedTextures(); + compositedRoot->prepare(m_glWebViewState); if (compositedRoot->drawGL(m_glWebViewState, matrix)) needsRedraw = true; else if (!animsRunning) m_glWebViewState->resetLayersDirtyArea(); } + m_glWebViewState->paintExtras(); m_previousVisible = visibleRect; diff --git a/Source/WebCore/platform/graphics/android/BaseTile.cpp b/Source/WebCore/platform/graphics/android/BaseTile.cpp index dc17a21..a4ce788 100644 --- a/Source/WebCore/platform/graphics/android/BaseTile.cpp +++ b/Source/WebCore/platform/graphics/android/BaseTile.cpp @@ -135,13 +135,12 @@ void BaseTile::reserveTexture() if (texture && m_backTexture != texture) { m_swapDrawCount = 0; // no longer ready to swap m_backTexture = texture; - - // this is to catch when the front texture is stolen from beneath us. We - // should refine the stealing method to be simpler, and not require last - // moment checks like this - if (!m_frontTexture) - m_dirty = true; } + + // a texture reservation will only happen if we're dirty, or ready to + // swap. if it's the former, ensure it's marked dirty. + if (!m_swapDrawCount) + m_dirty = true; } bool BaseTile::removeTexture(BaseTileTexture* texture) @@ -150,12 +149,15 @@ bool BaseTile::removeTexture(BaseTileTexture* texture) this, m_backTexture, m_frontTexture, m_page); // We update atomically, so paintBitmap() can see the correct value android::AutoMutex lock(m_atomicSync); - if (m_frontTexture == texture) { + if (m_frontTexture == texture) m_frontTexture = 0; - m_dirty = true; - } if (m_backTexture == texture) m_backTexture = 0; + + // mark dirty regardless of which texture was taken - the back texture may + // have been ready to swap + m_dirty = true; + return true; } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 5764a6b..40a9428 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp @@ -32,6 +32,7 @@ #include "ClassTracker.h" #include "GLUtils.h" #include "LayerAndroid.h" +#include "SkPath.h" #include "TilesManager.h" #include "TilesTracker.h" #include <wtf/CurrentTime.h> @@ -59,6 +60,14 @@ #define FRAMERATE_CAP 0.01666 // We cap at 60 fps +// Touch ring border width. This is doubled if the ring is not pressed +#define RING_BORDER_WIDTH 1 +// Color of the ring is 0x6633b5e5 (copied from framework) +#define RING_COLOR_ALPHA 0.4 +#define RING_COLOR_R 0x33 +#define RING_COLOR_G 0xb5 +#define RING_COLOR_B 0xe5 + namespace WebCore { using namespace android; @@ -170,7 +179,9 @@ void GLWebViewState::setRings(Vector<IntRect>& rings, bool isPressed) { android::Mutex::Autolock lock(m_baseLayerLock); m_displayRings = true; - m_rings = rings; + m_rings.setEmpty(); + for (size_t i = 0; i < rings.size(); i++) + m_rings.op(rings.at(i), SkRegion::kUnion_Op); m_ringsIsPressed = isPressed; } @@ -247,78 +258,80 @@ void GLWebViewState::resetRings() m_displayRings = false; } -void GLWebViewState::drawFocusRing(IntRect& srcRect) +void GLWebViewState::drawFocusRing(SkRect& srcRect) { - // TODO: use a 9-patch texture to draw the focus ring - // instead of plain colors - const float alpha = 0.3; - float borderAlpha = 0.4; - - const int r = 51; - const int g = 181; - const int b = 229; - - int padding = 4; - int border = 1; - int fuzzyBorder = border * 2; - if (!m_ringsIsPressed) { - padding = 0; - border = 2; - fuzzyBorder = 3; - borderAlpha = 0.2; - } if (m_focusRingTexture == -1) - m_focusRingTexture = GLUtils::createSampleColorTexture(r, g, b); - - SkRect rLeft, rTop, rRight, rBottom, rOverlay; - - IntRect rect(srcRect.x() - padding, srcRect.y() - padding, - srcRect.width() + (padding * 2), srcRect.height() + (padding * 2)); - rLeft.set(rect.x() - border, rect.y(), - rect.x(), rect.y() + rect.height()); - rTop.set(rect.x() - border, rect.y() - border, - rect.x() + rect.width() + border, rect.y()); - rRight.set(rect.x() + rect.width(), rect.y(), - rect.x() + rect.width() + border, - rect.y() + rect.height()); - rBottom.set(rect.x() - border, rect.y() + rect.height(), - rect.x() + rect.width() + border, - rect.y() + rect.height() + border); - rOverlay.set(rect.x() - fuzzyBorder, rect.y() - fuzzyBorder, - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height() + fuzzyBorder); - - TilesManager::instance()->shader()->drawQuad(rLeft, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rTop, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rRight, m_focusRingTexture, borderAlpha); - TilesManager::instance()->shader()->drawQuad(rBottom, m_focusRingTexture, borderAlpha); - if (m_ringsIsPressed) { - TilesManager::instance()->shader()->drawQuad(rOverlay, m_focusRingTexture, alpha); - } else { - rLeft.set(rect.x() - fuzzyBorder, rect.y(), - rect.x(), rect.y() + rect.height()); - rTop.set(rect.x() - fuzzyBorder, rect.y() - fuzzyBorder, - rect.x() + rect.width() + fuzzyBorder, rect.y()); - rRight.set(rect.x() + rect.width(), rect.y(), - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height()); - rBottom.set(rect.x() - fuzzyBorder, rect.y() + rect.height(), - rect.x() + rect.width() + fuzzyBorder, - rect.y() + rect.height() + fuzzyBorder); - TilesManager::instance()->shader()->drawQuad(rLeft, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rTop, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rRight, m_focusRingTexture, alpha); - TilesManager::instance()->shader()->drawQuad(rBottom, m_focusRingTexture, alpha); - } + m_focusRingTexture = GLUtils::createSampleColorTexture(RING_COLOR_R, + RING_COLOR_G, + RING_COLOR_B); + + TilesManager::instance()->shader()->drawQuad(srcRect, m_focusRingTexture, + RING_COLOR_ALPHA); } void GLWebViewState::paintExtras() { - if (m_displayRings) { - // TODO: handles correctly the multi-rings case - for (size_t i = 0; i < m_rings.size(); i++) { - IntRect rect = m_rings.at(i); - drawFocusRing(rect); + if (m_displayRings && !m_rings.isEmpty()) { + if (m_ringsIsPressed) { + SkRegion::Iterator rgnIter(m_rings); + while (!rgnIter.done()) { + SkIRect ir = rgnIter.rect(); + SkRect r; + r.set(ir.fLeft, ir.fTop, ir.fRight, ir.fBottom); + drawFocusRing(r); + rgnIter.next(); + } + } + SkPath path; + if (!m_rings.getBoundaryPath(&path)) + return; + SkPath::Iter iter(path, true); + SkPath::Verb verb; + SkPoint pts[4]; + SkRegion clip; + SkIRect startRect; + while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { + if (verb == SkPath::kLine_Verb) { + SkRect r; + r.set(pts, 2); + SkIRect line; + int borderWidth = RING_BORDER_WIDTH; + if (!m_ringsIsPressed) + borderWidth *= 2; + line.fLeft = r.fLeft - borderWidth; + line.fRight = r.fRight + borderWidth; + line.fTop = r.fTop - borderWidth; + line.fBottom = r.fBottom + borderWidth; + if (clip.intersects(line)) { + clip.op(line, SkRegion::kReverseDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + if (SkIRect::Intersects(startRect, line)) { + clip.op(startRect, SkRegion::kDifference_Op); + if (clip.isEmpty()) + continue; // Nothing to draw, continue + line = clip.getBounds(); + } + } else { + clip.setRect(line); + } + r.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + drawFocusRing(r); + if (!m_ringsIsPressed) { + r.fLeft += RING_BORDER_WIDTH; + r.fRight -= RING_BORDER_WIDTH; + r.fTop += RING_BORDER_WIDTH; + r.fBottom -= RING_BORDER_WIDTH; + drawFocusRing(r); + } + if (startRect.isEmpty()) { + startRect.set(line.fLeft, line.fTop, line.fRight, line.fBottom); + } + } + if (verb == SkPath::kMove_Verb) { + startRect.setEmpty(); + } } } } diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.h b/Source/WebCore/platform/graphics/android/GLWebViewState.h index a7803de..6c7d31e 100644 --- a/Source/WebCore/platform/graphics/android/GLWebViewState.h +++ b/Source/WebCore/platform/graphics/android/GLWebViewState.h @@ -179,7 +179,7 @@ public: void setRings(Vector<IntRect>& rings, bool isPressed); void resetRings(); - void drawFocusRing(IntRect& rect); + void drawFocusRing(SkRect& rect); TiledPage* sibling(TiledPage* page); TiledPage* frontPage(); @@ -269,7 +269,7 @@ private: bool m_measurePerfs; #endif bool m_displayRings; - Vector<IntRect> m_rings; + SkRegion m_rings; bool m_ringsIsPressed; int m_focusRingTexture; diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 6450fde..107c457 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -122,14 +122,17 @@ private: kInheritFromRootTransform_Flag = 0x01 }; - Layer* fParent; - SkScalar m_opacity; - SkSize m_size; - SkPoint m_position; - SkPoint m_anchorPoint; - SkMatrix fMatrix; - SkMatrix fChildrenMatrix; - uint32_t fFlags; + Layer* fParent; + SkScalar m_opacity; + SkSize m_size; + // The position of the origin of the layer, relative to the parent layer. + SkPoint m_position; + // The point in the layer used as the origin for local transformations, + // expressed as a fraction of the layer size. + SkPoint m_anchorPoint; + SkMatrix fMatrix; + SkMatrix fChildrenMatrix; + uint32_t fFlags; SkTDArray<Layer*> m_children; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp index 48dcaaa..a39614f 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.cpp @@ -267,7 +267,7 @@ void LayerAndroid::removeAnimationsForKeyframes(const String& name) } // We only use the bounding rect of the layer as mask... -// TODO: use a real mask? +// FIXME: use a real mask? void LayerAndroid::setMaskLayer(LayerAndroid* layer) { if (layer) @@ -546,7 +546,7 @@ void LayerAndroid::updatePositions() if (!m_isFixed) { // turn our fields into a matrix. // - // TODO: this should happen in the caller, and we should remove these + // FIXME: this should happen in the caller, and we should remove these // fields from our subclass SkMatrix matrix; GLUtils::toSkMatrix(matrix, m_transform); @@ -793,6 +793,26 @@ void LayerAndroid::clearDirtyRegion() m_dirtyRegion.setEmpty(); } +void LayerAndroid::prepare(GLWebViewState* glWebViewState) +{ + int count = this->countChildren(); + if (count > 0) { + Vector <LayerAndroid*> sublayers; + for (int i = 0; i < count; i++) + sublayers.append(this->getChild(i)); + + // now we sort for the transparency + std::stable_sort(sublayers.begin(), sublayers.end(), compareLayerZ); + + // iterate in reverse so top layers get textures first + for (int i = count-1; i >= 0; i--) + sublayers[i]->prepare(glWebViewState); + } + + if (m_texture) + m_texture->prepare(glWebViewState); +} + bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { TilesManager::instance()->shader()->clip(m_clippingRect); @@ -801,10 +821,8 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) bool askPaint = false; - if (m_texture) { - m_texture->prepare(glWebViewState); + if (m_texture) askPaint |= m_texture->draw(); - } // When the layer is dirty, the UI thread should be notified to redraw. askPaint |= drawChildrenGL(glWebViewState, matrix); @@ -817,7 +835,6 @@ bool LayerAndroid::drawGL(GLWebViewState* glWebViewState, SkMatrix& matrix) return askPaint; } - bool LayerAndroid::drawChildrenGL(GLWebViewState* glWebViewState, SkMatrix& matrix) { bool askPaint = false; @@ -926,6 +943,11 @@ SkRect LayerAndroid::subtractLayers(const SkRect& visibleRect) const { SkRect result; if (m_recordingPicture) { + // FIXME: This seems wrong. localToGlobal() applies the full local transform, + // se surely we should operate globalMatrix on size(), not bounds() with + // the position removed? Perhaps we never noticed the bug because most + // layers don't use a local transform? + // See http://b/5338388 SkRect globalRect = bounds(); globalRect.offset(-getPosition()); // localToGlobal adds in position SkMatrix globalMatrix; diff --git a/Source/WebCore/platform/graphics/android/LayerAndroid.h b/Source/WebCore/platform/graphics/android/LayerAndroid.h index 7192aaf..8078762 100644 --- a/Source/WebCore/platform/graphics/android/LayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/LayerAndroid.h @@ -109,6 +109,10 @@ public: void setBackfaceVisibility(bool value) { m_backfaceVisibility = value; } void setTransform(const TransformationMatrix& matrix) { m_transform = matrix; } FloatPoint translation() const; + // Returns a rect describing the bounds of the layer with the local + // transformation applied, expressed relative to the parent layer. + // FIXME: Currently we use only the translation component of the local + // transformation. SkRect bounds() const; IntRect clippedRect() const; bool outsideViewport(); @@ -121,8 +125,14 @@ public: void showLayer(int indent); float getScale() { return m_scale; } + + // draw layer and its children via Z, pre-order traversal virtual bool drawGL(GLWebViewState*, SkMatrix&); bool drawChildrenGL(GLWebViewState*, SkMatrix&); + + // prepare layer and its children via reverse-Z, post-order traversal + void prepare(GLWebViewState*); + void updateGLPositionsAndScale(const TransformationMatrix& parentMatrix, const FloatRect& clip, float opacity, float scale); void setDrawOpacity(float opacity) { m_drawOpacity = opacity; } @@ -183,9 +193,10 @@ public: SkPicture* picture() const { return m_recordingPicture; } - // remove layers bounds from visible rectangle to show what can be - // scrolled into view; returns original minus layer bounds in global space. - SkRect subtractLayers(const SkRect& visibleRect) const; + // Given a rect in global space, subtracts from it the bounds of this layer + // and of all of its children. Returns the bounding rectangle of the result, + // in global space. + SkRect subtractLayers(const SkRect&) const; void dumpLayers(FILE*, int indentLevel) const; void dumpToLog() const; diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp index ca8f03c..2bb8b5c 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.cpp @@ -18,10 +18,7 @@ bool ScrollableLayerAndroid::scrollTo(int x, int y) if (newX == scrollBounds.fLeft && newY == scrollBounds.fTop) return false; - SkScalar diffX = newX - scrollBounds.fLeft; - SkScalar diffY = newY - scrollBounds.fTop; - const SkPoint& pos = getPosition(); - setPosition(pos.fX - diffX, pos.fY - diffY); + setPosition(m_scrollLimits.fLeft - newX, m_scrollLimits.fTop - newY); return true; } diff --git a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h index c3fdecd..b59b4e1 100644 --- a/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/ScrollableLayerAndroid.h @@ -42,15 +42,16 @@ public: virtual LayerAndroid* copy() const { return new ScrollableLayerAndroid(*this); } - // Returns true if the content position has changed. - bool scrollTo(int dx, int dy); + // Scrolls to the given position in the layer. + // Returns whether or not any scrolling was required. + bool scrollTo(int x, int y); - // Fills the rect with the current scroll offset and the maximum scroll. + // Fills the rect with the current scroll offset and the maximum scroll offset. // fLeft = scrollX // fTop = scrollY - // fRight = maxX - // fBottom = maxY - void getScrollRect(SkIRect* out) const; + // fRight = maxScrollX + // fBottom = maxScrollY + void getScrollRect(SkIRect*) const; void setScrollLimits(float x, float y, float width, float height) { @@ -61,6 +62,9 @@ public: friend LayerAndroid* android::deserializeLayer(SkStream* stream); private: + // The position of the visible area of the layer, relative to the parent + // layer. This is fixed during scrolling. We acheive scrolling by modifying + // the position of the layer. SkRect m_scrollLimits; }; diff --git a/Source/WebCore/platform/graphics/android/TilesManager.cpp b/Source/WebCore/platform/graphics/android/TilesManager.cpp index ee35ce2..e1d7665 100644 --- a/Source/WebCore/platform/graphics/android/TilesManager.cpp +++ b/Source/WebCore/platform/graphics/android/TilesManager.cpp @@ -267,11 +267,13 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) } // The heuristic for selecting a texture is as follows: - // 1. If a tile isn't owned, break with that one - // 2. Don't let tiles acquire their front textures - // 3. If we find a tile in the same page with a different scale, + // 1. Skip textures currently being painted, they can't be painted while + // busy anyway + // 2. If a tile isn't owned, break with that one + // 3. Don't let tiles acquire their front textures + // 4. If we find a tile in the same page with a different scale, // it's old and not visible. Break with that one - // 4. Otherwise, use the least recently prepared tile, but ignoring tiles + // 5. Otherwise, use the least recently prepared tile, but ignoring tiles // drawn in the last frame to avoid flickering BaseTileTexture* farthestTexture = 0; @@ -280,15 +282,23 @@ BaseTileTexture* TilesManager::getAvailableTexture(BaseTile* owner) for (unsigned int i = 0; i < max; i++) { BaseTileTexture* texture = (*availableTexturePool)[i]; TextureOwner* currentOwner = texture->owner(); + + if (texture->busy()) { + // don't bother, since the acquire() will likely fail + continue; + } + if (!currentOwner) { + // unused texture! take it! farthestTexture = texture; break; } - // Don't let a tile acquire its own front texture, as the acquisition - // logic doesn't handle that - if (currentOwner == owner) + if (currentOwner == owner) { + // Don't let a tile acquire its own front texture, as the + // acquisition logic doesn't handle that continue; + } if (currentOwner->page() == owner->page() && texture->scale() != owner->scale()) { // if we render the back page with one scale, then another while diff --git a/Source/WebKit/android/RenderSkinMediaButton.cpp b/Source/WebKit/android/RenderSkinMediaButton.cpp index 294dec5..ef4b313 100644 --- a/Source/WebKit/android/RenderSkinMediaButton.cpp +++ b/Source/WebKit/android/RenderSkinMediaButton.cpp @@ -62,7 +62,7 @@ static const PatchData gFiles[] = { "ic_media_video_poster.png", 0, 0 }, // VIDEO { "btn_media_player_disabled.9.png", 0, 0 }, // BACKGROUND_SLIDER { "scrubber_track_holo_dark.9.png", 0, 0 }, // SLIDER_TRACK - { "scrubber_control_holo.png", 0, 0 } // SLIDER_THUMB + { "scrubber_control_normal_holo.png", 0, 0 } // SLIDER_THUMB }; static SkBitmap gButton[sizeof(gFiles)/sizeof(gFiles[0])]; diff --git a/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp index 500975c..f5029d5 100644 --- a/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp +++ b/Source/WebKit/android/WebCoreSupport/ChromiumInit.cpp @@ -68,7 +68,8 @@ void initChromium() if (!initCalled) { logging::SetLogMessageHandler(logMessageHandler); networkChangeNotifier.reset(net::NetworkChangeNotifier::Create()); - net::HttpNetworkLayer::EnableSpdy("npn"); + // Disable SPDY for bug 5226268 [Browser] http keep-alive packets are sent too frequently to network + // net::HttpNetworkLayer::EnableSpdy("npn"); initCalled = true; jni::SetJavaVM(JSC::Bindings::getJavaVM()); } diff --git a/Source/WebKit/android/jni/JavaSharedClient.cpp b/Source/WebKit/android/jni/JavaSharedClient.cpp index e884c99..4f40355 100644 --- a/Source/WebKit/android/jni/JavaSharedClient.cpp +++ b/Source/WebKit/android/jni/JavaSharedClient.cpp @@ -117,7 +117,7 @@ namespace android { void (*proc)(void*) = 0; void* payload = 0; const FuncPtrRec* rec; - + // we have to copy the proc/payload (if present). we do this so we // don't call the proc inside the mutex (possible deadlock!) gFuncPtrQMutex.acquire(); @@ -128,7 +128,7 @@ namespace android { gFuncPtrQ.pop_front(); } gFuncPtrQMutex.release(); - + if (!rec) break; proc(payload); diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 8b2029f..24266f6 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -2189,6 +2189,11 @@ void WebViewCore::setSelection(int start, int end) String WebViewCore::modifySelection(const int direction, const int axis) { DOMSelection* selection = m_mainFrame->domWindow()->getSelection(); + ASSERT(selection); + // We've seen crashes where selection is null, but we don't know why + // See http://b/5244036 + if (!selection) + return String(); if (selection->rangeCount() > 1) selection->removeAllRanges(); switch (axis) { diff --git a/Source/WebKit/android/nav/FindCanvas.cpp b/Source/WebKit/android/nav/FindCanvas.cpp index 2d310b3..ca3cfba 100644 --- a/Source/WebKit/android/nav/FindCanvas.cpp +++ b/Source/WebKit/android/nav/FindCanvas.cpp @@ -532,9 +532,6 @@ IntRect FindOnPage::currentMatchBounds() const { if (!m_matches || !m_matches->size()) return noBounds; MatchInfo& info = (*m_matches)[m_findIndex]; - // FIXME: this should test if the match in the layer is visible - if (info.isInLayer()) - return noBounds; return info.getLocation().getBounds(); } @@ -545,6 +542,10 @@ bool FindOnPage::currentMatchIsInLayer() const { return info.isInLayer(); } +int FindOnPage::currentMatchLayerId() const { + return (*m_matches)[m_findIndex].layerId(); +} + // This function is only used by findNext and setMatches. In it, we store // upper left corner of the match specified by m_findIndex in // m_currentMatchLocation. @@ -597,7 +598,7 @@ void FindOnPage::draw(SkCanvas* canvas, LayerAndroid* layer, IntRect* inval) { unsigned numberOfMatches = m_matches->size(); if (numberOfMatches > 1 && numberOfMatches < MAX_NUMBER_OF_MATCHES_TO_DRAW) { - for(unsigned i = 0; i < numberOfMatches; i++) { + for (unsigned i = 0; i < numberOfMatches; i++) { // The current match has already been drawn if (i == m_findIndex) continue; diff --git a/Source/WebKit/android/nav/FindCanvas.h b/Source/WebKit/android/nav/FindCanvas.h index 76ee1e2..994ff17 100644 --- a/Source/WebKit/android/nav/FindCanvas.h +++ b/Source/WebKit/android/nav/FindCanvas.h @@ -54,9 +54,9 @@ public: SkPicture* getPicture() const { return m_picture; } // This will make a copy of the region, and increase the ref count on the // SkPicture. If this MatchInfo already had one, unref it. + void set(const SkRegion& region, SkPicture* pic, int layerId); bool isInLayer() const { return m_layerId >= 0; } int layerId() const { return m_layerId; } - void set(const SkRegion& region, SkPicture* pic, int layerId); private: MatchInfo& operator=(MatchInfo& src); SkRegion m_location; @@ -141,7 +141,7 @@ public: const SkPaint& paint) { } - void drawLayers(LayerAndroid* ); + void drawLayers(LayerAndroid*); int found() const { return mNumFound; } void setLayerId(int layerId) { mLayerId = layerId; } @@ -227,6 +227,9 @@ public: IntRect currentMatchBounds() const; int currentMatchIndex() const { return m_findIndex; } bool currentMatchIsInLayer() const; + // This requires the current match to be in a layer. See + // currentMatchIsInLayer(). + int currentMatchLayerId() const; virtual void draw(SkCanvas* , LayerAndroid* , IntRect* ); void findNext(bool forward); bool isCurrentLocationValid() { return m_hasCurrentLocation; } diff --git a/Source/WebKit/android/nav/WebView.cpp b/Source/WebKit/android/nav/WebView.cpp index a528e9a..101e206 100644 --- a/Source/WebKit/android/nav/WebView.cpp +++ b/Source/WebKit/android/nav/WebView.cpp @@ -105,8 +105,7 @@ class WebView public: enum FrameCachePermission { DontAllowNewer, - AllowNewer, - AllowNewest + AllowNewer }; enum DrawExtras { // keep this in sync with WebView.java @@ -332,8 +331,32 @@ void nativeRecordButtons(bool hasFocus, bool pressed, bool invalidate) } } -// The caller has already determined that the desired document rect corresponds -// to the main picture, and not a layer +void scrollToCurrentMatch() +{ + if (!m_findOnPage.currentMatchIsInLayer()) { + scrollRectOnScreen(m_findOnPage.currentMatchBounds()); + return; + } + + SkRect matchBounds = m_findOnPage.currentMatchBounds(); + const LayerAndroid* rootLayer = getFrameCache(DontAllowNewer)->rootLayer(); + const 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. + + // Convert matchBounds to the global space so we can scroll the main page. + SkMatrix transform; + layerContainingMatch->localToGlobal(&transform); + SkRect transformedMatchBounds; + transform.mapRect(&transformedMatchBounds, matchBounds); + SkIRect roundedTransformedMatchBounds; + transformedMatchBounds.roundOut(&roundedTransformedMatchBounds); + scrollRectOnScreen(roundedTransformedMatchBounds); +} + void scrollRectOnScreen(const IntRect& rect) { if (rect.isEmpty()) @@ -489,8 +512,23 @@ bool drawGL(WebCore::IntRect& viewRect, WebCore::IntRect* invalRect, WebCore::In m_glWebViewState->resetRings(); if (extra) { if (extra == &m_ring) { + WTF::Vector<IntRect> rings; if (root == m_ring.m_frame) - m_glWebViewState->setRings(m_ring.rings(), m_ring.m_isPressed); + rings = m_ring.rings(); + else { + // TODO: Fix the navcache to work with layers correctly + // In the meantime, this works around the bug. However, the rings + // it produces are not as nice for some reason, thus we use + // m_ring.rings() above for the base layer instead of the below + for (size_t i = 0; i < m_ring.m_node->rings().size(); i++) { + IntRect rect = m_ring.m_node->rings().at(i); + rect = m_ring.m_frame->adjustBounds(m_ring.m_node, rect); + rect.inflate(4); + rings.append(rect); + } + } + m_glWebViewState->setRings(rings, m_ring.m_isPressed); + extra = 0; } else { LayerAndroid mainPicture(m_navPictureUI); PictureSet* content = m_baseLayer->content(); @@ -1290,8 +1328,7 @@ void sendMotionUp(WebCore::Frame* framePtr, WebCore::Node* nodePtr, int x, int y void findNext(bool forward) { m_findOnPage.findNext(forward); - if (!m_findOnPage.currentMatchIsInLayer()) - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); + scrollToCurrentMatch(); viewInvalidate(); } @@ -1303,21 +1340,16 @@ void setMatches(WTF::Vector<MatchInfo>* matches, jboolean sameAsLastSearch) // location to determine whether to scroll. If the same word is found // in the same place, then do not scroll. IntRect oldLocation; - bool checkAgainstOldLocation; + bool checkAgainstOldLocation = false; if (sameAsLastSearch && m_findOnPage.isCurrentLocationValid()) { oldLocation = m_findOnPage.currentMatchBounds(); checkAgainstOldLocation = true; - } else - checkAgainstOldLocation = false; + } m_findOnPage.setMatches(matches); - if (!checkAgainstOldLocation - || oldLocation != m_findOnPage.currentMatchBounds()) { - // FIXME: Need to scroll if the match is in a layer. - if (!m_findOnPage.currentMatchIsInLayer()) - scrollRectOnScreen(m_findOnPage.currentMatchBounds()); - } + if (!checkAgainstOldLocation || oldLocation != m_findOnPage.currentMatchBounds()) + scrollToCurrentMatch(); viewInvalidate(); } |