REGRESSION (r181972): Scroll position changes to top of youtube page when switching...
authorrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Oct 2015 11:37:46 +0000 (11:37 +0000)
committerrniwa@webkit.org <rniwa@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 22 Oct 2015 11:37:46 +0000 (11:37 +0000)
https://bugs.webkit.org/show_bug.cgi?id=150428

Reviewed by Antti Koivisto.

Source/WebCore:

The bug was caused by updateFocusAppearance in WebPage::restoreSelectionInFocusedEditableElement
revealing the focused element which was added in r181972. Fixed the bug by adding an option to
suppress this behavior here.

* dom/Document.cpp:
(WebCore::Document::Document):
(WebCore::Document::updateFocusAppearanceSoon):
* dom/Document.h:
* dom/Element.cpp:
(WebCore::Element::focus):
(WebCore::Element::updateFocusAppearanceAfterAttachIfNeeded):
(WebCore::Element::updateFocusAppearance):
* dom/Element.h:
* history/CachedPage.cpp:
(WebCore::CachedPage::restore):
* html/HTMLAreaElement.cpp:
(WebCore::HTMLAreaElement::updateFocusAppearance):
* html/HTMLAreaElement.h:
* html/HTMLInputElement.cpp:
(WebCore::HTMLInputElement::updateFocusAppearance):
(WebCore::HTMLInputElement::runPostTypeUpdateTasks):
(WebCore::HTMLInputElement::didAttachRenderers):
* html/HTMLInputElement.h:
* html/HTMLTextAreaElement.cpp:
(WebCore::HTMLTextAreaElement::updateFocusAppearance):
* html/HTMLTextAreaElement.h:

Source/WebKit2:

Call updateFocusAppearance with RevealMode::DoNotReveal to avoid revealing the focused element.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::restoreSelectionInFocusedEditableElement):

Tools:

Added a regression test using WebKit API test.

* TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
* TestWebKitAPI/Tests/mac/FirstResponderScrollingPosition.mm: Added.
(TestWebKitAPI::didFinishLoadForFrame):
(TestWebKitAPI::TEST):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@191451 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/Element.cpp
Source/WebCore/dom/Element.h
Source/WebCore/history/CachedPage.cpp
Source/WebCore/html/HTMLAreaElement.cpp
Source/WebCore/html/HTMLAreaElement.h
Source/WebCore/html/HTMLInputElement.cpp
Source/WebCore/html/HTMLInputElement.h
Source/WebCore/html/HTMLTextAreaElement.cpp
Source/WebCore/html/HTMLTextAreaElement.h
Source/WebKit2/ChangeLog
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Tools/ChangeLog
Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
Tools/TestWebKitAPI/Tests/mac/FirstResponderScrollingPosition.mm [new file with mode: 0644]

index 02c7c0626229501a5244669eb367c8e01fa1f061..879192560f34605bb656cf718b82d5f482697d5e 100644 (file)
@@ -1,3 +1,37 @@
+2015-10-22  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION (r181972): Scroll position changes to top of youtube page when switching tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150428
+
+        Reviewed by Antti Koivisto.
+
+        The bug was caused by updateFocusAppearance in WebPage::restoreSelectionInFocusedEditableElement
+        revealing the focused element which was added in r181972. Fixed the bug by adding an option to
+        suppress this behavior here.
+
+        * dom/Document.cpp:
+        (WebCore::Document::Document):
+        (WebCore::Document::updateFocusAppearanceSoon):
+        * dom/Document.h:
+        * dom/Element.cpp:
+        (WebCore::Element::focus):
+        (WebCore::Element::updateFocusAppearanceAfterAttachIfNeeded):
+        (WebCore::Element::updateFocusAppearance):
+        * dom/Element.h:
+        * history/CachedPage.cpp:
+        (WebCore::CachedPage::restore):
+        * html/HTMLAreaElement.cpp:
+        (WebCore::HTMLAreaElement::updateFocusAppearance):
+        * html/HTMLAreaElement.h:
+        * html/HTMLInputElement.cpp:
+        (WebCore::HTMLInputElement::updateFocusAppearance):
+        (WebCore::HTMLInputElement::runPostTypeUpdateTasks):
+        (WebCore::HTMLInputElement::didAttachRenderers):
+        * html/HTMLInputElement.h:
+        * html/HTMLTextAreaElement.cpp:
+        (WebCore::HTMLTextAreaElement::updateFocusAppearance):
+        * html/HTMLTextAreaElement.h:
+
 2015-10-22  Joonghun Park  <jh718.park@samsung.com>
 
         [EFL] Fix build break since r191439
