Diff
Modified: trunk/Source/WebKit/ChangeLog (124469 => 124470)
--- trunk/Source/WebKit/ChangeLog 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/ChangeLog 2012-08-02 16:42:13 UTC (rev 124470)
@@ -1,3 +1,15 @@
+2012-08-01 Antonio Gomes <[email protected]>
+
+ [BlackBerry] Implement InRegionScroller class as a in-region scroll controller
+ https://bugs.webkit.org/show_bug.cgi?id=92889
+ PR #186587
+
+ Reviewed by Yong Li.
+
+ Internally reviewed by Arvid Nilsson.
+
+ * PlatformBlackBerry.cmake: Added InRegionScroller.cpp|h to the build system.
+
2012-07-30 Simon Hausmann <[email protected]>
Unreviewed Qt/Mac build fix: Use libWebKitSystemInterfaceMountainLion.a
Modified: trunk/Source/WebKit/PlatformBlackBerry.cmake (124469 => 124470)
--- trunk/Source/WebKit/PlatformBlackBerry.cmake 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/PlatformBlackBerry.cmake 2012-08-02 16:42:13 UTC (rev 124470)
@@ -100,6 +100,8 @@
blackberry/WebKitSupport/FrameLayers.cpp
blackberry/WebKitSupport/InPageSearchManager.cpp
blackberry/WebKitSupport/InputHandler.cpp
+ blackberry/WebKitSupport/InRegionScrollableArea.cpp
+ blackberry/WebKitSupport/InRegionScroller.cpp
blackberry/WebKitSupport/RenderQueue.cpp
blackberry/WebKitSupport/SelectionHandler.cpp
blackberry/WebKitSupport/SelectionOverlay.cpp
Modified: trunk/Source/WebKit/blackberry/Api/WebPage.cpp (124469 => 124470)
--- trunk/Source/WebKit/blackberry/Api/WebPage.cpp 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/blackberry/Api/WebPage.cpp 2012-08-02 16:42:13 UTC (rev 124470)
@@ -393,7 +393,6 @@
, m_lastUserEventTimestamp(0.0)
, m_pluginMouseButtonPressed(false)
, m_pluginMayOpenNewTab(false)
- , m_inRegionScrollStartingNode(0)
#if USE(ACCELERATED_COMPOSITING)
, m_rootLayerCommitTimer(adoptPtr(new Timer<WebPagePrivate>(this, &WebPagePrivate::rootLayerCommitTimerFired)))
, m_needsOneShotDrawingSynchronization(false)
@@ -558,6 +557,8 @@
frameLoaderClient->setFrame(m_mainFrame, this);
m_mainFrame->init();
+ m_inRegionScroller = adoptPtr(new InRegionScroller(this));
+
#if ENABLE(WEBGL)
Platform::Settings* settings = Platform::Settings::instance();
m_page->settings()->setWebGLEnabled(settings && settings->isWebGLSupported());
@@ -1522,15 +1523,13 @@
delta.width() < 0 ? -untransformedCopiedDelta.width() : untransformedCopiedDelta.width(),
delta.height() < 0 ? -untransformedCopiedDelta.height(): untransformedCopiedDelta.height());
- if (m_inRegionScrollStartingNode) {
- if (scrollNodeRecursively(m_inRegionScrollStartingNode.get(), delta)) {
- m_selectionHandler->selectionPositionChanged();
- // FIXME: We have code in place to handle scrolling and clipping tap highlight
- // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
- // a backing store), we can reliably make use of it in the real world.
- // m_touchEventHandler->drawTapHighlight();
- return true;
- }
+ if (m_inRegionScroller->scrollBy(delta)) {
+ m_selectionHandler->selectionPositionChanged();
+ // FIXME: We have code in place to handle scrolling and clipping tap highlight
+ // on in-region scrolling. As soon as it is fast enough (i.e. we have it backed by
+ // a backing store), we can reliably make use of it in the real world.
+ // m_touchEventHandler->drawTapHighlight();
+ return true;
}
return false;
@@ -1550,9 +1549,9 @@
void WebPagePrivate::notifyInRegionScrollStatusChanged(bool status)
{
- if (!status && m_inRegionScrollStartingNode) {
- enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScrollStartingNode.get());
- m_inRegionScrollStartingNode = 0;
+ if (!status && m_inRegionScroller->hasNode()) {
+ enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(m_inRegionScroller->node());
+ m_inRegionScroller->reset();
}
}
@@ -2635,8 +2634,8 @@
if (m_currentBlockZoomAdjustedNode && m_currentBlockZoomAdjustedNode->document() == documentGoingAway)
m_currentBlockZoomAdjustedNode = 0;
- if (m_inRegionScrollStartingNode && m_inRegionScrollStartingNode->document() == documentGoingAway)
- m_inRegionScrollStartingNode = 0;
+ if (m_inRegionScroller->hasNode() && m_inRegionScroller->node()->document() == documentGoingAway)
+ m_inRegionScroller->reset();
if (documentGoingAway->frame())
m_inputHandler->frameUnloaded(documentGoingAway->frame());
@@ -2656,15 +2655,6 @@
return o->isRenderView() || o->isOutOfFlowPositioned() || o->isRelPositioned() || layer->hasTransform();
}
-static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
-{
- RenderObject* o = layer->renderer();
- if (o->isRenderView())
- return false;
-
- return o->isOutOfFlowPositioned() && o->style()->position() == FixedPosition;
-}
-
static bool isFixedPositionedContainer(RenderLayer* layer)
{
RenderObject* o = layer->renderer();
@@ -4223,12 +4213,12 @@
void WebPagePrivate::setScrollOriginPoint(const Platform::IntPoint& point)
{
- m_inRegionScrollStartingNode = 0;
+ m_inRegionScroller->reset();
if (!m_hasInRegionScrollableAreas)
return;
- m_client->notifyInRegionScrollingStartingPointChanged(inRegionScrollableAreasForPoint(point));
+ m_client->notifyInRegionScrollingStartingPointChanged(m_inRegionScroller->inRegionScrollableAreasForPoint(point));
}
void WebPage::setScrollOriginPoint(const Platform::IntPoint& point)
@@ -4398,120 +4388,6 @@
return d->focusedOrMainFrame()->loader()->reloadWithOverrideEncoding(encoding);
}
-bool WebPagePrivate::scrollNodeRecursively(Node* node, const IntSize& delta)
-{
- if (delta.isZero())
- return true;
-
- if (!node)
- return false;
-
- RenderObject* renderer = node->renderer();
- if (!renderer)
- return false;
-
- FrameView* view = renderer->view()->frameView();
- if (!view)
- return false;
-
- // Try scrolling the renderer.
- if (scrollRenderer(renderer, delta))
- return true;
-
- // We've hit the page, don't scroll it and return false.
- if (view == m_mainFrame->view())
- return false;
-
- // Try scrolling the FrameView.
- if (canScrollInnerFrame(view->frame())) {
- IntSize viewDelta = delta;
- IntPoint newViewOffset = view->scrollPosition();
- IntPoint maxViewOffset = view->maximumScrollPosition();
- adjustScrollDelta(maxViewOffset, newViewOffset, viewDelta);
-
- if (!viewDelta.isZero()) {
- view->setCanBlitOnScroll(false);
-
- BackingStoreClient* backingStoreClient = backingStoreClientForFrame(view->frame());
- if (backingStoreClient) {
- backingStoreClient->setIsClientGeneratedScroll(true);
- backingStoreClient->setIsScrollNotificationSuppressed(true);
- }
-
- m_inRegionScrollStartingNode = view->frame()->document();
-
- view->scrollBy(viewDelta);
-
- if (backingStoreClient) {
- backingStoreClient->setIsClientGeneratedScroll(false);
- backingStoreClient->setIsScrollNotificationSuppressed(false);
- }
-
- return true;
- }
- }
-
- // Try scrolling the node of the enclosing frame.
- Frame* frame = node->document()->frame();
- if (frame) {
- Node* ownerNode = frame->ownerElement();
- if (scrollNodeRecursively(ownerNode, delta))
- return true;
- }
-
- return false;
-}
-
-void WebPagePrivate::adjustScrollDelta(const IntPoint& maxOffset, const IntPoint& currentOffset, IntSize& delta) const
-{
- if (currentOffset.x() + delta.width() > maxOffset.x())
- delta.setWidth(min(maxOffset.x() - currentOffset.x(), delta.width()));
-
- if (currentOffset.x() + delta.width() < 0)
- delta.setWidth(max(-currentOffset.x(), delta.width()));
-
- if (currentOffset.y() + delta.height() > maxOffset.y())
- delta.setHeight(min(maxOffset.y() - currentOffset.y(), delta.height()));
-
- if (currentOffset.y() + delta.height() < 0)
- delta.setHeight(max(-currentOffset.y(), delta.height()));
-}
-
-static Node* enclosingLayerNode(RenderLayer*);
-
-bool WebPagePrivate::scrollRenderer(RenderObject* renderer, const IntSize& delta)
-{
- RenderLayer* layer = renderer->enclosingLayer();
- if (!layer)
- return false;
-
- // Try to scroll layer.
- bool restrictedByLineClamp = false;
- if (renderer->parent())
- restrictedByLineClamp = !renderer->parent()->style()->lineClamp().isNone();
-
- if (renderer->hasOverflowClip() && !restrictedByLineClamp) {
- IntSize layerDelta = delta;
- IntPoint maxOffset(layer->scrollWidth() - layer->renderBox()->clientWidth(), layer->scrollHeight() - layer->renderBox()->clientHeight());
- IntPoint currentOffset(layer->scrollXOffset(), layer->scrollYOffset());
- adjustScrollDelta(maxOffset, currentOffset, layerDelta);
- if (!layerDelta.isZero()) {
- m_inRegionScrollStartingNode = enclosingLayerNode(layer);
- IntPoint newOffset = currentOffset + layerDelta;
- layer->scrollToOffset(toSize(newOffset));
- renderer->repaint(true);
- return true;
- }
- }
-
- while (layer = layer->parent()) {
- if (canScrollRenderBox(layer->renderBox()))
- return scrollRenderer(layer->renderBox(), delta);
- }
-
- return false;
-}
-
static void handleScrolling(unsigned short character, WebPagePrivate* scroller)
{
const int scrollFactor = 20;
@@ -4775,169 +4651,6 @@
d->m_selectionHandler->selectAtPoint(selectionLocation);
}
-// FIXME: Move to DOMSupport.
-bool WebPagePrivate::canScrollInnerFrame(Frame* frame) const
-{
- if (!frame || !frame->view())
- return false;
-
- // Not having an owner element means that we are on the mainframe.
- if (!frame->ownerElement())
- return false;
-
- ASSERT(frame != m_mainFrame);
-
- IntSize visibleSize = frame->view()->visibleContentRect().size();
- IntSize contentsSize = frame->view()->contentsSize();
-
- bool canBeScrolled = contentsSize.height() > visibleSize.height() || contentsSize.width() > visibleSize.width();
-
- // Lets also consider the 'overflow-{x,y} property set directly to the {i}frame tag.
- return canBeScrolled && (frame->ownerElement()->scrollingMode() != ScrollbarAlwaysOff);
-}
-
-// The RenderBox::canbeScrolledAndHasScrollableArea method returns true for the
-// following scenario, for example:
-// (1) a div that has a vertical overflow but no horizontal overflow
-// with overflow-y: hidden and overflow-x: auto set.
-// The version below fixes it.
-// FIXME: Fix RenderBox::canBeScrolledAndHasScrollableArea method instead.
-bool WebPagePrivate::canScrollRenderBox(RenderBox* box)
-{
- if (!box || !box->hasOverflowClip())
- return false;
-
- if (box->scrollsOverflowX() && (box->scrollWidth() != box->clientWidth())
- || box->scrollsOverflowY() && (box->scrollHeight() != box->clientHeight()))
- return true;
-
- Node* node = box->node();
- return node && (node->rendererIsEditable() || node->isDocumentNode());
-}
-
-static RenderLayer* parentLayer(RenderLayer* layer)
-{
- ASSERT(layer);
- if (layer->parent())
- return layer->parent();
-
- RenderObject* renderer = layer->renderer();
- if (renderer->document() && renderer->document()->ownerElement() && renderer->document()->ownerElement()->renderer())
- return renderer->document()->ownerElement()->renderer()->enclosingLayer();
-
- return 0;
-}
-
-// FIXME: Make RenderLayer::enclosingElement public so this one can be removed.
-static Node* enclosingLayerNode(RenderLayer* layer)
-{
- for (RenderObject* r = layer->renderer(); r; r = r->parent()) {
- if (Node* e = r->node())
- return e;
- }
- ASSERT_NOT_REACHED();
- return 0;
-}
-
-static void pushBackInRegionScrollable(std::vector<Platform::ScrollViewBase*>& vector, InRegionScrollableArea* scroller, WebPagePrivate* webPage)
-{
- ASSERT(webPage);
- ASSERT(!scroller.isNull());
-
- scroller->setCanPropagateScrollingToEnclosingScrollable(!isNonRenderViewFixedPositionedContainer(scroller->layer()));
- vector.push_back(scroller);
- if (vector.size() == 1) {
- // FIXME: Use RenderLayer::renderBox()->node() instead?
- webPage->m_inRegionScrollStartingNode = enclosingLayerNode(scroller->layer());
- }
-}
-
-std::vector<Platform::ScrollViewBase*> WebPagePrivate::inRegionScrollableAreasForPoint(const Platform::IntPoint& point)
-{
- std::vector<Platform::ScrollViewBase*> validReturn;
- std::vector<Platform::ScrollViewBase*> emptyReturn;
-
- HitTestResult result = m_mainFrame->eventHandler()->hitTestResultAtPoint(mapFromViewportToContents(point), false /*allowShadowContent*/);
- Node* node = result.innerNonSharedNode();
- if (!node)
- return emptyReturn;
-
- RenderObject* renderer = node->renderer();
- // FIXME: Validate with elements with visibility:hidden.
- if (!renderer)
- return emptyReturn;
-
- RenderLayer* layer = renderer->enclosingLayer();
- do {
- RenderObject* renderer = layer->renderer();
-
- if (renderer->isRenderView()) {
- if (RenderView* renderView = toRenderView(renderer)) {
- FrameView* view = renderView->frameView();
- if (!view)
- return emptyReturn;
-
- if (canScrollInnerFrame(view->frame())) {
- pushBackInRegionScrollable(validReturn, new InRegionScrollableArea(this, layer), this);
- continue;
- }
- }
- } else if (canScrollRenderBox(layer->renderBox())) {
- pushBackInRegionScrollable(validReturn, new InRegionScrollableArea(this, layer), this);
- continue;
- }
-
- // If we run into a fix positioned layer, set the last scrollable in-region object
- // as not able to propagate scroll to its parent scrollable.
- if (isNonRenderViewFixedPositionedContainer(layer) && validReturn.size()) {
- Platform::ScrollViewBase* end = validReturn.back();
- end->setCanPropagateScrollingToEnclosingScrollable(false);
- }
-
- } while (layer = parentLayer(layer));
-
- if (validReturn.empty())
- return emptyReturn;
-
- // Post-calculate the visible window rects in reverse hit test order so
- // we account for all and any clipping rects.
- WebCore::IntRect recursiveClippingRect(WebCore::IntPoint::zero(), transformedViewportSize());
-
- std::vector<Platform::ScrollViewBase*>::reverse_iterator rend = validReturn.rend();
- for (std::vector<Platform::ScrollViewBase*>::reverse_iterator rit = validReturn.rbegin(); rit != rend; ++rit) {
-
- InRegionScrollableArea* curr = static_cast<InRegionScrollableArea*>(*rit);
- RenderLayer* layer = curr->layer();
-
- if (layer && layer->renderer()->isRenderView()) { // #document case
- FrameView* view = toRenderView(layer->renderer())->frameView();
- ASSERT(view);
- ASSERT(canScrollInnerFrame(view->frame()));
-
- WebCore::IntRect frameWindowRect = mapToTransformed(getRecursiveVisibleWindowRect(view));
- frameWindowRect.intersect(recursiveClippingRect);
- curr->setVisibleWindowRect(frameWindowRect);
- recursiveClippingRect = frameWindowRect;
-
- } else { // RenderBox-based elements case (scrollable boxes (div's, p's, textarea's, etc)).
-
- RenderBox* box = layer->renderBox();
- ASSERT(box);
- ASSERT(canScrollRenderBox(box));
-
- WebCore::IntRect visibleWindowRect = box->absoluteClippedOverflowRect();
- visibleWindowRect = box->frame()->view()->contentsToWindow(visibleWindowRect);
- visibleWindowRect = mapToTransformed(visibleWindowRect);
- visibleWindowRect.intersect(recursiveClippingRect);
-
- curr->setVisibleWindowRect(visibleWindowRect);
- recursiveClippingRect = visibleWindowRect;
- }
- }
-
- return validReturn;
-}
-
BackingStore* WebPage::backingStore() const
{
return d->m_backingStore;
Modified: trunk/Source/WebKit/blackberry/Api/WebPage_p.h (124469 => 124470)
--- trunk/Source/WebKit/blackberry/Api/WebPage_p.h 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/blackberry/Api/WebPage_p.h 2012-08-02 16:42:13 UTC (rev 124470)
@@ -20,6 +20,7 @@
#define WebPage_p_h
#include "ChromeClient.h"
+#include "InRegionScroller.h"
#include "InspectorClientBlackBerry.h"
#include "InspectorOverlay.h"
#if USE(ACCELERATED_COMPOSITING)
@@ -143,7 +144,6 @@
bool scrollBy(int deltaX, int deltaY, bool scrollMainFrame = true);
void enqueueRenderingOfClippedContentOfScrollableNodeAfterInRegionScrolling(WebCore::Node*);
- std::vector<Platform::ScrollViewBase*> inRegionScrollableAreasForPoint(const Platform::IntPoint&);
void notifyInRegionScrollStatusChanged(bool status);
void setScrollOriginPoint(const Platform::IntPoint&);
void setHasInRegionScrollableAreas(bool);
@@ -330,13 +330,6 @@
WebCore::Frame* focusedOrMainFrame() const;
WebCore::Frame* mainFrame() const { return m_mainFrame; }
- bool scrollNodeRecursively(WebCore::Node* originalNode, const WebCore::IntSize& delta);
- bool scrollRenderer(WebCore::RenderObject* renderer, const WebCore::IntSize& delta);
- void adjustScrollDelta(const WebCore::IntPoint& maxOffset, const WebCore::IntPoint& currentOffset, WebCore::IntSize& delta) const;
-
- bool canScrollRenderBox(WebCore::RenderBox*);
- bool canScrollInnerFrame(WebCore::Frame*) const;
-
#if ENABLE(EVENT_MODE_METATAGS)
void didReceiveCursorEventMode(WebCore::CursorEventMode);
void didReceiveTouchEventMode(WebCore::TouchEventMode);
@@ -556,7 +549,7 @@
HashSet<WebCore::PluginView*> m_pluginViews;
- RefPtr<WebCore::Node> m_inRegionScrollStartingNode;
+ OwnPtr<InRegionScroller> m_inRegionScroller;
#if USE(ACCELERATED_COMPOSITING)
bool m_isAcceleratedCompositingActive;
Modified: trunk/Source/WebKit/blackberry/ChangeLog (124469 => 124470)
--- trunk/Source/WebKit/blackberry/ChangeLog 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/blackberry/ChangeLog 2012-08-02 16:42:13 UTC (rev 124470)
@@ -1,3 +1,57 @@
+2012-08-01 Antonio Gomes <[email protected]>
+
+ [BlackBerry] Implement InRegionScroller class as a in-region scroll controller
+ https://bugs.webkit.org/show_bug.cgi?id=92889
+ PR #186587
+
+ Reviewed by Yong Li.
+
+ Internally reviewed by Arvid Nilsson.
+
+ Moved all in-region scrolling code out of WebPagePrivate to the just
+ created InRegionScroller class. This class aims to:
+
+ 1) Centralize all in-region scroll code and clean up WebPagePrivate as a consequence.
+ 2) Be the bases to add UI/Compositing thread driven scrolls to in-region.
+
+ The patch does not change any functionallity change.
+
+ * Api/WebPage.cpp:
+ (BlackBerry::WebKit::WebPagePrivate::WebPagePrivate):
+ (BlackBerry::WebKit::WebPagePrivate::init):
+ (BlackBerry::WebKit::WebPagePrivate::scrollBy):
+ (BlackBerry::WebKit::WebPagePrivate::notifyInRegionScrollStatusChanged):
+ (BlackBerry::WebKit::WebPagePrivate::clearDocumentData):
+ (BlackBerry::WebKit::WebPagePrivate::setScrollOriginPoint):
+ * Api/WebPage_p.h:
+ (WebPagePrivate):
+ * WebKitSupport/InRegionScrollableArea.cpp:
+ (BlackBerry::WebKit::InRegionScrollableArea::layer):
+ * WebKitSupport/InRegionScroller.cpp: Added.
+ (WebKit):
+ (BlackBerry::WebKit::canScrollInnerFrame):
+ (BlackBerry::WebKit::canScrollRenderBox):
+ (BlackBerry::WebKit::parentLayer):
+ (BlackBerry::WebKit::enclosingLayerNode):
+ (BlackBerry::WebKit::isNonRenderViewFixedPositionedContainer):
+ (BlackBerry::WebKit::pushBackInRegionScrollable):
+ (BlackBerry::WebKit::InRegionScroller::InRegionScroller):
+ (BlackBerry::WebKit::InRegionScroller::setNode):
+ (BlackBerry::WebKit::InRegionScroller::node):
+ (BlackBerry::WebKit::InRegionScroller::reset):
+ (BlackBerry::WebKit::InRegionScroller::isNull):
+ (BlackBerry::WebKit::InRegionScroller::scrollBy):
+ (BlackBerry::WebKit::InRegionScroller::inRegionScrollableAreasForPoint):
+ (BlackBerry::WebKit::InRegionScroller::scrollNodeRecursively):
+ (BlackBerry::WebKit::InRegionScroller::scrollRenderer):
+ (BlackBerry::WebKit::InRegionScroller::adjustScrollDelta):
+ * WebKitSupport/InRegionScroller.h: Added.
+ (WebCore):
+ (WebKit):
+ (InRegionScroller):
+ * WebKitSupport/TouchEventHandler.cpp:
+ (BlackBerry::WebKit::TouchEventHandler::drawTapHighlight):
+
2012-08-01 Charles Wei <[email protected]>
[BlackBerry] Favicon should be Base64 encoded for cross-process passing
Modified: trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScrollableArea.cpp (124469 => 124470)
--- trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScrollableArea.cpp 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScrollableArea.cpp 2012-08-02 16:42:13 UTC (rev 124470)
@@ -20,7 +20,6 @@
#include "InRegionScrollableArea.h"
#include "Frame.h"
-#include "NotImplemented.h"
#include "RenderBox.h"
#include "RenderLayer.h"
#include "RenderObject.h"
@@ -104,6 +103,6 @@
ASSERT(!m_isNull);
return m_layer;
}
-}
}
+}
Added: trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.cpp (0 => 124470)
--- trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.cpp (rev 0)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.cpp 2012-08-02 16:42:13 UTC (rev 124470)
@@ -0,0 +1,355 @@
+/*
+ * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+#include "InRegionScroller.h"
+
+#include "BackingStoreClient.h"
+#include "Frame.h"
+#include "HTMLFrameOwnerElement.h"
+#include "HitTestResult.h"
+#include "InRegionScrollableArea.h"
+#include "RenderBox.h"
+#include "RenderLayer.h"
+#include "RenderObject.h"
+#include "RenderView.h"
+#include "WebPage_p.h"
+
+using namespace WebCore;
+
+namespace BlackBerry {
+namespace WebKit {
+
+static bool canScrollInnerFrame(Frame* frame)
+{
+ if (!frame || !frame->view())
+ return false;
+
+ // Not having an owner element means that we are on the mainframe.
+ if (!frame->ownerElement())
+ return false;
+
+ ASSERT(frame != frame->page()->mainFrame());
+
+ IntSize visibleSize = frame->view()->visibleContentRect().size();
+ IntSize contentsSize = frame->view()->contentsSize();
+
+ bool canBeScrolled = contentsSize.height() > visibleSize.height() || contentsSize.width() > visibleSize.width();
+
+ // Lets also consider the 'overflow-{x,y} property set directly to the {i}frame tag.
+ return canBeScrolled && (frame->ownerElement()->scrollingMode() != ScrollbarAlwaysOff);
+}
+
+// The RenderBox::canbeScrolledAndHasScrollableArea method returns true for the
+// following scenario, for example:
+// (1) a div that has a vertical overflow but no horizontal overflow
+// with overflow-y: hidden and overflow-x: auto set.
+// The version below fixes it.
+// FIXME: Fix RenderBox::canBeScrolledAndHasScrollableArea method instead.
+static bool canScrollRenderBox(RenderBox* box)
+{
+ if (!box || !box->hasOverflowClip())
+ return false;
+
+ if (box->scrollsOverflowX() && (box->scrollWidth() != box->clientWidth())
+ || box->scrollsOverflowY() && (box->scrollHeight() != box->clientHeight()))
+ return true;
+
+ Node* node = box->node();
+ return node && (node->rendererIsEditable() || node->isDocumentNode());
+}
+
+static RenderLayer* parentLayer(RenderLayer* layer)
+{
+ ASSERT(layer);
+ if (layer->parent())
+ return layer->parent();
+
+ RenderObject* renderer = layer->renderer();
+ if (renderer->document() && renderer->document()->ownerElement() && renderer->document()->ownerElement()->renderer())
+ return renderer->document()->ownerElement()->renderer()->enclosingLayer();
+
+ return 0;
+}
+
+// FIXME: Make RenderLayer::enclosingElement public so this one can be removed.
+static Node* enclosingLayerNode(RenderLayer* layer)
+{
+ for (RenderObject* r = layer->renderer(); r; r = r->parent()) {
+ if (Node* e = r->node())
+ return e;
+ }
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+static bool isNonRenderViewFixedPositionedContainer(RenderLayer* layer)
+{
+ RenderObject* o = layer->renderer();
+ if (o->isRenderView())
+ return false;
+
+ return o->isPositioned() && o->style()->position() == FixedPosition;
+}
+
+static void pushBackInRegionScrollable(std::vector<Platform::ScrollViewBase*>& vector, InRegionScrollableArea* scrollableArea, InRegionScroller* scroller)
+{
+ ASSERT(webPage);
+ ASSERT(!scrollableArea->isNull());
+
+ scrollableArea->setCanPropagateScrollingToEnclosingScrollable(!isNonRenderViewFixedPositionedContainer(scrollableArea->layer()));
+ vector.push_back(scrollableArea);
+ if (vector.size() == 1) {
+ // FIXME: Use RenderLayer::renderBox()->node() instead?
+ scroller->setNode(enclosingLayerNode(scrollableArea->layer()));
+ }
+}
+
+InRegionScroller::InRegionScroller(WebPagePrivate* webPagePrivate)
+ : m_webPage(webPagePrivate)
+{
+}
+
+void InRegionScroller::setNode(WebCore::Node* node)
+{
+ m_inRegionScrollStartingNode = node;
+}
+
+WebCore::Node* InRegionScroller::node() const
+{
+ return m_inRegionScrollStartingNode.get();
+}
+
+void InRegionScroller::reset()
+{
+ setNode(0);
+}
+
+bool InRegionScroller::hasNode() const
+{
+ return !!m_inRegionScrollStartingNode;
+}
+
+bool InRegionScroller::canScroll() const
+{
+ return hasNode();
+}
+
+bool InRegionScroller::scrollBy(const Platform::IntSize& delta)
+{
+ if (!canScroll())
+ return false;
+
+ return scrollNodeRecursively(node(), delta);
+}
+
+std::vector<Platform::ScrollViewBase*> InRegionScroller::inRegionScrollableAreasForPoint(const WebCore::IntPoint& point)
+{
+ std::vector<Platform::ScrollViewBase*> validReturn;
+ std::vector<Platform::ScrollViewBase*> emptyReturn;
+
+ HitTestResult result = m_webPage->m_mainFrame->eventHandler()->hitTestResultAtPoint(m_webPage->mapFromViewportToContents(point), false /*allowShadowContent*/);
+ Node* node = result.innerNonSharedNode();
+ if (!node || !node->renderer())
+ return emptyReturn;
+
+ RenderLayer* layer = node->renderer()->enclosingLayer();
+ do {
+ RenderObject* renderer = layer->renderer();
+
+ if (renderer->isRenderView()) {
+ if (RenderView* renderView = toRenderView(renderer)) {
+ FrameView* view = renderView->frameView();
+ if (!view)
+ return emptyReturn;
+
+ if (canScrollInnerFrame(view->frame())) {
+ pushBackInRegionScrollable(validReturn, new InRegionScrollableArea(m_webPage, layer), this);
+ continue;
+ }
+ }
+ } else if (canScrollRenderBox(layer->renderBox())) {
+ pushBackInRegionScrollable(validReturn, new InRegionScrollableArea(m_webPage, layer), this);
+ continue;
+ }
+
+ // If we run into a fix positioned layer, set the last scrollable in-region object
+ // as not able to propagate scroll to its parent scrollable.
+ if (isNonRenderViewFixedPositionedContainer(layer) && validReturn.size()) {
+ Platform::ScrollViewBase* end = validReturn.back();
+ end->setCanPropagateScrollingToEnclosingScrollable(false);
+ }
+
+ } while (layer = parentLayer(layer));
+
+ if (validReturn.empty())
+ return emptyReturn;
+
+ // Post-calculate the visible window rects in reverse hit test order so
+ // we account for all and any clipping rects.
+ WebCore::IntRect recursiveClippingRect(WebCore::IntPoint::zero(), m_webPage->transformedViewportSize());
+
+ std::vector<Platform::ScrollViewBase*>::reverse_iterator rend = validReturn.rend();
+ for (std::vector<Platform::ScrollViewBase*>::reverse_iterator rit = validReturn.rbegin(); rit != rend; ++rit) {
+
+ InRegionScrollableArea* curr = static_cast<InRegionScrollableArea*>(*rit);
+ RenderLayer* layer = curr->layer();
+
+ if (layer && layer->renderer()->isRenderView()) { // #document case
+ FrameView* view = toRenderView(layer->renderer())->frameView();
+ ASSERT(view);
+ ASSERT(canScrollInnerFrame(view->frame()));
+
+ WebCore::IntRect frameWindowRect = m_webPage->mapToTransformed(m_webPage->getRecursiveVisibleWindowRect(view));
+ frameWindowRect.intersect(recursiveClippingRect);
+ curr->setVisibleWindowRect(frameWindowRect);
+ recursiveClippingRect = frameWindowRect;
+
+ } else { // RenderBox-based elements case (scrollable boxes (div's, p's, textarea's, etc)).
+
+ RenderBox* box = layer->renderBox();
+ ASSERT(box);
+ ASSERT(canScrollRenderBox(box));
+
+ WebCore::IntRect visibleWindowRect = enclosingIntRect(box->absoluteClippedOverflowRect());
+ visibleWindowRect = box->frame()->view()->contentsToWindow(visibleWindowRect);
+ visibleWindowRect = m_webPage->mapToTransformed(visibleWindowRect);
+ visibleWindowRect.intersect(recursiveClippingRect);
+
+ curr->setVisibleWindowRect(visibleWindowRect);
+ recursiveClippingRect = visibleWindowRect;
+ }
+ }
+
+ return validReturn;
+}
+
+bool InRegionScroller::scrollNodeRecursively(WebCore::Node* node, const WebCore::IntSize& delta)
+{
+ if (delta.isZero())
+ return true;
+
+ if (!node)
+ return false;
+
+ RenderObject* renderer = node->renderer();
+ if (!renderer)
+ return false;
+
+ FrameView* view = renderer->view()->frameView();
+ if (!view)
+ return false;
+
+ // Try scrolling the renderer.
+ if (scrollRenderer(renderer, delta))
+ return true;
+
+ // We've hit the page, don't scroll it and return false.
+ if (view == m_webPage->m_mainFrame->view())
+ return false;
+
+ // Try scrolling the FrameView.
+ if (canScrollInnerFrame(view->frame())) {
+ IntSize viewDelta = delta;
+ IntPoint newViewOffset = view->scrollPosition();
+ IntPoint maxViewOffset = view->maximumScrollPosition();
+ adjustScrollDelta(maxViewOffset, newViewOffset, viewDelta);
+
+ if (!viewDelta.isZero()) {
+ view->setCanBlitOnScroll(false);
+
+ BackingStoreClient* backingStoreClient = m_webPage->backingStoreClientForFrame(view->frame());
+ if (backingStoreClient) {
+ backingStoreClient->setIsClientGeneratedScroll(true);
+ backingStoreClient->setIsScrollNotificationSuppressed(true);
+ }
+
+ setNode(view->frame()->document());
+
+ view->scrollBy(viewDelta);
+
+ if (backingStoreClient) {
+ backingStoreClient->setIsClientGeneratedScroll(false);
+ backingStoreClient->setIsScrollNotificationSuppressed(false);
+ }
+
+ return true;
+ }
+ }
+
+ // Try scrolling the node of the enclosing frame.
+ Frame* frame = node->document()->frame();
+ if (frame) {
+ Node* ownerNode = frame->ownerElement();
+ if (scrollNodeRecursively(ownerNode, delta))
+ return true;
+ }
+
+ return false;
+}
+
+bool InRegionScroller::scrollRenderer(WebCore::RenderObject* renderer, const WebCore::IntSize& delta)
+{
+ RenderLayer* layer = renderer->enclosingLayer();
+ if (!layer)
+ return false;
+
+ // Try to scroll layer.
+ bool restrictedByLineClamp = false;
+ if (renderer->parent())
+ restrictedByLineClamp = !renderer->parent()->style()->lineClamp().isNone();
+
+ if (renderer->hasOverflowClip() && !restrictedByLineClamp) {
+ IntSize layerDelta = delta;
+ IntPoint maxOffset(layer->scrollWidth() - layer->renderBox()->clientWidth(), layer->scrollHeight() - layer->renderBox()->clientHeight());
+ IntPoint currentOffset(layer->scrollXOffset(), layer->scrollYOffset());
+ adjustScrollDelta(maxOffset, currentOffset, layerDelta);
+ if (!layerDelta.isZero()) {
+ setNode(enclosingLayerNode(layer));
+ IntPoint newOffset = currentOffset + layerDelta;
+ layer->scrollToOffset(newOffset.x(), newOffset.y());
+ renderer->repaint(true);
+ return true;
+ }
+ }
+
+ while (layer = layer->parent()) {
+ if (canScrollRenderBox(layer->renderBox()))
+ return scrollRenderer(layer->renderBox(), delta);
+ }
+
+ return false;
+}
+
+void InRegionScroller::adjustScrollDelta(const WebCore::IntPoint& maxOffset, const WebCore::IntPoint& currentOffset, WebCore::IntSize& delta) const
+{
+ if (currentOffset.x() + delta.width() > maxOffset.x())
+ delta.setWidth(std::min(maxOffset.x() - currentOffset.x(), delta.width()));
+
+ if (currentOffset.x() + delta.width() < 0)
+ delta.setWidth(std::max(-currentOffset.x(), delta.width()));
+
+ if (currentOffset.y() + delta.height() > maxOffset.y())
+ delta.setHeight(std::min(maxOffset.y() - currentOffset.y(), delta.height()));
+
+ if (currentOffset.y() + delta.height() < 0)
+ delta.setHeight(std::max(-currentOffset.y(), delta.height()));
+}
+
+}
+}
Added: trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.h (0 => 124470)
--- trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.h (rev 0)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/InRegionScroller.h 2012-08-02 16:42:13 UTC (rev 124470)
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef InRegionScroller_h
+#define InRegionScroller_h
+
+#include "IntRect.h"
+
+#include <interaction/ScrollViewBase.h>
+#include <vector>
+
+namespace WebCore {
+class Frame;
+class Node;
+class RenderObject;
+}
+
+namespace BlackBerry {
+namespace WebKit {
+
+class WebPagePrivate;
+
+class InRegionScroller {
+
+public:
+ InRegionScroller(WebPagePrivate*);
+
+ void setNode(WebCore::Node*);
+ WebCore::Node* node() const;
+ void reset();
+
+ bool canScroll() const;
+ bool hasNode() const;
+
+ bool scrollBy(const Platform::IntSize& delta);
+
+ std::vector<Platform::ScrollViewBase*> inRegionScrollableAreasForPoint(const WebCore::IntPoint&);
+private:
+
+ bool scrollNodeRecursively(WebCore::Node*, const WebCore::IntSize& delta);
+ bool scrollRenderer(WebCore::RenderObject*, const WebCore::IntSize& delta);
+
+ void adjustScrollDelta(const WebCore::IntPoint& maxOffset, const WebCore::IntPoint& currentOffset, WebCore::IntSize& delta) const;
+
+ RefPtr<WebCore::Node> m_inRegionScrollStartingNode;
+ WebPagePrivate* m_webPage;
+};
+
+}
+}
+
+#endif
Modified: trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp (124469 => 124470)
--- trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp 2012-08-02 16:36:56 UTC (rev 124469)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/TouchEventHandler.cpp 2012-08-02 16:42:13 UTC (rev 124470)
@@ -363,7 +363,7 @@
// On the client side, this info is being used to hide the tap highlight window on scroll.
RenderLayer* layer = m_webPage->enclosingFixedPositionedAncestorOrSelfIfFixedPositioned(renderer->enclosingLayer());
bool shouldHideTapHighlightRightAfterScrolling = !layer->renderer()->isRenderView();
- shouldHideTapHighlightRightAfterScrolling |= !!m_webPage->m_inRegionScrollStartingNode.get();
+ shouldHideTapHighlightRightAfterScrolling |= !!m_webPage->m_inRegionScroller->node();
IntPoint framePos(m_webPage->frameOffset(elementFrame));