Reviewed by Sam Weinig.
Add logical scrolling to WebCore. It basically mirrors physical scrolling but works in abstract logical
directions and only converts to physical when it's time to attempt the scroll.
Also fixed bugs in scrollRecursively and logicalScrollRecursively where overflow sections in containing
frames got skipped over.
Made the resetting of the inline axis scroll position on Home/End Mac-specific for overflow sections.
* WebCore.exp.in:
* page/EventHandler.cpp:
(WebCore::EventHandler::logicalScrollOverflow):
(WebCore::EventHandler::scrollRecursively):
(WebCore::EventHandler::logicalScrollRecursively):
* page/EventHandler.h:
* page/FrameView.cpp:
(WebCore::FrameView::isVerticalDocument):
(WebCore::FrameView::isFlippedDocument):
* page/FrameView.h:
* platform/ScrollTypes.h:
(WebCore::logicalToPhysical):
* platform/ScrollView.cpp:
(WebCore::ScrollView::scroll):
(WebCore::ScrollView::logicalScroll):
* platform/ScrollView.h:
(WebCore::ScrollView::isVerticalDocument):
(WebCore::ScrollView::isFlippedDocument):
* rendering/RenderBox.cpp:
(WebCore::RenderBox::logicalScroll):
* rendering/RenderBox.h:
* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::scroll):
* rendering/RenderListBox.cpp:
(WebCore::RenderListBox::logicalScroll):
* rendering/RenderListBox.h:
* rendering/RenderTextControlSingleLine.cpp:
(WebCore::RenderTextControlSingleLine::logicalScroll):
* rendering/RenderTextControlSingleLine.h:
WebKit2: https://bugs.webkit.org/show_bug.cgi?id=48545, Home/End, PageUp/PageDwn should respect writing-mode. Use
logical scrolling instead of physical scrolling for those keys in WebKit2.
Reviewed by Sam Weinig.
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::logicalScroll):
(WebKit::WebPage::performDefaultBehaviorForKeyEvent):
* WebProcess/WebPage/qt/WebPageQt.cpp:
(WebKit::logicalScroll):
(WebKit::WebPage::performDefaultBehaviorForKeyEvent):
* WebProcess/WebPage/win/WebPageWin.cpp:
(WebKit::logicalScroll):
(WebKit::WebPage::performDefaultBehaviorForKeyEvent):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@73941
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2010-12-13 David Hyatt <hyatt@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48545, Home/End, PageUp/PageDwn should respect writing-mode.
+
+ Add logical scrolling to WebCore. It basically mirrors physical scrolling but works in abstract logical
+ directions and only converts to physical when it's time to attempt the scroll.
+
+ Also fixed bugs in scrollRecursively and logicalScrollRecursively where overflow sections in containing
+ frames got skipped over.
+
+ Made the resetting of the inline axis scroll position on Home/End Mac-specific for overflow sections.
+
+ * WebCore.exp.in:
+ * page/EventHandler.cpp:
+ (WebCore::EventHandler::logicalScrollOverflow):
+ (WebCore::EventHandler::scrollRecursively):
+ (WebCore::EventHandler::logicalScrollRecursively):
+ * page/EventHandler.h:
+ * page/FrameView.cpp:
+ (WebCore::FrameView::isVerticalDocument):
+ (WebCore::FrameView::isFlippedDocument):
+ * page/FrameView.h:
+ * platform/ScrollTypes.h:
+ (WebCore::logicalToPhysical):
+ * platform/ScrollView.cpp:
+ (WebCore::ScrollView::scroll):
+ (WebCore::ScrollView::logicalScroll):
+ * platform/ScrollView.h:
+ (WebCore::ScrollView::isVerticalDocument):
+ (WebCore::ScrollView::isFlippedDocument):
+ * rendering/RenderBox.cpp:
+ (WebCore::RenderBox::logicalScroll):
+ * rendering/RenderBox.h:
+ * rendering/RenderLayer.cpp:
+ (WebCore::RenderLayer::scroll):
+ * rendering/RenderListBox.cpp:
+ (WebCore::RenderListBox::logicalScroll):
+ * rendering/RenderListBox.h:
+ * rendering/RenderTextControlSingleLine.cpp:
+ (WebCore::RenderTextControlSingleLine::logicalScroll):
+ * rendering/RenderTextControlSingleLine.h:
+
2010-12-13 Yury Semikhatsky <yurys@chromium.org>
Unreviewed. Rollout 73914, 73915, 73917, 73920 and 73921.
__ZN7WebCore12EventHandler15sendScrollEventEv
__ZN7WebCore12EventHandler16handleWheelEventERNS_18PlatformWheelEventE
__ZN7WebCore12EventHandler17scrollRecursivelyENS_15ScrollDirectionENS_17ScrollGranularityEPNS_4NodeE
+__ZN7WebCore12EventHandler24logicalScrollRecursivelyENS_22ScrollLogicalDirectionENS_17ScrollGranularityEPNS_4NodeE
__ZN7WebCore12EventHandler20hitTestResultAtPointERKNS_8IntPointEbbNS_17HitTestScrollbarsEjRKNS_7IntSizeE
__ZN7WebCore12EventHandler21handleMousePressEventERKNS_18PlatformMouseEventE
__ZN7WebCore12EventHandler23handleMouseReleaseEventERKNS_18PlatformMouseEventE
return false;
}
+bool EventHandler::logicalScrollOverflow(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ Node* node = startingNode;
+
+ if (!node)
+ node = m_frame->document()->focusedNode();
+
+ if (!node)
+ node = m_mousePressNode.get();
+
+ if (node) {
+ RenderObject* r = node->renderer();
+ if (r && !r->isListBox() && r->enclosingBox()->logicalScroll(direction, granularity)) {
+ setFrameWasScrolledByUser();
+ return true;
+ }
+ }
+
+ return false;
+}
+
bool EventHandler::scrollRecursively(ScrollDirection direction, ScrollGranularity granularity, Node* startingNode)
{
// The layout needs to be up to date to determine if we can scroll. We may be
// here because of an onLoad event, in which case the final layout hasn't been performed yet.
m_frame->document()->updateLayoutIgnorePendingStylesheets();
- bool handled = scrollOverflow(direction, granularity, startingNode);
- if (!handled) {
- Frame* frame = m_frame;
- do {
- FrameView* view = frame->view();
- handled = view ? view->scroll(direction, granularity) : false;
- frame = frame->tree()->parent();
- } while (!handled && frame);
- }
+ if (scrollOverflow(direction, granularity, startingNode))
+ return true;
+ Frame* frame = m_frame;
+ FrameView* view = frame->view();
+ if (view && view->scroll(direction, granularity))
+ return true;
+ frame = frame->tree()->parent();
+ if (!frame)
+ return false;
+ return frame->eventHandler()->scrollRecursively(direction, granularity, m_frame->document()->ownerElement());
+}
- return handled;
+bool EventHandler::logicalScrollRecursively(ScrollLogicalDirection direction, ScrollGranularity granularity, Node* startingNode)
+{
+ // The layout needs to be up to date to determine if we can scroll. We may be
+ // here because of an onLoad event, in which case the final layout hasn't been performed yet.
+ m_frame->document()->updateLayoutIgnorePendingStylesheets();
+ if (logicalScrollOverflow(direction, granularity, startingNode))
+ return true;
+ Frame* frame = m_frame;
+ FrameView* view = frame->view();
+
+ bool scrolled = false;
+#if PLATFORM(MAC)
+ // Mac also resets the scroll position in the inline direction.
+ if (granularity == ScrollByDocument && view && view->logicalScroll(ScrollInlineDirectionBackward, ScrollByDocument))
+ scrolled = true;
+#endif
+ if (view && view->logicalScroll(direction, granularity))
+ scrolled = true;
+
+ if (scrolled)
+ return true;
+
+ frame = frame->tree()->parent();
+ if (!frame)
+ return false;
+
+ return frame->eventHandler()->logicalScrollRecursively(direction, granularity, m_frame->document()->ownerElement());
}
IntPoint EventHandler::currentMousePosition() const
static Frame* subframeForTargetNode(Node*);
bool scrollOverflow(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
+ bool logicalScrollOverflow(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
bool scrollRecursively(ScrollDirection, ScrollGranularity, Node* startingNode = 0);
+ bool logicalScrollRecursively(ScrollLogicalDirection, ScrollGranularity, Node* startingNode = 0);
#if ENABLE(DRAG_SUPPORT)
bool shouldDragAutoNode(Node*, const IntPoint&) const; // -webkit-user-drag == auto
s_deferredRepaintDelayIncrementDuringLoading = p;
}
+bool FrameView::isVerticalDocument() const
+{
+ if (!m_frame)
+ return true;
+ Document* doc = m_frame->document();
+ if (!doc)
+ return true;
+ RenderObject* renderView = doc->renderer();
+ if (!renderView)
+ return true;
+ return renderView->style()->isHorizontalWritingMode();
+}
+
+bool FrameView::isFlippedDocument() const
+{
+ if (!m_frame)
+ return false;
+ Document* doc = m_frame->document();
+ if (!doc)
+ return false;
+ RenderObject* renderView = doc->renderer();
+ if (!renderView)
+ return false;
+ return renderView->style()->isFlippedBlocksWritingMode();
+}
+
} // namespace WebCore
virtual bool scrollContentsFastPath(const IntSize& scrollDelta, const IntRect& rectToScroll, const IntRect& clipRect);
virtual void scrollContentsSlowPath(const IntRect& updateRect);
+ virtual bool isVerticalDocument() const;
+ virtual bool isFlippedDocument() const;
+
private:
FrameView(Frame*);
ScrollRight
};
+ enum ScrollLogicalDirection {
+ ScrollBlockDirectionBackward,
+ ScrollBlockDirectionForward,
+ ScrollInlineDirectionBackward,
+ ScrollInlineDirectionForward
+ };
+
+
+ inline ScrollDirection logicalToPhysical(ScrollLogicalDirection direction, bool isVertical, bool isFlipped)
+ {
+ switch (direction) {
+ case ScrollBlockDirectionBackward: {
+ if (isVertical) {
+ if (!isFlipped)
+ return ScrollUp;
+ return ScrollDown;
+ } else {
+ if (!isFlipped)
+ return ScrollLeft;
+ return ScrollRight;
+ }
+ break;
+ }
+ case ScrollBlockDirectionForward: {
+ if (isVertical) {
+ if (!isFlipped)
+ return ScrollDown;
+ return ScrollUp;
+ } else {
+ if (!isFlipped)
+ return ScrollRight;
+ return ScrollLeft;
+ }
+ break;
+ }
+ case ScrollInlineDirectionBackward: {
+ if (isVertical) {
+ if (!isFlipped)
+ return ScrollLeft;
+ return ScrollRight;
+ } else {
+ if (!isFlipped)
+ return ScrollUp;
+ return ScrollDown;
+ }
+ break;
+ }
+ case ScrollInlineDirectionForward: {
+ if (isVertical) {
+ if (!isFlipped)
+ return ScrollRight;
+ return ScrollLeft;
+ } else {
+ if (!isFlipped)
+ return ScrollDown;
+ return ScrollUp;
+ }
+ break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ return ScrollUp;
+ }
+
enum ScrollGranularity {
ScrollByLine,
ScrollByPage,
{
if (platformWidget())
return platformScroll(direction, granularity);
-
+
if (direction == ScrollUp || direction == ScrollDown) {
if (m_verticalScrollbar)
return m_verticalScrollbar->scroll(direction, granularity);
return false;
}
+bool ScrollView::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity)
+{
+ return scroll(logicalToPhysical(direction, isVerticalDocument(), isFlippedDocument()), granularity);
+}
+
void ScrollView::windowResizerRectChanged()
{
if (platformWidget())
// This function scrolls by lines, pages or pixels.
bool scroll(ScrollDirection, ScrollGranularity);
-
+
+ // A logical scroll that just ends up calling the corresponding physical scroll() based off the document's writing mode.
+ bool logicalScroll(ScrollLogicalDirection, ScrollGranularity);
+
// Scroll the actual contents of the view (either blitting or invalidating as needed).
void scrollContents(const IntSize& scrollDelta);
void setScrollOrigin(const IntPoint&, bool updatePosition);
IntPoint scrollOrigin() { return m_scrollOrigin; }
+ // Subclassed by FrameView to check the writing-mode of the document.
+ virtual bool isVerticalDocument() const { return true; }
+ virtual bool isFlippedDocument() const { return false; }
+
private:
RefPtr<Scrollbar> m_horizontalScrollbar;
RefPtr<Scrollbar> m_verticalScrollbar;
return false;
}
+bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
+{
+ bool scrolled = false;
+
+ RenderLayer* l = layer();
+ if (l) {
+#if PLATFORM(MAC)
+ // On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
+ if (granularity == ScrollByDocument)
+ scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
+#endif
+ if (l->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
+ scrolled = true;
+
+ if (scrolled) {
+ if (stopNode)
+ *stopNode = node();
+ return true;
+ }
+ }
+
+ if (stopNode && *stopNode && *stopNode == node())
+ return true;
+
+ RenderBlock* b = containingBlock();
+ if (b && !b->isRenderView())
+ return b->logicalScroll(direction, granularity, multiplier, stopNode);
+ return false;
+}
+
bool RenderBox::canBeScrolledAndHasScrollableArea() const
{
return canBeProgramaticallyScrolled(false) && (scrollHeight() != clientHeight() || scrollWidth() != clientWidth());
int horizontalScrollbarHeight() const;
int scrollbarLogicalHeight() const { return style()->isHorizontalWritingMode() ? horizontalScrollbarHeight() : verticalScrollbarWidth(); }
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
+ virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
bool canBeScrolledAndHasScrollableArea() const;
virtual bool canBeProgramaticallyScrolled(bool) const;
virtual void autoscroll();
{
bool didHorizontalScroll = false;
bool didVerticalScroll = false;
-
- if (m_hBar) {
- // Special-case for the ScrollByDocument granularity. A document scroll
- // can only be up or down and in both cases the horizontal bar goes all
- // the way to the left.
- didHorizontalScroll = m_hBar->scroll((granularity == ScrollByDocument) ? ScrollLeft : direction, granularity, multiplier);
- }
+ if (m_hBar)
+ didHorizontalScroll = m_hBar->scroll(direction, granularity, multiplier);
if (m_vBar)
didVerticalScroll = m_vBar->scroll(direction, granularity, multiplier);
return m_vBar && m_vBar->scroll(direction, granularity, multiplier);
}
+bool RenderListBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node**)
+{
+ return m_vBar && m_vBar->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier);
+}
+
void RenderListBox::valueChanged(unsigned listIndex)
{
Element* element = static_cast<Element*>(node());
virtual bool isPointInOverflowControl(HitTestResult&, int x, int y, int tx, int ty);
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
+ virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
virtual void computePreferredLogicalWidths();
virtual int baselinePosition(FontBaseline, bool firstLine, LineDirectionMode, LinePositionMode = PositionOnContainingLine) const;
return RenderBlock::scroll(direction, granularity, multiplier, stopNode);
}
+bool RenderTextControlSingleLine::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Node** stopNode)
+{
+ RenderLayer* layer = innerTextElement()->renderBox()->layer();
+ if (layer && layer->scroll(logicalToPhysical(direction, style()->isHorizontalWritingMode(), style()->isFlippedBlocksWritingMode()), granularity, multiplier))
+ return true;
+ return RenderBlock::logicalScroll(direction, granularity, multiplier, stopNode);
+}
+
PassRefPtr<Scrollbar> RenderTextControlSingleLine::createScrollbar(ScrollbarClient* client, ScrollbarOrientation orientation, ScrollbarControlSize controlSize)
{
RefPtr<Scrollbar> widget;
virtual void setScrollLeft(int);
virtual void setScrollTop(int);
virtual bool scroll(ScrollDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
+ virtual bool logicalScroll(ScrollLogicalDirection, ScrollGranularity, float multiplier = 1, Node** stopNode = 0);
int textBlockWidth() const;
virtual float getAvgCharWidth(AtomicString family);
+2010-12-13 David Hyatt <hyatt@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48545, Home/End, PageUp/PageDwn should respect writing-mode. Use
+ logical scrolling instead of physical scrolling for those keys in WebKit2.
+
+ * WebProcess/WebPage/mac/WebPageMac.mm:
+ (WebKit::logicalScroll):
+ (WebKit::WebPage::performDefaultBehaviorForKeyEvent):
+ * WebProcess/WebPage/qt/WebPageQt.cpp:
+ (WebKit::logicalScroll):
+ (WebKit::WebPage::performDefaultBehaviorForKeyEvent):
+ * WebProcess/WebPage/win/WebPageWin.cpp:
+ (WebKit::logicalScroll):
+ (WebKit::WebPage::performDefaultBehaviorForKeyEvent):
+
2010-12-13 Brian Weinstein <bweinstein@apple.com>
Reviewed by Darin Adler.
page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
}
+static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
+{
+ page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
+}
+
bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
{
if (keyboardEvent.type() != WebEvent::KeyDown)
break;
case VK_SPACE:
if (keyboardEvent.shiftKey())
- scroll(m_page.get(), ScrollUp, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
else
- scroll(m_page.get(), ScrollDown, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
break;
case VK_PRIOR:
- scroll(m_page.get(), ScrollUp, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
break;
case VK_NEXT:
- scroll(m_page.get(), ScrollDown, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
break;
case VK_HOME:
- scroll(m_page.get(), ScrollUp, ScrollByDocument);
- scroll(m_page.get(), ScrollLeft, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
break;
case VK_END:
- scroll(m_page.get(), ScrollDown, ScrollByDocument);
- scroll(m_page.get(), ScrollLeft, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
break;
case VK_UP:
if (keyboardEvent.shiftKey())
page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
}
+static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
+{
+ page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
+}
+
bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
{
if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
m_page->goBack();
break;
case VK_SPACE:
- scroll(m_page.get(), keyboardEvent.shiftKey() ? ScrollUp : ScrollDown, ScrollByPage);
+ logicalScroll(m_page.get(), keyboardEvent.shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward, ScrollByPage);
break;
case VK_LEFT:
scroll(m_page.get(), ScrollLeft, ScrollByLine);
scroll(m_page.get(), ScrollDown, ScrollByLine);
break;
case VK_HOME:
- scroll(m_page.get(), ScrollUp, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
break;
case VK_END:
- scroll(m_page.get(), ScrollDown, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
break;
case VK_PRIOR:
- scroll(m_page.get(), ScrollUp, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
break;
case VK_NEXT:
- scroll(m_page.get(), ScrollDown, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
break;
default:
return false;
page->focusController()->focusedOrMainFrame()->eventHandler()->scrollRecursively(direction, granularity);
}
+static inline void logicalScroll(Page* page, ScrollLogicalDirection direction, ScrollGranularity granularity)
+{
+ page->focusController()->focusedOrMainFrame()->eventHandler()->logicalScrollRecursively(direction, granularity);
+}
+
bool WebPage::performDefaultBehaviorForKeyEvent(const WebKeyboardEvent& keyboardEvent)
{
if (keyboardEvent.type() != WebEvent::KeyDown && keyboardEvent.type() != WebEvent::RawKeyDown)
else
m_page->goBack();
break;
+ case VK_SPACE:
+ logicalScroll(m_page.get(), keyboardEvent.shiftKey() ? ScrollBlockDirectionBackward : ScrollBlockDirectionForward, ScrollByPage);
+ break;
case VK_LEFT:
scroll(m_page.get(), ScrollLeft, ScrollByLine);
break;
scroll(m_page.get(), ScrollDown, ScrollByLine);
break;
case VK_HOME:
- scroll(m_page.get(), ScrollUp, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByDocument);
break;
case VK_END:
- scroll(m_page.get(), ScrollDown, ScrollByDocument);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByDocument);
break;
case VK_PRIOR:
- scroll(m_page.get(), ScrollUp, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionBackward, ScrollByPage);
break;
case VK_NEXT:
- scroll(m_page.get(), ScrollDown, ScrollByPage);
+ logicalScroll(m_page.get(), ScrollBlockDirectionForward, ScrollByPage);
break;
default:
return false;