index d0603b15b9c58f3991b93e7d8746521d4f9daa3a..ea14de999413f000259d56609bb39a6f4cff401c 100644 (file)
@@ -455,7 +455,7 @@ Document::Document(Frame* frame, const URL& url, unsigned documentClasses, unsig
     , m_closeAfterStyleRecalc(false)
     , m_gotoAnchorNeededAfterStylesheetsLoad(false)
     , m_frameElementsShouldIgnoreScrolling(false)
-    , m_updateFocusAppearanceRestoresSelection(false)
+    , m_updateFocusAppearanceRestoresSelection(SelectionRestorationMode::SetDefault)
     , m_ignoreDestructiveWriteCount(0)
     , m_markers(std::make_unique<DocumentMarkerController>(*this))
     , m_updateFocusAppearanceTimer(*this, &Document::updateFocusAppearanceTimerFired)
@@ -5079,9 +5079,9 @@ void Document::statePopped(PassRefPtr<SerializedScriptValue> stateObject)
         m_pendingStateObject = stateObject;
 }
 
-void Document::updateFocusAppearanceSoon(bool restorePreviousSelection)
+void Document::updateFocusAppearanceSoon(SelectionRestorationMode mode)
 {
-    m_updateFocusAppearanceRestoresSelection = restorePreviousSelection;
+    m_updateFocusAppearanceRestoresSelection = mode;
     if (!m_updateFocusAppearanceTimer.isActive())
         m_updateFocusAppearanceTimer.startOneShot(0);
 }
index 5f552d120a31cf9ff7085d65e8a48e349a8ecb32..1da2e3d04c77da63281be2a698711f3133edeaf4 100644 (file)
@@ -274,6 +274,16 @@ enum class DocumentCompatibilityMode : unsigned char {
 
 enum DimensionsCheck { WidthDimensionsCheck = 1 << 0, HeightDimensionsCheck = 1 << 1, AllDimensionsCheck = 1 << 2 };
 
+enum class SelectionRestorationMode {
+    Restore,
+    SetDefault,
+};
+
+enum class SelectionRevealMode {
+    Reveal,
+    DoNotReveal
+};
+
 enum class HttpEquivPolicy {
     Enabled,
     DisabledBySettings,
@@ -966,7 +976,7 @@ public:
     bool hasNodesWithPlaceholderStyle() const { return m_hasNodesWithPlaceholderStyle; }
     void setHasNodesWithPlaceholderStyle() { m_hasNodesWithPlaceholderStyle = true; }
 
-    void updateFocusAppearanceSoon(bool restorePreviousSelection);
+    void updateFocusAppearanceSoon(SelectionRestorationMode);
     void cancelFocusAppearanceUpdate();
 
     // Extension for manipulating canvas drawing contexts for use in CSS
@@ -1492,7 +1502,7 @@ private:
     bool m_isDNSPrefetchEnabled;
     bool m_haveExplicitlyDisabledDNSPrefetch;
     bool m_frameElementsShouldIgnoreScrolling;
-    bool m_updateFocusAppearanceRestoresSelection;
+    SelectionRestorationMode m_updateFocusAppearanceRestoresSelection;
 
     // http://www.whatwg.org/specs/web-apps/current-work/#ignore-destructive-writes-counter
     unsigned m_ignoreDestructiveWriteCount;
index a68fa87e98f9156409f805d3ee7f99b3175c1a8d..f874220aa0597ad155e918e1b85adb9a9f7fe173 100644 (file)
@@ -2219,7 +2219,7 @@ void Element::focus(bool restorePreviousSelection, FocusDirection direction)
     if (isFormControl)
         view->setProhibitsScrolling(true);
 #endif
-    updateFocusAppearance(restorePreviousSelection);
+    updateFocusAppearance(restorePreviousSelection ? SelectionRestorationMode::Restore : SelectionRestorationMode::SetDefault);
 #if PLATFORM(IOS)
     if (isFormControl)
         view->setProhibitsScrolling(false);
@@ -2234,11 +2234,11 @@ void Element::updateFocusAppearanceAfterAttachIfNeeded()
     if (!data->needsFocusAppearanceUpdateSoonAfterAttach())
         return;
     if (isFocusable() && document().focusedElement() == this)
-        document().updateFocusAppearanceSoon(false /* don't restore selection */);
+        document().updateFocusAppearanceSoon(SelectionRestorationMode::SetDefault);
     data->setNeedsFocusAppearanceUpdateSoonAfterAttach(false);
 }
 
-void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
+void Element::updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode revealMode)
 {
     if (isRootEditableElement()) {
         Frame* frame = document().frame();
@@ -2254,9 +2254,10 @@ void Element::updateFocusAppearance(bool /*restorePreviousSelection*/)
         
         if (frame->selection().shouldChangeSelection(newSelection)) {
             frame->selection().setSelection(newSelection, FrameSelection::defaultSetSelectionOptions(), Element::defaultFocusTextStateChangeIntent());
-            frame->selection().revealSelection();
+            if (revealMode == SelectionRevealMode::Reveal)
+                frame->selection().revealSelection();
         }
-    } else if (renderer() && !renderer()->isWidget())
+    } else if (renderer() && !renderer()->isWidget() && revealMode == SelectionRevealMode::Reveal)
         renderer()->scrollRectToVisible(renderer()->anchorRect());
 }
 
