diff options
26 files changed, 389 insertions, 209 deletions
diff --git a/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp b/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp index 90dc097..0de99f8 100644 --- a/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp +++ b/Source/WebCore/bindings/v8/V8AbstractEventListener.cpp @@ -72,6 +72,14 @@ V8AbstractEventListener::~V8AbstractEventListener() void V8AbstractEventListener::handleEvent(ScriptExecutionContext* context, Event* event) { +#ifdef ANDROID + // Monkey data shows that we can crash here, due to script executing while the + // page's frame has been detached (in the middle of a navigation). + // See b/5201341 + if (!context) + return; +#endif + // Don't reenter V8 if execution was terminated in this instance of V8. if (context->isJSExecutionForbidden()) return; diff --git a/Source/WebCore/platform/android/RenderThemeAndroid.cpp b/Source/WebCore/platform/android/RenderThemeAndroid.cpp index c6e3bc5..7ef814e 100644 --- a/Source/WebCore/platform/android/RenderThemeAndroid.cpp +++ b/Source/WebCore/platform/android/RenderThemeAndroid.cpp @@ -212,9 +212,12 @@ void RenderThemeAndroid::adjustButtonStyle(CSSStyleSelector*, RenderStyle* style { // Code is taken from RenderThemeSafari.cpp // It makes sure we have enough space for the button text. - const int padding = 8; - style->setPaddingLeft(Length(padding, Fixed)); - style->setPaddingRight(Length(padding, Fixed)); + const int paddingHoriz = 12; + const int paddingVert = 8; + style->setPaddingLeft(Length(paddingHoriz, Fixed)); + style->setPaddingRight(Length(paddingHoriz, Fixed)); + style->setPaddingTop(Length(paddingVert, Fixed)); + style->setPaddingBottom(Length(paddingVert, Fixed)); // Set a min-height so that we can't get smaller than the mini button. style->setMinHeight(Length(15, Fixed)); diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp index 1fa69f8..547ac39 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.cpp @@ -54,6 +54,12 @@ #endif // DEBUG +// TODO: dynamically determine based on DPI +#define PREFETCH_SCALE_MODIFIER 0.3 +#define PREFETCH_OPACITY 1 +#define PREFETCH_X_DIST 1 +#define PREFETCH_Y_DIST 2 + namespace WebCore { using namespace android; @@ -116,6 +122,49 @@ void BaseLayerAndroid::drawCanvas(SkCanvas* canvas) } #if USE(ACCELERATED_COMPOSITING) + +void BaseLayerAndroid::prefetchBasePicture(SkRect& viewport, float currentScale, + TiledPage* prefetchTiledPage) +{ + SkIRect bounds; + float prefetchScale = currentScale * PREFETCH_SCALE_MODIFIER; + + float invTileWidth = (prefetchScale) + / TilesManager::instance()->tileWidth(); + float invTileHeight = (prefetchScale) + / TilesManager::instance()->tileHeight(); + bool goingDown = m_glWebViewState->goingDown(); + bool goingLeft = m_glWebViewState->goingLeft(); + + + XLOG("fetch rect %f %f %f %f, scale %f", + viewport.fLeft, + viewport.fTop, + viewport.fRight, + viewport.fBottom, + scale); + + bounds.fLeft = static_cast<int>(floorf(viewport.fLeft * invTileWidth)) - PREFETCH_X_DIST; + bounds.fTop = static_cast<int>(floorf(viewport.fTop * invTileHeight)) - PREFETCH_Y_DIST; + bounds.fRight = static_cast<int>(ceilf(viewport.fRight * invTileWidth)) + PREFETCH_X_DIST; + bounds.fBottom = static_cast<int>(ceilf(viewport.fBottom * invTileHeight)) + PREFETCH_Y_DIST; + + XLOG("prefetch rect %d %d %d %d, scale %f, preparing page %p", + bounds.fLeft, bounds.fTop, + bounds.fRight, bounds.fBottom, + scale * PREFETCH_SCALE, + prefetchTiledPage); + + prefetchTiledPage->setScale(prefetchScale); + prefetchTiledPage->updateTileDirtiness(bounds); + prefetchTiledPage->prepare(goingDown, goingLeft, bounds, + TiledPage::ExpandedBounds); + prefetchTiledPage->swapBuffersIfReady(bounds, + prefetchScale, + TiledPage::SwapWhateverIsReady); + prefetchTiledPage->draw(PREFETCH_OPACITY, bounds); +} + bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, double currentTime, bool* buffersSwappedPtr) { @@ -183,6 +232,13 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, bool scrolling = m_scrollState != NotScrolling; bool zooming = ZoomManager::kNoScaleRequest != zoomManager->scaleRequestState(); + // prefetch in the nextTiledPage if unused by zooming (even if not scrolling + // since we want the tiles to be ready before they're needed) + bool usePrefetchPage = !zooming; + nextTiledPage->setIsPrefetchPage(usePrefetchPage); + if (usePrefetchPage) + prefetchBasePicture(viewport, scale, nextTiledPage); + // When we aren't zooming, we should TRY and swap tile buffers if they're // ready. When scrolling, we swap whatever's ready. Otherwise, buffer until // the entire page is ready and then swap. @@ -239,7 +295,6 @@ bool BaseLayerAndroid::drawBasePictureInGL(SkRect& viewport, float scale, tiledPage->draw(transparency, preZoomBounds); - m_glWebViewState->paintExtras(); return needsRedraw; } #endif // USE(ACCELERATED_COMPOSITING) @@ -281,6 +336,7 @@ 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) diff --git a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h index a42a372..26fd158 100644 --- a/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h +++ b/Source/WebCore/platform/graphics/android/BaseLayerAndroid.h @@ -66,6 +66,8 @@ public: void swapExtra(BaseLayerAndroid* base) { m_extra.swap(base->m_extra); } private: #if USE(ACCELERATED_COMPOSITING) + void prefetchBasePicture(SkRect& viewport, float currentScale, + TiledPage* prefetchTiledPage); bool drawBasePictureInGL(SkRect& viewport, float scale, double currentTime, bool* buffersSwappedPtr); diff --git a/Source/WebCore/platform/graphics/android/GLWebViewState.cpp b/Source/WebCore/platform/graphics/android/GLWebViewState.cpp index 5764a6b..55419f4 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,13 @@ 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++) { + if (i == 0) + m_rings.setRect(rings.at(i)); + else + m_rings.op(rings.at(i), SkRegion::kUnion_Op); + } m_ringsIsPressed = isPressed; } @@ -247,78 +262,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(); + } } } } @@ -558,6 +575,10 @@ bool GLWebViewState::drawGL(IntRect& rect, SkRect& viewport, IntRect* invalRect, double currentTime = setupDrawing(rect, viewport, webViewRect, titleBarHeight, clip, scale); bool ret = baseLayer->drawGL(currentTime, compositedRoot, rect, viewport, scale, buffersSwappedPtr); + // Reset the clip to make sure we can draw the rings. If this isn't done, the + // current clip will be the clip of whatever layer was last drawn + TilesManager::instance()->shader()->clip(clip); + paintExtras(); glBindBuffer(GL_ARRAY_BUFFER, 0); 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.cpp b/Source/WebCore/platform/graphics/android/Layer.cpp index 22c40f1..361cb4e 100644 --- a/Source/WebCore/platform/graphics/android/Layer.cpp +++ b/Source/WebCore/platform/graphics/android/Layer.cpp @@ -18,9 +18,9 @@ Layer::Layer() { m_position.set(0, 0); m_anchorPoint.set(SK_ScalarHalf, SK_ScalarHalf); - fMatrix.reset(); - fChildrenMatrix.reset(); - fFlags = 0; + m_matrix.reset(); + m_childrenMatrix.reset(); + m_shouldInheritFromRootTransform = false; m_hasOverflowChildren = false; @@ -37,9 +37,9 @@ Layer::Layer(const Layer& src) : INHERITED() { m_position = src.m_position; m_anchorPoint = src.m_anchorPoint; - fMatrix = src.fMatrix; - fChildrenMatrix = src.fChildrenMatrix; - fFlags = src.fFlags; + m_matrix = src.m_matrix; + m_childrenMatrix = src.m_childrenMatrix; + m_shouldInheritFromRootTransform = src.m_shouldInheritFromRootTransform; m_hasOverflowChildren = src.m_hasOverflowChildren; @@ -50,7 +50,7 @@ Layer::Layer(const Layer& src) : INHERITED() { } Layer::~Layer() { - this->removeChildren(); + removeChildren(); #ifdef DEBUG_TRACK_NEW_DELETE gLayerAllocCount -= 1; @@ -60,28 +60,6 @@ Layer::~Layer() { /////////////////////////////////////////////////////////////////////////////// -bool Layer::isInheritFromRootTransform() const { - return (fFlags & kInheritFromRootTransform_Flag) != 0; -} - -void Layer::setInheritFromRootTransform(bool doInherit) { - if (doInherit) { - fFlags |= kInheritFromRootTransform_Flag; - } else { - fFlags &= ~kInheritFromRootTransform_Flag; - } -} - -void Layer::setMatrix(const SkMatrix& matrix) { - fMatrix = matrix; -} - -void Layer::setChildrenMatrix(const SkMatrix& matrix) { - fChildrenMatrix = matrix; -} - -/////////////////////////////////////////////////////////////////////////////// - int Layer::countChildren() const { return m_children.count(); } @@ -111,7 +89,7 @@ void Layer::detachFromParent() { SkASSERT(index >= 0); fParent->m_children.remove(index); fParent = NULL; - this->unref(); // this call might delete us + unref(); // this call might delete us } } @@ -142,15 +120,15 @@ void Layer::getLocalTransform(SkMatrix* matrix) const { SkScalar tx = SkScalarMul(m_anchorPoint.fX, m_size.width()); SkScalar ty = SkScalarMul(m_anchorPoint.fY, m_size.height()); matrix->preTranslate(tx, ty); - matrix->preConcat(this->getMatrix()); + matrix->preConcat(getMatrix()); matrix->preTranslate(-tx, -ty); } void Layer::localToGlobal(SkMatrix* matrix) const { - this->getLocalTransform(matrix); + getLocalTransform(matrix); - if (this->isInheritFromRootTransform()) { - matrix->postConcat(this->getRootLayer()->getMatrix()); + if (shouldInheritFromRootTransform()) { + matrix->postConcat(getRootLayer()->getMatrix()); return; } @@ -176,14 +154,14 @@ void Layer::onDraw(SkCanvas*, SkScalar opacity) { void Layer::draw(SkCanvas* canvas, SkScalar opacity) { #if 0 SkString str1, str2; - // this->getMatrix().toDumpString(&str1); - // this->getChildrenMatrix().toDumpString(&str2); + // getMatrix().toDumpString(&str1); + // getChildrenMatrix().toDumpString(&str2); SkDebugf("--- drawlayer %p opacity %g size [%g %g] pos [%g %g] matrix %s children %s\n", - this, opacity * this->getOpacity(), m_size.width(), m_size.height(), + this, opacity * getOpacity(), m_size.width(), m_size.height(), m_position.fX, m_position.fY, str1.c_str(), str2.c_str()); #endif - opacity = SkScalarMul(opacity, this->getOpacity()); + opacity = SkScalarMul(opacity, getOpacity()); if (opacity <= 0) { // SkDebugf("---- abort drawing %p opacity %g\n", this, opacity); return; @@ -194,19 +172,19 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) { // apply our local transform { SkMatrix tmp; - this->getLocalTransform(&tmp); - if (this->isInheritFromRootTransform()) { + getLocalTransform(&tmp); + if (shouldInheritFromRootTransform()) { // should we also apply the root's childrenMatrix? canvas->setMatrix(getRootLayer()->getMatrix()); } canvas->concat(tmp); } - this->onDraw(canvas, opacity); + onDraw(canvas, opacity); #ifdef DEBUG_DRAW_LAYER_BOUNDS { - SkRect r = SkRect::MakeSize(this->getSize()); + SkRect r = SkRect::MakeSize(getSize()); SkPaint p; p.setAntiAlias(true); p.setStyle(SkPaint::kStroke_Style); @@ -218,11 +196,11 @@ void Layer::draw(SkCanvas* canvas, SkScalar opacity) { } #endif - int count = this->countChildren(); + int count = countChildren(); if (count > 0) { - canvas->concat(this->getChildrenMatrix()); + canvas->concat(getChildrenMatrix()); for (int i = 0; i < count; i++) { - this->getChild(i)->draw(canvas, opacity); + getChild(i)->draw(canvas, opacity); } } } diff --git a/Source/WebCore/platform/graphics/android/Layer.h b/Source/WebCore/platform/graphics/android/Layer.h index 6450fde..7b27349 100644 --- a/Source/WebCore/platform/graphics/android/Layer.h +++ b/Source/WebCore/platform/graphics/android/Layer.h @@ -34,24 +34,27 @@ public: Layer(const Layer&); virtual ~Layer(); - bool isInheritFromRootTransform() const; + // Whether the layer should apply its tranform directly onto the root + // layer, rather than using the transforms of all ancestor layers. This is + // used for fixed position layers. + bool shouldInheritFromRootTransform() const { return m_shouldInheritFromRootTransform; } SkScalar getOpacity() const { return m_opacity; } const SkSize& getSize() const { return m_size; } const SkPoint& getPosition() const { return m_position; } const SkPoint& getAnchorPoint() const { return m_anchorPoint; } - const SkMatrix& getMatrix() const { return fMatrix; } - const SkMatrix& getChildrenMatrix() const { return fChildrenMatrix; } + const SkMatrix& getMatrix() const { return m_matrix; } + const SkMatrix& getChildrenMatrix() const { return m_childrenMatrix; } SkScalar getWidth() const { return m_size.width(); } SkScalar getHeight() const { return m_size.height(); } - void setInheritFromRootTransform(bool); + void setShouldInheritFromRootTransform(bool inherit) { m_shouldInheritFromRootTransform = inherit; } void setOpacity(SkScalar opacity) { m_opacity = opacity; } void setSize(SkScalar w, SkScalar h) { m_size.set(w, h); } void setPosition(SkScalar x, SkScalar y) { m_position.set(x, y); } void setAnchorPoint(SkScalar x, SkScalar y) { m_anchorPoint.set(x, y); } - void setMatrix(const SkMatrix&); - void setChildrenMatrix(const SkMatrix&); + void setMatrix(const SkMatrix& matrix) { m_matrix = matrix; } + void setChildrenMatrix(const SkMatrix& matrix) { m_childrenMatrix = matrix; } // children @@ -118,18 +121,17 @@ protected: bool m_hasOverflowChildren; private: - enum Flags { - 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 m_matrix; + SkMatrix m_childrenMatrix; + bool m_shouldInheritFromRootTransform; 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..31bb185 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; } @@ -160,7 +170,7 @@ public: m_fixedRect = viewRect; m_isFixed = true; m_renderLayerPos = renderLayerPos; - setInheritFromRootTransform(true); + setShouldInheritFromRootTransform(true); } void setBackgroundColor(SkColor color); @@ -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/PaintTileOperation.cpp b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp index aa3f320..19b49f1 100644 --- a/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp +++ b/Source/WebCore/platform/graphics/android/PaintTileOperation.cpp @@ -81,6 +81,10 @@ int PaintTileOperation::priority() unsigned long long drawDelta = currentDraw - m_tile->drawCount(); int priority = 100000 * (int)std::min(drawDelta, (unsigned long long)1000); + // prioritize the prefetch page, if it exists + if (!m_tile->page() || !m_tile->page()->isPrefetchPage()) + priority += 200000; + // prioritize unpainted tiles, within the same drawCount if (m_tile->frontTexture()) priority += 50000; 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/ShaderProgram.cpp b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp index bf5f760..857623a 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.cpp +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.cpp @@ -294,6 +294,7 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, GLenum textureTarget, GLint position, GLint alpha, + GLint texFilter, GLint contrast) { glUseProgram(program); @@ -313,8 +314,8 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, glActiveTexture(GL_TEXTURE0); glUniform1i(texSampler, 0); glBindTexture(textureTarget, textureId); - glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, texFilter); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, texFilter); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -330,26 +331,26 @@ void ShaderProgram::drawQuadInternal(SkRect& geometry, } void ShaderProgram::drawQuad(SkRect& geometry, int textureId, float opacity, - GLenum textureTarget) + GLenum textureTarget, GLint texFilter) { if (textureTarget == GL_TEXTURE_2D) { drawQuadInternal(geometry, textureId, opacity, m_program, m_hProjectionMatrix, m_hTexSampler, GL_TEXTURE_2D, - m_hPosition, alpha()); + m_hPosition, alpha(), texFilter); } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES && !TilesManager::instance()->invertedScreen()) { drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgram, m_hSTOESProjectionMatrix, m_hSTOESTexSampler, GL_TEXTURE_EXTERNAL_OES, - m_hSTOESPosition, m_hSTOESAlpha); + m_hSTOESPosition, m_hSTOESAlpha, texFilter); } else if (textureTarget == GL_TEXTURE_EXTERNAL_OES && TilesManager::instance()->invertedScreen()) { drawQuadInternal(geometry, textureId, opacity, m_surfTexOESProgramInverted, m_hSTOESProjectionMatrixInverted, m_hSTOESTexSamplerInverted, GL_TEXTURE_EXTERNAL_OES, m_hSTOESPositionInverted, m_hSTOESAlphaInverted, - m_hSTOESContrastInverted); + texFilter, m_hSTOESContrastInverted); } GLUtils::checkGlError("drawQuad"); } diff --git a/Source/WebCore/platform/graphics/android/ShaderProgram.h b/Source/WebCore/platform/graphics/android/ShaderProgram.h index d8447bf..5f5ce9f 100644 --- a/Source/WebCore/platform/graphics/android/ShaderProgram.h +++ b/Source/WebCore/platform/graphics/android/ShaderProgram.h @@ -54,7 +54,8 @@ public: // support Surface texture in GL_TEXTURE_EXTERNAL_OES target on all // platforms. void drawQuad(SkRect& geometry, int textureId, float opacity, - GLenum textureTarget = GL_TEXTURE_2D); + GLenum textureTarget = GL_TEXTURE_2D, + GLint texFilter = GL_LINEAR); void drawLayerQuad(const TransformationMatrix& drawMatrix, SkRect& geometry, int textureId, float opacity, bool forceBlending = false, @@ -99,7 +100,8 @@ private: void drawQuadInternal(SkRect& geometry, GLint textureId, float opacity, GLint program, GLint projectionMatrixHandle, GLint texSampler, GLenum textureTarget, - GLint position, GLint alpha, GLint contrast = -1); + GLint position, GLint alpha, + GLint texFilter, GLint contrast = -1); void drawLayerQuadInternal(const GLfloat* projectionMatrix, int textureId, float opacity, GLenum textureTarget, GLint program, diff --git a/Source/WebCore/platform/graphics/android/TiledPage.cpp b/Source/WebCore/platform/graphics/android/TiledPage.cpp index ede7d1b..2b8ebcc 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.cpp +++ b/Source/WebCore/platform/graphics/android/TiledPage.cpp @@ -31,6 +31,8 @@ #include "GLUtils.h" #include "IntRect.h" #include "PaintTileOperation.h" +#include "SkPaint.h" +#include "SkPaintFlagsDrawFilter.h" #include "TilesManager.h" #include <cutils/log.h> @@ -65,6 +67,7 @@ TiledPage::TiledPage(int id, GLWebViewState* state) , m_glWebViewState(state) , m_latestPictureInval(0) , m_prepare(false) + , m_isPrefetchPage(false) { m_baseTiles = new BaseTile[TilesManager::getMaxTextureAllocation() + 1]; #ifdef DEBUG_COUNT @@ -366,9 +369,15 @@ void TiledPage::draw(float transparency, const SkIRect& tileBounds) bool TiledPage::paint(BaseTile* tile, SkCanvas* canvas, unsigned int* pictureUsed) { + // TODO: consider other flags so the pre-rendered tiles aren't so ugly + static SkPaintFlagsDrawFilter prefetchFilter(SkPaint::kAllFlags, 0); + if (!m_glWebViewState) return false; + if (isPrefetchPage()) + canvas->setDrawFilter(&prefetchFilter); + *pictureUsed = m_glWebViewState->paintBaseLayerContent(canvas); return true; } diff --git a/Source/WebCore/platform/graphics/android/TiledPage.h b/Source/WebCore/platform/graphics/android/TiledPage.h index 946421c..c903abc 100644 --- a/Source/WebCore/platform/graphics/android/TiledPage.h +++ b/Source/WebCore/platform/graphics/android/TiledPage.h @@ -98,6 +98,8 @@ public: void updateBaseTileSize(); bool scrollingDown() { return m_scrollingDown; } SkIRect* expandedTileBounds() { return &m_expandedTileBounds; } + bool isPrefetchPage() { return m_isPrefetchPage; } + void setIsPrefetchPage(bool isPrefetch) { m_isPrefetchPage = isPrefetch; } private: void prepareRow(bool goingLeft, int tilesInRow, int firstTileX, int y, const SkIRect& tileBounds); @@ -127,6 +129,7 @@ private: bool m_prepare; bool m_scrollingDown; SkIRect m_expandedTileBounds; + bool m_isPrefetchPage; }; } // namespace WebCore diff --git a/Source/WebCore/platform/graphics/android/TransferQueue.cpp b/Source/WebCore/platform/graphics/android/TransferQueue.cpp index 918d484..a8451a6 100644 --- a/Source/WebCore/platform/graphics/android/TransferQueue.cpp +++ b/Source/WebCore/platform/graphics/android/TransferQueue.cpp @@ -135,9 +135,6 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, GLuint srcTexId, GLenum srcTexTarget, int index) { - // guarantee that we have a texture to blit into - destTex->requireTexture(); - // Then set up the FBO and copy the SurfTex content in. glBindFramebuffer(GL_FRAMEBUFFER, fboID); glFramebufferTexture2D(GL_FRAMEBUFFER, @@ -157,7 +154,7 @@ void TransferQueue::blitTileFromQueue(GLuint fboID, BaseTileTexture* destTex, // Use empty rect to set up the special matrix to draw. SkRect rect = SkRect::MakeEmpty(); TilesManager::instance()->shader()->drawQuad(rect, srcTexId, 1.0, - srcTexTarget); + srcTexTarget, GL_NEAREST); // To workaround a sync issue on some platforms, we should insert the sync // here while in the current FBO. @@ -260,7 +257,9 @@ void TransferQueue::discardQueue() // Call on UI thread to copy from the shared Surface Texture to the BaseTile's texture. void TransferQueue::updateDirtyBaseTiles() { +#if !DEBUG_TRANSFER_USING_CPU_UPLOAD saveGLState(); +#endif android::Mutex::Autolock lock(m_transferQueueItemLocks); cleanupTransportQueue(); @@ -279,9 +278,9 @@ void TransferQueue::updateDirtyBaseTiles() BaseTileTexture* destTexture = 0; if (!obsoleteBaseTile) destTexture = m_transferQueue[index].savedBaseTilePtr->backTexture(); - +#if !DEBUG_TRANSFER_USING_CPU_UPLOAD m_sharedSurfaceTexture->updateTexImage(); - +#endif m_transferQueue[index].savedBaseTilePtr = 0; m_transferQueue[index].status = emptyItem; if (obsoleteBaseTile) { @@ -290,6 +289,9 @@ void TransferQueue::updateDirtyBaseTiles() continue; } + // guarantee that we have a texture to blit into + destTexture->requireTexture(); + #if DEBUG_TRANSFER_USING_CPU_UPLOAD // Here we just need to upload the bitmap content to the GL Texture GLUtils::updateTextureWithBitmap(destTexture->m_ownTextureId, 0, 0, @@ -317,7 +319,9 @@ void TransferQueue::updateDirtyBaseTiles() index = (index + 1) % ST_BUFFER_NUMBER; } +#if !DEBUG_TRANSFER_USING_CPU_UPLOAD restoreGLState(); +#endif m_emptyItemCount = ST_BUFFER_NUMBER; m_transferQueueItemCond.signal(); @@ -334,7 +338,7 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, renderInfo->x, renderInfo->y); return; } - +#if !DEBUG_TRANSFER_USING_CPU_UPLOAD // a) Dequeue the Surface Texture and write into the buffer if (!m_ANW.get()) { XLOG("ERROR: ANW is null"); @@ -370,6 +374,7 @@ void TransferQueue::updateQueueWithBitmap(const TileRenderInfo* renderInfo, } ANativeWindow_unlockAndPost(m_ANW.get()); +#endif m_transferQueueItemLocks.lock(); // b) After update the Surface Texture, now udpate the transfer queue info. addItemInTransferQueue(renderInfo); @@ -417,8 +422,9 @@ void TransferQueue::cleanupTransportQueue() for (int i = 0 ; i < ST_BUFFER_NUMBER; i++) { if (m_transferQueue[index].status == pendingDiscard) { +#if !DEBUG_TRANSFER_USING_CPU_UPLOAD m_sharedSurfaceTexture->updateTexImage(); - +#endif m_transferQueue[index].savedBaseTilePtr = 0; m_transferQueue[index].status = emptyItem; } @@ -455,7 +461,7 @@ void TransferQueue::restoreGLState() if (m_GLStateBeforeBlit.scissor[0]) glEnable(GL_SCISSOR_TEST); - if (m_GLStateBeforeBlit.depth) + if (m_GLStateBeforeBlit.depth[0]) glEnable(GL_DEPTH_TEST); glClearColor(m_GLStateBeforeBlit.clearColor[0], diff --git a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp index 9de6c09..3134a44 100644 --- a/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp +++ b/Source/WebKit/android/WebCoreSupport/FrameLoaderClientAndroid.cpp @@ -373,10 +373,16 @@ void FrameLoaderClientAndroid::dispatchDidFailProvisionalLoad(const ResourceErro url.append(buf, res); } } + // Vector sets up its data buffer lazilly, so if failingUrl is the empty + // string, the data buffer will be null. This will result in sanitizedUrl + // being null, and the string substitution below will be a no-op. + // FIXME: Ideally we'd always have a non-empty URL, or at least improve the + // wording of the error page in this case. See http://b/5293782. + String sanitizedUrl = url.data() ? String(url.data(), url.size()) : ""; // Replace all occurances of %s with the failing url. String s = UTF8Encoding().decode((const char*)a->getBuffer(false), a->getLength()); - s = s.replace("%s", String(url.data(), url.size())); + s = s.replace("%s", sanitizedUrl); // Replace all occurances of %e with the error text s = s.replace("%e", error.localizedDescription()); @@ -913,6 +919,10 @@ void FrameLoaderClientAndroid::transitionToCommittedFromCachedFrame(WebCore::Cac #ifdef ANDROID_META_SUPPORT platformData->restoreMetadata(m_frame->settings()); #endif + WebViewCore* webViewCore = WebViewCore::getWebViewCore(m_frame->view()); + + webViewCore->clearContent(); + m_webFrame->transitionToCommitted(m_frame); } @@ -946,6 +956,7 @@ void FrameLoaderClientAndroid::transitionToCommittedForNewPage() { // Create a new WebFrameView for the new FrameView WebFrameView* newFrameView = new WebFrameView(m_frame->view(), webViewCore); + webViewCore->clearContent(); newFrameView->setLocation(bounds.x(), bounds.y()); newFrameView->setSize(bounds.width(), bounds.height()); newFrameView->setVisibleSize(visBounds.width(), visBounds.height()); 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/ViewStateSerializer.cpp b/Source/WebKit/android/jni/ViewStateSerializer.cpp index 794c118..b3556c3 100644 --- a/Source/WebKit/android/jni/ViewStateSerializer.cpp +++ b/Source/WebKit/android/jni/ViewStateSerializer.cpp @@ -257,7 +257,7 @@ void serializeLayer(LayerAndroid* layer, SkWStream* stream) stream->write8(type); // Start with Layer fields - stream->writeBool(layer->isInheritFromRootTransform()); + stream->writeBool(layer->shouldInheritFromRootTransform()); stream->writeScalar(layer->getOpacity()); stream->writeScalar(layer->getSize().width()); stream->writeScalar(layer->getSize().height()); @@ -338,7 +338,7 @@ LayerAndroid* deserializeLayer(SkStream* stream) } // Layer fields - layer->setInheritFromRootTransform(stream->readBool()); + layer->setShouldInheritFromRootTransform(stream->readBool()); layer->setOpacity(stream->readScalar()); layer->setSize(stream->readScalar(), stream->readScalar()); layer->setPosition(stream->readScalar(), stream->readScalar()); diff --git a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp index f243b09..46499b1 100644 --- a/Source/WebKit/android/jni/WebCoreFrameBridge.cpp +++ b/Source/WebKit/android/jni/WebCoreFrameBridge.cpp @@ -1479,11 +1479,6 @@ static void LoadUrl(JNIEnv *env, jobject obj, jstring url, jobject headers) } LOGV("LoadUrl %s", kurl.string().latin1().data()); pFrame->loader()->load(request, false); - - // Loading a new URL, clear the picture set. - WebCore::FrameView* view = pFrame->view(); - if (view) - WebViewCore::getWebViewCore(view)->clearContent(); } static void PostUrl(JNIEnv *env, jobject obj, jstring url, jbyteArray postData) diff --git a/Source/WebKit/android/jni/WebViewCore.cpp b/Source/WebKit/android/jni/WebViewCore.cpp index 9b5a6fa..24266f6 100644 --- a/Source/WebKit/android/jni/WebViewCore.cpp +++ b/Source/WebKit/android/jni/WebViewCore.cpp @@ -1729,7 +1729,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) Node* eventNode = it->get(); while (eventNode) { RenderObject* render = eventNode->renderer(); - if (render->isBody() || render->isRenderView()) + if (render && (render->isBody() || render->isRenderView())) break; if (eventNode->supportsFocus() || eventNode->hasEventListeners(eventNames().clickEvent) @@ -1755,7 +1755,7 @@ Vector<IntRect> WebViewCore::getTouchHighlightRects(int x, int y, int slop) // If the fat point touches everyone, the order in the list should be "b", "d", "c" // and "a". When we search for the event node for "b", we really don't want "a" as // in the z-order it is behind everything else. - if (!render->style()->hasAutoZIndex()) + if (render && !render->style()->hasAutoZIndex()) break; eventNode = eventNode->parentNode(); } @@ -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) { @@ -2219,12 +2224,16 @@ void WebViewCore::scrollNodeIntoView(Frame* frame, Node* node) if (!node->isElementNode()) { HTMLElement* body = frame->document()->body(); do { - if (!node || node == body) + if (node == body) return; node = node->parentNode(); - } while (!node->isElementNode() && !isVisible(node)); + } while (node && !node->isElementNode() && !isVisible(node)); } + // Couldn't find a visible predecessor. + if (!node) + return; + elementNode = static_cast<Element*>(node); elementNode->scrollIntoViewIfNeeded(true); } 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(); } |