index 4c719be7ff4c39ed9ea0f1e471690b32013e672c..12d1414107e5425e68c133d6d0d76b5ccc5da3b0 100644 (file)
@@ -327,7 +327,7 @@ public:
     static AXTextStateChangeIntent defaultFocusTextStateChangeIntent() { return AXTextStateChangeIntent(AXTextStateChangeTypeSelectionMove, AXTextSelection { AXTextSelectionDirectionDiscontiguous, AXTextSelectionGranularityUnknown, true }); }
     void updateFocusAppearanceAfterAttachIfNeeded();
     virtual void focus(bool restorePreviousSelection = true, FocusDirection = FocusDirectionNone);
-    virtual void updateFocusAppearance(bool restorePreviousSelection);
+    virtual void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode = SelectionRevealMode::Reveal);
     virtual void blur();
 
     String innerHTML() const;
index e30fc10b811a83d387c1f3e3be2cafea089aa88f..add64e0c1b2e37d2c564b70226e9c62324b537d4 100644 (file)
@@ -92,7 +92,7 @@ void CachedPage::restore(Page& page)
             frameView->setProhibitsScrolling(true);
         }
 #endif
-        element->updateFocusAppearance(true);
+        element->updateFocusAppearance(SelectionRestorationMode::Restore);
 #if PLATFORM(IOS)
         if (frameView)
             frameView->setProhibitsScrolling(hadProhibitsScrolling);
index 5a0ad839a9100c3d3605d032ae3c568ba8367bac..fcfeed581b176ebf11dad351888dbd676058cdc3 100644 (file)
@@ -224,7 +224,7 @@ void HTMLAreaElement::setFocus(bool shouldBeFocused)
     downcast<RenderImage>(*renderer).areaElementFocusChanged(this);
 }
     
-void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
+void HTMLAreaElement::updateFocusAppearance(SelectionRestorationMode restorationMode, SelectionRevealMode revealMode)
 {
     if (!isFocusable())
         return;
@@ -233,7 +233,7 @@ void HTMLAreaElement::updateFocusAppearance(bool restorePreviousSelection)
     if (!imageElement)
         return;
 
-    imageElement->updateFocusAppearance(restorePreviousSelection);
+    imageElement->updateFocusAppearance(restorationMode, revealMode);
 }
     
 bool HTMLAreaElement::supportsFocus() const
index c8e4bf95a158fbc444db2b6398054ce29189637b..a063b8186cf34ac44068abe0566c3b42a36dbe78 100644 (file)
@@ -57,7 +57,7 @@ private:
     virtual bool isKeyboardFocusable(KeyboardEvent*) const override;
     virtual bool isMouseFocusable() const override;
     virtual bool isFocusable() const override;
-    virtual void updateFocusAppearance(bool /*restorePreviousSelection*/) override;
+    virtual void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode) override;
     virtual void setFocus(bool) override;
 
     enum Shape { Default, Poly, Rect, Circle, Unknown };
index 971abfedd60370eec0cb0811c061fb3b04d061e2..8f961600df35478d617b96782440d84d576138b1 100644 (file)
@@ -402,17 +402,17 @@ bool HTMLInputElement::isTextFormControlMouseFocusable() const
     return HTMLTextFormControlElement::isMouseFocusable();
 }
 
-void HTMLInputElement::updateFocusAppearance(bool restorePreviousSelection)
+void HTMLInputElement::updateFocusAppearance(SelectionRestorationMode restorationMode, SelectionRevealMode revealMode)
 {
     if (isTextField()) {
-        if (!restorePreviousSelection || !hasCachedSelection())
+        if (restorationMode == SelectionRestorationMode::SetDefault || !hasCachedSelection())
             select(Element::defaultFocusTextStateChangeIntent());
         else
             restoreCachedSelection();
-        if (document().frame())
+        if (document().frame() && revealMode == SelectionRevealMode::Reveal)
             document().frame()->selection().revealSelection();
     } else
-        HTMLTextFormControlElement::updateFocusAppearance(restorePreviousSelection);
+        HTMLTextFormControlElement::updateFocusAppearance(restorationMode, revealMode);
 }
 
 void HTMLInputElement::endEditing()
@@ -528,7 +528,7 @@ inline void HTMLInputElement::runPostTypeUpdateTasks()
         setNeedsStyleRecalc(ReconstructRenderTree);
 
     if (document().focusedElement() == this)
-        updateFocusAppearance(true);
+        updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::Reveal);
 
     setChangedSinceLastFormControlChangeEvent(false);
 
@@ -785,7 +785,7 @@ void HTMLInputElement::didAttachRenderers()
     m_inputType->attach();
 
     if (document().focusedElement() == this)
-        document().updateFocusAppearanceSoon(true /* restore selection */);
+        document().updateFocusAppearanceSoon(SelectionRestorationMode::Restore);
 }
 
 void HTMLInputElement::didDetachRenderers()
index 50549f4b673beca5867ae8316f9efcf7edaee444..36ba5f95ec45b5ad26f3954f6bb54f9a35e97510 100644 (file)
@@ -343,7 +343,7 @@ private:
     virtual bool isMouseFocusable() const override final;
     virtual bool isEnumeratable() const override final;
     virtual bool supportLabels() const override final;
-    virtual void updateFocusAppearance(bool restorePreviousSelection) override final;
+    virtual void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode) override final;
     virtual bool shouldUseInputMethod() override final;
 
     virtual bool isTextFormControl() const override final { return isTextField(); }
index 7e3ba76543d17445b614c94ca042dc09e50de77e..76a3b645f2e7becf8f0d10f1d6da645b46bc6927 100644 (file)
@@ -251,9 +251,9 @@ bool HTMLTextAreaElement::isMouseFocusable() const
     return isFocusable();
 }
 
-void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection)
+void HTMLTextAreaElement::updateFocusAppearance(SelectionRestorationMode restorationMode, SelectionRevealMode revealMode)
 {
-    if (!restorePreviousSelection || !hasCachedSelection()) {
+    if (restorationMode == SelectionRestorationMode::SetDefault || !hasCachedSelection()) {
         // If this is the first focus, set a caret at the beginning of the text.  
         // This matches some browsers' behavior; see bug 11746 Comment #15.
         // http://bugs.webkit.org/show_bug.cgi?id=11746#c15
@@ -261,7 +261,7 @@ void HTMLTextAreaElement::updateFocusAppearance(bool restorePreviousSelection)
     } else
         restoreCachedSelection(Element::defaultFocusTextStateChangeIntent());
 
-    if (document().frame())
+    if (document().frame() && revealMode == SelectionRevealMode::Reveal)
         document().frame()->selection().revealSelection();
 }
 
index 608a3d107abcf229c3d48323dda7b682b2f4acf7..dca07a6a5467043e37c35500aac71c407e8a1c67 100644 (file)
@@ -108,7 +108,7 @@ private:
     virtual bool hasCustomFocusLogic() const override;
     virtual bool isMouseFocusable() const override;
     virtual bool isKeyboardFocusable(KeyboardEvent*) const override;
-    virtual void updateFocusAppearance(bool restorePreviousSelection) override;
+    virtual void updateFocusAppearance(SelectionRestorationMode, SelectionRevealMode) override;
 
     virtual void accessKeyAction(bool sendMouseEvents) override;
 
index 2f58451868ae57efa4fa9a4cc40746fca65e09cb..67830f295965bd7779fb0d48bfdecdf748027a95 100644 (file)
@@ -1,3 +1,15 @@
+2015-10-22  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION (r181972): Scroll position changes to top of youtube page when switching tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150428
+
+        Reviewed by Antti Koivisto.
+
+        Call updateFocusAppearance with RevealMode::DoNotReveal to avoid revealing the focused element.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::restoreSelectionInFocusedEditableElement):
+
 2015-10-22  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Fix a crash in GTk+ after r191402.
index f2d7ef6e5c99d2a489cb36bacd6ea76f7bc52d56..15de61d0fa7f2f11cb57957b24ca58fdf08ab8be 100644 (file)
@@ -3444,7 +3444,7 @@ void WebPage::restoreSelectionInFocusedEditableElement()
 
     if (auto document = frame.document()) {
         if (auto element = document->focusedElement())
-            element->updateFocusAppearance(true /* restoreSelection */);
+            element->updateFocusAppearance(SelectionRestorationMode::Restore, SelectionRevealMode::DoNotReveal);
     }
 }
 
index d5183fc23c56a793cffdffc707d13b18fd29781f..0db2f4958a1ea84725e824df6aff13f7d3ed2c41 100644 (file)
@@ -1,3 +1,17 @@
+2015-10-22  Ryosuke Niwa  <rniwa@webkit.org>
+
+        REGRESSION (r181972): Scroll position changes to top of youtube page when switching tabs
+        https://bugs.webkit.org/show_bug.cgi?id=150428
+
+        Reviewed by Antti Koivisto.
+
+        Added a regression test using WebKit API test.
+
+        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+        * TestWebKitAPI/Tests/mac/FirstResponderScrollingPosition.mm: Added.
+        (TestWebKitAPI::didFinishLoadForFrame):
+        (TestWebKitAPI::TEST):
+
 2015-10-22  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed. Fix GTK+ build after r191423.
index 2babed938dd51435e74ec3ad7b22d4478d2d1667..58b32c9bd6ef9db65fb8f1fce4b51b0f4fed87cf 100644 (file)
                93F7E86F14DC8E5C00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93F7E86E14DC8E5B00C84A99 /* NewFirstVisuallyNonEmptyLayoutFrames_Bundle.cpp */; };
                9B26FCCA159D16DE00CC3765 /* HTMLFormCollectionNamedItem.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B26FCB4159D15E700CC3765 /* HTMLFormCollectionNamedItem.html */; };
                9B4F8FA7159D52DD002D9F94 /* HTMLCollectionNamedItem.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */; };
+               9B7916501BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */; settings = {ASSET_TAGS = (); }; };
                A13EBBAA1B87428D00097110 /* WebProcessPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A13EBBA91B87428D00097110 /* WebProcessPlugIn.mm */; };
                A13EBBAB1B87434600097110 /* PlatformUtilitiesCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0F139E721A423A2B00F590F5 /* PlatformUtilitiesCocoa.mm */; };
                A13EBBB01B87436F00097110 /* BundleParametersPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = A13EBBAE1B87436F00097110 /* BundleParametersPlugIn.mm */; };
                9B26FCB4159D15E700CC3765 /* HTMLFormCollectionNamedItem.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = HTMLFormCollectionNamedItem.html; sourceTree = "<group>"; };
                9B4F8FA3159D52B1002D9F94 /* HTMLCollectionNamedItem.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HTMLCollectionNamedItem.mm; sourceTree = "<group>"; };
                9B4F8FA6159D52CA002D9F94 /* HTMLCollectionNamedItem.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = HTMLCollectionNamedItem.html; sourceTree = "<group>"; };
+               9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FirstResponderScrollingPosition.mm; sourceTree = "<group>"; };
                A13EBB491B87339E00097110 /* TestWebKitAPI.wkbundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TestWebKitAPI.wkbundle; sourceTree = BUILT_PRODUCTS_DIR; };
                A13EBB521B87346600097110 /* WebProcessPlugIn.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = WebProcessPlugIn.xcconfig; sourceTree = "<group>"; };
                A13EBB541B8734E000097110 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
                                7A99D9931AD4A29D00373141 /* MenuTypesForMouseEvents.mm */,
                                E19DB9781B32137C00DB38D4 /* NavigatorLanguage.mm */,
                                A57A34EF16AF677200C2501F /* PageVisibilityStateWithWindowChanges.mm */,
+                               9B79164F1BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm */,
                                00BC16851680FE810065F1E5 /* PublicSuffix.mm */,
                                37C784DE197C8F2E0010A496 /* RenderedImageFromDOMNode.mm */,
                                3722C8681461E03E00C45D00 /* RenderedImageFromDOMRange.mm */,
                                A1C4FB6E1BACCE50003742D0 /* QuickLook.mm in Sources */,
                                7A5623111AD5AF3E0096B920 /* MenuTypesForMouseEvents.cpp in Sources */,
                                51CB4AD81B3A079C00C1B1C6 /* ModalAlertsSPI.cpp in Sources */,
+                               9B7916501BD89D0D00D50B8F /* FirstResponderScrollingPosition.mm in Sources */,
                                1CF0D3791BBF2F3D00B4EF54 /* WKRetainPtr.cpp in Sources */,
                                26F6E1F01ADC749B00DE696B /* DFAMinimizer.cpp in Sources */,
                                260BA5791B1D2E7B004FA07C /* DFACombiner.cpp in Sources */,
diff --git a/Tools/TestWebKitAPI/Tests/mac/FirstResponderScrollingPosition.mm b/Tools/TestWebKitAPI/Tests/mac/FirstResponderScrollingPosition.mm
new file mode 100644 (file)
index 0000000..19e71b5
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2011, 2015 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "JavaScriptTest.h"
+#import "PlatformUtilities.h"
+#import "PlatformWebView.h"
+#import <WebKit/WKRetainPtr.h>
+#import <WebKit/WKPage.h>
+#import <WebKit/WKPreferencesPrivate.h>
+#import <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+    
+static bool didFinishLoad;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+    didFinishLoad = true;
+}
+
+TEST(WebKit2, FirstResponderScrollingPosition)
+{
+    WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextWithInjectedBundle());
+
+    // Turn off threaded scrolling; synchronously waiting for the main thread scroll position to
+    // update using WKPageForceRepaint would be better, but for some reason the test still fails occasionally.
+    WKRetainPtr<WKPageGroupRef> pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(Util::toWK("NoThreadedScrollingPageGroup").get()));
+    WKPreferencesRef preferences = WKPageGroupGetPreferences(pageGroup.get());
+    WKPreferencesSetThreadedScrollingEnabled(preferences, false);
+
+    RetainPtr<NSWindow> window = adoptNS([[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 800, 600)
+        styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]);
+    [window.get() makeKeyAndOrderFront:nil];
+    EXPECT_TRUE([window.get() isVisible]);
+
+    PlatformWebView webView(context.get(), pageGroup.get());
+
+    WKPageLoaderClientV0 loaderClient;
+    memset(&loaderClient, 0, sizeof(loaderClient));
+    loaderClient.base.version = 0;
+    loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+    WKPageSetPageLoaderClient(webView.page(), &loaderClient.base);
+    
+    [window.get().contentView addSubview:webView.platformView()];
+    [window.get() makeFirstResponder:webView.platformView()];
+
+    WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple-tall", "html"));
+    WKPageLoadURL(webView.page(), url.get());
+    Util::run(&didFinishLoad);
+    didFinishLoad = false;
+
+    EXPECT_JS_EQ(webView.page(), "var input = document.createElement('input');"
+        "document.body.insertBefore(input, document.body.firstChild);"
+        "input.focus(); false", "false");
+    EXPECT_JS_EQ(webView.page(), "window.scrollY", "0");
+
+    ASSERT_TRUE([webView.platformView() respondsToSelector:@selector(scrollLineDown:)]);
+    [webView.platformView() scrollLineDown:nil];
+
+    EXPECT_JS_EQ(webView.page(), "window.scrollY", "40");
+
+    PlatformWebView newWebView(context.get(), pageGroup.get());
+    WKPageSetPageLoaderClient(newWebView.page(), &loaderClient.base);
+
+    [window.get().contentView addSubview:newWebView.platformView()];
+    [window.get() makeFirstResponder:newWebView.platformView()];
+
+    WKPageLoadURL(newWebView.page(), url.get());
+    Util::run(&didFinishLoad);
+
+    EXPECT_JS_EQ(webView.page(), "window.scrollY", "40");
+    EXPECT_JS_EQ(newWebView.page(), "window.scrollY", "0");
+
+    [window.get() makeFirstResponder:webView.platformView()];
+
+    EXPECT_JS_EQ(webView.page(), "window.scrollY", "40");
+    EXPECT_JS_EQ(newWebView.page(), "window.scrollY", "0");
+}
+    
+} // namespace TestWebKitAPI