diff --git a/DEPS b/DEPS index e958979..c23563f 100644 --- a/DEPS +++ b/DEPS
@@ -39,7 +39,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '7fb4f8bd031eda87e1da9bc0f749968c0e872e6f', + 'skia_revision': '351c0d24f1c093ca48d0d832b1d64df8644f87b7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -59,7 +59,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': 'f1fa151e146d70c5e031726581e176a8c7d0d579', + 'pdfium_revision': '55265016faac358266af280db6c62afa34ce2891', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -87,7 +87,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling NaCl # and whatever else without interference from each other. - 'nacl_revision': '878664c34e02d61eed4cc9cf64aaea02123e9256', + 'nacl_revision': '31d93be091724bc94f4bbee5de70e2e7aa174ae6', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling dEQP # and whatever else without interference from each other. @@ -131,7 +131,7 @@ Var('chromium_git') + '/external/colorama.git' + '@' + '799604a1041e9b3bc5d2789ecbd7e8db2e18e6b8', 'src/third_party/icu': - Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'e466f6ac8f60bb9697af4a91c6911c6fc4aec95f', + Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '6d3b55dfa17d9a597c064eeef7ceac18c73184b7', 'src/third_party/hunspell_dictionaries': Var('chromium_git') + '/chromium/deps/hunspell_dictionaries.git' + '@' + 'c106afdcec5d3de2622e19f1b3294c47bbd8bd72', @@ -267,7 +267,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - 'c56019de05c674d27b24ff4a6d5f1448fd923f09', + '7942605f5c11af22decaa83528b72d1d51d9283d', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/android_webview/DEPS b/android_webview/DEPS index cd20d21f..609c15cf 100644 --- a/android_webview/DEPS +++ b/android_webview/DEPS
@@ -14,6 +14,7 @@ "+content/public/common", "+crypto", "+gpu", + "+grit/components_strings.h", "+jni", "+net", "+skia",
diff --git a/android_webview/android_webview_tests.gypi b/android_webview/android_webview_tests.gypi index c87b792..ab92ffc 100644 --- a/android_webview/android_webview_tests.gypi +++ b/android_webview/android_webview_tests.gypi
@@ -34,7 +34,7 @@ '<(asset_location)/full_screen_video_test.html', '<(asset_location)/full_screen_video_inside_div_test.html', '<(asset_location)/multiple_videos_test.html', - '<(asset_location)/video.webm', + '<(asset_location)/video.mp4', '<(asset_location)/visual_state_during_fullscreen_test.html', '<(asset_location)/visual_state_waits_for_js_test.html', '<(asset_location)/visual_state_waits_for_js_detached_test.html', @@ -62,7 +62,7 @@ '<(java_in_dir)/assets/full_screen_video_test.html', '<(java_in_dir)/assets/full_screen_video_inside_div_test.html', '<(java_in_dir)/assets/multiple_videos_test.html', - '<(java_in_dir)/assets/video.webm', + '<(java_in_dir)/assets/video.mp4', '<(java_in_dir)/assets/visual_state_during_fullscreen_test.html', '<(java_in_dir)/assets/visual_state_waits_for_js_test.html', '<(java_in_dir)/assets/visual_state_waits_for_js_detached_test.html',
diff --git a/android_webview/browser/aw_contents_client_bridge_base.h b/android_webview/browser/aw_contents_client_bridge_base.h index 6ac592b9..00598ba 100644 --- a/android_webview/browser/aw_contents_client_bridge_base.h +++ b/android_webview/browser/aw_contents_client_bridge_base.h
@@ -59,7 +59,6 @@ virtual void RunBeforeUnloadDialog( const GURL& origin_url, - const base::string16& message_text, const content::JavaScriptDialogManager::DialogClosedCallback& callback) = 0;
diff --git a/android_webview/browser/aw_javascript_dialog_manager.cc b/android_webview/browser/aw_javascript_dialog_manager.cc index afe9bda..acc139e 100644 --- a/android_webview/browser/aw_javascript_dialog_manager.cc +++ b/android_webview/browser/aw_javascript_dialog_manager.cc
@@ -39,7 +39,6 @@ void AwJavaScriptDialogManager::RunBeforeUnloadDialog( content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { AwContentsClientBridgeBase* bridge = @@ -50,7 +49,6 @@ } bridge->RunBeforeUnloadDialog(web_contents->GetURL(), - message_text, callback); }
diff --git a/android_webview/browser/aw_javascript_dialog_manager.h b/android_webview/browser/aw_javascript_dialog_manager.h index e5b3815..9d0bf4a 100644 --- a/android_webview/browser/aw_javascript_dialog_manager.h +++ b/android_webview/browser/aw_javascript_dialog_manager.h
@@ -25,7 +25,6 @@ const DialogClosedCallback& callback, bool* did_suppress_message) override; void RunBeforeUnloadDialog(content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override; void CancelActiveAndPendingDialogs(
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index 94be4df..fd8040be 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -5,6 +5,7 @@ package org.chromium.android_webview; import android.content.Context; +import android.os.StrictMode; import org.chromium.android_webview.policy.AwPolicyProvider; import org.chromium.base.CommandLine; @@ -93,20 +94,26 @@ } private static void tryObtainingDataDirLockOrDie(Context context) { - String dataPath = PathUtils.getDataDirectory(context); - File lockFile = new File(dataPath, EXCLUSIVE_LOCK_FILE); - boolean success = false; + StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); + StrictMode.allowThreadDiskWrites(); try { - // Note that the file is not closed intentionally. - RandomAccessFile file = new RandomAccessFile(lockFile, "rw"); - sExclusiveFileLock = file.getChannel().tryLock(); - success = sExclusiveFileLock != null; - } catch (IOException e) { - Log.w(TAG, "Failed to create lock file " + lockFile, e); - } - if (!success) { - Log.w(TAG, "The app may have another WebView opened in a separate process. " - + "This is not recommended and may stop working in future versions."); + String dataPath = PathUtils.getDataDirectory(context); + File lockFile = new File(dataPath, EXCLUSIVE_LOCK_FILE); + boolean success = false; + try { + // Note that the file is not closed intentionally. + RandomAccessFile file = new RandomAccessFile(lockFile, "rw"); + sExclusiveFileLock = file.getChannel().tryLock(); + success = sExclusiveFileLock != null; + } catch (IOException e) { + Log.w(TAG, "Failed to create lock file " + lockFile, e); + } + if (!success) { + Log.w(TAG, "The app may have another WebView opened in a separate process. " + + "This is not recommended and may stop working in future versions."); + } + } finally { + StrictMode.setThreadPolicy(oldPolicy); } } }
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java index ff9e489f..32ee9aa9 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/KeySystemTest.java
@@ -4,7 +4,6 @@ package org.chromium.android_webview.test; -import android.os.Build; import android.test.suitebuilder.annotation.SmallTest; import org.chromium.android_webview.AwContents; @@ -67,16 +66,12 @@ + " navigator.requestMediaKeySystemAccess(keySystem, [{}]).then(" + " success, failure);" + "}" - + "function areProprietaryCodecsSupported() {" - + " var video = document.createElement('video');" - + " return video.canPlayType('video/mp4; codecs=\"avc1\"');" - + "}" + "</script> </html>"; } private String isKeySystemSupported(String keySystem) throws Exception { - executeJavaScriptAndWaitForResult( - mAwContents, mContentsClient, "isKeySystemSupported('" + keySystem + "')"); + executeJavaScriptAndWaitForResult(mAwContents, mContentsClient, + "isKeySystemSupported('" + keySystem + "')"); poll(new Callable<Boolean>() { @Override @@ -88,12 +83,6 @@ return getResultFromJS(); } - private boolean areProprietaryCodecsSupported() throws Exception { - String result = executeJavaScriptAndWaitForResult( - mAwContents, mContentsClient, "areProprietaryCodecsSupported()"); - return !result.isEmpty(); - } - private String getResultFromJS() { String result = "null"; try { @@ -105,18 +94,6 @@ return result; } - private String getPlatformKeySystemExpectations() throws Exception { - // Android key systems only support non-proprietary codecs on Lollipop+. - // When neither is true isKeySystemSupported() will return an error for - // all key systems except ClearKey (which is handled by Chrome itself). - if (!areProprietaryCodecsSupported() - && Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { - return "\"NotSupportedError\""; - } - - return "\"supported\""; - } - @Feature({"AndroidWebView"}) @SmallTest public void testSupportClearKeySystem() throws Throwable { @@ -126,8 +103,7 @@ @Feature({"AndroidWebView"}) @SmallTest public void testSupportWidevineKeySystem() throws Throwable { - assertEquals( - getPlatformKeySystemExpectations(), isKeySystemSupported("com.widevine.alpha")); + assertEquals("\"supported\"", isKeySystemSupported("com.widevine.alpha")); } @Feature({"AndroidWebView"}) @@ -139,8 +115,7 @@ @Feature({"AndroidWebView"}) @SmallTest public void testSupportPlatformKeySystem() throws Throwable { - assertEquals(getPlatformKeySystemExpectations(), - isKeySystemSupported("x-com.oem.test-keysystem")); + assertEquals("\"supported\"", isKeySystemSupported("x-com.oem.test-keysystem")); } @Feature({"AndroidWebView"})
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java index 288ed3b8..4557d2c 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PopupWindowTest.java
@@ -132,14 +132,14 @@ } // Copied from imeTest.java. - private void assertWaitForSelectActionBarStatus(final boolean show, final ContentViewCore cvc) + private void assertWaitForSelectActionBarStatus(boolean show, final ContentViewCore cvc) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(show, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return show == cvc.isSelectActionBarShowing(); + public Boolean call() { + return cvc.isSelectActionBarShowing(); } - }); + })); } private void hideSelectActionMode(final ContentViewCore cvc) {
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java index ec62fdb..e9c9073 100644 --- a/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java +++ b/android_webview/javatests/src/org/chromium/android_webview/test/PostMessageTest.java
@@ -4,13 +4,12 @@ package org.chromium.android_webview.test; +import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; + import android.os.Handler; import android.test.suitebuilder.annotation.SmallTest; import android.webkit.JavascriptInterface; -import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout; -import static org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; - import org.chromium.android_webview.AwContents; import org.chromium.android_webview.AwMessagePort; import org.chromium.android_webview.AwMessagePortService; @@ -21,6 +20,7 @@ import org.chromium.base.test.util.Feature; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content.browser.test.util.TestCallbackHelperContainer.OnPageFinishedHelper; import org.chromium.net.test.util.TestWebServer; import java.util.concurrent.Callable; @@ -156,15 +156,13 @@ + "</body></html>"; // Call on non-UI thread. - private void expectTitle(final String title) throws Throwable { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + private void expectTitle(String title) throws Throwable { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(title, new Callable<String>() { @Override - public boolean isSatisfied() { - updateFailureReason( - "Received title " + mAwContents.getTitle() + " while expecting " + title); - return mAwContents.getTitle().equals(title); + public String call() { + return mAwContents.getTitle(); } - }); + })); } private void loadPage(String page) throws Throwable {
diff --git a/android_webview/native/BUILD.gn b/android_webview/native/BUILD.gn index 6e09894..94c4613 100644 --- a/android_webview/native/BUILD.gn +++ b/android_webview/native/BUILD.gn
@@ -14,6 +14,7 @@ "//cc:cc", "//components/autofill/content/browser:browser", "//components/devtools_http_handler:devtools_http_handler", + "//components/strings", "//components/web_contents_delegate_android:web_contents_delegate_android", "//content/public/common", "//device/battery:mojo_bindings",
diff --git a/android_webview/native/aw_contents_client_bridge.cc b/android_webview/native/aw_contents_client_bridge.cc index 4d2fd4dcb..d5b3b44 100644 --- a/android_webview/native/aw_contents_client_bridge.cc +++ b/android_webview/native/aw_contents_client_bridge.cc
@@ -17,12 +17,14 @@ #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" #include "crypto/scoped_openssl_types.h" +#include "grit/components_strings.h" #include "jni/AwContentsClientBridge_jni.h" #include "net/android/keystore_openssl.h" #include "net/cert/x509_certificate.h" #include "net/ssl/openssl_client_key_store.h" #include "net/ssl/ssl_cert_request_info.h" #include "net/ssl/ssl_client_cert_type.h" +#include "ui/base/l10n/l10n_util.h" #include "url/gurl.h" using base::android::AttachCurrentThread; @@ -318,7 +320,6 @@ void AwContentsClientBridge::RunBeforeUnloadDialog( const GURL& origin_url, - const base::string16& message_text, const content::JavaScriptDialogManager::DialogClosedCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); JNIEnv* env = AttachCurrentThread(); @@ -329,6 +330,9 @@ return; } + const base::string16 message_text = + l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE); + int callback_id = pending_js_dialog_callbacks_.Add( new content::JavaScriptDialogManager::DialogClosedCallback(callback)); ScopedJavaLocalRef<jstring> jurl(
diff --git a/android_webview/native/aw_contents_client_bridge.h b/android_webview/native/aw_contents_client_bridge.h index 2af63ca..d415dfa5 100644 --- a/android_webview/native/aw_contents_client_bridge.h +++ b/android_webview/native/aw_contents_client_bridge.h
@@ -51,7 +51,6 @@ override; void RunBeforeUnloadDialog( const GURL& origin_url, - const base::string16& message_text, const content::JavaScriptDialogManager::DialogClosedCallback& callback) override; bool ShouldOverrideUrlLoading(const base::string16& url,
diff --git a/android_webview/native/webview_native.gyp b/android_webview/native/webview_native.gyp index 0b57cae..14c371e 100644 --- a/android_webview/native/webview_native.gyp +++ b/android_webview/native/webview_native.gyp
@@ -18,6 +18,7 @@ '../../components/components.gyp:autofill_content_browser', '../../components/components.gyp:devtools_http_handler', '../../components/components.gyp:web_contents_delegate_android', + '../../components/components_strings.gyp:components_strings', '../../content/content.gyp:content_common', '../../media/media.gyp:player_android', '../../net/net.gyp:net',
diff --git a/android_webview/test/BUILD.gn b/android_webview/test/BUILD.gn index 68b71d4..92b46fa 100644 --- a/android_webview/test/BUILD.gn +++ b/android_webview/test/BUILD.gn
@@ -65,7 +65,7 @@ "shell/assets/full_screen_video_inside_div_test.html", "shell/assets/full_screen_video_test.html", "shell/assets/multiple_videos_test.html", - "shell/assets/video.webm", + "shell/assets/video.mp4", "shell/assets/visual_state_during_fullscreen_test.html", "shell/assets/visual_state_on_page_commit_visible_test.html", "shell/assets/visual_state_waits_for_js_detached_test.html",
diff --git a/android_webview/test/shell/assets/full_screen_video_inside_div_test.html b/android_webview/test/shell/assets/full_screen_video_inside_div_test.html index f76d98110..7a8f4f2 100644 --- a/android_webview/test/shell/assets/full_screen_video_inside_div_test.html +++ b/android_webview/test/shell/assets/full_screen_video_inside_div_test.html
@@ -9,7 +9,7 @@ <div id='div'> <button id="playControl" style='padding:10px 10px;' onclick="playVideo(); return false">Play</button> <video style = 'width: 300px; height: 300px;' id='video'> - <source src="video.webm" type="video/webm"> + <source src="video.mp4" type="video/mp4"> </video> </div> </body>
diff --git a/android_webview/test/shell/assets/full_screen_video_test.html b/android_webview/test/shell/assets/full_screen_video_test.html index 6d1979d..c046e70 100644 --- a/android_webview/test/shell/assets/full_screen_video_test.html +++ b/android_webview/test/shell/assets/full_screen_video_test.html
@@ -9,7 +9,7 @@ <button id="fullscreenControl" autofocus style ='padding:10px 10px;' onclick="goFullscreen('video'); return false">Go fullscreen</button> <button id="playControl" style='padding:10px 10px;' onclick="playVideo(); return false">Play</button> <video style = 'width: 10px; height: 10px;' id='video' controls> - <source src="video.webm" type="video/webm"> + <source src="video.mp4" type="video/mp4"> </video> </body> </html>
diff --git a/android_webview/test/shell/assets/multiple_videos_test.html b/android_webview/test/shell/assets/multiple_videos_test.html index 70c3945..12ded883 100644 --- a/android_webview/test/shell/assets/multiple_videos_test.html +++ b/android_webview/test/shell/assets/multiple_videos_test.html
@@ -18,11 +18,11 @@ <button id="playSecondButton" style='padding:10px 10px;' onclick="playSecondVideo(); return false">Play second</button> <video style='width: 10px; height: 10px;' id='firstVideo' controls> - <source src="video.webm" type="video/webm"> + <source src="video.mp4" type="video/mp4"> </video> <video style='width: 10px; height: 10px;' id='secondVideo' controls> - <source src="video.webm" type="video/webm"> + <source src="video.mp4" type="video/mp4"> </video> </body>
diff --git a/android_webview/test/shell/assets/video.mp4 b/android_webview/test/shell/assets/video.mp4 new file mode 100644 index 0000000..3763b59 --- /dev/null +++ b/android_webview/test/shell/assets/video.mp4 Binary files differ
diff --git a/android_webview/test/shell/assets/video.webm b/android_webview/test/shell/assets/video.webm deleted file mode 100644 index 7bfc552..0000000 --- a/android_webview/test/shell/assets/video.webm +++ /dev/null Binary files differ
diff --git a/android_webview/ui/grit_components_whitelist.txt b/android_webview/ui/grit_components_whitelist.txt index f1739e8..84238b6 100644 --- a/android_webview/ui/grit_components_whitelist.txt +++ b/android_webview/ui/grit_components_whitelist.txt
@@ -1,3 +1,4 @@ IDS_POLICY_LIST_ENTRY_ERROR IDS_POLICY_SCHEMA_VALIDATION_ERROR IDS_POLICY_TYPE_ERROR +IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE
diff --git a/ash/wm/ash_focus_rules_unittest.cc b/ash/wm/ash_focus_rules_unittest.cc index fe06fa47..542f10f 100644 --- a/ash/wm/ash_focus_rules_unittest.cc +++ b/ash/wm/ash_focus_rules_unittest.cc
@@ -14,6 +14,7 @@ #include "ash/wm/window_util.h" #include "ui/aura/client/aura_constants.h" #include "ui/aura/client/window_tree_client.h" +#include "ui/views/test/widget_test.h" #include "ui/views/view.h" #include "ui/views/widget/widget.h" @@ -186,5 +187,23 @@ EXPECT_TRUE(normal_window->HasFocus()); } +// Tests that if a widget has a view which should be initially focused, this +// view doesn't get focused if the widget shows behind the lock screen. +TEST_F(LockScreenAshFocusRulesTest, PreventFocusChangeWithLockScreenPresent) { + BlockUserSession(BLOCKED_BY_LOCK_SCREEN); + EXPECT_TRUE(shell()->session_state_delegate()->IsScreenLocked()); + + views::test::TestInitialFocusWidgetDelegate delegate(CurrentContext()); + EXPECT_FALSE(delegate.view()->HasFocus()); + delegate.GetWidget()->Show(); + EXPECT_FALSE(delegate.GetWidget()->IsActive()); + EXPECT_FALSE(delegate.view()->HasFocus()); + + UnblockUserSession(); + EXPECT_FALSE(shell()->session_state_delegate()->IsScreenLocked()); + EXPECT_TRUE(delegate.GetWidget()->IsActive()); + EXPECT_TRUE(delegate.view()->HasFocus()); +} + } // namespace test } // namespace ash
diff --git a/base/BUILD.gn b/base/BUILD.gn index 0b41b0e..2159d22 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -1593,6 +1593,15 @@ ] } + loadable_module("scoped_handle_test_dll") { + sources = [ + "win/scoped_handle_test_dll.cc", + ] + deps = [ + ":base", + ] + } + if (target_cpu == "x64") { # Must be a shared library so that it can be unloaded during testing. shared_library("base_profiler_test_support_library") { @@ -1851,6 +1860,7 @@ "win/shortcut_unittest.cc", "win/startup_information_unittest.cc", "win/win_util_unittest.cc", + "win/windows_version_unittest.cc", "win/wrapped_window_proc_unittest.cc", ] @@ -1956,9 +1966,12 @@ set_sources_assignment_filter(sources_assignment_filter) } - if (is_win && target_cpu == "x64") { - sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ] - deps += [ ":base_profiler_test_support_library" ] + if (is_win) { + deps += [ "//base:scoped_handle_test_dll" ] + if (target_cpu == "x64") { + sources += [ "profiler/win32_stack_frame_unwinder_unittest.cc" ] + deps += [ ":base_profiler_test_support_library" ] + } } if (use_experimental_allocator_shim) {
diff --git a/base/base.gyp b/base/base.gyp index 5b20cfe..46752e3 100644 --- a/base/base.gyp +++ b/base/base.gyp
@@ -599,6 +599,7 @@ 'win/shortcut_unittest.cc', 'win/startup_information_unittest.cc', 'win/win_util_unittest.cc', + 'win/windows_version_unittest.cc', 'win/wrapped_window_proc_unittest.cc', '<@(trace_event_test_sources)', ], @@ -699,6 +700,9 @@ ], }], ['OS == "win"', { + 'dependencies': [ + 'scoped_handle_test_dll' + ], 'sources!': [ 'file_descriptor_shuffle_unittest.cc', 'files/dir_reader_posix_unittest.cc', @@ -1680,6 +1684,16 @@ }, }, }, + { + 'target_name': 'scoped_handle_test_dll', + 'type': 'loadable_module', + 'dependencies': [ + 'base', + ], + 'sources': [ + 'win/scoped_handle_test_dll.cc', + ], + }, ], }], ['test_isolation_mode != "noop"', {
diff --git a/base/base_switches.cc b/base/base_switches.cc index 02b22298..d1a38e4b 100644 --- a/base/base_switches.cc +++ b/base/base_switches.cc
@@ -46,6 +46,11 @@ // to the test framework that the current process is a child process. const char kTestChildProcess[] = "test-child-process"; +// When running certain tests that spawn child processes, this switch indicates +// to the test framework that the current process should not initialize ICU to +// avoid creating any scoped handles too early in startup. +const char kTestDoNotInitializeIcu[] = "test-do-not-initialize-icu"; + // Gives the default maximal active V-logging level; 0 is the default. // Normally positive values are used for V-logging levels. const char kV[] = "v";
diff --git a/base/base_switches.h b/base/base_switches.h index c97a629..300c5f7 100644 --- a/base/base_switches.h +++ b/base/base_switches.h
@@ -22,6 +22,7 @@ extern const char kProfilerTiming[]; extern const char kProfilerTimingDisabledValue[]; extern const char kTestChildProcess[]; +extern const char kTestDoNotInitializeIcu[]; extern const char kTraceToFile[]; extern const char kTraceToFileName[]; extern const char kV[];
diff --git a/base/logging.cc b/base/logging.cc index 9ad50e8..8ff22608 100644 --- a/base/logging.cc +++ b/base/logging.cc
@@ -862,7 +862,7 @@ } void RawLog(int level, const char* message) { - if (level >= g_min_log_level) { + if (level >= g_min_log_level && message) { size_t bytes_written = 0; const size_t message_len = strlen(message); int rv; @@ -915,5 +915,5 @@ } // namespace logging std::ostream& std::operator<<(std::ostream& out, const wchar_t* wstr) { - return out << base::WideToUTF8(wstr); + return out << (wstr ? base::WideToUTF8(wstr) : std::string()); }
diff --git a/base/metrics/field_trial.cc b/base/metrics/field_trial.cc index 486d639..a0cfdce 100644 --- a/base/metrics/field_trial.cc +++ b/base/metrics/field_trial.cc
@@ -315,7 +315,8 @@ : entropy_provider_(entropy_provider), observer_list_(new ObserverListThreadSafe<FieldTrialList::Observer>( ObserverListBase<FieldTrialList::Observer>::NOTIFY_EXISTING_ONLY)) { - DCHECK(!global_); + // TODO(asvitkine): Turn into a DCHECK after http://crbug.com/359406 is fixed. + CHECK(!global_); DCHECK(!used_without_global_); global_ = this;
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc index 82510a20..74bd9ddf 100644 --- a/base/test/test_suite.cc +++ b/base/test/test_suite.cc
@@ -331,7 +331,10 @@ logging::SetLogAssertHandler(UnitTestAssertHandler); } - i18n::InitializeICU(); + if (!CommandLine::ForCurrentProcess()->HasSwitch( + switches::kTestDoNotInitializeIcu)) { + i18n::InitializeICU(); + } // On the Mac OS X command line, the default locale is *_POSIX. In Chromium, // the locale is set via an OS X locale API and is never *_POSIX. // Some tests (such as those involving word break iterator) will behave
diff --git a/base/win/scoped_handle.cc b/base/win/scoped_handle.cc index 99dae66..7fa8b43 100644 --- a/base/win/scoped_handle.cc +++ b/base/win/scoped_handle.cc
@@ -22,6 +22,9 @@ typedef void* (*GetHandleVerifierFn)(); } +// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx +extern "C" IMAGE_DOS_HEADER __ImageBase; + namespace { struct HandleHash { @@ -85,6 +88,7 @@ const void* pc1, const void* pc2); virtual void Disable(); virtual void OnHandleBeingClosed(HANDLE handle); + virtual HMODULE GetModule() const; private: ~ActiveVerifier(); // Not implemented. @@ -242,6 +246,10 @@ CHECK(false); // CloseHandle called on tracked handle. } +HMODULE ActiveVerifier::GetModule() const { + return reinterpret_cast<HMODULE>(&__ImageBase); +} + } // namespace void* GetHandleVerifier() { @@ -276,5 +284,9 @@ return ActiveVerifier::Get()->OnHandleBeingClosed(handle); } +HMODULE GetHandleVerifierModuleForTesting() { + return g_active_verifier->GetModule(); +} + } // namespace win } // namespace base
diff --git a/base/win/scoped_handle.h b/base/win/scoped_handle.h index ac01485..6603e68 100644 --- a/base/win/scoped_handle.h +++ b/base/win/scoped_handle.h
@@ -171,13 +171,17 @@ // This function may be called by the embedder to disable the use of // VerifierTraits at runtime. It has no effect if DummyVerifierTraits is used // for ScopedHandle. -void BASE_EXPORT DisableHandleVerifier(); +BASE_EXPORT void DisableHandleVerifier(); // This should be called whenever the OS is closing a handle, if extended // verification of improper handle closing is desired. If |handle| is being // tracked by the handle verifier and ScopedHandle is not the one closing it, // a CHECK is generated. -void BASE_EXPORT OnHandleBeingClosed(HANDLE handle); +BASE_EXPORT void OnHandleBeingClosed(HANDLE handle); + +// This testing function returns the module that the ActiveVerifier concrete +// implementation was instantiated in. +BASE_EXPORT HMODULE GetHandleVerifierModuleForTesting(); } // namespace win } // namespace base
diff --git a/base/win/scoped_handle_test_dll.cc b/base/win/scoped_handle_test_dll.cc new file mode 100644 index 0000000..e6e1215d --- /dev/null +++ b/base/win/scoped_handle_test_dll.cc
@@ -0,0 +1,126 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <windows.h> + +#include <vector> + +#include "base/win/scoped_handle.h" + +// http://blogs.msdn.com/oldnewthing/archive/2004/10/25/247180.aspx +extern "C" IMAGE_DOS_HEADER __ImageBase; + +namespace base { +namespace win { +namespace testing { + +extern "C" bool __declspec(dllexport) RunTest(); + +namespace { + +struct ThreadParams { + HANDLE ready_event; + HANDLE start_event; +}; + +// Note, this must use all native functions to avoid instantiating the +// ActiveVerifier. e.g. can't use base::Thread or even base::PlatformThread. +DWORD __stdcall ThreadFunc(void* params) { + ThreadParams* thread_params = reinterpret_cast<ThreadParams*>(params); + HANDLE handle = ::CreateMutex(nullptr, false, nullptr); + + ::SetEvent(thread_params->ready_event); + ::WaitForSingleObject(thread_params->start_event, INFINITE); + ScopedHandle handle_holder(handle); + return 0; +} + +bool InternalRunThreadTest() { + std::vector<HANDLE> threads_; + // From manual testing, the bug fixed by crrev.com/678736a starts reliably + // causing handle verifier asserts to trigger at around 100 threads, so make + // it 200 to be sure to detect any future regressions. + const size_t kNumThreads = 200; + + // bManualReset is set to true to allow signalling multiple threads. + HANDLE start_event = ::CreateEvent(nullptr, true, false, nullptr); + if (!start_event) + return false; + + HANDLE ready_event = CreateEvent(nullptr, false, false, nullptr); + if (!ready_event) + return false; + + ThreadParams thread_params = { ready_event, start_event }; + + for (size_t i = 0; i < kNumThreads; i++) { + HANDLE thread_handle = + ::CreateThread(nullptr, 0, ThreadFunc, + reinterpret_cast<void*>(&thread_params), 0, nullptr); + if (!thread_handle) + break; + ::WaitForSingleObject(ready_event, INFINITE); + threads_.push_back(thread_handle); + } + + ::CloseHandle(ready_event); + + if (threads_.size() != kNumThreads) { + for (const auto& thread : threads_) + ::CloseHandle(thread); + ::CloseHandle(start_event); + return false; + } + + ::SetEvent(start_event); + ::CloseHandle(start_event); + for (const auto& thread : threads_) { + ::WaitForSingleObject(thread, INFINITE); + ::CloseHandle(thread); + } + + return true; +} + +bool InternalRunLocationTest() { + // Create a new handle and then set LastError again. + HANDLE handle = ::CreateMutex(nullptr, false, nullptr); + if (!handle) + return false; + ScopedHandle handle_holder(handle); + + HMODULE verifier_module = GetHandleVerifierModuleForTesting(); + if (!verifier_module) + return false; + + // Get my module + HMODULE my_module = reinterpret_cast<HMODULE>(&__ImageBase); + if (!my_module) + return false; + + HMODULE main_module = ::GetModuleHandle(NULL); + +#if defined(COMPONENT_BUILD) + // In a component build ActiveVerifier will always be created inside base.dll + // as the code always lives there. + if (verifier_module == my_module || verifier_module == main_module) + return false; +#else + // In a non-component build, ActiveVerifier should always be created in the + // version of base linked with the main executable. + if (verifier_module == my_module || verifier_module != main_module) + return false; +#endif + return true; +} + +} // namespace + +bool RunTest() { + return InternalRunThreadTest() && InternalRunLocationTest(); +} + +} // testing +} // win +} // base
diff --git a/base/win/scoped_handle_unittest.cc b/base/win/scoped_handle_unittest.cc index 598e3f4..2d90f9fcf 100644 --- a/base/win/scoped_handle_unittest.cc +++ b/base/win/scoped_handle_unittest.cc
@@ -5,15 +5,24 @@ #include <windows.h> #include <winternl.h> +#include "base/base_switches.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/scoped_native_library.h" +#include "base/test/multiprocess_test.h" +#include "base/test/test_timeouts.h" #include "base/win/scoped_handle.h" -#include <utility> - #include "testing/gtest/include/gtest/gtest.h" +#include "testing/multiprocess_func_list.h" namespace base { namespace win { +namespace testing { +extern "C" bool __declspec(dllexport) RunTest(); +} // namespace testing + TEST(ScopedHandleTest, ScopedHandle) { // Any illegal error code will do. We just need to test that it is preserved // by ScopedHandle to avoid bug 528394. @@ -90,5 +99,36 @@ ASSERT_TRUE(::CloseHandle(handle)); } +TEST(ScopedHandleTest, MultiProcess) { + // Initializing ICU in the child process causes a scoped handle to be created + // before the test gets a chance to test the race condition, so disable ICU + // for the child process here. + CommandLine command_line(base::GetMultiProcessTestChildBaseCommandLine()); + command_line.AppendSwitch(switches::kTestDoNotInitializeIcu); + + base::Process test_child_process = base::SpawnMultiProcessTestChild( + "ActiveVerifierChildProcess", command_line, LaunchOptions()); + + int rv = -1; + ASSERT_TRUE(test_child_process.WaitForExitWithTimeout( + TestTimeouts::action_timeout(), &rv)); + EXPECT_EQ(0, rv); +} + +MULTIPROCESS_TEST_MAIN(ActiveVerifierChildProcess) { + ScopedNativeLibrary module(FilePath(L"scoped_handle_test_dll.dll")); + + if (!module.is_valid()) + return 1; + auto run_test_function = reinterpret_cast<decltype(&testing::RunTest)>( + module.GetFunctionPointer("RunTest")); + if (!run_test_function) + return 1; + if (!run_test_function()) + return 1; + + return 0; +} + } // namespace win } // namespace base
diff --git a/base/win/windows_version.cc b/base/win/windows_version.cc index 7a8b8fdb..d2f766e 100644 --- a/base/win/windows_version.cc +++ b/base/win/windows_version.cc
@@ -6,17 +6,81 @@ #include <windows.h> +#include "base/file_version_info_win.h" +#include "base/files/file_path.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" #include "base/strings/utf_string_conversions.h" #include "base/win/registry.h" namespace { typedef BOOL (WINAPI *GetProductInfoPtr)(DWORD, DWORD, DWORD, DWORD, PDWORD); -} +} // namespace namespace base { namespace win { +namespace { + +// Helper to map a major.minor.x.build version (e.g. 6.1) to a Windows release. +Version MajorMinorBuildToVersion(int major, int minor, int build) { + if ((major == 5) && (minor > 0)) { + // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003. + return (minor == 1) ? VERSION_XP : VERSION_SERVER_2003; + } else if (major == 6) { + switch (minor) { + case 0: + // Treat Windows Server 2008 the same as Windows Vista. + return VERSION_VISTA; + case 1: + // Treat Windows Server 2008 R2 the same as Windows 7. + return VERSION_WIN7; + case 2: + // Treat Windows Server 2012 the same as Windows 8. + return VERSION_WIN8; + default: + DCHECK_EQ(minor, 3); + return VERSION_WIN8_1; + } + } else if (major == 10) { + if (build < 10586) { + return VERSION_WIN10; + } else { + return VERSION_WIN10_TH2; + } + } else if (major > 6) { + NOTREACHED(); + return VERSION_WIN_LAST; + } + + NOTREACHED(); + return VERSION_WIN_LAST; +} + +// Retrieve a version from kernel32. This is useful because when running in +// compatibility mode for a down-level version of the OS, the file version of +// kernel32 will still be the "real" version. +Version GetVersionFromKernel32() { + scoped_ptr<FileVersionInfoWin> file_version_info( + static_cast<FileVersionInfoWin*>( + FileVersionInfoWin::CreateFileVersionInfo( + base::FilePath(FILE_PATH_LITERAL("kernel32.dll"))))); + if (file_version_info) { + const int major = + HIWORD(file_version_info->fixed_file_info()->dwFileVersionMS); + const int minor = + LOWORD(file_version_info->fixed_file_info()->dwFileVersionMS); + const int build = + HIWORD(file_version_info->fixed_file_info()->dwFileVersionLS); + return MajorMinorBuildToVersion(major, minor, build); + } + + NOTREACHED(); + return VERSION_WIN_LAST; +} + +} // namespace + // static OSInfo* OSInfo::GetInstance() { // Note: we don't use the Singleton class because it depends on AtExitManager, @@ -35,6 +99,8 @@ OSInfo::OSInfo() : version_(VERSION_PRE_XP), + kernel32_version_(VERSION_PRE_XP), + got_kernel32_version_(false), architecture_(OTHER_ARCHITECTURE), wow64_status_(GetWOW64StatusForProcess(GetCurrentProcess())) { OSVERSIONINFOEX version_info = { sizeof version_info }; @@ -42,38 +108,8 @@ version_number_.major = version_info.dwMajorVersion; version_number_.minor = version_info.dwMinorVersion; version_number_.build = version_info.dwBuildNumber; - if ((version_number_.major == 5) && (version_number_.minor > 0)) { - // Treat XP Pro x64, Home Server, and Server 2003 R2 as Server 2003. - version_ = (version_number_.minor == 1) ? VERSION_XP : VERSION_SERVER_2003; - } else if (version_number_.major == 6) { - switch (version_number_.minor) { - case 0: - // Treat Windows Server 2008 the same as Windows Vista. - version_ = VERSION_VISTA; - break; - case 1: - // Treat Windows Server 2008 R2 the same as Windows 7. - version_ = VERSION_WIN7; - break; - case 2: - // Treat Windows Server 2012 the same as Windows 8. - version_ = VERSION_WIN8; - break; - default: - DCHECK_EQ(version_number_.minor, 3); - version_ = VERSION_WIN8_1; - break; - } - } else if (version_number_.major == 10) { - if (version_number_.build < 10586) { - version_ = VERSION_WIN10; - } else { - version_ = VERSION_WIN10_TH2; - } - } else if (version_number_.major > 6) { - NOTREACHED(); - version_ = VERSION_WIN_LAST; - } + version_ = MajorMinorBuildToVersion( + version_number_.major, version_number_.minor, version_number_.build); service_pack_.major = version_info.wServicePackMajor; service_pack_.minor = version_info.wServicePackMinor; @@ -149,6 +185,14 @@ OSInfo::~OSInfo() { } +Version OSInfo::Kernel32Version() const { + if (!got_kernel32_version_) { + kernel32_version_ = GetVersionFromKernel32(); + got_kernel32_version_ = true; + } + return kernel32_version_; +} + std::string OSInfo::processor_model_name() { if (processor_model_name_.empty()) { const wchar_t kProcessorNameString[] =
diff --git a/base/win/windows_version.h b/base/win/windows_version.h index 676bd97..7bc8b6f 100644 --- a/base/win/windows_version.h +++ b/base/win/windows_version.h
@@ -21,17 +21,20 @@ // syntactic sugar reasons; see the declaration of GetVersion() below. // NOTE: Keep these in order so callers can do things like // "if (base::win::GetVersion() >= base::win::VERSION_VISTA) ...". +// +// This enum is used in metrics histograms, so they shouldn't be reordered or +// removed. New values can be added before VERSION_WIN_LAST. enum Version { VERSION_PRE_XP = 0, // Not supported. - VERSION_XP, - VERSION_SERVER_2003, // Also includes XP Pro x64 and Server 2003 R2. - VERSION_VISTA, // Also includes Windows Server 2008. - VERSION_WIN7, // Also includes Windows Server 2008 R2. - VERSION_WIN8, // Also includes Windows Server 2012. - VERSION_WIN8_1, // Also includes Windows Server 2012 R2. - VERSION_WIN10, // Also includes Windows 10 Server. - VERSION_WIN10_TH2, // Threshold 2: Version 1511, Build 10586. - VERSION_WIN_LAST, // Indicates error condition. + VERSION_XP = 1, + VERSION_SERVER_2003 = 2, // Also includes XP Pro x64 and Server 2003 R2. + VERSION_VISTA = 3, // Also includes Windows Server 2008. + VERSION_WIN7 = 4, // Also includes Windows Server 2008 R2. + VERSION_WIN8 = 5, // Also includes Windows Server 2012. + VERSION_WIN8_1 = 6, // Also includes Windows Server 2012 R2. + VERSION_WIN10 = 7, // Also includes Windows 10 Server. + VERSION_WIN10_TH2 = 8, // Threshold 2: Version 1511, Build 10586. + VERSION_WIN_LAST, // Indicates error condition. }; // A rough bucketing of the available types of versions of Windows. This is used @@ -86,6 +89,7 @@ static OSInfo* GetInstance(); Version version() const { return version_; } + Version Kernel32Version() const; // The next two functions return arrays of values, [major, minor(, build)]. VersionNumber version_number() const { return version_number_; } VersionType version_type() const { return version_type_; } @@ -105,6 +109,8 @@ ~OSInfo(); Version version_; + mutable Version kernel32_version_; + mutable bool got_kernel32_version_; VersionNumber version_number_; VersionType version_type_; ServicePack service_pack_;
diff --git a/base/win/windows_version_unittest.cc b/base/win/windows_version_unittest.cc new file mode 100644 index 0000000..f0d6d96 --- /dev/null +++ b/base/win/windows_version_unittest.cc
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/win/windows_version.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace base { +namespace win { +namespace { + +TEST(WindowsVersion, GetVersionExAndKernelVersionMatch) { + // If this fails, we're running in compatibility mode, or need to update the + // application manifest. + EXPECT_EQ(OSInfo::GetInstance()->version(), + OSInfo::GetInstance()->Kernel32Version()); +} + +} // namespace +} // namespace win +} // namespace base
diff --git a/blimp/docs/build.md b/blimp/docs/build.md index a235121..e5e20d7 100644 --- a/blimp/docs/build.md +++ b/blimp/docs/build.md
@@ -3,10 +3,12 @@ overview over how to use GN can be found in the GN [quick start guide](../../tools/gn/docs/quick_start.md). -There are three different build configurations depending on what you want to +## Building + +There are two different build configurations depending on what you want to build: -## Android client +### Android client Create an out-directory and set the GN args: @@ -35,7 +37,7 @@ gn args out-android/Debug ``` -## Engine +### Engine Create another out-directory and set the GN args: @@ -56,3 +58,24 @@ ```bash gn args out-android/Debug ``` + +## Adding new build arguments + +Adding new build arguments should be fairly rare. Arguments first need to be +[declared](../../tools/gn/docs/quick_start.md#Add-a-new-build-argument). + +They can then be used to change how the binary is built or passed through to +code as a +[defines](../../tools/gn/docs/reference.md#defines_C-preprocessor-defines). + +Finally the Blimp argument templates should be updated to reflect the +(non-default for Chrome) behavior desired by Blimp (see below). + +## Updating bulid arguments in templates + +Build argument templates exist for the client and engine at +[`build/args/blimp_client.gn`](../../build/args/blimp_client.gn) and +[`build/args/blimp_engine.gn`](../../build/args/blimp_engine.gn). + +These can be updated as in the same manner as your personal `args.gn` files +to override default argument values.
diff --git a/build/android/android.isolate b/build/android/android.isolate index bada53cf..dfedc6f 100644 --- a/build/android/android.isolate +++ b/build/android/android.isolate
@@ -17,7 +17,6 @@ '<(PRODUCT_DIR)/forwarder_dist/', '<(PRODUCT_DIR)/md5sum_bin_host', '<(PRODUCT_DIR)/md5sum_dist/', - 'devil/', 'devil_chromium.json', 'devil_chromium.py', 'gyp/util/',
diff --git a/build/android/gyp/util/build_utils.py b/build/android/gyp/util/build_utils.py index cd62c2f..3fa91aabf 100644 --- a/build/android/gyp/util/build_utils.py +++ b/build/android/gyp/util/build_utils.py
@@ -471,11 +471,18 @@ def CallAndWriteDepfileIfStale(function, options, record_path=None, input_paths=None, input_strings=None, output_paths=None, force=False, - pass_changes=False): + pass_changes=False, + depfile_deps=None): """Wraps md5_check.CallAndRecordIfStale() and also writes dep & stamp files. Depfiles and stamp files are automatically added to output_paths when present in the |options| argument. They are then created after |function| is called. + + By default, only python dependencies are added to the depfile. If there are + other input paths that are not captured by GN deps, then they should be listed + in depfile_deps. It's important to write paths to the depfile that are already + captured by GN deps since GN args can cause GN deps to change, and such + changes are not immediately reflected in depfiles (http://crbug.com/589311). """ if not output_paths: raise Exception('At least one output_path must be specified.') @@ -499,7 +506,10 @@ args = (changes,) if pass_changes else () function(*args) if python_deps is not None: - WriteDepfile(options.depfile, python_deps + input_paths) + all_depfile_deps = list(python_deps) + if depfile_deps: + all_depfile_deps.extend(depfile_deps) + WriteDepfile(options.depfile, all_depfile_deps) if stamp_file: Touch(stamp_file)
diff --git a/build/args/blimp_engine.gn b/build/args/blimp_engine.gn index b78ba7a..ef990cd60 100644 --- a/build/args/blimp_engine.gn +++ b/build/args/blimp_engine.gn
@@ -9,9 +9,10 @@ use_aura = true use_ozone = true +metrics_use_blimp = true # Not available within docker container. use_alsa = false use_pulseaudio = false use_cups = false -use_glib = false \ No newline at end of file +use_glib = false
diff --git a/build/common.gypi b/build/common.gypi index 885e3251..a73eb1b 100644 --- a/build/common.gypi +++ b/build/common.gypi
@@ -833,9 +833,10 @@ 'use_browser_spellchecker%': 1, }], - # Enables proprietary codecs and demuxers; e.g. H264, AAC, MP3, and MP4. - # We always build Google Chrome and Chromecast with proprietary codecs. - ['branding=="Chrome" or chromecast==1', { + # Android OS includes support for proprietary codecs regardless of + # building Chromium or Google Chrome. We also ship Google Chrome and + # Chromecast with proprietary codecs. + ['OS=="android" or branding=="Chrome" or chromecast==1', { 'proprietary_codecs%': 1, }, { 'proprietary_codecs%': 0, @@ -5634,11 +5635,13 @@ ], }], ], + # Add extra include directories here that need to be in front of the + # installed and packaged include directories. This may be needed in + # order to force a particular SDK version, such as to get VS 2013 to use + # the Windows 10 SDK. Beware of making the INCLUDE variable excessively + # long, and be sure to make corresponding changes to + # build\toolchain\win\setup_toolchain.py 'msvs_system_include_dirs': [ - '<(windows_sdk_path)/Include/10.0.10586.0/shared', - '<(windows_sdk_path)/Include/10.0.10586.0/um', - '<(windows_sdk_path)/Include/10.0.10586.0/winrt', - '$(VSInstallDir)/VC/atlmfc/include', ], 'msvs_cygwin_shell': 0, 'msvs_disabled_warnings': [
diff --git a/build/config/features.gni b/build/config/features.gni index c965844..8efa7cf3 100644 --- a/build/config/features.gni +++ b/build/config/features.gni
@@ -46,9 +46,11 @@ # Enables the Media Router. enable_media_router = !is_ios - # Enables proprietary codecs and demuxers; e.g. H264, AAC, MP3, and MP4. - # We always build Google Chrome and Chromecast with proprietary codecs. - proprietary_codecs = is_chrome_branded || is_chromecast + # Enables proprietary codecs and demuxers; e.g. H264, MOV, AAC, and MP3. + # Android OS includes support for proprietary codecs regardless of building + # Chromium or Google Chrome. We also ship Google Chrome and Chromecast with + # proprietary codecs. + proprietary_codecs = is_android || is_chrome_branded || is_chromecast enable_configuration_policy = !is_ios
diff --git a/build/get_landmines.py b/build/get_landmines.py index 4139957..62116f91 100755 --- a/build/get_landmines.py +++ b/build/get_landmines.py
@@ -52,9 +52,7 @@ print "Switched win x64 trybots from VS2010 to VS2012." if (platform() == 'win' and builder() == 'ninja' and gyp_msvs_version().startswith('2013')): - print "Switched win from VS2010 to VS2013." - print "Update to VS2013 Update 2." - print "Update to VS2013 Update 4." + print "Switch to VS2013" if (platform() == 'win' and gyp_msvs_version().startswith('2015')): print 'Switch to VS2015' print 'Need to clobber everything due to an IDL change in r154579 (blink)'
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py index 1e20387..7248ed24 100644 --- a/build/toolchain/win/setup_toolchain.py +++ b/build/toolchain/win/setup_toolchain.py
@@ -156,18 +156,18 @@ vc_bin_dir = os.path.realpath(path) break - # The Windows SDK include directories must be first. They both have a sal.h, - # and the SDK one is newer and the SDK uses some newer features from it not - # present in the Visual Studio one. - # Having the Windows SDK first is also the only way to control which SDK - # version is used. - - if win_sdk_path: - additional_includes = [ - os.path.join(win_sdk_path, 'Include', '10.0.10586.0', p) - for p in ['shared', 'um', 'winrt']] - additional_includes = os.path.pathsep.join(additional_includes) - env['INCLUDE'] = additional_includes + os.path.pathsep + env['INCLUDE'] + # Add extra include directories here that need to be in front of the + # installed and packaged include directories. This may be needed in + # order to force a particular SDK version, such as to get VS 2013 to use + # the Windows 10 SDK. Beware of making the INCLUDE variable excessively + # long and be sure to make corresponding changes to build\common.gypi. + # Not currently used. + #if win_sdk_path: + # additional_includes = [ + # os.path.join(win_sdk_path, 'Include', '10.0.10586.0', p) + # for p in ['shared', 'um', 'winrt']] + # additional_includes = os.path.pathsep.join(additional_includes) + # env['INCLUDE'] = additional_includes + os.path.pathsep + env['INCLUDE'] env_block = _FormatAsEnvironmentBlock(env) with open('environment.' + cpu, 'wb') as f: f.write(env_block)
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index 66f4cc4..1105ea74 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py
@@ -22,8 +22,8 @@ import gyp -# Use MSVS2013 as the default toolchain. -CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2013' +# Use MSVS2015 as the default toolchain. +CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2015' def SetEnvironmentAndGetRuntimeDllDirs(): @@ -281,7 +281,6 @@ # Update 1 with hot fixes. return ['391bbf1220d3edcd3cc3fccdb56224181e3b13a7'] else: - # Default to VS2013. return ['4087e065abebdca6dbd0caca2910c6718d2ec67f'] @@ -315,6 +314,9 @@ depot_tools_win_toolchain): import find_depot_tools depot_tools_path = find_depot_tools.add_depot_tools_to_path() + # Necessary so that get_toolchain_if_necessary.py will put the VS toolkit + # in the correct directory. + os.environ['GYP_MSVS_VERSION'] = GetVisualStudioVersion() get_toolchain_args = [ sys.executable, os.path.join(depot_tools_path,
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h index b81ee99..8aac2de 100644 --- a/cc/input/input_handler.h +++ b/cc/input/input_handler.h
@@ -100,10 +100,7 @@ }; enum ScrollInputType { - // TODO(dtapuska): crbug.com/593017; Remove GESTURE and just use - // TOUCHSCREEN. - GESTURE, - TOUCHSCREEN = GESTURE, + TOUCHSCREEN, WHEEL, ANIMATED_WHEEL, NON_BUBBLING_GESTURE
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc index 08167ef..753beca 100644 --- a/cc/layers/layer_impl.cc +++ b/cc/layers/layer_impl.cc
@@ -742,13 +742,8 @@ return "cc::LayerImpl"; } -void LayerImpl::ResetAllChangeTrackingForSubtreeInternal() { +void LayerImpl::ResetChangeTracking() { layer_property_changed_ = false; - if (TransformNode* transform_node = - layer_tree_impl_->property_trees()->transform_tree.Node( - transform_tree_index())) { - transform_node->data.transform_changed = false; - } update_rect_.SetRect(0, 0, 0, 0); damage_rect_.SetRect(0, 0, 0, 0); @@ -757,20 +752,12 @@ render_surface_->ResetPropertyChangedFlag(); if (mask_layer_) - mask_layer_->ResetAllChangeTrackingForSubtreeInternal(); + mask_layer_->ResetChangeTracking(); if (replica_layer_) { // This also resets the replica mask, if it exists. - replica_layer_->ResetAllChangeTrackingForSubtreeInternal(); + replica_layer_->ResetChangeTracking(); } - - for (size_t i = 0; i < children_.size(); ++i) - children_[i]->ResetAllChangeTrackingForSubtreeInternal(); -} - -void LayerImpl::ResetAllChangeTrackingForSubtree() { - layer_tree_impl()->LayersThatShouldPushProperties().clear(); - ResetAllChangeTrackingForSubtreeInternal(); } int LayerImpl::num_copy_requests_in_target_subtree() {
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 5accffa..1bc1bc6 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -524,7 +524,7 @@ bool LayerPropertyChanged() const; - void ResetAllChangeTrackingForSubtree(); + void ResetChangeTracking(); virtual SimpleEnclosedRegion VisibleOpaqueRegion() const; @@ -652,7 +652,6 @@ void NoteLayerPropertyChangedForDescendantsInternal(); void PushLayerPropertyChangedForSubtreeInternal(); - void ResetAllChangeTrackingForSubtreeInternal(); virtual const char* LayerTypeAsString() const;
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc index 11c372452..177866a 100644 --- a/cc/layers/layer_impl_unittest.cc +++ b/cc/layers/layer_impl_unittest.cc
@@ -27,8 +27,7 @@ namespace { #define EXECUTE_AND_VERIFY_SUBTREE_CHANGED(code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ - root->layer_tree_impl()->property_trees()->ResetAllChangeTracking( \ + root->layer_tree_impl()->ResetAllChangeTracking( \ PropertyTrees::ResetFlags::ALL_TREES); \ code_to_test; \ EXPECT_TRUE( \ @@ -42,7 +41,8 @@ EXPECT_TRUE(grand_child->LayerPropertyChanged()); #define EXECUTE_AND_VERIFY_SUBTREE_DID_NOT_CHANGE(code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ + root->layer_tree_impl()->ResetAllChangeTracking( \ + PropertyTrees::ResetFlags::ALL_TREES); \ code_to_test; \ EXPECT_FALSE( \ root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root)); \ @@ -56,7 +56,8 @@ #define EXECUTE_AND_VERIFY_NEEDS_PUSH_PROPERTIES_AND_SUBTREE_DID_NOT_CHANGE( \ code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ + root->layer_tree_impl()->ResetAllChangeTracking( \ + PropertyTrees::ResetFlags::ALL_TREES); \ code_to_test; \ EXPECT_TRUE( \ root->layer_tree_impl()->LayerNeedsPushPropertiesForTesting(root)); \ @@ -69,7 +70,8 @@ EXPECT_FALSE(grand_child->LayerPropertyChanged()); #define EXECUTE_AND_VERIFY_ONLY_LAYER_CHANGED(code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ + root->layer_tree_impl()->ResetAllChangeTracking( \ + PropertyTrees::ResetFlags::ALL_TREES); \ root->layer_tree_impl()->property_trees()->full_tree_damaged = false; \ code_to_test; \ EXPECT_TRUE( \ @@ -83,7 +85,8 @@ EXPECT_FALSE(grand_child->LayerPropertyChanged()); #define VERIFY_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ + root->layer_tree_impl()->ResetAllChangeTracking( \ + PropertyTrees::ResetFlags::ALL_TREES); \ host_impl.active_tree()->property_trees()->needs_rebuild = true; \ host_impl.active_tree()->BuildPropertyTreesForTesting(); \ host_impl.ForcePrepareToDraw(); \ @@ -92,7 +95,8 @@ EXPECT_TRUE(host_impl.active_tree()->needs_update_draw_properties()); #define VERIFY_NO_NEEDS_UPDATE_DRAW_PROPERTIES(code_to_test) \ - root->ResetAllChangeTrackingForSubtree(); \ + root->layer_tree_impl()->ResetAllChangeTracking( \ + PropertyTrees::ResetFlags::ALL_TREES); \ host_impl.active_tree()->property_trees()->needs_rebuild = true; \ host_impl.active_tree()->BuildPropertyTreesForTesting(); \ host_impl.ForcePrepareToDraw(); \ @@ -132,6 +136,7 @@ LayerImpl::Create(host_impl.active_tree(), 2); LayerImpl* root = root_ptr.get(); root_clip_ptr->AddChild(std::move(root_ptr)); + host_impl.active_tree()->SetRootLayer(std::move(root_clip_ptr)); scoped_ptr<LayerImpl> scroll_parent = LayerImpl::Create(host_impl.active_tree(), 3); LayerImpl* scroll_child = LayerImpl::Create(host_impl.active_tree(), 4).get(); @@ -146,13 +151,13 @@ std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>(); clip_children->insert(clip_child); clip_children->insert(root); - root->ResetAllChangeTrackingForSubtree(); + root->layer_tree_impl()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); root->AddChild(LayerImpl::Create(host_impl.active_tree(), 7)); LayerImpl* child = root->children()[0].get(); child->AddChild(LayerImpl::Create(host_impl.active_tree(), 8)); LayerImpl* grand_child = child->children()[0].get(); - host_impl.active_tree()->SetRootLayer(std::move(root_clip_ptr)); root->SetScrollClipLayer(root_clip->id()); host_impl.active_tree()->BuildPropertyTreesForTesting();
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc index b9fe4a8..5b213c9a 100644 --- a/cc/layers/layer_unittest.cc +++ b/cc/layers/layer_unittest.cc
@@ -1676,25 +1676,28 @@ EXPECT_SET_NEEDS_FULL_TREE_SYNC(1, layer_tree_host_->SetRootLayer(test_layer)); + host_impl_.active_tree()->SetRootLayer(std::move(impl_layer)); + LayerImpl* impl_layer_ptr = host_impl_.active_tree()->LayerById(1); test_layer->SetNeedsDisplayRect(gfx::Rect(5, 5)); - test_layer->PushPropertiesTo(impl_layer.get()); + test_layer->PushPropertiesTo(impl_layer_ptr); EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 5.f, 5.f), - impl_layer->update_rect()); + impl_layer_ptr->update_rect()); // The LayerImpl's update_rect() should be accumulated here, since we did not // do anything to clear it. test_layer->SetNeedsDisplayRect(gfx::Rect(10, 10, 5, 5)); - test_layer->PushPropertiesTo(impl_layer.get()); + test_layer->PushPropertiesTo(impl_layer_ptr); EXPECT_FLOAT_RECT_EQ(gfx::RectF(0.f, 0.f, 15.f, 15.f), - impl_layer->update_rect()); + impl_layer_ptr->update_rect()); // If we do clear the LayerImpl side, then the next update_rect() should be // fresh without accumulation. - impl_layer->ResetAllChangeTrackingForSubtree(); + host_impl_.active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); test_layer->SetNeedsDisplayRect(gfx::Rect(10, 10, 5, 5)); - test_layer->PushPropertiesTo(impl_layer.get()); + test_layer->PushPropertiesTo(impl_layer_ptr); EXPECT_FLOAT_RECT_EQ(gfx::RectF(10.f, 10.f, 5.f, 5.f), - impl_layer->update_rect()); + impl_layer_ptr->update_rect()); } TEST_F(LayerTest, PushPropertiesCausesLayerPropertyChangedForTransform) {
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc index a237bcb3..2c15bf6 100644 --- a/cc/layers/render_surface_unittest.cc +++ b/cc/layers/render_surface_unittest.cc
@@ -13,6 +13,7 @@ #include "cc/test/mock_occlusion_tracker.h" #include "cc/test/test_shared_bitmap_manager.h" #include "cc/test/test_task_graph_runner.h" +#include "cc/trees/layer_tree_impl.h" #include "cc/trees/single_thread_proxy.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -47,7 +48,8 @@ ASSERT_TRUE(owning_layer->render_surface()); RenderSurfaceImpl* render_surface = owning_layer->render_surface(); gfx::Rect test_rect(3, 4, 5, 6); - owning_layer->ResetAllChangeTrackingForSubtree(); + host_impl.active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); // Currently, the content_rect, clip_rect, and // owning_layer->layerPropertyChanged() are the only sources of change. @@ -56,7 +58,8 @@ owning_layer->SetOpacity(0.5f); EXPECT_TRUE(render_surface->SurfacePropertyChanged()); - owning_layer->ResetAllChangeTrackingForSubtree(); + host_impl.active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); // Setting the surface properties to the same values again should not be // considered "change".
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc index ee41989..a592c50 100644 --- a/cc/layers/scrollbar_layer_unittest.cc +++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -168,7 +168,7 @@ // responded to on the main thread as the compositor does not yet implement // scrollbar scrolling. InputHandler::ScrollStatus status = layer_tree_host_->host_impl()->TryScroll( - gfx::PointF(), InputHandler::GESTURE, scroll_tree, scroll_node); + gfx::PointF(), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kScrollbarScrolling, status.main_thread_scrolling_reasons); @@ -189,7 +189,7 @@ // The user shouldn't be able to drag an overlay scrollbar and the scroll // may be handled in the compositor. status = layer_tree_host_->host_impl()->TryScroll( - gfx::PointF(), InputHandler::GESTURE, scroll_tree, scroll_node); + gfx::PointF(), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollable, status.main_thread_scrolling_reasons);
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc index 5b4751d5..5615455 100644 --- a/cc/resources/video_resource_updater.cc +++ b/cc/resources/video_resource_updater.cc
@@ -625,7 +625,10 @@ return VideoFrameExternalResources(); VideoFrameExternalResources external_resources; - external_resources.read_lock_fences_enabled = true; + if (video_frame->metadata()->IsTrue( + media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED)) { + external_resources.read_lock_fences_enabled = true; + } external_resources.type = ResourceTypeForVideoFrame(video_frame.get()); if (external_resources.type == VideoFrameExternalResources::NONE) {
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc index 98b1fa7..4adf8372 100644 --- a/cc/resources/video_resource_updater_unittest.cc +++ b/cc/resources/video_resource_updater_unittest.cc
@@ -460,10 +460,17 @@ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame); EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type); - EXPECT_TRUE(resources.read_lock_fences_enabled); EXPECT_EQ(3u, resources.mailboxes.size()); EXPECT_EQ(3u, resources.release_callbacks.size()); EXPECT_EQ(0u, resources.software_resources.size()); + EXPECT_FALSE(resources.read_lock_fences_enabled); + + video_frame = CreateTestYuvHardwareVideoFrame(); + video_frame->metadata()->SetBoolean( + media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, true); + + resources = updater.CreateExternalResourcesFromVideoFrame(video_frame); + EXPECT_TRUE(resources.read_lock_fences_enabled); } TEST_F(VideoResourceUpdaterTest, CreateForHardwarePlanes_StreamTexture) {
diff --git a/cc/tiles/software_image_decode_controller.cc b/cc/tiles/software_image_decode_controller.cc index f47213a..48bd02d 100644 --- a/cc/tiles/software_image_decode_controller.cc +++ b/cc/tiles/software_image_decode_controller.cc
@@ -280,7 +280,7 @@ decoded_images_.Erase(image_it); } - scoped_refptr<DecodedImage> decoded_image; + scoped_ptr<DecodedImage> decoded_image; { base::AutoUnlock unlock(lock_); decoded_image = DecodeImageInternal(key, image); @@ -321,7 +321,7 @@ SanityCheckState(__LINE__, true); } -scoped_refptr<SoftwareImageDecodeController::DecodedImage> +scoped_ptr<SoftwareImageDecodeController::DecodedImage> SoftwareImageDecodeController::DecodeImageInternal( const ImageKey& key, const DrawImage& draw_image) { @@ -360,7 +360,7 @@ } } - return make_scoped_refptr(new DecodedImage( + return make_scoped_ptr(new DecodedImage( decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); } @@ -433,7 +433,7 @@ // deleted automatically when we return. DrawWithImageFinished(original_size_draw_image, decoded_draw_image); - return make_scoped_refptr( + return make_scoped_ptr( new DecodedImage(scaled_info, std::move(scaled_pixels), SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); } @@ -464,9 +464,10 @@ auto decoded_images_it = decoded_images_.Get(key); // If we found the image and it's locked, then return it. If it's not locked, // erase it from the cache since it might be put into the at-raster cache. - scoped_refptr<DecodedImage> decoded_image; + scoped_ptr<DecodedImage> scoped_decoded_image; + DecodedImage* decoded_image = nullptr; if (decoded_images_it != decoded_images_.end()) { - decoded_image = decoded_images_it->second; + decoded_image = decoded_images_it->second.get(); if (decoded_image->is_locked()) { RefImage(key); SanityCheckState(__LINE__, true); @@ -474,6 +475,7 @@ decoded_image->image(), decoded_image->src_rect_offset(), GetScaleAdjustment(key), GetDecodedFilterQuality(key)); } else { + scoped_decoded_image = std::move(decoded_images_it->second); decoded_images_.Erase(decoded_images_it); } } @@ -485,8 +487,7 @@ DCHECK(at_raster_images_it->second->is_locked()); RefAtRasterImage(key); SanityCheckState(__LINE__, true); - const scoped_refptr<DecodedImage>& at_raster_decoded_image = - at_raster_images_it->second; + DecodedImage* at_raster_decoded_image = at_raster_images_it->second.get(); auto decoded_draw_image = DecodedDrawImage(at_raster_decoded_image->image(), at_raster_decoded_image->src_rect_offset(), @@ -505,7 +506,8 @@ // on the compositor thread. This means holding on to the lock might stall // the compositor thread for the duration of the decode! base::AutoUnlock unlock(lock_); - decoded_image = DecodeImageInternal(key, draw_image); + scoped_decoded_image = DecodeImageInternal(key, draw_image); + decoded_image = scoped_decoded_image.get(); // Skip the image if we couldn't decode it. if (!decoded_image) @@ -513,25 +515,26 @@ check_at_raster_cache = true; } + DCHECK(decoded_image == scoped_decoded_image.get()); + // While we unlocked the lock, it could be the case that another thread // already decoded this already and put it in the at-raster cache. Look it up // first. - bool need_to_add_image_to_cache = true; if (check_at_raster_cache) { at_raster_images_it = at_raster_decoded_images_.Get(key); if (at_raster_images_it != at_raster_decoded_images_.end()) { // We have to drop our decode, since the one in the cache is being used by // another thread. decoded_image->Unlock(); - decoded_image = at_raster_images_it->second; - need_to_add_image_to_cache = false; + decoded_image = at_raster_images_it->second.get(); + scoped_decoded_image = nullptr; } } // If we really are the first ones, or if the other thread already unlocked // the image, then put our work into at-raster time cache. - if (need_to_add_image_to_cache) - at_raster_decoded_images_.Put(key, decoded_image); + if (scoped_decoded_image) + at_raster_decoded_images_.Put(key, std::move(scoped_decoded_image)); DCHECK(decoded_image); DCHECK(decoded_image->is_locked()); @@ -604,7 +607,7 @@ decoded_images_ref_counts_.end()) { at_raster_image_it->second->Unlock(); } - decoded_images_.Put(key, at_raster_image_it->second); + decoded_images_.Put(key, std::move(at_raster_image_it->second)); } else if (image_it->second->is_locked()) { at_raster_image_it->second->Unlock(); } else { @@ -612,7 +615,7 @@ decoded_images_ref_counts_.end()); at_raster_image_it->second->Unlock(); decoded_images_.Erase(image_it); - decoded_images_.Put(key, at_raster_image_it->second); + decoded_images_.Put(key, std::move(at_raster_image_it->second)); } at_raster_decoded_images_.Erase(at_raster_image_it); }
diff --git a/cc/tiles/software_image_decode_controller.h b/cc/tiles/software_image_decode_controller.h index d68ac90c..7e370bb8 100644 --- a/cc/tiles/software_image_decode_controller.h +++ b/cc/tiles/software_image_decode_controller.h
@@ -118,12 +118,12 @@ private: // DecodedImage is a convenience storage for discardable memory. It can also // construct an image out of SkImageInfo and stored discardable memory. - // TODO(vmpstr): Make this scoped_ptr. - class DecodedImage : public base::RefCounted<DecodedImage> { + class DecodedImage { public: DecodedImage(const SkImageInfo& info, scoped_ptr<base::DiscardableMemory> memory, const SkSize& src_rect_offset); + ~DecodedImage(); SkImage* image() const { DCHECK(locked_); @@ -137,10 +137,6 @@ void Unlock(); private: - friend class base::RefCounted<DecodedImage>; - - ~DecodedImage(); - bool locked_; SkImageInfo image_info_; scoped_ptr<base::DiscardableMemory> memory_; @@ -175,8 +171,8 @@ // Actually decode the image. Note that this function can (and should) be // called with no lock acquired, since it can do a lot of work. Note that it // can also return nullptr to indicate the decode failed. - scoped_refptr<DecodedImage> DecodeImageInternal(const ImageKey& key, - const DrawImage& draw_image); + scoped_ptr<DecodedImage> DecodeImageInternal(const ImageKey& key, + const DrawImage& draw_image); // Get the decoded draw image for the given key and draw_image. Note that this // function has to be called with no lock acquired, since it will acquire its @@ -207,9 +203,8 @@ // ensure that they are safe to access on multiple threads. base::Lock lock_; - using ImageMRUCache = base::HashingMRUCache<ImageKey, - scoped_refptr<DecodedImage>, - ImageKeyHash>; + using ImageMRUCache = + base::HashingMRUCache<ImageKey, scoped_ptr<DecodedImage>, ImageKeyHash>; // Decoded images and ref counts (predecode path). ImageMRUCache decoded_images_;
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc index 3b9d0af..abb0369a 100644 --- a/cc/trees/damage_tracker_unittest.cc +++ b/cc/trees/damage_tracker_unittest.cc
@@ -76,10 +76,8 @@ render_surface_layer_list[index]->filters()); } - root->ResetAllChangeTrackingForSubtree(); - root->layer_tree_impl()->property_trees()->ResetAllChangeTracking( + root->layer_tree_impl()->ResetAllChangeTracking( PropertyTrees::ResetFlags::ALL_TREES); - root->layer_tree_impl()->property_trees()->effect_tree.ResetChangeTracking(); } class DamageTrackerTest : public testing::Test { @@ -89,7 +87,8 @@ &shared_bitmap_manager_, &task_graph_runner_) {} - scoped_ptr<LayerImpl> CreateTestTreeWithOneSurface() { + LayerImpl* CreateTestTreeWithOneSurface() { + host_impl_.active_tree()->DetachLayerTree(); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.active_tree(), 1); scoped_ptr<LayerImpl> child = @@ -104,15 +103,17 @@ child->SetBounds(gfx::Size(30, 30)); child->SetDrawsContent(true); root->AddChild(std::move(child)); + host_impl_.active_tree()->SetRootLayer(std::move(root)); - return root; + return host_impl_.active_tree()->root_layer(); } - scoped_ptr<LayerImpl> CreateTestTreeWithTwoSurfaces() { + LayerImpl* CreateTestTreeWithTwoSurfaces() { // This test tree has two render surfaces: one for the root, and one for // child1. Additionally, the root has a second child layer, and child1 has // two children of its own. + host_impl_.active_tree()->DetachLayerTree(); scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.active_tree(), 1); scoped_ptr<LayerImpl> child1 = @@ -153,28 +154,29 @@ child1->AddChild(std::move(grand_child2)); root->AddChild(std::move(child1)); root->AddChild(std::move(child2)); + host_impl_.active_tree()->SetRootLayer(std::move(root)); - return root; + return host_impl_.active_tree()->root_layer(); } - scoped_ptr<LayerImpl> CreateAndSetUpTestTreeWithOneSurface() { - scoped_ptr<LayerImpl> root = CreateTestTreeWithOneSurface(); + LayerImpl* CreateAndSetUpTestTreeWithOneSurface() { + LayerImpl* root = CreateTestTreeWithOneSurface(); // Setup includes going past the first frame which always damages // everything, so that we can actually perform specific tests. root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); return root; } - scoped_ptr<LayerImpl> CreateAndSetUpTestTreeWithTwoSurfaces() { - scoped_ptr<LayerImpl> root = CreateTestTreeWithTwoSurfaces(); + LayerImpl* CreateAndSetUpTestTreeWithTwoSurfaces() { + LayerImpl* root = CreateTestTreeWithTwoSurfaces(); // Setup includes going past the first frame which always damages // everything, so that we can actually perform specific tests. root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); return root; } @@ -190,7 +192,7 @@ // Sanity check that the simple test tree will actually produce the expected // render surfaces and layer lists. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); EXPECT_EQ(2u, root->render_surface()->layer_list().size()); EXPECT_EQ(1, root->render_surface()->layer_list()[0]->id()); @@ -206,7 +208,7 @@ // Sanity check that the complex test tree will actually produce the expected // render surfaces and layer lists. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* child2 = root->children()[1].get(); @@ -228,15 +230,15 @@ } TEST_F(DamageTrackerTest, VerifyDamageForUpdateRects) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // CASE 1: Setting the update rect should cause the corresponding damage to // the surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (10, 11) // relative to the child (100, 100). @@ -247,10 +249,10 @@ // CASE 2: The same update rect twice in a row still produces the same // damage. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(110, 111, 12, 13).ToString(), @@ -258,10 +260,10 @@ // CASE 3: Setting a different update rect should cause damage on the new // update region, but no additional exposed old region. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(20, 25, 1, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (20, 25) // relative to the child (100, 100). @@ -271,15 +273,15 @@ } TEST_F(DamageTrackerTest, VerifyDamageForLayerDamageRects) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // CASE 1: Adding the layer damage rect should cause the corresponding damage // to the surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of layer damage_rect // (10, 11) relative to the child (100, 100). @@ -289,20 +291,20 @@ // CASE 2: The same layer damage rect twice in a row still produces the same // damage. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 12, 13))); // CASE 3: Adding a different layer damage rect should cause damage on the // new damaged region, but no additional exposed old region. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(20, 25, 1, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of layer damage_rect // (20, 25) relative to the child (100, 100). @@ -312,11 +314,11 @@ // CASE 4: Adding multiple layer damage rects should cause a unified // damage on root damage rect. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(20, 25, 1, 2)); child->AddDamageRect(gfx::Rect(10, 15, 3, 4)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of layer damage_rect // (20, 25) relative to the child (100, 100). @@ -327,16 +329,16 @@ } TEST_F(DamageTrackerTest, VerifyDamageForLayerUpdateAndDamageRects) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // CASE 1: Adding the layer damage rect and update rect should cause the // corresponding damage to the surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(5, 6, 12, 13)); child->SetUpdateRect(gfx::Rect(15, 16, 14, 10)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of unified layer // damage_rect and update rect (5, 6) @@ -347,22 +349,22 @@ // CASE 2: The same layer damage rect and update rect twice in a row still // produces the same damage. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(10, 11, 12, 13)); child->SetUpdateRect(gfx::Rect(10, 11, 14, 15)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(true, root_damage_rect.Contains(gfx::Rect(110, 111, 14, 15))); // CASE 3: Adding a different layer damage rect and update rect should cause // damage on the new damaged region, but no additional exposed old region. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->AddDamageRect(gfx::Rect(20, 25, 2, 3)); child->SetUpdateRect(gfx::Rect(5, 10, 7, 8)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of unified layer damage // rect and update rect (5, 10) relative to the child (100, 100). @@ -372,18 +374,18 @@ } TEST_F(DamageTrackerTest, VerifyDamageForPropertyChanges) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // CASE 1: The layer's property changed flag takes priority over update rect. // child->SetForceRenderSurface(true); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); - ClearDamageForAllSurfaces(root.get()); + EmulateDrawingOneFrame(root); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); child->OnOpacityAnimated(0.5f); - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); ASSERT_EQ(2u, root->render_surface()->layer_list().size()); @@ -399,19 +401,19 @@ // Cycle one frame of no change, just to sanity check that the next rect is // not because of the old damage state. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_TRUE(root_damage_rect.IsEmpty()); // Then, test the actual layer movement. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetPosition(gfx::PointF(200.f, 230.f)); child->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Expect damage to be the combination of the previous one and the new one. expected_rect.Union(gfx::Rect(200, 230, 30, 30)); @@ -424,20 +426,20 @@ // If a layer is transformed, the damage rect should still enclose the entire // transformed layer. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); child->SetForceRenderSurface(true); gfx::Transform rotation; rotation.Rotate(45.0); - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetTransformOrigin(gfx::Point3F( child->bounds().width() * 0.5f, child->bounds().height() * 0.5f, 0.f)); child->SetPosition(gfx::PointF(85.f, 85.f)); child->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that the layer actually moved to (85, 85), damaging its old // location and new location. @@ -447,9 +449,9 @@ // With the anchor on the layer's center, now we can test the rotation more // intuitively, since it applies about the layer's anchor. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->OnTransformAnimated(rotation); - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Since the child layer is square, rotation by 45 degrees about the center // should increase the size of the expected rect by sqrt(2), centered around @@ -477,7 +479,7 @@ // approximately 501 units in root surface space. // - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); gfx::Transform transform; @@ -491,7 +493,7 @@ child->SetBounds(gfx::Size(100, 100)); child->SetTransform(transform); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that the child layer's bounds would actually get clipped by // w < 0, otherwise this test is not actually testing the intended scenario. @@ -503,10 +505,10 @@ // Damage the child without moving it. child->SetForceRenderSurface(true); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); - ClearDamageForAllSurfaces(root.get()); + EmulateDrawingOneFrame(root); + ClearDamageForAllSurfaces(root); child->OnOpacityAnimated(0.5f); - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // The expected damage should cover the entire root surface (500x500), but we // don't care whether the damage rect was clamped or is larger than the @@ -518,7 +520,7 @@ } TEST_F(DamageTrackerTest, VerifyDamageForBlurredSurface) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* surface = root->children()[0].get(); LayerImpl* child = surface->children()[0].get(); @@ -528,17 +530,17 @@ filters.GetOutsets(&outset_top, &outset_right, &outset_bottom, &outset_left); // Setting the filter will damage the whole surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); surface->SetFilters(filters); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Setting the update rect should cause the corresponding damage to the // surface, blurred based on the size of the blur filter. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(1, 2, 3, 4)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damage position on the surface should be: position of update_rect (1, 2) // relative to the child (300, 300), but expanded by the blur outsets. @@ -554,7 +556,7 @@ } TEST_F(DamageTrackerTest, VerifyDamageForImageFilter) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); gfx::Rect root_damage_rect, child_damage_rect; @@ -569,11 +571,11 @@ filters.GetOutsets(&outset_top, &outset_right, &outset_bottom, &outset_left); // Setting the filter will damage the whole surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetForceRenderSurface(true); child->SetFilters(filters); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); child_damage_rect = @@ -587,10 +589,10 @@ child_damage_rect.ToString()); // CASE 1: Setting the update rect should damage the whole surface (for now) - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(1, 1)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -609,7 +611,7 @@ } TEST_F(DamageTrackerTest, VerifyDamageForBackgroundBlurredChild) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* child2 = root->children()[1].get(); @@ -622,18 +624,18 @@ filters.GetOutsets(&outset_top, &outset_right, &outset_bottom, &outset_left); // Setting the filter will damage the whole surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetBackgroundFilters(filters); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // CASE 1: Setting the update rect should cause the corresponding damage to // the surface, blurred based on the size of the child's background // blur filter. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->SetUpdateRect(gfx::Rect(297, 297, 2, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -652,10 +654,10 @@ // the surface, blurred based on the size of the child's background // blur filter. Since the damage extends to the right/bottom outside // of the blurred layer, only the left/top should end up expanded. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->SetUpdateRect(gfx::Rect(297, 297, 30, 30)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -672,10 +674,10 @@ // CASE 3: Setting this update rect outside the blurred content_bounds of the // blurred child1 will not cause it to be expanded. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->SetUpdateRect(gfx::Rect(30, 30, 2, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -688,10 +690,10 @@ // CASE 4: Setting this update rect inside the blurred content_bounds but // outside the original content_bounds of the blurred child1 will // cause it to be expanded. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->SetUpdateRect(gfx::Rect(99, 99, 1, 1)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -708,10 +710,10 @@ // CASE 5: Setting the update rect on child2, which is above child1, will // not get blurred by child1, so it does not need to get expanded. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child2->SetUpdateRect(gfx::Rect(1, 1)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -724,10 +726,10 @@ // CASE 6: Setting the update rect on child1 will also blur the damage, so // that any pixels needed for the blur are redrawn in the current // frame. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetUpdateRect(gfx::Rect(1, 1)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -743,12 +745,12 @@ } TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingLayer) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child1 = root->children()[0].get(); // CASE 1: Adding a new layer should cause the appropriate damage. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); { scoped_ptr<LayerImpl> child2 = LayerImpl::Create(host_impl_.active_tree(), 3); @@ -758,7 +760,7 @@ root->AddChild(std::move(child2)); } root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check - all 3 layers should be on the same render surface; render // surfaces are tested elsewhere. @@ -773,9 +775,9 @@ // Advance one frame without damage so that we know the damage rect is not // leftover from the previous case. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -785,7 +787,7 @@ root->RemoveChild(child1); child1 = NULL; root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); @@ -797,25 +799,27 @@ // If child2 is added to the layer tree, but it doesn't have any explicit // damage of its own, it should still indeed damage the target surface. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); { scoped_ptr<LayerImpl> child2 = LayerImpl::Create(host_impl_.active_tree(), 3); child2->SetPosition(gfx::PointF(400.f, 380.f)); child2->SetBounds(gfx::Size(6, 8)); child2->SetDrawsContent(true); - child2->ResetAllChangeTrackingForSubtree(); + root->AddChild(std::move(child2)); + host_impl_.active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); + LayerImpl* child2_ptr = host_impl_.active_tree()->LayerById(3); // Sanity check the initial conditions of the test, if these asserts // trigger, it means the test no longer actually covers the intended // scenario. - ASSERT_FALSE(child2->LayerPropertyChanged()); - ASSERT_TRUE(child2->update_rect().IsEmpty()); - root->AddChild(std::move(child2)); + ASSERT_FALSE(child2_ptr->LayerPropertyChanged()); + ASSERT_TRUE(child2_ptr->update_rect().IsEmpty()); } root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check - all 3 layers should be on the same render surface; render // surfaces are tested elsewhere. @@ -827,12 +831,12 @@ } TEST_F(DamageTrackerTest, VerifyDamageForMultipleLayers) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child1 = root->children()[0].get(); // In this test we don't want the above tree manipulation to be considered // part of the same frame. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); { scoped_ptr<LayerImpl> child2 = LayerImpl::Create(host_impl_.active_tree(), 3); @@ -843,16 +847,16 @@ } LayerImpl* child2 = root->children()[1].get(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Damaging two layers simultaneously should cause combined damage. // - child1 update rect in surface space: gfx::Rect(100, 100, 1, 2); // - child2 update rect in surface space: gfx::Rect(400, 380, 3, 4); - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetUpdateRect(gfx::Rect(1, 2)); child2->SetUpdateRect(gfx::Rect(3, 4)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(100, 100, 303, 284).ToString(), @@ -860,22 +864,22 @@ } TEST_F(DamageTrackerTest, VerifyDamageForNestedSurfaces) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* child2 = root->children()[1].get(); LayerImpl* grand_child1 = root->children()[0]->children()[0].get(); child2->SetForceRenderSurface(true); grand_child1->SetForceRenderSurface(true); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; // CASE 1: Damage to a descendant surface should propagate properly to // ancestor surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); grand_child1->OnOpacityAnimated(0.5f); - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -889,10 +893,10 @@ // gfx::Rect(300, 300, 6, 8); // - child2 damage in root surface space: // gfx::Rect(11, 11, 18, 18); - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); grand_child1->OnOpacityAnimated(0.7f); child2->OnOpacityAnimated(0.7f); - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -910,16 +914,16 @@ // This is a tricky case, since only the first grand_child changes, but the // entire surface should be marked dirty. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* grand_child1 = root->children()[0]->children()[0].get(); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); grand_child1->SetPosition(gfx::PointF(195.f, 205.f)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -949,20 +953,20 @@ // child1 surface should be completely unchanged, since we are only // transforming it, while the root surface would be damaged appropriately. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* grand_child1 = child1->children()[0].get(); LayerImpl* grand_child2 = child1->children()[1].get(); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetPosition(gfx::PointF(50.f, 50.f)); child1->NoteLayerPropertyChanged(); grand_child1->NoteLayerPropertyChanged(); grand_child2->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -981,17 +985,17 @@ } TEST_F(DamageTrackerTest, VerifyDamageForAddingAndRemovingRenderSurfaces) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; // CASE 1: If a descendant surface disappears, its entire old area becomes // exposed. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetForceRenderSurface(false); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that there is only one surface now. ASSERT_FALSE(child1->render_surface()); @@ -1007,19 +1011,19 @@ // Cycle one frame of no change, just to sanity check that the next rect is // not because of the old damage state. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_TRUE(root_damage_rect.IsEmpty()); // Then change the tree so that the render surface is added back. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetForceRenderSurface(true); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that there is a new surface now. ASSERT_TRUE(child1->render_surface()); @@ -1037,16 +1041,16 @@ } TEST_F(DamageTrackerTest, VerifyNoDamageWhenNothingChanged) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; // CASE 1: If nothing changes, the damage rect should be empty. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -1057,9 +1061,9 @@ // CASE 2: If nothing changes twice in a row, the damage rect should still be // empty. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -1069,17 +1073,17 @@ } TEST_F(DamageTrackerTest, VerifyNoDamageForUpdateRectThatDoesNotDrawContent) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); gfx::Rect child_damage_rect; gfx::Rect root_damage_rect; // In our specific tree, the update rect of child1 should not cause any // damage to any surface because it does not actually draw content. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child1->SetUpdateRect(gfx::Rect(1, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); root_damage_rect = @@ -1089,7 +1093,7 @@ } TEST_F(DamageTrackerTest, VerifyDamageForReplica) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* grand_child1 = child1->children()[0].get(); LayerImpl* grand_child2 = child1->children()[1].get(); @@ -1111,11 +1115,11 @@ } child1->SetOpacity(0.5f); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // CASE 1: adding a reflection about the left edge of grand_child1. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); { scoped_ptr<LayerImpl> grand_child1_replica = LayerImpl::Create(host_impl_.active_tree(), 7); @@ -1127,7 +1131,7 @@ grand_child1->SetForceRenderSurface(true); } root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect grand_child_damage_rect = grand_child1->render_surface()->damage_tracker()->current_damage_rect(); @@ -1145,12 +1149,12 @@ // CASE 2: moving the descendant surface should cause both the original and // reflected areas to be damaged on the target. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); gfx::Rect old_content_rect = child1->render_surface()->content_rect(); grand_child1->SetPosition(gfx::PointF(195.f, 205.f)); grand_child1->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); ASSERT_EQ(old_content_rect.width(), child1->render_surface()->content_rect().width()); ASSERT_EQ(old_content_rect.height(), @@ -1176,11 +1180,11 @@ // CASE 3: removing the reflection should cause the entire region including // reflection to damage the target surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); grand_child1->SetReplicaLayer(nullptr); grand_child1->SetForceRenderSurface(false); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); ASSERT_EQ(old_content_rect.width(), child1->render_surface()->content_rect().width()); ASSERT_EQ(old_content_rect.height(), @@ -1198,13 +1202,13 @@ } TEST_F(DamageTrackerTest, VerifyDamageForMask) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // In the current implementation of the damage tracker, changes to mask // layers should damage the entire corresponding surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); // Set up the mask layer. { @@ -1228,14 +1232,14 @@ child->AddChild(std::move(grand_child)); } root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // CASE 1: the update_rect on a mask layer should damage the entire target // surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); mask_layer->SetUpdateRect(gfx::Rect(1, 2, 3, 4)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect child_damage_rect = child->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString()); @@ -1245,19 +1249,19 @@ // Advance one frame without damage so that we know the damage rect is not // leftover from the previous case. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_TRUE(child_damage_rect.IsEmpty()); // Then test the property change. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); mask_layer->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(30, 30).ToString(), child_damage_rect.ToString()); @@ -1267,20 +1271,20 @@ // Advance one frame without damage so that we know the damage rect is not // leftover from the previous case. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); child_damage_rect = child->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_TRUE(child_damage_rect.IsEmpty()); // Then test mask removal. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetMaskLayer(nullptr); child->NoteLayerPropertyChanged(); ASSERT_TRUE(child->LayerPropertyChanged()); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that a render surface still exists. ASSERT_TRUE(child->render_surface()); @@ -1291,14 +1295,14 @@ } TEST_F(DamageTrackerTest, VerifyDamageForReplicaMask) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* grand_child1 = child1->children()[0].get(); // Changes to a replica's mask should not damage the original surface, // because it is not masked. But it does damage the ancestor target surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); // Create a reflection about the left edge of grand_child1. { @@ -1324,17 +1328,17 @@ LayerImpl* replica_mask_layer = grand_child1_replica->mask_layer(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that the appropriate render surfaces were created ASSERT_TRUE(grand_child1->render_surface()); // CASE 1: a property change on the mask should damage only the reflected // region on the target surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); replica_mask_layer->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect grand_child_damage_rect = grand_child1->render_surface()->damage_tracker()->current_damage_rect(); @@ -1347,10 +1351,10 @@ // CASE 2: removing the replica mask damages only the reflected region on the // target surface. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); grand_child1_replica->SetMaskLayer(nullptr); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); grand_child_damage_rect = grand_child1->render_surface()->damage_tracker()-> @@ -1363,13 +1367,13 @@ } TEST_F(DamageTrackerTest, VerifyDamageForReplicaMaskWithTransformOrigin) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithTwoSurfaces(); + LayerImpl* root = CreateAndSetUpTestTreeWithTwoSurfaces(); LayerImpl* child1 = root->children()[0].get(); LayerImpl* grand_child1 = child1->children()[0].get(); // Verify that the correct replica_origin_transform is used for the // replica_mask. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); // This is not actually the transform origin point being tested, but by // convention its @@ -1405,18 +1409,18 @@ LayerImpl* replica_mask_layer = grand_child1_replica->mask_layer(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check that the appropriate render surfaces were created ASSERT_TRUE(grand_child1->render_surface()); // A property change on the replica_mask should damage the reflected region on // the target surface. - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); replica_mask_layer->NoteLayerPropertyChanged(); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect child_damage_rect = child1->render_surface()->damage_tracker()->current_damage_rect(); @@ -1424,18 +1428,18 @@ } TEST_F(DamageTrackerTest, DamageWhenAddedExternally) { - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); // Case 1: This test ensures that when the tracker is given damage, that // it is included with any other partial damage. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(10, 11, 12, 13)); root->render_surface()->damage_tracker()->AddDamageNextUpdate( gfx::Rect(15, 16, 32, 33)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); gfx::Rect root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::UnionRects(gfx::Rect(15, 16, 32, 33), @@ -1445,11 +1449,11 @@ // Case 2: An additional sanity check that adding damage works even when // nothing on the layer tree changed. // - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); root->render_surface()->damage_tracker()->AddDamageNextUpdate( gfx::Rect(30, 31, 14, 15)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(30, 31, 14, 15).ToString(), root_damage_rect.ToString()); @@ -1485,13 +1489,13 @@ TEST_F(DamageTrackerTest, VerifyDamageAccumulatesUntilReset) { // If damage is not cleared, it should accumulate. - scoped_ptr<LayerImpl> root = CreateAndSetUpTestTreeWithOneSurface(); + LayerImpl* root = CreateAndSetUpTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); - ClearDamageForAllSurfaces(root.get()); + ClearDamageForAllSurfaces(root); child->SetUpdateRect(gfx::Rect(10.f, 11.f, 1.f, 2.f)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // Sanity check damage after the first frame; this isnt the actual test yet. gfx::Rect root_damage_rect = @@ -1502,7 +1506,7 @@ // to the previous one. child->SetUpdateRect(gfx::Rect(20, 25, 1, 2)); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_EQ(gfx::Rect(110, 111, 11, 16).ToString(), @@ -1518,7 +1522,7 @@ // Damage should remain empty even after one frame, since there's yet no new // damage. root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); root_damage_rect = root->render_surface()->damage_tracker()->current_damage_rect(); EXPECT_TRUE(root_damage_rect.IsEmpty()); @@ -1532,7 +1536,7 @@ const int kRange = 5000; for (int i = 0; i < kRange; ++i) { - scoped_ptr<LayerImpl> root = CreateTestTreeWithOneSurface(); + LayerImpl* root = CreateTestTreeWithOneSurface(); LayerImpl* child = root->children()[0].get(); gfx::Transform transform; @@ -1544,7 +1548,7 @@ child->SetBounds(gfx::Size(kBigNumber + i, kBigNumber + i)); child->SetTransform(transform); root->layer_tree_impl()->property_trees()->needs_rebuild = true; - EmulateDrawingOneFrame(root.get()); + EmulateDrawingOneFrame(root); // The expected damage should cover the visible part of the child layer, // which is (0, 0, i, i) in the viewport.
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc index 6e2dd2d..0a9fdb3 100644 --- a/cc/trees/layer_tree_host_impl.cc +++ b/cc/trees/layer_tree_host_impl.cc
@@ -1681,9 +1681,7 @@ (*frame->render_surface_layer_list)[i]->render_surface()->damage_tracker()-> DidDrawDamagedArea(); } - active_tree_->root_layer()->ResetAllChangeTrackingForSubtree(); - active_tree_->property_trees()->ResetAllChangeTracking( - PropertyTrees::ResetFlags::ALL_TREES); + active_tree_->ResetAllChangeTracking(PropertyTrees::ResetFlags::ALL_TREES); active_tree_->set_has_ever_been_drawn(true); devtools_instrumentation::DidDrawFrame(id_); @@ -3199,7 +3197,7 @@ bool scroll_on_main_thread = false; uint32_t main_thread_scrolling_reasons; LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint( - device_viewport_point, InputHandler::GESTURE, layer_impl, + device_viewport_point, InputHandler::TOUCHSCREEN, layer_impl, &scroll_on_main_thread, &main_thread_scrolling_reasons); if (scroll_layer_impl == InnerViewportScrollLayer()) scroll_layer_impl = OuterViewportScrollLayer();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc index 370c1b2a..43bcbe9 100644 --- a/cc/trees/layer_tree_host_impl_unittest.cc +++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -774,7 +774,7 @@ // But gesture scrolls can still be handled. status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -817,7 +817,7 @@ // But they don't influence the actual handling of the scroll gestures. InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::GESTURE); + BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -843,7 +843,7 @@ // Start scrolling a layer status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -893,7 +893,7 @@ // Start scrolling a layer InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::GESTURE); + BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, status.main_thread_scrolling_reasons); @@ -922,7 +922,7 @@ status.main_thread_scrolling_reasons); status = host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects, status.main_thread_scrolling_reasons); @@ -948,12 +948,12 @@ InputHandler::WHEEL)); status = host_impl_->ScrollBegin(BeginState(gfx::Point(25, 25)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); - EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25), - InputHandler::GESTURE)); + EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(25, 25), InputHandler::TOUCHSCREEN)); // All scroll types outside this region should succeed. status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), @@ -962,26 +962,26 @@ EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(75, 75), InputHandler::TOUCHSCREEN)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); - EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25), - InputHandler::GESTURE)); + EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(25, 25), InputHandler::TOUCHSCREEN)); host_impl_->ScrollEnd(EndState().get()); - EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), - InputHandler::GESTURE)); + EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(75, 75), InputHandler::TOUCHSCREEN)); status = host_impl_->ScrollBegin(BeginState(gfx::Point(75, 75)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(75, 75), InputHandler::TOUCHSCREEN)); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->ScrollEnd(EndState().get()); - EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75), - InputHandler::GESTURE)); + EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(75, 75), InputHandler::TOUCHSCREEN)); } TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) { @@ -1025,7 +1025,7 @@ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); @@ -1039,7 +1039,7 @@ EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); EXPECT_TRUE(host_impl_->scroll_affects_scroll_handler()); host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler()); @@ -1052,7 +1052,7 @@ DrawFrame(); InputHandler::ScrollStatus status = host_impl_->ScrollBegin( - BeginState(gfx::Point()).get(), InputHandler::GESTURE); + BeginState(gfx::Point()).get(), InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, status.main_thread_scrolling_reasons); @@ -1489,7 +1489,7 @@ float page_scale_delta = 2.f; host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); @@ -1517,7 +1517,7 @@ float page_scale_delta = 2.f; host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -1560,7 +1560,7 @@ RebuildPropertyTrees(); host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); host_impl_->PinchGestureEnd(); @@ -1576,7 +1576,7 @@ // Scroll down - only the inner viewport should scroll. host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(0, 0), gfx::Vector2dF(100.f, 100.f)).get()); host_impl_->ScrollEnd(EndState().get()); @@ -1591,7 +1591,7 @@ // Scroll down - outer viewport should start scrolling after the inner is at // its maximum. host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(0, 0), gfx::Vector2dF(1000.f, 1000.f)).get()); host_impl_->ScrollEnd(EndState().get()); @@ -1631,7 +1631,7 @@ // Scroll only the layout viewport. host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(250, 250), gfx::Vector2dF(0.125f, 0.125f)).get()); EXPECT_VECTOR2DF_EQ( @@ -1646,7 +1646,7 @@ // Now that we zoomed in, the scroll should be applied to the inner viewport. host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(250, 250), gfx::Vector2dF(0.5f, 0.5f)).get()); EXPECT_VECTOR2DF_EQ( @@ -1682,7 +1682,7 @@ RebuildPropertyTrees(); host_impl_->ScrollBegin(BeginState(gfx::Point(250, 250)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, gfx::Point(250, 250)); @@ -1740,7 +1740,7 @@ // Pinch in within the margins. The scroll should stay exactly locked to the // bottom and right. RebuildPropertyTrees(); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::GESTURE); + host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(); @@ -1758,7 +1758,7 @@ // Pinch in within the margins. The scroll should stay exactly locked to the // top and left. anchor = gfx::Point(offsetFromEdge, offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::GESTURE); + host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(); @@ -1776,7 +1776,7 @@ // Pinch in just outside the margin. There should be no snapping. offsetFromEdge = Viewport::kPinchZoomSnapMarginDips; anchor = gfx::Point(offsetFromEdge, offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::GESTURE); + host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(); @@ -1795,7 +1795,7 @@ offsetFromEdge = Viewport::kPinchZoomSnapMarginDips; anchor = gfx::Point(viewport_size.width() - offsetFromEdge, viewport_size.height() - offsetFromEdge); - host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::GESTURE); + host_impl_->ScrollBegin(BeginState(anchor).get(), InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2, anchor); host_impl_->PinchGestureEnd(); @@ -1877,8 +1877,9 @@ SetupScrollAndContentsLayers(gfx::Size(100, 100)); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gfx::Vector2d(0, 10)).get()); host_impl_->QueueSwapPromiseForMainThreadScrollUpdate( @@ -1933,7 +1934,7 @@ { host_impl_->ScrollBegin(BeginState(gfx::Point(21, 21)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(5, 5)).get()); host_impl_->ScrollBy( @@ -1957,7 +1958,7 @@ { host_impl_->ScrollBegin(BeginState(gfx::Point(21, 21)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(21, 21), gfx::Vector2d(3, 4)).get()); host_impl_->ScrollBy( @@ -2001,7 +2002,7 @@ float page_scale_delta = 2.f; host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); @@ -2023,7 +2024,7 @@ float page_scale_delta = 10.f; host_impl_->ScrollBegin(BeginState(gfx::Point(50, 50)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50)); host_impl_->PinchGestureEnd(); @@ -2047,7 +2048,7 @@ float page_scale_delta = 0.1f; host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -2073,7 +2074,7 @@ float page_scale_delta = 1.f; host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20)); @@ -2099,7 +2100,7 @@ float page_scale_delta = 1.f; host_impl_->ScrollBegin(BeginState(gfx::Point(10, 10)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10)); host_impl_->ScrollBy( @@ -2126,7 +2127,7 @@ gfx::ScrollOffset(0, 0)); host_impl_->ScrollBegin(BeginState(gfx::Point(0, 0)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0)); host_impl_->PinchGestureUpdate(1.f, gfx::Point(0, 0)); @@ -3136,7 +3137,7 @@ // Page scale should update metadata correctly (shrinking only the viewport). host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2.f, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -3855,8 +3856,9 @@ EXPECT_EQ(gfx::SizeF(50, 50), active_tree->ScrollableSize()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->top_controls_manager()->ScrollBegin(); @@ -3899,8 +3901,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); // Make the test scroll delta a fractional amount, to verify that the @@ -3944,8 +3947,9 @@ host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0.f, 50.f)).get()); @@ -3967,8 +3971,9 @@ host_impl_->ScrollEnd(EndState().get()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); @@ -4021,8 +4026,9 @@ host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); // Scroll down, the top controls hiding should expand the viewport size so @@ -4071,8 +4077,9 @@ // Scroll 25px to hide top controls gfx::Vector2dF scroll_delta(0.f, 25.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); EXPECT_FALSE(did_request_commit_); @@ -4116,8 +4123,9 @@ host_impl_->active_tree()->property_trees()->needs_rebuild = true; host_impl_->active_tree()->BuildPropertyTreesForTesting(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4277,8 +4285,9 @@ // Hide the top controls by 25px. gfx::Vector2dF scroll_delta(0.f, 25.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -4305,8 +4314,9 @@ // Bring the top controls down by 25px. scroll_delta = gfx::Vector2dF(0.f, -25.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4335,8 +4345,9 @@ gfx::Vector2dF scroll_delta(0.f, 25.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -4377,8 +4388,9 @@ // top controls get scrolled. gfx::Vector2dF scroll_delta(0.f, 15.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -4392,8 +4404,9 @@ scroll_delta = gfx::Vector2dF(0.f, 50.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -4412,8 +4425,9 @@ scroll_delta = gfx::Vector2dF(0.f, -65.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); @@ -4435,8 +4449,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->top_controls_manager()->ScrollBegin(); @@ -4451,8 +4466,9 @@ host_impl_->ScrollEnd(EndState().get()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); float scroll_increment_y = -25.f; @@ -4482,8 +4498,9 @@ host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); } @@ -4710,7 +4727,7 @@ // Set new page scale on impl thread by pinching. host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -4760,7 +4777,7 @@ SetNeedsRebuildPropertyTrees(); RebuildPropertyTrees(); host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -5128,8 +5145,9 @@ // Scroll to the right in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(10, 0); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5192,8 +5210,9 @@ // Scroll down in screen coordinates with a gesture. gfx::Vector2d gesture_scroll_delta(0, 10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5217,8 +5236,9 @@ SetScrollOffsetDelta(child_ptr, gfx::Vector2dF()); gfx::Vector2d gesture_scroll_delta(10, 0); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point(1, 1)).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), gesture_scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5298,8 +5318,9 @@ SetScrollOffsetDelta(child_ptr, gfx::Vector2dF()); DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(viewport_point).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(viewport_point).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy( UpdateState(viewport_point, gesture_scroll_deltas[i]).get()); @@ -5334,8 +5355,9 @@ // Scroll down in screen coordinates with a gesture. gfx::Vector2d scroll_delta(0, 10); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); host_impl_->ScrollEnd(EndState().get()); @@ -5500,7 +5522,7 @@ // offset is outside of the scroll range. (this is verified by DCHECKs in the // delegate). host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(2.f, gfx::Point()); host_impl_->PinchGestureUpdate(.5f, gfx::Point()); @@ -5512,8 +5534,9 @@ gfx::ScrollOffset current_offset(7.f, 8.f); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); host_impl_->SetSynchronousInputHandlerRootScrollOffset(current_offset); @@ -7642,8 +7665,9 @@ DrawFrame(); { EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, @@ -7704,8 +7728,9 @@ gfx::Vector2d scroll_delta(0, -2); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_TRUE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) @@ -8190,8 +8215,9 @@ // Scrolling normally should not trigger any forwarding. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_TRUE( host_impl_->ScrollBy( @@ -8207,8 +8233,9 @@ // thread. host_impl_->active_tree()->set_have_scroll_event_handlers(true); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_TRUE( host_impl_->ScrollBy( @@ -8297,8 +8324,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), @@ -8406,8 +8434,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF().ToString(), @@ -8486,8 +8515,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), @@ -8559,8 +8589,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(), @@ -8628,8 +8659,9 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset()); @@ -8812,8 +8844,9 @@ // Scrolling the viewport always sets the outer scroll layer as the // currently scrolling layer. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, @@ -8834,8 +8867,9 @@ // Fling past the inner viewport boundry, make sure outer viewport scrolls. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(inner_scroll, host_impl_->CurrentlyScrollingLayer()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, @@ -8878,21 +8912,22 @@ // Make sure the scroll goes to the inner viewport first. EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, host_impl_->FlingScrollBegin().thread); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(), InputHandler::TOUCHSCREEN)); // Scroll near the edge of the outer viewport. gfx::Vector2d scroll_delta(inner_viewport.width() / 2.f, inner_viewport.height() / 2.f); host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()); inner_expected += scroll_delta; - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(), InputHandler::TOUCHSCREEN)); EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset()); EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); @@ -8902,13 +8937,13 @@ // and outer viewport layers is perfect. host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::ScaleVector2d(scroll_delta, 2)).get()); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(), InputHandler::TOUCHSCREEN)); outer_expected += scroll_delta; inner_expected += scroll_delta; host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( - gfx::Point(), InputHandler::GESTURE)); + gfx::Point(), InputHandler::TOUCHSCREEN)); EXPECT_VECTOR_EQ(inner_expected, inner_scroll->CurrentScrollOffset()); EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset()); @@ -8938,14 +8973,15 @@ gfx::Vector2d scroll_delta(0, inner_viewport.height()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_TRUE( host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(), InputHandler::TOUCHSCREEN)); // The child should have scrolled up to its limit. scroll_info = host_impl_->ProcessScrollDeltas(); @@ -8961,8 +8997,8 @@ host_impl_->ScrollBy(UpdateState(gfx::Point(), scroll_delta).get()) .did_scroll); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); - EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(), - InputHandler::GESTURE)); + EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt( + gfx::Point(), InputHandler::TOUCHSCREEN)); // The inner viewport shouldn't have scrolled. scroll_info = host_impl_->ProcessScrollDeltas(); @@ -8978,7 +9014,7 @@ EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); host_impl_->ScrollEnd(EndState().get()); EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt( - gfx::Point(), InputHandler::GESTURE)); + gfx::Point(), InputHandler::TOUCHSCREEN)); } } @@ -9002,14 +9038,16 @@ DrawFrame(); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->RootScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->RootScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll); host_impl_->ScrollEnd(EndState().get()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child_scroll); host_impl_->ScrollEnd(EndState().get()); @@ -9033,8 +9071,9 @@ // Ensure inner viewport doesn't react to scrolls (test it's unscrollable). EXPECT_VECTOR_EQ(gfx::Vector2dF(), inner_scroll->CurrentScrollOffset()); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, - host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE) + host_impl_ + ->ScrollBegin(BeginState(gfx::Point()).get(), + InputHandler::TOUCHSCREEN) .thread); scroll_result = host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, 100)).get()); @@ -9838,7 +9877,7 @@ float page_scale_delta = 2.f; host_impl_->ScrollBegin(BeginState(gfx::Point()).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->PinchGestureBegin(); host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point()); host_impl_->PinchGestureEnd(); @@ -10254,7 +10293,7 @@ ++i) { host_impl_->ActivateSyncTree(); host_impl_->ScrollBegin(BeginState(gfx::Point(5, 5)).get(), - InputHandler::GESTURE); + InputHandler::TOUCHSCREEN); host_impl_->ScrollBy( UpdateState(gfx::Point(), gfx::Vector2dF(0, scroll)).get()); accumulated_scroll += scroll;
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc index a4fff259..33c3ff6 100644 --- a/cc/trees/layer_tree_host_unittest.cc +++ b/cc/trees/layer_tree_host_unittest.cc
@@ -714,17 +714,16 @@ switch (static_cast<Animations>(index_)) { case OPACITY: index_++; - impl->active_tree()->root_layer()->ResetAllChangeTrackingForSubtree(); + impl->active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); impl->active_tree()->root_layer()->OnOpacityAnimated(0.5f); PostSetNeedsCommitToMainThread(); break; case TRANSFORM: index_++; EXPECT_TRUE(impl->active_tree()->root_layer()->LayerPropertyChanged()); - impl->active_tree()->root_layer()->ResetAllChangeTrackingForSubtree(); - impl->active_tree() - ->property_trees() - ->effect_tree.ResetChangeTracking(); + impl->active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::EFFECT_TREE); EXPECT_FALSE(impl->active_tree()->root_layer()->LayerPropertyChanged()); transform.Translate(10, 10); impl->active_tree()->root_layer()->OnTransformAnimated(transform); @@ -733,10 +732,8 @@ case FILTER: index_++; EXPECT_TRUE(impl->active_tree()->root_layer()->LayerPropertyChanged()); - impl->active_tree()->root_layer()->ResetAllChangeTrackingForSubtree(); - impl->active_tree() - ->property_trees() - ->transform_tree.ResetChangeTracking(); + impl->active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::TRANSFORM_TREE); EXPECT_FALSE(impl->active_tree()->root_layer()->LayerPropertyChanged()); filters.Append(FilterOperation::CreateOpacityFilter(0.5f)); impl->active_tree()->root_layer()->OnFilterAnimated(filters);
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc index 4df2e0b4..8abb9ee 100644 --- a/cc/trees/layer_tree_host_unittest_scroll.cc +++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -641,7 +641,7 @@ gfx::ToCeiledPoint(expected_scroll_layer_impl->position() - gfx::Vector2dF(0.5f, 0.5f)); InputHandler::ScrollStatus status = impl->ScrollBegin( - BeginState(scroll_point).get(), InputHandler::GESTURE); + BeginState(scroll_point).get(), InputHandler::TOUCHSCREEN); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); impl->ScrollBy(UpdateState(gfx::Point(), scroll_amount_).get()); LayerImpl* scrolling_layer = impl->CurrentlyScrollingLayer(); @@ -1099,7 +1099,7 @@ scroll_tree.Node(scroll_layer->scroll_tree_index()); InputHandler::ScrollStatus status = - impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, + impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); @@ -1112,7 +1112,7 @@ impl->active_tree()->BuildPropertyTreesForTesting(); scroll_tree = impl->active_tree()->property_trees()->scroll_tree; scroll_node = scroll_tree.Node(scroll_layer->scroll_tree_index()); - status = impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, + status = impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollable, @@ -1124,7 +1124,7 @@ impl->active_tree()->BuildPropertyTreesForTesting(); scroll_tree = impl->active_tree()->property_trees()->scroll_tree; scroll_node = scroll_tree.Node(scroll_layer->scroll_tree_index()); - status = impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE, + status = impl->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_IGNORED, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollable, @@ -1168,13 +1168,14 @@ // checking whether the screen space point is inside the non-fast // scrollable region. - InputHandler::ScrollStatus status = impl->TryScroll( - gfx::PointF(1.f, 1.f), InputHandler::GESTURE, scroll_tree, scroll_node); + InputHandler::ScrollStatus status = + impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN, + scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNonFastScrollableRegion, status.main_thread_scrolling_reasons); - status = impl->TryScroll(gfx::PointF(21.f, 21.f), InputHandler::GESTURE, + status = impl->TryScroll(gfx::PointF(21.f, 21.f), InputHandler::TOUCHSCREEN, scroll_tree, scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain, @@ -1215,13 +1216,13 @@ scroll_tree.Node(outer_scroll_layer->scroll_tree_index()); InputHandler::ScrollStatus status = - impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::GESTURE, + impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN, scroll_tree, inner_scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kEventHandlers, status.main_thread_scrolling_reasons); - status = impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::GESTURE, + status = impl->TryScroll(gfx::PointF(1.f, 1.f), InputHandler::TOUCHSCREEN, scroll_tree, outer_scroll_node); EXPECT_EQ(InputHandler::SCROLL_ON_IMPL_THREAD, status.thread); EXPECT_EQ(MainThreadScrollingReason::kNotScrollingOnMain,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc index ec65108..ea3851a 100644 --- a/cc/trees/layer_tree_impl.cc +++ b/cc/trees/layer_tree_impl.cc
@@ -2065,4 +2065,11 @@ : true; } +void LayerTreeImpl::ResetAllChangeTracking(PropertyTrees::ResetFlags flag) { + layers_that_should_push_properties_.clear(); + for (auto* layer : *this) + layer->ResetChangeTracking(); + property_trees_.ResetAllChangeTracking(flag); +} + } // namespace cc
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h index c6c1cae..d33d6d00 100644 --- a/cc/trees/layer_tree_impl.h +++ b/cc/trees/layer_tree_impl.h
@@ -473,6 +473,8 @@ event_properties; } + void ResetAllChangeTracking(PropertyTrees::ResetFlags flag); + protected: explicit LayerTreeImpl( LayerTreeHostImpl* layer_tree_host_impl,
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc index d35036d..174dd80 100644 --- a/cc/trees/tree_synchronizer_unittest.cc +++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -304,36 +304,35 @@ host_->SetRootLayer(layer_tree_root); - scoped_ptr<LayerImpl> layer_impl_tree_root = - TreeSynchronizer::SynchronizeTrees( - layer_tree_root.get(), nullptr, host_->active_tree()); - ExpectTreesAreIdentical(layer_tree_root.get(), - layer_impl_tree_root.get(), + host_->active_tree()->SetRootLayer(TreeSynchronizer::SynchronizeTrees( + layer_tree_root.get(), nullptr, host_->active_tree())); + LayerImpl* layer_impl_tree_root = host_->active_tree()->root_layer(); + ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root, host_->active_tree()); // We have to push properties to pick up the destruction list pointer. - TreeSynchronizer::PushProperties(layer_tree_root.get(), - layer_impl_tree_root.get()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl_tree_root); - layer_impl_tree_root->ResetAllChangeTrackingForSubtree(); + host_->active_tree()->ResetAllChangeTracking( + PropertyTrees::ResetFlags::ALL_TREES); // re-insert the layer and sync again. child2->RemoveFromParent(); layer_tree_root->AddChild(child2); - layer_impl_tree_root = TreeSynchronizer::SynchronizeTrees( - layer_tree_root.get(), std::move(layer_impl_tree_root), - host_->active_tree()); - ExpectTreesAreIdentical(layer_tree_root.get(), - layer_impl_tree_root.get(), + host_->active_tree()->SetRootLayer(TreeSynchronizer::SynchronizeTrees( + layer_tree_root.get(), host_->active_tree()->DetachLayerTree(), + host_->active_tree())); + layer_impl_tree_root = host_->active_tree()->root_layer(); + ExpectTreesAreIdentical(layer_tree_root.get(), layer_impl_tree_root, host_->active_tree()); - TreeSynchronizer::PushProperties(layer_tree_root.get(), - layer_impl_tree_root.get()); + TreeSynchronizer::PushProperties(layer_tree_root.get(), layer_impl_tree_root); // Check that the impl thread properly tracked the change. EXPECT_FALSE(layer_impl_tree_root->LayerPropertyChanged()); EXPECT_FALSE(layer_impl_tree_root->children()[0]->LayerPropertyChanged()); EXPECT_TRUE(layer_impl_tree_root->children()[1]->LayerPropertyChanged()); + host_->active_tree()->DetachLayerTree(); } TEST_F(TreeSynchronizerTest, SyncSimpleTreeAndProperties) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java index 41c12ba..ac110e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/bottombar/OverlayPanelBase.java
@@ -328,7 +328,7 @@ * @return Whether the Overlay Panel is opened. That is, whether it is EXPANDED or MAXIMIZED. */ public boolean isPanelOpened() { - return mPanelState == PanelState.EXPANDED || mPanelState == PanelState.MAXIMIZED; + return mHeight > mBarHeightPeeking; } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java index 8cc347d..d8eded3 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/dom_distiller/ReaderModeManager.java
@@ -86,10 +86,14 @@ private final int mHeaderBackgroundColor; private boolean mIsFullscreenModeEntered; - private boolean mIsInfoBarContainerShown; private boolean mIsFindToolbarShowing; private boolean mIsKeyboardShowing; + // InfoBar tracking. + private boolean mIsInfoBarContainerShown; + private boolean mContainerHasInfoBars; + + public ReaderModeManager(TabModelSelector selector, ChromeActivity activity) { super(selector); mTabId = Tab.INVALID_TAB_ID; @@ -261,8 +265,12 @@ @Override public void onAddInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isFirst) { - // Temporarily hides the reader mode button while the infobars are shown. - if (isFirst) { + mContainerHasInfoBars = true; + // If the panel is opened past the peeking state, obscure the infobar. + if (mReaderModePanel != null && mReaderModePanel.isPanelOpened()) { + container.setIsObscuredByOtherView(true); + } else if (isFirst) { + // Temporarily hides the reader mode button while the infobars are shown. mIsInfoBarContainerShown = true; closeReaderPanel(StateChangeReason.INFOBAR_SHOWN, false); } @@ -272,6 +280,7 @@ public void onRemoveInfoBar(InfoBarContainer container, InfoBar infoBar, boolean isLast) { // Re-shows the reader mode button if necessary once the infobars are dismissed. if (isLast) { + mContainerHasInfoBars = false; mIsInfoBarContainerShown = false; requestReaderPanelShow(StateChangeReason.INFOBAR_HIDDEN); } @@ -315,6 +324,14 @@ @Override public void onClosed(StateChangeReason reason) { + if (mContainerHasInfoBars && mTabModelSelector != null) { + Tab curTab = mTabModelSelector.getCurrentTab(); + if (curTab != null) { + InfoBarContainer container = curTab.getInfoBarContainer(); + container.setIsObscuredByOtherView(false); + } + } + if (mReaderModePanel == null) return; // Only dismiss the panel if the close was a result of user interaction.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java index 5593a0f..d0c5c5cd 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/ChromeMediaRouter.java
@@ -31,6 +31,9 @@ private static final String TAG = "MediaRouter"; + private static MediaRouteProvider.Builder sRouteProviderBuilder = + new CastMediaRouteProvider.Builder(); + // The pointer to the native object. Can be null only during tests. private final long mNativeMediaRouterAndroid; private final List<MediaRouteProvider> mRouteProviders = new ArrayList<MediaRouteProvider>(); @@ -42,6 +45,11 @@ new HashMap<String, List<MediaSink>>(); @VisibleForTesting + public static void setRouteProviderBuilderForTest(MediaRouteProvider.Builder builder) { + sRouteProviderBuilder = builder; + } + + @VisibleForTesting protected List<MediaRouteProvider> getRouteProvidersForTest() { return mRouteProviders; } @@ -149,7 +157,7 @@ public static ChromeMediaRouter create(long nativeMediaRouterAndroid, Context applicationContext) { ChromeMediaRouter router = new ChromeMediaRouter(nativeMediaRouterAndroid); - MediaRouteProvider provider = CastMediaRouteProvider.create(applicationContext, router); + MediaRouteProvider provider = sRouteProviderBuilder.create(applicationContext, router); if (provider != null) router.addMediaRouteProvider(provider); return router; @@ -232,7 +240,8 @@ int requestId) { MediaRouteProvider provider = getProviderForSource(sourceId); if (provider == null) { - onRouteRequestError("Presentation URL is not supported", requestId); + onRouteRequestError("No provider supports createRoute with source: " + sourceId + + " and sink: " + sinkId, requestId); return; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteProvider.java index 58bd6cd..0b50874 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/MediaRouteProvider.java
@@ -4,12 +4,20 @@ package org.chromium.chrome.browser.media.router; +import android.content.Context; + /** * An interface components providing media sinks and routes need to implement to hooks up into * {@link ChromeMediaRouter}. */ public interface MediaRouteProvider { /** + * Builder for {@link MediaRouteProvider}. + */ + interface Builder { + MediaRouteProvider create(Context applicationContext, MediaRouteManager manager); + } + /** * @param sourceId The id of the source to check. * @return if the specified source is supported by this route provider. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java index 5fc4b6d..2dbe6597 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/media/router/cast/CastMediaRouteProvider.java
@@ -54,6 +54,16 @@ private CreateRouteRequest mPendingCreateRouteRequest; private Handler mHandler = new Handler(); + /** + * Builder class for {@link CastMediaRouteProvider}. + */ + public static class Builder implements MediaRouteProvider.Builder { + @Override + public MediaRouteProvider create(Context applicationContext, MediaRouteManager manager) { + return CastMediaRouteProvider.create(applicationContext, manager); + } + } + private static class OnSinksReceivedRunnable implements Runnable { private final WeakReference<MediaRouteManager> mRouteManager; @@ -455,7 +465,8 @@ return new CastMediaRouteProvider(applicationContext, androidMediaRouter, manager); } - private CastMediaRouteProvider( + @VisibleForTesting + CastMediaRouteProvider( Context applicationContext, MediaRouter androidMediaRouter, MediaRouteManager manager) { mApplicationContext = applicationContext; mAndroidMediaRouter = androidMediaRouter;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java index 0f4b44c..35fbafb8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -26,7 +26,7 @@ * Access gate to C++ side offline pages functionalities. */ @JNINamespace("offline_pages::android") -public final class OfflinePageBridge { +public class OfflinePageBridge { public static final String BOOKMARK_NAMESPACE = "bookmark"; public static final long INVALID_OFFLINE_ID = 0; @@ -155,8 +155,9 @@ /** * Creates an offline page bridge for a given profile. + * Accessible by the package for testability. */ - private OfflinePageBridge(long nativeOfflinePageBridge) { + OfflinePageBridge(long nativeOfflinePageBridge) { mNativeOfflinePageBridge = nativeOfflinePageBridge; } @@ -224,7 +225,7 @@ * @return A list of all offline ids that match a particular * (namespace, client_id) */ - private Set<Long> getOfflineIdsForClientId(ClientId clientId) { + Set<Long> getOfflineIdsForClientId(ClientId clientId) { assert mIsNativeOfflinePageModelLoaded; long[] offlineIds = nativeGetOfflineIdsForClientId( mNativeOfflinePageBridge, clientId.getNamespace(), clientId.getId()); @@ -464,7 +465,7 @@ } @CalledByNative - private void offlinePageModelLoaded() { + void offlinePageModelLoaded() { mIsNativeOfflinePageModelLoaded = true; for (OfflinePageModelObserver observer : mObservers) { observer.offlinePageModelLoaded(); @@ -520,7 +521,7 @@ private native void nativeGetAllPages( long nativeOfflinePageBridge, List<OfflinePageItem> offlinePages); - private native long[] nativeGetOfflineIdsForClientId( + protected native long[] nativeGetOfflineIdsForClientId( long nativeOfflinePageBridge, String clientNamespace, String clientId); private native OfflinePageItem nativeGetPageByOfflineId( long nativeOfflinePageBridge, long offlineId);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java index e4b0618..a18141d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -80,8 +80,8 @@ return dialog; } - private void selectItem(Dialog dialog, int position, final String expectedItemId, - final boolean expectedEnabledState) throws InterruptedException { + private void selectItem(Dialog dialog, int position, String expectedItemId, + boolean expectedEnabledState) throws InterruptedException { final ListView items = (ListView) dialog.findViewById(R.id.items); final Button button = (Button) dialog.findViewById(R.id.positive); @@ -95,23 +95,25 @@ // Verify first item selected gets selected. TouchCommon.singleClickView(items.getChildAt(position - 1)); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return button.isEnabled() == expectedEnabledState; - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(expectedEnabledState, new Callable<Boolean>() { + @Override + public Boolean call() { + return button.isEnabled(); + } + })); if (!expectedEnabledState) return; TouchCommon.singleClickView(button); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return mLastSelectedId.equals(expectedItemId); - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(expectedItemId, new Callable<String>() { + @Override + public String call() { + return mLastSelectedId; + } + })); } @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java index 36f1495..a586a62 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/NavigateTest.java
@@ -251,12 +251,12 @@ mTestServer.getURL("/chrome/test/data/android/redirect/one.html"); typeInOmniboxAndNavigate(initialUrl, null); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(redirectedUrl, new Callable<String>() { @Override - public boolean isSatisfied() { - return getActivity().getActivityTab().getUrl().equals(redirectedUrl); + public String call() { + return getActivity().getActivityTab().getUrl(); } - }); + })); } /** @@ -283,12 +283,12 @@ typeInOmniboxAndNavigate(initialUrl, null); // Now intent fallback should be triggered assuming 'non_existent' scheme cannot be handled. - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(targetUrl, new Callable<String>() { @Override - public boolean isSatisfied() { - return getActivity().getActivityTab().getUrl().equals(targetUrl); + public String call() { + return getActivity().getActivityTab().getUrl(); } - }); + })); // Check if Java redirections were removed from the history. // Note that if we try to go back in the test: NavigateToEntry() is called, but @@ -411,12 +411,12 @@ // Wait for the url to change. final Tab tab = TabModelUtils.getCurrentTab(model); assertWaitForPageScaleFactorMatch(0.75f); - CriteriaHelper.pollForCriteria(new Criteria("Page url didn't change") { + CriteriaHelper.pollForCriteria(Criteria.equals(mockedUrl, new Callable<String>() { @Override - public boolean isSatisfied() { - return mockedUrl.equals(getTabUrlOnUIThread(tab)); + public String call() { + return getTabUrlOnUIThread(tab); } - }, 5000, 50); + }), 5000, 50); // Make sure that we're showing new content now. assertEquals("Still showing spoofed data", "\"Real\"", getTabBodyText(tab));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java index cb53bfb..c71d4ba9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PopupTest.java
@@ -23,6 +23,7 @@ import org.chromium.net.test.EmbeddedTestServer; import java.util.ArrayList; +import java.util.concurrent.Callable; /** * Tests whether popup windows appear. @@ -73,12 +74,12 @@ @Feature({"Popup"}) public void testPopupInfobarAppears() throws Exception { loadUrl(mPopupHtmlUrl); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getNumInfobarsShowing() == 1; + public Integer call() { + return getNumInfobarsShowing(); } - }); + })); } @MediumTest @@ -91,12 +92,12 @@ : getActivity().getTabModelSelector(); loadUrl(mPopupHtmlUrl); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getNumInfobarsShowing() == 1; + public Integer call() { + return getNumInfobarsShowing(); } - }); + })); assertEquals(1, selector.getTotalTabCount()); final InfoBarContainer container = selector.getCurrentTab().getInfoBarContainer(); ArrayList<InfoBar> infobars = container.getInfoBarsForTesting();
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java index 32cfec2c..ed57be8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -557,12 +557,12 @@ TabModelUtils.closeTabByIndex(getActivity().getCurrentTabModel(), 0); } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getTotalTabCount() == 0; + public Integer call() { + return getActivity().getTabModelSelector().getTotalTabCount(); } - }); + })); // Open a tab via an external application. final Intent intent = new Intent( @@ -573,12 +573,12 @@ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); getInstrumentation().getTargetContext().startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getTotalTabCount() == 1; + public Integer call() { + return getActivity().getTabModelSelector().getTotalTabCount(); } - }); + })); ApplicationTestUtils.assertWaitForPageScaleFactorMatch(getActivity(), 0.5f, false); // Long press the center of the page, which should bring up the context menu. @@ -610,12 +610,12 @@ }); // The second tab should open in the background. - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(2, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getTotalTabCount() == 2; + public Integer call() { + return getActivity().getTabModelSelector().getTotalTabCount(); } - }); + })); // Hitting "back" should close the tab, minimize Chrome, and select the background tab. // Confirm that the number of tabs is correct and that closing the tab didn't cause a crash. @@ -625,12 +625,12 @@ getActivity().onBackPressed(); } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getTotalTabCount() == 1; + public Integer call() { + return getActivity().getTabModelSelector().getTotalTabCount(); } - }); + })); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java index bd5031c0..3a683998 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsTest.java
@@ -70,6 +70,7 @@ import org.chromium.net.test.EmbeddedTestServer; import java.util.Locale; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -156,12 +157,12 @@ } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria("Tab never spawned in normal model.") { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(2, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getModel(false).getCount() == 2; + public Integer call() { + return getActivity().getTabModelSelector().getModel(false).getCount(); } - }); + })); } @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java index 96daa473..911957e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/appmenu/AppMenuTest.java
@@ -27,6 +27,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Tests AppMenu popup */ @@ -92,12 +94,12 @@ mAppMenu.getPopup().getListView().setSelection(0); } }); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getCurrentFocusedRow() == 0; + public Integer call() { + return getCurrentFocusedRow(); } - }); + })); getInstrumentation().waitForIdleSync(); } @@ -244,23 +246,23 @@ pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN); final int expectedPosition = index + increment; CriteriaHelper.pollForCriteria( - new Criteria("Focus did not move to the next menu item") { + Criteria.equals(expectedPosition, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getCurrentFocusedRow() == expectedPosition; + public Integer call() { + return getCurrentFocusedRow(); } - }); + })); } // Try moving past it by one. if (movePast) { pressKey(towardsTop ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN); - CriteriaHelper.pollForCriteria(new Criteria("Focus moved past the edge menu item") { + CriteriaHelper.pollForCriteria(Criteria.equals(end, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getCurrentFocusedRow() == end; + public Integer call() { + return getCurrentFocusedRow(); } - }); + })); } // The menu should stay open.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java index e347efa..a581a01d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; @@ -305,12 +306,12 @@ private void waitForKeyboardShowRequest(final TestInputMethodManagerWrapper immw, final int count) throws InterruptedException { CriteriaHelper.pollForUIThreadCriteria( - new Criteria("Keyboard was never requested to be shown.") { + Criteria.equals(count, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return immw.getShowSoftInputCounter() == count; + public Integer call() { + return immw.getShowSoftInputCounter(); } - }); + })); } private void waitForAnchorViewAdd(final ViewGroup view) throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java index 75419df..c89f579 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/banners/AppBannerManagerTest.java
@@ -40,6 +40,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; /** * Tests the app banners. @@ -449,12 +450,13 @@ new TabLoadObserver(getActivity().getActivityTab()).fullyLoadUrl(mNativeAppUrl); final Integer iteration = Integer.valueOf(i); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return mDetailsDelegate.mNumRetrieved == iteration; - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(iteration, new Callable<Integer>() { + @Override + public Integer call() { + return mDetailsDelegate.mNumRetrieved; + } + })); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java index 73aa40e..e0041736 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextmenu/ContextMenuTest.java
@@ -10,7 +10,6 @@ import android.os.Environment; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; -import android.text.TextUtils; import android.view.ContextMenu; import android.view.KeyEvent; @@ -33,6 +32,7 @@ import org.chromium.net.test.EmbeddedTestServer; import java.io.IOException; +import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; @@ -157,14 +157,12 @@ // Only check for the URL matching as the tab will not be fully created in svelte mode. final String expectedUrl = mTestServer.getURL(expectedPath); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(expectedUrl, new Callable<String>() { @Override - public boolean isSatisfied() { - String actualUrl = newTab.get().getUrl(); - updateFailureReason("Expected URL: " + expectedUrl + ", actual: " + actualUrl); - return TextUtils.equals(actualUrl, expectedUrl); + public String call() { + return newTab.get().getUrl(); } - }); + })); } @MediumTest @@ -236,7 +234,7 @@ throws InterruptedException, TimeoutException, SecurityException, IOException { // Click the video to enable playback DOMUtils.clickNode(this, getActivity().getCurrentContentViewCore(), "videoDOMElement"); - saveMediaFromContextMenu("videoDOMElement", R.id.contextmenu_save_video, "test.webm"); + saveMediaFromContextMenu("videoDOMElement", R.id.contextmenu_save_video, "test.mp4"); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index cd5180f..efc9f59 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -19,7 +19,6 @@ import android.preference.PreferenceManager; import android.test.FlakyTest; import android.test.suitebuilder.annotation.SmallTest; -import android.text.TextUtils; import android.view.KeyEvent; import android.view.View; import android.view.ViewConfiguration; @@ -63,6 +62,7 @@ import org.chromium.ui.base.PageTransition; import org.chromium.ui.touch_selection.SelectionEventType; +import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; // TODO(pedrosimonetti): Create class with limited API to encapsulate the internals of simulations. @@ -172,12 +172,12 @@ * @param text The string to wait for the selection to become. */ public void waitForSelectionToBe(final String text) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria("Bar never showed desired text.") { + CriteriaHelper.pollForCriteria(Criteria.equals(text, new Callable<String>() { @Override - public boolean isSatisfied() { - return TextUtils.equals(text, getSelectedText()); + public String call() { + return getSelectedText(); } - }, TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL); + }), TEST_TIMEOUT, DEFAULT_POLLING_INTERVAL); } /** @@ -1676,14 +1676,12 @@ * Asserts whether the App Menu is visible. */ private void assertAppMenuVisibility(final boolean isVisible) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(isVisible, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - if (getActivity() - .getAppMenuHandler().isAppMenuShowing() == isVisible) return true; - return false; + public Boolean call() { + return getActivity().getAppMenuHandler().isAppMenuShowing(); } - }); + })); } /** @@ -1896,13 +1894,13 @@ private void assertWaitForSelectActionBarVisible(final boolean visible) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(visible, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return visible == getActivity().getActivityTab().getContentViewCore() + public Boolean call() { + return getActivity().getActivityTab().getContentViewCore() .isSelectActionBarShowing(); } - }); + })); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index c50b6de8..6fd392f 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -569,12 +569,12 @@ (new CustomTabsTestUtils.DummyCallback()).asBinder())); } })); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(mTestPage, new Callable<String>() { @Override - public boolean isSatisfied() { - return mActivity.getActivityTab().getUrl().equals(mTestPage); + public String call() { + return mActivity.getActivityTab().getUrl(); } - }); + })); assertTrue("CustomTabContentHandler can't handle intent with same session", ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { @Override @@ -597,12 +597,12 @@ } catch (TimeoutException e) { fail(); } - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(mTestPage2, new Callable<String>() { @Override - public boolean isSatisfied() { - return mActivity.getActivityTab().getUrl().equals(mTestPage2); + public String call() { + return mActivity.getActivityTab().getUrl(); } - }); + })); } @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java index f857bda6..47faa00 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/DocumentModeReferrerTest.java
@@ -22,6 +22,8 @@ import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.content_public.browser.LoadUrlParams; +import java.util.concurrent.Callable; + /** * Tests that Document mode handles referrers correctly. */ @@ -85,12 +87,12 @@ IntentHandler.addTrustedIntentExtras(intent, mContext); mContext.startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(URL_1, new Callable<String>() { @Override - public boolean isSatisfied() { - return URL_1.equals(mUrl); + public String call() { + return mUrl; } - }); + })); assertEquals(URL_2, mReferrer); } @@ -138,12 +140,12 @@ intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(androidAppReferrer)); mContext.startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(URL_1, new Callable<String>() { @Override - public boolean isSatisfied() { - return URL_1.equals(mUrl); + public String call() { + return mUrl; } - }); + })); assertEquals(androidAppReferrer, mReferrer); } @@ -191,12 +193,12 @@ intent.putExtra(Intent.EXTRA_REFERRER, Uri.parse(nonAppExtra)); mContext.startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(URL_1, new Callable<String>() { @Override - public boolean isSatisfied() { - return URL_1.equals(mUrl); + public String call() { + return mUrl; } - }); + })); // Check that referrer is not carried over assertNull(mReferrer); @@ -246,12 +248,12 @@ IntentHandler.setPendingReferrer(intent, "http://www.google.com"); mContext.startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(URL_1, new Callable<String>() { @Override - public boolean isSatisfied() { - return URL_1.equals(mUrl); + public String call() { + return mUrl; } - }); + })); // Check that referrer is not carried over assertEquals("http://www.google.com", mReferrer);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java index 913c952..aee9d25 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/document/LauncherActivityTest.java
@@ -16,6 +16,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Tests for launching Chrome. */ @@ -41,13 +43,13 @@ mContext.startActivity(intent); // Check that Chrome launched successfully - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - int state = ApplicationStatus.getStateForApplication(); - return state == ApplicationState.HAS_RUNNING_ACTIVITIES; - } - }); + CriteriaHelper.pollForCriteria( + Criteria.equals(ApplicationState.HAS_RUNNING_ACTIVITIES, new Callable<Integer>() { + @Override + public Integer call() { + return ApplicationStatus.getStateForApplication(); + } + })); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java index 15e3d85b..9529560 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadTest.java
@@ -28,6 +28,7 @@ import org.chromium.net.test.EmbeddedTestServer; import java.io.File; +import java.util.concurrent.Callable; /** * Tests Chrome download feature by attempting to download some files. @@ -127,12 +128,13 @@ assertEquals(mTestServer.getURL("/chrome/test/data/android/download/test.gzip"), callbackHelper.getDownloadInfo().getUrl()); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return getActivity().getCurrentTabModel().getCount() == initialTabCount; - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(initialTabCount, new Callable<Integer>() { + @Override + public Integer call() { + return getActivity().getCurrentTabModel().getCount(); + } + })); } @MediumTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java index 7159f16..b428b9c9 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/externalnav/UrlOverridingTest.java
@@ -34,6 +34,7 @@ import org.chromium.ui.base.PageTransition; import java.io.UnsupportedEncodingException; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -323,12 +324,12 @@ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); targetContext.startActivity(intent); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return mActivityMonitor.getHits() == 1; + public Integer call() { + return mActivityMonitor.getHits(); } - }); + })); } @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java index dca5582..ee9b9ec 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -40,6 +40,7 @@ import org.chromium.content.browser.test.util.UiUtils; import org.chromium.net.test.EmbeddedTestServer; +import java.util.concurrent.Callable; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; @@ -380,17 +381,14 @@ waitForTopControlsPosition(expectedPosition); } - private void waitForTopControlsPosition(final float position) - throws InterruptedException { + private void waitForTopControlsPosition(float position) throws InterruptedException { final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(position, new Callable<Float>() { @Override - public boolean isSatisfied() { - updateFailureReason("Top controls did not reach expected position. Expected: " - + position + ", Actual: " + fullscreenManager.getControlOffset()); - return position == fullscreenManager.getControlOffset(); + public Float call() { + return fullscreenManager.getControlOffset(); } - }); + })); } private void waitForNoBrowserTopControlsOffset() throws InterruptedException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java index 6697902..697be73 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfobarTest.java
@@ -126,12 +126,12 @@ } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getModel(false).getCount() == 1; + public Integer call() { + return getActivity().getTabModelSelector().getModel(false).getCount(); } - }); + })); } finally { ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override @@ -198,12 +198,12 @@ assertFalse(webContents.isDestroyed()); runJavaScriptCodeInCurrentTab("document.querySelector('iframe').src = '';"); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getInfoBars().size() == 0; + public Integer call() { + return getInfoBars().size(); } - }); + })); ChromeTabUtils.closeCurrentTab(getInstrumentation(), getActivity()); CriteriaHelper.pollForUIThreadCriteria(new Criteria() { @@ -213,12 +213,12 @@ } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getActivity().getTabModelSelector().getModel(false).getCount() == 1; + public Integer call() { + return getActivity().getTabModelSelector().getModel(false).getCount(); } - }); + })); } finally { ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java new file mode 100644 index 0000000..be5ba33 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MediaRouterIntegrationTest.java
@@ -0,0 +1,342 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.media.router; + +import android.os.Environment; +import android.os.StrictMode; +import android.test.suitebuilder.annotation.LargeTest; +import android.view.View; + +import org.chromium.base.ThreadUtils; +import org.chromium.base.test.util.CommandLineFlags; +import org.chromium.chrome.browser.ChromeActivity; +import org.chromium.chrome.browser.media.RouterTestUtils; +import org.chromium.chrome.test.ChromeActivityTestCaseBase; +import org.chromium.content.browser.test.util.Criteria; +import org.chromium.content.browser.test.util.CriteriaHelper; +import org.chromium.content.browser.test.util.JavaScriptUtils; +import org.chromium.content.common.ContentSwitches; +import org.chromium.content_public.browser.WebContents; +import org.chromium.net.test.EmbeddedTestServer; + +import org.json.JSONObject; + +import java.io.StringWriter; +import java.util.concurrent.TimeoutException; + +/** + * Integration tests for MediaRouter. + */ +@CommandLineFlags.Add(ContentSwitches.DISABLE_GESTURE_REQUIREMENT_FOR_PRESENTATION) +public class MediaRouterIntegrationTest extends ChromeActivityTestCaseBase<ChromeActivity> { + + private static final String TEST_PAGE = + "/chrome/test/media_router/resources/basic_test.html?__is_android__=true"; + private static final String TEST_PAGE_RECONNECT_FAIL = + "/chrome/test/media_router/resources/fail_reconnect_session.html?__is_android__=true"; + + private static final String TEST_SINK_NAME = "test-sink-1"; + // The javascript snippets. + private static final String UNSET_RESULT_SCRIPT = "lastExecutionResult = null"; + private static final String GET_RESULT_SCRIPT = "lastExecutionResult"; + private static final String CHECK_SESSION_SCRIPT = "checkSession();"; + private static final String CHECK_START_FAILED_SCRIPT = "checkStartFailed('%s', '%s');"; + private static final String START_SESSION_SCRIPT = "startSession();"; + private static final String TERMINATE_SESSION_SCRIPT = + "terminateSessionAndWaitForStateChange();"; + private static final String WAIT_DEVICE_SCRIPT = "waitUntilDeviceAvailable();"; + private static final String SEND_MESSAGE_AND_EXPECT_RESPONSE_SCRIPT = + "sendMessageAndExpectResponse('%s');"; + private static final String SEND_MESSAGE_AND_EXPECT_CONNECTION_CLOSE_ON_ERROR_SCRIPT = + "sendMessageAndExpectConnectionCloseOnError()"; + + private static final int VIEW_TIMEOUT_MS = 10000; + private static final int VIEW_RETRY_MS = 100; + private static final int SCRIPT_TIMEOUT_MS = 10000; + private static final int SCRIPT_RETRY_MS = 50; + + private StrictMode.ThreadPolicy mOldPolicy; + + private EmbeddedTestServer mTestServer; + + public MediaRouterIntegrationTest() { + super(ChromeActivity.class); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + // Temporary until support library is updated, see http://crbug.com/576393. + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + mOldPolicy = StrictMode.allowThreadDiskReads(); + StrictMode.allowThreadDiskWrites(); + } + }); + mTestServer = EmbeddedTestServer.createAndStartFileServer( + getInstrumentation().getContext(), Environment.getExternalStorageDirectory()); + } + + @Override + public void tearDown() throws Exception { + // Temporary until support library is updated, see http://crbug.com/576393. + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + StrictMode.setThreadPolicy(mOldPolicy); + } + }); + mTestServer.stopAndDestroyServer(); + super.tearDown(); + } + + // TODO(zqzhang): Move this to a util class? + // TODO(zqzhang): This method does not handle Unicode escape sequences. + private String unescapeString(String str) { + assert str.charAt(0) == '\"' && str.charAt(str.length() - 1) == '\"'; + str = str.substring(1, str.length() - 1); + StringWriter writer = new StringWriter(); + for (int i = 0; i < str.length(); i++) { + char thisChar = str.charAt(i); + if (thisChar != '\\') { + writer.write(str.charAt(i)); + continue; + } + char nextChar = str.charAt(++i); + switch (nextChar) { + case 't': + writer.write('\t'); + break; + case 'b': + writer.write('\b'); + break; + case 'n': + writer.write('\n'); + break; + case 'r': + writer.write('\r'); + break; + case 'f': + writer.write('\f'); + break; + case '\'': + writer.write('\''); + break; + case '\"': + writer.write('\"'); + break; + case '\\': + writer.write('\\'); + break; + default: + writer.write(nextChar); + } + } + return writer.toString(); + } + + private void executeJavaScriptApi(WebContents webContents, String script) { + executeJavaScriptApi(webContents, script, SCRIPT_TIMEOUT_MS, SCRIPT_RETRY_MS); + } + + private void executeJavaScriptApi( + final WebContents webContents, final String script, int maxTimeoutMs, int intervalMs) { + try { + JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents, UNSET_RESULT_SCRIPT); + JavaScriptUtils.executeJavaScriptAndWaitForResult(webContents, script); + CriteriaHelper.pollForCriteria(new Criteria() { + @Override + public boolean isSatisfied() { + try { + String result = JavaScriptUtils.executeJavaScriptAndWaitForResult( + webContents, GET_RESULT_SCRIPT); + return !result.equals("null"); + } catch (Exception e) { + return false; + } + } + }, maxTimeoutMs, intervalMs); + String unescapedResult = unescapeString(JavaScriptUtils + .executeJavaScriptAndWaitForResult(webContents, GET_RESULT_SCRIPT)); + JSONObject jsonResult = new JSONObject(unescapedResult); + assertTrue(jsonResult.getString("errorMessage"), + jsonResult.getBoolean("passed")); + } catch (Exception e) { + e.printStackTrace(); + fail("caught exception while executing javascript:" + script); + } + } + + String getJavaScriptVariable(WebContents webContents, String script) { + try { + String result = JavaScriptUtils.executeJavaScriptAndWaitForResult( + webContents, script); + if (result.charAt(0) == '\"' && result.charAt(result.length() - 1) == '\"') { + result = result.substring(1, result.length() - 1); + } + return result; + } catch (Exception e) { + e.printStackTrace(); + fail(); + return null; + } + } + + void checkStartFailed(WebContents webContents, String errorName, String errorMessageSubstring) { + String script = String.format(CHECK_START_FAILED_SCRIPT, errorName, errorMessageSubstring); + executeJavaScriptApi(webContents, script); + } + + @Override + public void startMainActivity() throws InterruptedException { + ChromeMediaRouter.setRouteProviderBuilderForTest(new MockMediaRouteProvider.Builder()); + startMainActivityOnBlankPage(); + } + + @LargeTest + public void testMANUALBasic() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + executeJavaScriptApi(webContents, CHECK_SESSION_SCRIPT); + String sessionId = getJavaScriptVariable(webContents, "startedConnection.id"); + assertFalse(sessionId.length() == 0); + String defaultRequestSessionId = getJavaScriptVariable( + webContents, "defaultRequestSessionId"); + assertEquals(sessionId, defaultRequestSessionId); + // TODO(zqzhang): The route state change callbacks are not properly called in Android, so + // the following script is skipped. See http://crbug.com/592732 + // executeJavaScriptApi(webContents, TERMINATE_SESSION_SCRIPT); + } + + @LargeTest + public void testMANUALSendAndOnMessage() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + executeJavaScriptApi(webContents, CHECK_SESSION_SCRIPT); + String sessionId = getJavaScriptVariable(webContents, "startedConnection.id"); + assertFalse(sessionId.length() == 0); + executeJavaScriptApi(webContents, + String.format(SEND_MESSAGE_AND_EXPECT_RESPONSE_SCRIPT, "foo")); + } + + @LargeTest + public void testMANUALOnClose() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + executeJavaScriptApi(webContents, CHECK_SESSION_SCRIPT); + String sessionId = getJavaScriptVariable(webContents, "startedConnection.id"); + assertFalse(sessionId.length() == 0); + // TODO(zqzhang): The route state change callbacks are not properly called in Android, so + // the following script is skipped. See http://crbug.com/592732 + // executeJavaScriptApi(webContents, + // SEND_MESSAGE_AND_EXPECT_CONNECTION_CLOSE_ON_ERROR_SCRIPT); + } + + @LargeTest + public void testMANUALFailNoProvider() throws InterruptedException, TimeoutException { + MockMediaRouteProvider.Builder.sProvider.setIsSupportsSource(false); + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + checkStartFailed( + webContents, "UnknownError", "No provider supports createRoute with source"); + } + + @LargeTest + public void testMANUALFailCreateRoute() throws InterruptedException, TimeoutException { + MockMediaRouteProvider.Builder.sProvider.setCreateRouteErrorMessage("Unknown sink"); + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + checkStartFailed( + webContents, "UnknownError", "Unknown sink"); + } + + @LargeTest + public void testMANUALReconnectSession() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + executeJavaScriptApi(webContents, CHECK_SESSION_SCRIPT); + String sessionId = getJavaScriptVariable(webContents, "startedConnection.id"); + + loadUrlInNewTab(mTestServer.getURL(TEST_PAGE)); + WebContents newWebContents = getActivity().getActivityTab().getWebContents(); + assertTrue(webContents != newWebContents); + executeJavaScriptApi(newWebContents, String.format("reconnectSession(\'%s\');", sessionId)); + String reconnectedSessionId = + getJavaScriptVariable(newWebContents, "reconnectedSession.id"); + assertEquals(sessionId, reconnectedSessionId); + // TODO(zqzhang): The route state change callbacks are not properly called in Android, so + // the following script is skipped. See http://crbug.com/592732 + // executeJavaScriptApi(webContents, TERMINATE_SESSION_SCRIPT); + } + + @LargeTest + public void testMANUALFailReconnectSession() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + RouterTestUtils.mouseSingleClickView(getInstrumentation(), testRouteButton); + executeJavaScriptApi(webContents, CHECK_SESSION_SCRIPT); + String sessionId = getJavaScriptVariable(webContents, "startedConnection.id"); + + MockMediaRouteProvider.Builder.sProvider.setJoinRouteErrorMessage("Unknown route"); + loadUrlInNewTab(mTestServer.getURL(TEST_PAGE_RECONNECT_FAIL)); + WebContents newWebContents = getActivity().getActivityTab().getWebContents(); + assertTrue(webContents != newWebContents); + executeJavaScriptApi(newWebContents, + String.format("checkReconnectSessionFails('%s');", sessionId)); + } + + @LargeTest + public void testMANUALFailStartCancelled() throws InterruptedException, TimeoutException { + loadUrl(mTestServer.getURL(TEST_PAGE)); + WebContents webContents = getActivity().getActivityTab().getWebContents(); + executeJavaScriptApi(webContents, WAIT_DEVICE_SCRIPT); + executeJavaScriptApi(webContents, START_SESSION_SCRIPT); + View testRouteButton = RouterTestUtils.waitForRouteButton( + getActivity(), TEST_SINK_NAME, VIEW_TIMEOUT_MS, VIEW_RETRY_MS); + assertNotNull(testRouteButton); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + RouterTestUtils.getDialogFragment(getActivity()).getDialog().cancel(); + } + }); + checkStartFailed(webContents, "AbortError", "Dialog closed."); + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java new file mode 100644 index 0000000..4431397 --- /dev/null +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/router/MockMediaRouteProvider.java
@@ -0,0 +1,189 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.media.router; + +import android.content.Context; + +import org.chromium.base.Log; +import org.chromium.base.ThreadUtils; +import org.chromium.chrome.browser.media.router.cast.MediaSink; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +/** + * Mocked {@link MediaRouteProvider}. + */ +public class MockMediaRouteProvider implements MediaRouteProvider { + private static final String TAG = "MediaRouter"; + + private static final String SINK_ID1 = "test_sink_id_1"; + private static final String SINK_ID2 = "test_sink_id_2"; + private static final String SINK_NAME1 = "test-sink-1"; + private static final String SINK_NAME2 = "test-sink-2"; + + private Context mApplicationContext; + private MediaRouteManager mManager; + + private final Map<String, MediaRoute> mRoutes = new HashMap<String, MediaRoute>(); + private final Map<String, MediaRoute> mPresentationIdToRoute = + new HashMap<String, MediaRoute>(); + + private int mSinksObservedDelayMillis = 0; + private int mCreateRouteDelayMillis = 0; + private boolean mIsSupportsSource = true; + private String mCreateRouteErrorMessage = null; + private String mJoinRouteErrorMessage = null; + private boolean mCloseRouteWithErrorOnSend = false; + + /** + * Builder for {@link MockMediaRouteProvider}. + */ + public static class Builder implements MediaRouteProvider.Builder { + public static final MockMediaRouteProvider sProvider = new MockMediaRouteProvider(); + + @Override + public MediaRouteProvider create(Context applicationContext, MediaRouteManager manager) { + sProvider.mApplicationContext = applicationContext; + sProvider.mManager = manager; + return sProvider; + } + } + + private MockMediaRouteProvider() {} + + public void setCreateRouteDelayMillis(int delayMillis) { + assert delayMillis >= 0; + mCreateRouteDelayMillis = delayMillis; + } + + public void setSinksObservedDelayMillis(int delayMillis) { + assert delayMillis >= 0; + mSinksObservedDelayMillis = delayMillis; + } + + public void setIsSupportsSource(boolean isSupportsSource) { + mIsSupportsSource = isSupportsSource; + } + + public void setCreateRouteErrorMessage(String errorMessage) { + mCreateRouteErrorMessage = errorMessage; + } + + public void setJoinRouteErrorMessage(String errorMessage) { + mJoinRouteErrorMessage = errorMessage; + } + + public void setCloseRouteWithErrorOnSend(boolean closeRouteWithErrorOnSend) { + mCloseRouteWithErrorOnSend = closeRouteWithErrorOnSend; + } + + @Override + public boolean supportsSource(String sourceId) { + return mIsSupportsSource; + } + + @Override + public void startObservingMediaSinks(final String sourceId) { + final ArrayList<MediaSink> sinks = new ArrayList<MediaSink>(); + sinks.add(new MediaSink(SINK_ID1, SINK_NAME1, null)); + sinks.add(new MediaSink(SINK_ID2, SINK_NAME2, null)); + ThreadUtils.postOnUiThreadDelayed(new Runnable() { + @Override + public void run() { + mManager.onSinksReceived(sourceId, MockMediaRouteProvider.this, sinks); + } + }, mSinksObservedDelayMillis); + } + + @Override + public void stopObservingMediaSinks(String sourceId) { + } + + @Override + public void createRoute(final String sourceId, final String sinkId, final String presentationId, + final String origin, final int tabId, final int nativeRequestId) { + if (mCreateRouteErrorMessage != null) { + mManager.onRouteRequestError(mCreateRouteErrorMessage, nativeRequestId); + return; + } + + if (mCreateRouteDelayMillis == 0) { + doCreateRoute(sourceId, sinkId, presentationId, origin, tabId, nativeRequestId); + } else { + ThreadUtils.postOnUiThreadDelayed(new Runnable() { + @Override + public void run() { + doCreateRoute( + sourceId, sinkId, presentationId, origin, tabId, nativeRequestId); + } + }, mCreateRouteDelayMillis); + } + } + + private void doCreateRoute(String sourceId, String sinkId, String presentationId, String origin, + int tabId, int nativeRequestId) { + MediaRoute route = new MediaRoute(sinkId, sourceId, presentationId); + mRoutes.put(route.id, route); + mPresentationIdToRoute.put(presentationId, route); + mManager.onRouteCreated(route.id, sinkId, nativeRequestId, this, true); + } + + @Override + public void joinRoute(String sourceId, String presentationId, String origin, int tabId, + int nativeRequestId) { + if (mJoinRouteErrorMessage != null) { + mManager.onRouteRequestError(mJoinRouteErrorMessage, nativeRequestId); + return; + } + MediaRoute existingRoute = mPresentationIdToRoute.get(presentationId); + if (existingRoute == null) { + mManager.onRouteRequestError("Presentation does not exist", nativeRequestId); + return; + } + mManager.onRouteCreated( + existingRoute.id, existingRoute.sinkId, nativeRequestId, this, true); + } + + @Override + public void closeRoute(String routeId) { + MediaRoute route = mRoutes.get(routeId); + if (route == null) { + Log.i(TAG, "closeRoute: Route does not exist: " + routeId); + return; + } + mRoutes.remove(routeId); + Map<String, MediaRoute> newPresentationIdToRoute = new HashMap<String, MediaRoute>(); + for (Map.Entry<String, MediaRoute> entry : mPresentationIdToRoute.entrySet()) { + if (!entry.getValue().id.equals(routeId)) { + newPresentationIdToRoute.put(entry.getKey(), entry.getValue()); + } + } + mPresentationIdToRoute.clear(); + mPresentationIdToRoute.putAll(newPresentationIdToRoute); + mManager.onRouteClosed(routeId); + } + + @Override + public void detachRoute(String routeId) { + } + + @Override + public void sendStringMessage(String routeId, String message, int nativeCallbackId) { + if (mCloseRouteWithErrorOnSend) { + // TODO(zqzhang): The method need to notify the router that the connection state has + // changed, so PresentationConnection.onclose will be called. See + // http://crbug.com/592732 + } else { + // Sending a string enclosed by double quotes to behave like JSON.stringify(). + mManager.onMessage(routeId, "\"" + "Pong: " + message + "\""); + } + } + + @Override + public void sendBinaryMessage(String routeId, byte[] data, int nativeCallbackId) { + } +}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java index d7a8d80e..1cddfd8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/DocumentModeRecentlyClosedTest.java
@@ -114,12 +114,12 @@ }); // Wait until the DocumentTabModel updates and shows a single tab. - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return selector.getTotalTabCount() == 1; + public Integer call() { + return selector.getTotalTabCount(); } - }); + })); // Check recently closed, make sure it shows one open and one closed tab. DocumentActivity activity = @@ -165,12 +165,12 @@ selector.getModel(false).closeTabAt(0); } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(2, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return selector.getTotalTabCount() == 2; + public Integer call() { + return selector.getTotalTabCount(); } - }); + })); // Check that the right things appear in Recent Tabs. List<CurrentlyOpenTab> afterOpenTabs = recentTabsManager.getCurrentlyOpenTabs(); @@ -240,12 +240,12 @@ ActivityDelegate delegate = new ActivityDelegateImpl(DocumentActivity.class, IncognitoDocumentActivity.class); delegate.finishAndRemoveTask(false, tabIds[0]); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(2, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return selector.getTotalTabCount() == 2; + public Integer call() { + return selector.getTotalTabCount(); } - }); + })); // Check that the Tab shows up under Recently closed. final DocumentRecentTabsManager recentTabsManager = getRecentTabsManager(thirdActivity);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java index 829f4fa94..54d0566 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/NewTabPageTest.java
@@ -299,14 +299,14 @@ }); } - private void waitForUrlFocusAnimationsDisabledState(final boolean disabled) + private void waitForUrlFocusAnimationsDisabledState(boolean disabled) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(disabled, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return getUrlFocusAnimatonsDisabled() == disabled; + public Boolean call() { + return getUrlFocusAnimatonsDisabled(); } - }); + })); } private void waitForTabLoading() throws InterruptedException { @@ -322,14 +322,14 @@ waitForUrlFocusPercent(ntp, 1f); } - private void waitForUrlFocusPercent(final NewTabPage ntp, final float percent) + private void waitForUrlFocusPercent(final NewTabPage ntp, float percent) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(percent, new Callable<Float>() { @Override - public boolean isSatisfied() { - return ntp.getNewTabPageView().getUrlFocusChangeAnimationPercent() == percent; + public Float call() { + return ntp.getNewTabPageView().getUrlFocusChangeAnimationPercent(); } - }); + })); } private void clickFakebox() { @@ -355,13 +355,13 @@ /** * Waits until the top of the fakebox reaches the given position. */ - private void waitForFakeboxTopPosition(final NewTabPage ntp, final int position) + private void waitForFakeboxTopPosition(final NewTabPage ntp, int position) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(position, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getFakeboxTop(ntp) == position; + public Integer call() { + return getFakeboxTop(ntp); } - }); + })); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java index 9d6871ff..f8de189 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxTest.java
@@ -103,22 +103,22 @@ final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); OmniboxTestUtils.toggleUrlBarFocus(urlBar, true); - CriteriaHelper.pollForCriteria(new Criteria("Soft input mode failed to switch on focus") { - @Override - public boolean isSatisfied() { - return getActivity().getWindow().getAttributes().softInputMode - == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; - } - }); + CriteriaHelper.pollForCriteria(Criteria.equals( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, new Callable<Integer>() { + @Override + public Integer call() { + return getActivity().getWindow().getAttributes().softInputMode; + } + })); OmniboxTestUtils.toggleUrlBarFocus(urlBar, false); - CriteriaHelper.pollForCriteria(new Criteria("Soft input mode failed to switch on unfocus") { - @Override - public boolean isSatisfied() { - return getActivity().getWindow().getAttributes().softInputMode - == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; - } - }); + CriteriaHelper.pollForCriteria(Criteria.equals( + WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE, new Callable<Integer>() { + @Override + public Integer call() { + return getActivity().getWindow().getAttributes().softInputMode; + } + })); } /** @@ -145,13 +145,12 @@ OmniboxTestUtils.toggleUrlBarFocus(urlBar, true); - CriteriaHelper.pollForCriteria(new Criteria( - "Should have requested zero suggest on focusing") { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return controller.numZeroSuggestRequests() == 1; + public Integer call() { + return controller.numZeroSuggestRequests(); } - }); + })); } /** @@ -201,13 +200,12 @@ singleClickView(deleteButton); - CriteriaHelper.pollForCriteria(new Criteria( - "Should have requested zero suggest results on url bar empty") { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return controller.numZeroSuggestRequests() == 1; + public Integer call() { + return controller.numZeroSuggestRequests(); } - }); + })); } @MediumTest @@ -242,13 +240,12 @@ assertEquals("No calls to zero suggest yet", 0, controller.numZeroSuggestRequests()); KeyUtils.singleKeyEventView(getInstrumentation(), urlBar, KeyEvent.KEYCODE_DEL); - CriteriaHelper.pollForCriteria(new Criteria( - "Should have requested zero suggest results on url bar empty") { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return controller.numZeroSuggestRequests() == 1; + public Integer call() { + return controller.numZeroSuggestRequests(); } - }); + })); } // Sanity check that no text is displayed in the omnibox when on the NTP page and that the hint
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java index fa733fc..3e7da6e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarTest.java
@@ -10,7 +10,6 @@ import android.content.Intent; import android.test.suitebuilder.annotation.SmallTest; import android.text.Editable; -import android.text.TextUtils; import android.view.inputmethod.BaseInputConnection; import org.chromium.base.ThreadUtils; @@ -365,13 +364,12 @@ } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals("testy", new Callable<String>() { @Override - public boolean isSatisfied() { - return TextUtils.equals("testy", requestedAutocompleteText.get()); + public String call() { + return requestedAutocompleteText.get(); } - }); - assertEquals("Autocomplete sent incorrectly.", "testy", requestedAutocompleteText.get()); + })); } @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java index bf1865b..26d6ff2 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerDisableIncognitoModeIntegrationTest.java
@@ -162,13 +162,12 @@ toggleActivityForegroundState(); waitForParentalControlsEnabledState(true); - CriteriaHelper.pollForCriteria( - new Criteria("Incognito tabs did not close as expected") { - @Override - public boolean isSatisfied() { - return incognitoTabsCount() == 0; - } - }); + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { + @Override + public Integer call() { + return incognitoTabsCount(); + } + })); } finally { testServer.stopAndDestroyServer(); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java index 4db649dd..03207c7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/partnercustomizations/PartnerHomepageIntegrationTest.java
@@ -36,6 +36,7 @@ import org.chromium.content.browser.test.util.UiUtils; import org.chromium.net.test.EmbeddedTestServer; +import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; /** @@ -148,18 +149,18 @@ }); } - private void waitForCheckedState(final Preferences preferenceActivity, final boolean isChecked) + private void waitForCheckedState(final Preferences preferenceActivity, boolean isChecked) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(isChecked, new Callable<Boolean>() { @Override - public boolean isSatisfied() { + public Boolean call() { // The underlying switch view in the preference can change, so we need to fetch // it each time to ensure we are checking the activity view. SwitchCompat homepageSwitch = (SwitchCompat) preferenceActivity.findViewById(R.id.switch_widget); - return homepageSwitch.isChecked() == isChecked; + return homepageSwitch.isChecked(); } - }); + })); } /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java index 3b5d2d8..d36d07c7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/tab/InterceptNavigationDelegateTest.java
@@ -17,6 +17,7 @@ import org.chromium.net.test.EmbeddedTestServer; import java.util.ArrayList; +import java.util.concurrent.Callable; import java.util.concurrent.TimeoutException; /** @@ -66,15 +67,14 @@ startMainActivityOnBlankPage(); } - private void waitTillExpectedCallsComplete(final int count, long timeout) { + private void waitTillExpectedCallsComplete(int count, long timeout) { try { - CriteriaHelper.pollForCriteria(new Criteria( - "Failed while waiting for all calls to complete.") { + CriteriaHelper.pollForCriteria(Criteria.equals(count, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return mHistory.size() == count; + public Integer call() { + return mHistory.size(); } - }, timeout, CriteriaHelper.DEFAULT_POLLING_INTERVAL); + }), timeout, CriteriaHelper.DEFAULT_POLLING_INTERVAL); } catch (InterruptedException e) { fail("Failed while waiting for all calls to complete." + e); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java index 5f3039fc..0eeb82d 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/toolbar/BrandColorTest.java
@@ -26,6 +26,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Contains tests for the brand color feature. */ @@ -74,26 +76,25 @@ == mToolbar.getBackgroundDrawable().getColor(); } }); - CriteriaHelper.pollForUIThreadCriteria(new Criteria( - "The overlay drawable doesn't contain the right color") { - @Override - public boolean isSatisfied() { - return mToolbar.getOverlayDrawable().getColor() == brandColor; - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(brandColor, new Callable<Integer>() { + @Override + public Integer call() { + return mToolbar.getOverlayDrawable().getColor(); + } + })); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !SysUtils.isLowEndDevice()) { final int expectedStatusBarColor = brandColor == mDefaultColor ? Color.BLACK : ColorUtils.getDarkenedColorForStatusBar(brandColor); - CriteriaHelper.pollForUIThreadCriteria(new Criteria( - "The status bar is not set to the right color") { - @Override - public boolean isSatisfied() { - return expectedStatusBarColor - == getActivity().getWindow().getStatusBarColor(); - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(expectedStatusBarColor, new Callable<Integer>() { + @Override + public Integer call() { + return getActivity().getWindow().getStatusBarColor(); + } + })); } } catch (InterruptedException e) {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java index 4beef50..fc65f566 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappDirectoryManagerTest.java
@@ -21,6 +21,7 @@ import java.io.File; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; /** * Tests that directories for WebappActivities are managed correctly. @@ -157,11 +158,12 @@ private void runCleanup() throws Exception { final AsyncTask task = mWebappDirectoryManager.cleanUpDirectories(mMockContext, WEBAPP_ID_1); - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return task.getStatus() == AsyncTask.Status.FINISHED; - } - }); + CriteriaHelper.pollForCriteria( + Criteria.equals(AsyncTask.Status.FINISHED, new Callable<AsyncTask.Status>() { + @Override + public AsyncTask.Status call() { + return task.getStatus(); + } + })); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java index 3faea04..970c218 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappSplashScreenThemeColorTest.java
@@ -20,6 +20,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Tests for splash screens with EXTRA_THEME_COLOR specified in the Intent. */ @@ -63,13 +65,13 @@ }); // Waits for theme-color to change so the test doesn't rely on system timing. - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return getActivity().getWindow().getStatusBarColor() - == ColorUtils.getDarkenedColorForStatusBar(Color.GREEN); - } - }); + CriteriaHelper.pollForCriteria(Criteria.equals( + ColorUtils.getDarkenedColorForStatusBar(Color.GREEN), new Callable<Integer>() { + @Override + public Integer call() { + return getActivity().getWindow().getStatusBarColor(); + } + })); } @SmallTest
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java index 2a67ce64..f801ea7 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/widget/findinpage/FindTest.java
@@ -35,6 +35,8 @@ import org.chromium.content.browser.test.util.UiUtils; import org.chromium.net.test.EmbeddedTestServer; +import java.util.concurrent.Callable; + /** * Find in page tests. */ @@ -59,16 +61,17 @@ /** * Returns the FindResults text. */ - private String waitForFindResults(final String expectedResult) throws InterruptedException { + private String waitForFindResults(String expectedResult) throws InterruptedException { final TextView findResults = (TextView) getActivity().findViewById(R.id.find_status); assertNotNull(expectedResult); assertNotNull(findResults); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return expectedResult.equals(findResults.getText()); - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(expectedResult, new Callable<CharSequence>() { + @Override + public CharSequence call() { + return findResults.getText(); + } + })); return findResults.getText().toString(); }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java new file mode 100644 index 0000000..5f2d216 --- /dev/null +++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeTest.java
@@ -0,0 +1,73 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.offlinepages; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.chromium.base.BaseChromiumApplication; +import org.chromium.base.test.util.Feature; +import org.chromium.testing.local.LocalRobolectricTestRunner; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.annotation.Config; + +import java.util.Set; + +/** + * Unit tests for OfflinePageUtils. + */ +@RunWith(LocalRobolectricTestRunner.class) +@Config(manifest = Config.NONE, application = BaseChromiumApplication.class) +public class OfflinePageBridgeTest { + private OfflinePageBridge mBridge; + + private static final String TEST_NAMESPACE = "TEST_NAMESPACE"; + private static final String TEST_ID = "TEST_ID"; + + @Before + public void setUp() throws Exception { + OfflinePageBridge bridge = new OfflinePageBridge(0); + // Using the spy to automatically marshal all the calls to the original methods if they are + // not mocked explicitly. + mBridge = spy(bridge); + } + + /** + * Tests OfflinePageBridge#getPageByClientId() method in a scenario where a model was loaded. + */ + @Test + @Feature({"OfflinePages"}) + public void testGetPageByClientId() { + doReturn(new long[] {123, 456}) + .when(mBridge) + .nativeGetOfflineIdsForClientId(anyLong(), eq(TEST_NAMESPACE), eq(TEST_ID)); + + mBridge.offlinePageModelLoaded(); + + ClientId testClientId = new ClientId(TEST_NAMESPACE, TEST_ID); + Set<Long> result = mBridge.getOfflineIdsForClientId(testClientId); + assertEquals(2, result.size()); + assertTrue(result.contains(123L)); + assertTrue(result.contains(456L)); + verify(mBridge, times(1)) + .nativeGetOfflineIdsForClientId(anyLong(), anyString(), anyString()); + } + + @Test(expected = AssertionError.class) + @Feature({"OfflinePages"}) + public void testGetPageByClientId_ModelNotLoaded() { + ClientId testClientId = new ClientId("TEST_NAMESPACE", "TEST_ID"); + Set<Long> result = mBridge.getOfflineIdsForClientId(testClientId); + } +}
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java index c29eba9..ebfd590d 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/AutofillTest.java
@@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; /** * Test suite for the autofill profile sync data type. @@ -181,18 +182,13 @@ count, ModelType.AUTOFILL_PROFILE, name)); } - private void waitForClientAutofillProfileCount(final int count) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria( - "Expected " + count + " local autofill profiles.") { + private void waitForClientAutofillProfileCount(int count) throws InterruptedException { + CriteriaHelper.pollForCriteria(Criteria.equals(count, new Callable<Integer>() { @Override - public boolean isSatisfied() { - try { - return SyncTestUtil.getLocalData(mContext, AUTOFILL_TYPE).size() == count; - } catch (Exception e) { - throw new RuntimeException(e); - } + public Integer call() throws Exception { + return SyncTestUtil.getLocalData(mContext, AUTOFILL_TYPE).size(); } - }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS); + }), SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS); } private void waitForServerAutofillProfileCountWithName(final int count, final String name)
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java index d2e2aa83..c7476ea 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/BookmarksTest.java
@@ -470,17 +470,13 @@ count, ModelType.BOOKMARKS, name)); } - private void waitForClientBookmarkCount(final int n) throws InterruptedException { - pollForCriteria(new Criteria("There should be " + n + " local bookmarks.") { + private void waitForClientBookmarkCount(int n) throws InterruptedException { + pollForCriteria(Criteria.equals(n, new Callable<Integer>() { @Override - public boolean isSatisfied() { - try { - return SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).size() == n; - } catch (Exception e) { - throw new RuntimeException(e); - } + public Integer call() throws Exception { + return SyncTestUtil.getLocalData(mContext, BOOKMARKS_TYPE_STRING).size(); } - }); + })); } private void waitForServerBookmarkCountWithName(final int count, final String name)
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java index fb9ac579..edd1562 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/GmsCoreSyncListenerTest.java
@@ -13,6 +13,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Test suite for the GmsCoreSyncListener. */ @@ -117,13 +119,12 @@ }); } - private void waitForCallCount(final int count) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + private void waitForCallCount(int count) throws InterruptedException { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(count, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return mListener.callCount() == count; + public Integer call() { + return mListener.callCount(); } - }); - assertEquals(count, mListener.callCount()); + })); } }
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java index 7bb262e..1d10992 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/OpenTabsTest.java
@@ -32,6 +32,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; /** * Test suite for the open tabs (sessions) sync data type. @@ -241,17 +242,12 @@ throws InterruptedException { final List<String> urlList = new ArrayList<String>(urls.length); for (String url : urls) urlList.add(url); - pollForCriteria(new Criteria("Expected local open tabs for client " + clientName + ": " - + Arrays.toString(urls)) { + pollForCriteria(Criteria.equals(urlList, new Callable<List<String>>() { @Override - public boolean isSatisfied() { - try { - return getLocalTabsForClient(clientName).urls.equals(urlList); - } catch (Exception e) { - throw new RuntimeException(e); - } + public List<String> call() throws Exception { + return getLocalTabsForClient(clientName).urls; } - }); + })); } private void waitForServerTabs(final String... urls) @@ -269,16 +265,12 @@ } private String getClientName() throws Exception { - pollForCriteria(new Criteria("Expected 2 entities when getting the client name.") { + pollForCriteria(Criteria.equals(2, new Callable<Integer>() { @Override - public boolean isSatisfied() { - try { - return SyncTestUtil.getLocalData(mContext, OPEN_TABS_TYPE).size() == 2; - } catch (JSONException e) { - throw new RuntimeException(e); - } + public Integer call() throws Exception { + return SyncTestUtil.getLocalData(mContext, OPEN_TABS_TYPE).size(); } - }); + })); List<Pair<String, JSONObject>> tabEntities = SyncTestUtil.getLocalData( mContext, OPEN_TABS_TYPE); for (Pair<String, JSONObject> tabEntity : tabEntities) {
diff --git a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java index 71fbece..d2287b9 100644 --- a/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java +++ b/chrome/android/sync_shell/javatests/src/org/chromium/chrome/browser/sync/TypedUrlsTest.java
@@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.concurrent.Callable; /** * Test suite for the typed URLs sync data type. @@ -140,18 +141,13 @@ count, ModelType.TYPED_URLS, name)); } - private void waitForClientTypedUrlCount(final int count) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria( - "Expected " + count + " local typed URL entities.") { + private void waitForClientTypedUrlCount(int count) throws InterruptedException { + CriteriaHelper.pollForCriteria(Criteria.equals(count, new Callable<Integer>() { @Override - public boolean isSatisfied() { - try { - return SyncTestUtil.getLocalData(mContext, TYPED_URLS_TYPE).size() == count; - } catch (Exception e) { - throw new RuntimeException(e); - } + public Integer call() throws Exception { + return SyncTestUtil.getLocalData(mContext, TYPED_URLS_TYPE).size(); } - }, SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS); + }), SyncTestUtil.TIMEOUT_MS, SyncTestUtil.INTERVAL_MS); } private void waitForServerTypedUrlCountWithName(final int count, final String name)
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index 5eae9de..3dd8bb6b 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp
@@ -1583,14 +1583,14 @@ Previous password </message> <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_TITLE" desc="Title for the fatal cryptohome error dialog box"> - Could not sign in + Can't sign in </message> <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_MESSAGE" desc="Message for the fatal cryptohome error dialog box"> - We're very sorry, but a serious error has occurred and your profile on this device will need to be re-created to continue.<ph name="BR"><br></ph> + We're sorry. We can't access your profile. Files and data stored on this device may have been lost.<ph name="BR"><br></ph> <ph name="BR"><br></ph> - Don't worry, your account is safe, but unfortunately, your local data and files on this device may have been lost.<ph name="BR"><br></ph> + You'll have to set up your profile again.<ph name="BR"><br></ph> <ph name="BR"><br></ph> - Please send feedback to help us prevent this issue in the future. + On the next screen, please send feedback to help us fix the issue. </message> <message name="IDS_LOGIN_UNRECOVERABLE_CRYPTOHOME_ERROR_CONTINUE" desc="Label of the button to continue with re-creating cryptohome for the fatal cryptohome error dialog box"> Continue @@ -5666,12 +5666,6 @@ <message name="IDS_PLATFORM_VERIFICATION_DIALOG_HEADLINE" desc="The label to describe what the dialog wants to confirm."> <ph name="DOMAIN">$1<ex>example.com</ex></ph> wants your device's identity to be verified, by Google, to determine eligibility for enhanced playback of protected media. <ph name="LEARN_MORE">$2<ex>Learn more</ex></ph>. </message> - <message name="IDS_PLATFORM_VERIFICATION_DIALOG_ALLOW" desc="The button label to allow access of HD playback."> - OK, I got it - </message> - <message name="IDS_PLATFORM_VERIFICATION_DIALOG_DENY" desc="The button label to deny access of HD playback."> - Disable on <ph name="DOMAIN">$1<ex>example.com</ex></ph> - </message> <!-- Multi-profiles mode --> <message name="IDS_MULTIPROFILES_INTRO_HEADLINE" desc="Describes which feature multi-profiles intro dialog presents.">
diff --git a/chrome/app/settings_chromium_strings.grdp b/chrome/app/settings_chromium_strings.grdp index 3a07c5b..5098bd3 100644 --- a/chrome/app/settings_chromium_strings.grdp +++ b/chrome/app/settings_chromium_strings.grdp
@@ -1,6 +1,11 @@ <?xml version="1.0" encoding="utf-8"?> <!-- Settings-specific Chromium strings (included from chromium_strings.grd). --> <grit-part> + <!-- About Page --> + <message name="IDS_SETTINGS_ABOUT_PROGRAM" desc="Menu title for the About Chromium page."> + About Chromium + </message> + <!-- Default Browser Page --> <if expr="not chromeos"> <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is not the default browser">
diff --git a/chrome/app/settings_google_chrome_strings.grdp b/chrome/app/settings_google_chrome_strings.grdp index d4a7e4f..23ddc7f 100644 --- a/chrome/app/settings_google_chrome_strings.grdp +++ b/chrome/app/settings_google_chrome_strings.grdp
@@ -1,6 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> <!-- Settings-specific Google Chrome strings (included from google_chrome_strings.grd). --> <grit-part> + <!-- About Page --> + <if expr="chromeos"> + <message name="IDS_SETTINGS_ABOUT_PROGRAM" desc="Menu title for the About Chrome OS page."> + About Chrome OS + </message> + </if> + <if expr="not chromeos"> + <message name="IDS_SETTINGS_ABOUT_PROGRAM" desc="Menu title for the About Chrome page."> + About Chrome + </message> + </if> + <!-- Default Browser Page --> <if expr="not chromeos"> <message name="IDS_SETTINGS_DEFAULT_BROWSER_DEFAULT" desc="The text displayed when Chrome is not the default browser">
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp index 5120d6c..bbeddb0d 100644 --- a/chrome/app/settings_strings.grdp +++ b/chrome/app/settings_strings.grdp
@@ -6,11 +6,11 @@ This setting is controlled by extension <ph name="NAME">$1<ex>Settings Extension</ex></ph> </message> + <!-- Accessibility Page --> + <message name="IDS_SETTINGS_ACCESSIBILITY" desc="Name of the settings page which displays accessibility preferences."> + Accessibility + </message> <if expr="chromeos"> - <!-- Accessibility Page --> - <message name="IDS_SETTINGS_ACCESSIBILITY" desc="Name of the settings page which displays accessibility preferences."> - Accessibility - </message> <message name="IDS_SETTINGS_MORE_FEATURES_LINK" desc="Link which opens page where users can install extensions which provide additional accessibility features."> Add additional accessibility features </message> @@ -335,6 +335,11 @@ This clears synced data from all devices. </message> + <!-- Cloud Print --> + <message name="IDS_SETTINGS_GOOGLE_CLOUD_PRINT" desc="Label for the Google cloud print page and menu option."> + Google cloud print + </message> + <!-- Downloads Page --> <message name="IDS_SETTINGS_DOWNLOADS" desc="Name of the settings page which displays download preferences."> Downloads
diff --git a/chrome/browser/app_controller_mac.h b/chrome/browser/app_controller_mac.h index b5febc94..432e120 100644 --- a/chrome/browser/app_controller_mac.h +++ b/chrome/browser/app_controller_mac.h
@@ -29,6 +29,7 @@ class Profile; @class ProfileMenuController; class QuitWithAppsController; +class ScopedKeepAlive; namespace ui { class WorkAreaWatcherObserver; @@ -107,6 +108,9 @@ // This will be true after receiving a NSWorkspaceWillPowerOffNotification. BOOL isPoweringOff_; + + // Request to keep the browser alive during that object's lifetime. + scoped_ptr<ScopedKeepAlive> keep_alive_; } @property(readonly, nonatomic) BOOL startupComplete;
diff --git a/chrome/browser/app_controller_mac.mm b/chrome/browser/app_controller_mac.mm index c0a864c..819b204 100644 --- a/chrome/browser/app_controller_mac.mm +++ b/chrome/browser/app_controller_mac.mm
@@ -34,6 +34,8 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/first_run/first_run.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/mac/mac_startup_profiler.h" #include "chrome/browser/prefs/incognito_mode_prefs.h" #include "chrome/browser/profiles/profile_info_cache_observer.h" @@ -520,7 +522,7 @@ // Tell BrowserList not to keep the browser process alive. Once all the // browsers get dealloc'd, it will stop the RunLoop and fall back into main(). - chrome::DecrementKeepAliveCount(); + keep_alive_.reset(); // Reset all pref watching, as this object outlives the prefs system. profilePrefRegistrar_.reset(); @@ -728,7 +730,8 @@ // Notify BrowserList to keep the application running so it doesn't go away // when all the browser windows get closed. - chrome::IncrementKeepAliveCount(); + keep_alive_.reset(new ScopedKeepAlive(KeepAliveOrigin::APP_CONTROLLER, + KeepAliveRestartOption::DISABLED)); [self setUpdateCheckInterval];
diff --git a/chrome/browser/apps/app_window_interactive_uitest.cc b/chrome/browser/apps/app_window_interactive_uitest.cc index 4099c7d..f7e32b3 100644 --- a/chrome/browser/apps/app_window_interactive_uitest.cc +++ b/chrome/browser/apps/app_window_interactive_uitest.cc
@@ -6,6 +6,7 @@ #include "build/build_config.h" #include "chrome/browser/apps/app_browsertest_util.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/test/base/interactive_test_utils.h" @@ -528,9 +529,9 @@ for (auto* browser : *BrowserList::GetInstance()) browser->window()->Close(); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); GetFirstAppWindow()->Hide(); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); } // A window that is hidden but re-shown should still keep Chrome alive. @@ -540,10 +541,10 @@ app_window->Hide(); app_window->Show(AppWindow::SHOW_ACTIVE); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); for (auto* browser : *BrowserList::GetInstance()) browser->window()->Close(); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); app_window->GetBaseWindow()->Close(); } @@ -577,7 +578,7 @@ launched_listener.Reply(""); EXPECT_TRUE(shown_listener.WaitUntilSatisfied()); EXPECT_FALSE(app_window->is_hidden()); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); app_window->GetBaseWindow()->Close(); }
diff --git a/chrome/browser/background/background_mode_manager.cc b/chrome/browser/background/background_mode_manager.cc index c653c9f1..1e21d156 100644 --- a/chrome/browser/background/background_mode_manager.cc +++ b/chrome/browser/background/background_mode_manager.cc
@@ -29,6 +29,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/lifetime/keep_alive_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_attributes_entry.h" @@ -648,7 +649,7 @@ // Background mode must already be enabled (as otherwise this menu would // not be visible). DCHECK(IsBackgroundModePrefEnabled()); - DCHECK(chrome::WillKeepAlive()); + DCHECK(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); RecordMenuItemClick(MENU_ITEM_KEEP_RUNNING);
diff --git a/chrome/browser/background/background_mode_manager_unittest.cc b/chrome/browser/background/background_mode_manager_unittest.cc index c1f3de76..9c9fe87 100644 --- a/chrome/browser/background/background_mode_manager_unittest.cc +++ b/chrome/browser/background/background_mode_manager_unittest.cc
@@ -22,6 +22,9 @@ #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/profiles/profile_attributes_entry.h" #include "chrome/browser/profiles/profile_attributes_storage.h" #include "chrome/browser/status_icons/status_icon_menu_model.h" @@ -139,12 +142,12 @@ }; void AssertBackgroundModeActive(const TestBackgroundModeManager& manager) { - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); EXPECT_TRUE(manager.HaveStatusTray()); } void AssertBackgroundModeInactive(const TestBackgroundModeManager& manager) { - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); EXPECT_FALSE(manager.HaveStatusTray()); } @@ -236,18 +239,9 @@ // Aura clears notifications from the message center at shutdown. message_center::MessageCenter::Initialize(); - // BackgroundModeManager actually affects Chrome start/stop state, - // tearing down our thread bundle before we've had chance to clean - // everything up. Keeping Chrome alive prevents this. - // We aren't interested in if the keep alive works correctly in this test. - chrome::IncrementKeepAliveCount(); - -#if defined(OS_CHROMEOS) - // On ChromeOS shutdown, HandleAppExitingForPlatform will call - // chrome::DecrementKeepAliveCount because it assumes the aura shell - // called chrome::IncrementKeepAliveCount. Simulate the call here. - chrome::IncrementKeepAliveCount(); -#endif + test_keep_alive_.reset( + new ScopedKeepAlive(KeepAliveOrigin::BACKGROUND_MODE_MANAGER, + KeepAliveRestartOption::DISABLED)); // Create our test BackgroundModeManager. manager_.reset(new TestBackgroundModeManager( @@ -274,8 +268,8 @@ // We're getting ready to shutdown the message loop. Clear everything out! base::MessageLoop::current()->RunUntilIdle(); - // Matching the call to IncrementKeepAliveCount in SetUp(). - chrome::DecrementKeepAliveCount(); + + test_keep_alive_.reset(); // TestBackgroundModeManager has dependencies on the infrastructure. // It should get cleared first. @@ -288,9 +282,8 @@ // before tearing down the Message Center. profile_manager_.reset(); - // Message Center shutdown must occur after the DecrementKeepAliveCount - // because DecrementKeepAliveCount will end up referencing the message - // center during cleanup. + // Message Center shutdown must occur after the KeepAlive is released + // because clearing it will end up referencing the message center. message_center::MessageCenter::Shutdown(); // Clear the shutdown flag to isolate the remaining effect of this test. @@ -329,6 +322,12 @@ // Required for extension service. content::TestBrowserThreadBundle thread_bundle_; + // BackgroundModeManager actually affects Chrome start/stop state, + // tearing down our thread bundle before we've had chance to clean + // everything up. Keeping Chrome alive prevents this. + // We aren't interested in if the keep alive works correctly in this test. + scoped_ptr<ScopedKeepAlive> test_keep_alive_; + #if defined(OS_CHROMEOS) // ChromeOS needs extra services to run in the following order. chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; @@ -344,7 +343,7 @@ AdvancedTestBackgroundModeManager manager( *command_line_, profile_manager_->profile_attributes_storage(), true); manager.RegisterProfile(profile_); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); // Mimic app load. EXPECT_CALL(manager, EnableLaunchOnStartup(true)).Times(Exactly(1)); @@ -477,7 +476,7 @@ *command_line_, profile_manager_->profile_attributes_storage(), true); manager.RegisterProfile(profile_); manager.RegisterProfile(profile2); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); // Install app, should show status tray icon. EXPECT_CALL(manager, EnableLaunchOnStartup(true)).Times(Exactly(1)); @@ -528,7 +527,7 @@ AdvancedTestBackgroundModeManager manager(*command_line_, storage, true); manager.RegisterProfile(profile_); manager.RegisterProfile(profile2); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); EXPECT_EQ(2u, storage->GetNumberOfProfiles()); ProfileAttributesEntry* entry1; @@ -577,7 +576,7 @@ AdvancedTestBackgroundModeManager manager( *command_line_, profile_manager_->profile_attributes_storage(), true); manager.RegisterProfile(profile_); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); // Install app, should show status tray icon. EXPECT_CALL(manager, EnableLaunchOnStartup(true)).Times(Exactly(1)); @@ -595,7 +594,7 @@ EXPECT_EQ(base::UTF8ToUTF16("p1"), manager.GetBackgroundModeData(profile_)->name()); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); TestingProfile* profile2 = profile_manager_->CreateTestingProfile("p2"); manager.RegisterProfile(profile2); EXPECT_EQ(2, manager.NumberOfBackgroundModeData()); @@ -606,7 +605,7 @@ manager.OnProfileWillBeRemoved(profile2->GetPath()); // Should still be in background mode after deleting profile. - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); EXPECT_EQ(1, manager.NumberOfBackgroundModeData()); // Check that the background mode data we think is in the map actually is. @@ -620,7 +619,7 @@ AdvancedTestBackgroundModeManager manager( *command_line_, profile_manager_->profile_attributes_storage(), true); manager.RegisterProfile(profile_); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); // Install app, should show status tray icon. EXPECT_CALL(manager, EnableLaunchOnStartup(true)).Times(Exactly(1)); @@ -634,11 +633,11 @@ manager.GetBackgroundModeData(profile_)->name()); EXPECT_CALL(manager, EnableLaunchOnStartup(false)).Times(Exactly(1)); - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); manager.SetBackgroundClientCountForProfile(profile_, 0); manager.OnProfileWillBeRemoved(profile_->GetPath()); Mock::VerifyAndClearExpectations(&manager); - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); } TEST_F(BackgroundModeManagerTest, DisableBackgroundModeUnderTestFlag) {
diff --git a/chrome/browser/bookmarks/bookmark_model_factory.cc b/chrome/browser/bookmarks/bookmark_model_factory.cc index cece0df9..88abc71 100644 --- a/chrome/browser/bookmarks/bookmark_model_factory.cc +++ b/chrome/browser/bookmarks/bookmark_model_factory.cc
@@ -28,6 +28,7 @@ #if BUILDFLAG(ANDROID_JAVA_UI) #include "chrome/browser/android/offline_pages/offline_page_model_factory.h" +#include "components/offline_pages/offline_page_bookmark_bridge.h" #include "components/offline_pages/offline_page_feature.h" #include "components/offline_pages/offline_page_model.h" #endif // BUILDFLAG(ANDROID_JAVA_UI) @@ -91,8 +92,10 @@ #if BUILDFLAG(ANDROID_JAVA_UI) if (offline_pages::IsOfflinePagesEnabled()) { - offline_pages::OfflinePageModelFactory::GetForBrowserContext(profile)-> - Start(bookmark_model); + // This observer will delete itself when BookmarkModelDeleted is called. + bookmark_model->AddObserver(new offline_pages::OfflinePageBookmarkBridge( + offline_pages::OfflinePageModelFactory::GetForBrowserContext(profile), + bookmark_model)); } #endif // BUILDFLAG(ANDROID_JAVA_UI)
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc index d1b356c..d5d441a 100644 --- a/chrome/browser/browser_process_impl.cc +++ b/chrome/browser/browser_process_impl.cc
@@ -46,6 +46,7 @@ #include "chrome/browser/intranet_redirect_detector.h" #include "chrome/browser/io_thread.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/metrics/chrome_metrics_service_accessor.h" #include "chrome/browser/metrics/chrome_metrics_services_manager_client.h" #include "chrome/browser/metrics/thread_watcher.h" @@ -853,8 +854,16 @@ registry->RegisterStringPref(prefs::kHardwareKeyboardLayout, std::string()); #endif // defined(OS_CHROMEOS) + +#if defined(ENABLE_REPORTING_BLIMP) + // Enables reporting for the (headless) blimp engine. Defined in + // components/metrics/BUILD.gn + registry->RegisterBooleanPref(metrics::prefs::kMetricsReportingEnabled, true); +#else registry->RegisterBooleanPref(metrics::prefs::kMetricsReportingEnabled, GoogleUpdateSettings::GetCollectStatsConsent()); +#endif // defined(ENABLE_REPORTING_HEADLESS) + #if BUILDFLAG(ANDROID_JAVA_UI) registry->RegisterBooleanPref( prefs::kCrashReportingEnabled, false); @@ -1251,7 +1260,8 @@ bool BrowserProcessImpl::CanAutorestartForUpdate() const { // Check if browser is in the background and if it needs to be restarted to // apply a pending update. - return chrome::GetTotalBrowserCount() == 0 && chrome::WillKeepAlive() && + return chrome::GetTotalBrowserCount() == 0 && + KeepAliveRegistry::GetInstance()->IsKeepingAlive() && upgrade_util::IsUpdatePendingRestart(); }
diff --git a/chrome/browser/browser_process_platform_part_chromeos.cc b/chrome/browser/browser_process_platform_part_chromeos.cc index 254d379..7e6b13c 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.cc +++ b/chrome/browser/browser_process_platform_part_chromeos.cc
@@ -20,6 +20,8 @@ #include "chrome/browser/chromeos/system/device_disabling_manager_default_delegate.h" #include "chrome/browser/chromeos/system/system_clock.h" #include "chrome/browser/chromeos/system/timezone_util.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/chrome_switches.h" #include "chromeos/geolocation/simple_geolocation_provider.h" @@ -91,6 +93,17 @@ return session_manager_.get(); } +void BrowserProcessPlatformPart::RegisterKeepAlive() { + DCHECK(!keep_alive_); + keep_alive_.reset( + new ScopedKeepAlive(KeepAliveOrigin::BROWSER_PROCESS_CHROMEOS, + KeepAliveRestartOption::DISABLED)); +} + +void BrowserProcessPlatformPart::UnregisterKeepAlive() { + keep_alive_.reset(); +} + chromeos::ProfileHelper* BrowserProcessPlatformPart::profile_helper() { DCHECK(CalledOnValidThread()); if (!created_profile_helper_)
diff --git a/chrome/browser/browser_process_platform_part_chromeos.h b/chrome/browser/browser_process_platform_part_chromeos.h index 11eed8e..d5d3887 100644 --- a/chrome/browser/browser_process_platform_part_chromeos.h +++ b/chrome/browser/browser_process_platform_part_chromeos.h
@@ -40,6 +40,7 @@ } class Profile; +class ScopedKeepAlive; class BrowserProcessPlatformPart : public BrowserProcessPlatformPartBase, public base::NonThreadSafe { @@ -70,6 +71,11 @@ // out-of-box or login. virtual session_manager::SessionManager* SessionManager(); + // Used to register a KeepAlive when Ash is initialized, and release it + // when until Chrome starts exiting. Ensure we stay running the whole time. + void RegisterKeepAlive(); + void UnregisterKeepAlive(); + // Returns the ProfileHelper instance that is used to identify // users and their profiles in Chrome OS multi user session. chromeos::ProfileHelper* profile_helper(); @@ -120,6 +126,8 @@ scoped_ptr<chromeos::system::SystemClock> system_clock_; + scoped_ptr<ScopedKeepAlive> keep_alive_; + DISALLOW_COPY_AND_ASSIGN(BrowserProcessPlatformPart); };
diff --git a/chrome/browser/browsing_data/cookies_tree_model.cc b/chrome/browser/browsing_data/cookies_tree_model.cc index 1f4cfd3..79befcee 100644 --- a/chrome/browser/browsing_data/cookies_tree_model.cc +++ b/chrome/browser/browsing_data/cookies_tree_model.cc
@@ -290,9 +290,8 @@ // CookieTreeNode, public: void CookieTreeNode::DeleteStoredObjects() { - std::for_each(children().begin(), - children().end(), - std::mem_fun(&CookieTreeNode::DeleteStoredObjects)); + for (auto* child : children()) + child->DeleteStoredObjects(); } CookiesTreeModel* CookieTreeNode::GetModel() const {
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc index fee88f7..7a59f02b 100644 --- a/chrome/browser/chrome_browser_main.cc +++ b/chrome/browser/chrome_browser_main.cc
@@ -656,6 +656,8 @@ // Initialize FieldTrialList to support FieldTrials that use one-time // randomization. metrics::MetricsService* metrics = browser_process_->metrics_service(); + // TODO(asvitkine): Turn into a DCHECK after http://crbug.com/359406 is fixed. + CHECK(!field_trial_list_); field_trial_list_.reset( new base::FieldTrialList(metrics->CreateEntropyProvider().release()));
diff --git a/chrome/browser/chromeos/arc/arc_auth_service.cc b/chrome/browser/chromeos/arc/arc_auth_service.cc index 86ae290..facd3f3 100644 --- a/chrome/browser/chromeos/arc/arc_auth_service.cc +++ b/chrome/browser/chromeos/arc/arc_auth_service.cc
@@ -150,6 +150,11 @@ Shutdown(); + if (profile->IsLegacySupervised()) { + VLOG(2) << "Supervised profiles are not supported in Arc."; + return; + } + profile_ = profile; // Reuse storage used in ARC OptIn platform app. const std::string site_url =
diff --git a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc index 7344761d..ef7f651 100644 --- a/chrome/browser/chromeos/attestation/platform_verification_dialog.cc +++ b/chrome/browser/chromeos/attestation/platform_verification_dialog.cc
@@ -111,10 +111,9 @@ ui::DialogButton button) const { switch (button) { case ui::DIALOG_BUTTON_OK: - return l10n_util::GetStringUTF16(IDS_PLATFORM_VERIFICATION_DIALOG_ALLOW); + return l10n_util::GetStringUTF16(IDS_PERMISSION_ALLOW); case ui::DIALOG_BUTTON_CANCEL: - return l10n_util::GetStringFUTF16( - IDS_PLATFORM_VERIFICATION_DIALOG_DENY, domain_); + return l10n_util::GetStringUTF16(IDS_PERMISSION_DENY); default: NOTREACHED(); }
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper_api.cc index 126e53bd..58e0c30 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_api.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_api.cc
@@ -106,11 +106,13 @@ params_ = set_wallpaper::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_); - // Gets account id and username hash while at UI thread. - account_id_ = - user_manager::UserManager::Get()->GetLoggedInUser()->GetAccountId(); - user_id_hash_ = - user_manager::UserManager::Get()->GetLoggedInUser()->username_hash(); + // Gets account id and user wallpaper files id while at UI thread. + const user_manager::User* user = + user_manager::UserManager::Get()->GetLoggedInUser(); + account_id_ = user->GetAccountId(); + chromeos::WallpaperManager* wallpaper_manager = + chromeos::WallpaperManager::Get(); + wallpaper_files_id_ = wallpaper_manager->GetFilesId(*user); if (params_->details.data) { StartDecode(*params_->details.data); @@ -136,7 +138,7 @@ chromeos::WallpaperManager* wallpaper_manager = chromeos::WallpaperManager::Get(); base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath( - wallpaper::kThumbnailWallpaperSubDir, user_id_hash_, + wallpaper::kThumbnailWallpaperSubDir, wallpaper_files_id_, params_->details.filename); sequence_token_ = BrowserThread::GetBlockingPool()->GetNamedSequenceToken( @@ -153,7 +155,7 @@ account_id_ == user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(); wallpaper_manager->SetCustomWallpaper( - account_id_, user_id_hash_, params_->details.filename, layout, + account_id_, wallpaper_files_id_, params_->details.filename, layout, user_manager::User::CUSTOMIZED, image, update_wallpaper); unsafe_wallpaper_decoder_ = NULL;
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.h b/chrome/browser/chromeos/extensions/wallpaper_api.h index 9776ea7..0792c7a4 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_api.h +++ b/chrome/browser/chromeos/extensions/wallpaper_api.h
@@ -9,6 +9,7 @@ #include "chrome/browser/chromeos/extensions/wallpaper_function_base.h" #include "chrome/common/extensions/api/wallpaper.h" #include "components/signin/core/account_id/account_id.h" +#include "components/wallpaper/wallpaper_files_id.h" #include "net/url_request/url_request_status.h" namespace base { @@ -17,8 +18,8 @@ // Implementation of chrome.wallpaper.setWallpaper API. // After this API being called, a jpeg encoded wallpaper will be saved to -// /home/chronos/custom_wallpaper/{resolution}/{user_id_hash}/file_name. The -// wallpaper can then persistent after Chrome restart. New call to this API +// /home/chronos/custom_wallpaper/{resolution}/{wallpaper_files_id_}/file_name. +// The wallpaper can then persist after Chrome restart. New call to this API // will replace the previous saved wallpaper with new one. // Note: For security reason, the original encoded wallpaper image is not saved // directly. It is decoded and re-encoded to jpeg format before saved to file @@ -59,8 +60,8 @@ // User id of the user who initiate this API call. AccountId account_id_ = EmptyAccountId(); - // User id hash of the logged in user. - std::string user_id_hash_; + // Id used to identify user wallpaper files on hard drive. + wallpaper::WallpaperFilesId wallpaper_files_id_; // Sequence token associated with wallpaper operations. Shared with // WallpaperManager.
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc index 22fecf87..a51750f0 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_private_api.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.cc
@@ -601,7 +601,9 @@ // Gets account id from the caller, ensuring multiprofile compatibility. const user_manager::User* user = GetUserFromBrowserContext(browser_context()); account_id_ = user->GetAccountId(); - user_id_hash_ = user->username_hash(); + chromeos::WallpaperManager* wallpaper_manager = + chromeos::WallpaperManager::Get(); + wallpaper_files_id_ = wallpaper_manager->GetFilesId(*user); StartDecode(params->wallpaper); @@ -613,7 +615,8 @@ chromeos::WallpaperManager* wallpaper_manager = chromeos::WallpaperManager::Get(); base::FilePath thumbnail_path = wallpaper_manager->GetCustomWallpaperPath( - wallpaper::kThumbnailWallpaperSubDir, user_id_hash_, params->file_name); + wallpaper::kThumbnailWallpaperSubDir, wallpaper_files_id_, + params->file_name); sequence_token_ = BrowserThread::GetBlockingPool()->GetNamedSequenceToken( wallpaper::kWallpaperSequenceTokenName); @@ -630,7 +633,7 @@ account_id_ == user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(); wallpaper_manager->SetCustomWallpaper( - account_id_, user_id_hash_, params->file_name, layout, + account_id_, wallpaper_files_id_, params->file_name, layout, user_manager::User::CUSTOMIZED, image, update_wallpaper); unsafe_wallpaper_decoder_ = NULL;
diff --git a/chrome/browser/chromeos/extensions/wallpaper_private_api.h b/chrome/browser/chromeos/extensions/wallpaper_private_api.h index 91adf5dd..3636978 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_private_api.h +++ b/chrome/browser/chromeos/extensions/wallpaper_private_api.h
@@ -12,6 +12,7 @@ #include "chrome/browser/chromeos/extensions/wallpaper_function_base.h" #include "chrome/common/extensions/api/wallpaper_private.h" #include "components/signin/core/account_id/account_id.h" +#include "components/wallpaper/wallpaper_files_id.h" #include "net/url_request/url_fetcher_delegate.h" namespace base { @@ -167,7 +168,7 @@ AccountId account_id_ = EmptyAccountId(); // User id hash of the logged in user. - std::string user_id_hash_; + wallpaper::WallpaperFilesId wallpaper_files_id_; // Sequence token associated with wallpaper operations. Shared with // WallpaperManager.
diff --git a/chrome/browser/chromeos/login/login_browsertest.cc b/chrome/browser/chromeos/login/login_browsertest.cc index bd7b287..4d57ef6 100644 --- a/chrome/browser/chromeos/login/login_browsertest.cc +++ b/chrome/browser/chromeos/login/login_browsertest.cc
@@ -75,6 +75,12 @@ command_line->AppendSwitch(switches::kForceLoginManagerInTests); } + void TearDownOnMainThread() override { + // Close the login manager, which otherwise holds a KeepAlive that is not + // cleared in time by the end of the test. + LoginDisplayHost::default_host()->Finalize(); + } + void SetUpOnMainThread() override { LoginDisplayHostImpl::DisableRestrictiveProxyCheckForTest();
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc index e309abbc..bdd8eb1 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.cc +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.cc
@@ -54,7 +54,8 @@ #include "chrome/browser/chromeos/system/input_device_settings.h" #include "chrome/browser/chromeos/system/timezone_util.h" #include "chrome/browser/chromeos/ui/focus_ring_controller.h" -#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/ui/webui/chromeos/login/gaia_screen_handler.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" @@ -311,8 +312,9 @@ DCHECK(default_host() == nullptr); default_host_ = this; - // Make sure chrome won't exit while we are at login/oobe screen. - chrome::IncrementKeepAliveCount(); + keep_alive_.reset( + new ScopedKeepAlive(KeepAliveOrigin::LOGIN_DISPLAY_HOST_IMPL, + KeepAliveRestartOption::DISABLED)); bool is_registered = StartupUtils::IsDeviceRegistered(); bool zero_delay_enabled = WizardController::IsZeroDelayEnabled(); @@ -401,8 +403,7 @@ views::FocusManager::set_arrow_key_traversal_enabled(false); ResetLoginWindowAndView(); - // Let chrome process exit after login/oobe screen if needed. - chrome::DecrementKeepAliveCount(); + keep_alive_.reset(); default_host_ = nullptr; // TODO(tengs): This should be refactored. See crbug.com/314934.
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_impl.h b/chrome/browser/chromeos/login/ui/login_display_host_impl.h index 45b3f702..e4063c4 100644 --- a/chrome/browser/chromeos/login/ui/login_display_host_impl.h +++ b/chrome/browser/chromeos/login/ui/login_display_host_impl.h
@@ -35,6 +35,7 @@ #include "ui/wm/public/scoped_drag_drop_disabler.h" class PrefService; +class ScopedKeepAlive; namespace content { class RenderFrameHost; @@ -218,6 +219,9 @@ // Demo app launcher. scoped_ptr<DemoAppLauncher> demo_app_launcher_; + // Make sure chrome won't exit while we are at login/oobe screen. + scoped_ptr<ScopedKeepAlive> keep_alive_; + // Has ShutdownDisplayHost() already been called? Used to avoid posting our // own deletion to the message loop twice if the user logs out while we're // still in the process of cleaning up after login (http://crbug.com/134463).
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc index edfcc68..e83f13cc 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.cc
@@ -47,10 +47,12 @@ #include "components/prefs/pref_service.h" #include "components/prefs/scoped_user_pref_update.h" #include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/known_user.h" #include "components/user_manager/user.h" #include "components/user_manager/user_image/user_image.h" #include "components/user_manager/user_manager.h" #include "components/user_manager/user_type.h" +#include "components/wallpaper/wallpaper_files_id.h" #include "components/wallpaper/wallpaper_layout.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" @@ -84,6 +86,9 @@ const char kNewWallpaperLocationNodeName[] = "file"; const char kNewWallpaperTypeNodeName[] = "type"; +// Known user keys. +const char kWallpaperFilesId[] = "wallpaper-files-id"; + // These global default values are used to set customized default // wallpaper path in WallpaperManager::InitializeWallpaper(). base::FilePath GetCustomizedWallpaperDefaultRescaledFileName( @@ -124,6 +129,31 @@ return index; } +cryptohome::Identification GetUnhashedSourceForWallpaperFilesId( + const user_manager::User& user) { + const AccountId& account_id = user.GetAccountId(); + const std::string& old_id = account_id.GetUserEmail(); // Migrated + return cryptohome::Identification::FromString(old_id); +} + +wallpaper::WallpaperFilesId GetKnownUserWallpaperFilesId( + const user_manager::User& user) { + const AccountId& account_id = user.GetAccountId(); + std::string stored_value; + if (user_manager::known_user::GetStringPref(account_id, kWallpaperFilesId, + &stored_value)) { + return wallpaper::WallpaperFilesId::FromString(stored_value); + } + return wallpaper::WallpaperFilesId::FromString(user.username_hash()); +} + +void SetKnownUserWallpaperFilesId( + const AccountId& account_id, + const wallpaper::WallpaperFilesId& wallpaper_files_id) { + user_manager::known_user::SetStringPref(account_id, kWallpaperFilesId, + wallpaper_files_id.id()); +} + } // namespace // This is "wallpaper either scheduled to load, or loading right now". @@ -458,7 +488,7 @@ void WallpaperManager::SetCustomWallpaper( const AccountId& account_id, - const std::string& user_id_hash, + const wallpaper::WallpaperFilesId& wallpaper_files_id, const std::string& file, wallpaper::WallpaperLayout layout, user_manager::User::WallpaperType type, @@ -475,7 +505,7 @@ return; base::FilePath wallpaper_path = GetCustomWallpaperPath( - wallpaper::kOriginalWallpaperSubDir, user_id_hash, file); + wallpaper::kOriginalWallpaperSubDir, wallpaper_files_id, file); // If decoded wallpaper is empty, we have probably failed to decode the file. // Use default wallpaper in this case. @@ -512,12 +542,13 @@ // TODO(bshe): This may break if RawImage becomes RefCountedMemory. blocking_task_runner->PostTask( FROM_HERE, - base::Bind(&WallpaperManager::SaveCustomWallpaper, user_id_hash, + base::Bind(&WallpaperManager::SaveCustomWallpaper, wallpaper_files_id, base::FilePath(wallpaper_info.location), wallpaper_info.layout, base::Passed(std::move(deep_copy)))); } - std::string relative_path = base::FilePath(user_id_hash).Append(file).value(); + std::string relative_path = + base::FilePath(wallpaper_files_id.id()).Append(file).value(); // User's custom wallpaper path is determined by relative path and the // appropriate wallpaper resolution in GetCustomWallpaperInternal. WallpaperInfo info = { @@ -804,17 +835,19 @@ return; } - if (user->username_hash().empty()) { + const wallpaper::WallpaperFilesId wallpaper_files_id = + GetKnownUserWallpaperFilesId(*user); + if (!wallpaper_files_id.is_valid()) { cryptohome::AsyncMethodCaller::GetInstance()->AsyncGetSanitizedUsername( - cryptohome::Identification(account_id), + GetUnhashedSourceForWallpaperFilesId(*user), base::Bind(&WallpaperManager::SetCustomWallpaperOnSanitizedUsername, weak_factory_.GetWeakPtr(), account_id, user_image.image(), true /* update wallpaper */)); } else { - SetCustomWallpaper( - account_id, user->username_hash(), "policy-controlled.jpeg", - wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, user_manager::User::POLICY, - user_image.image(), true /* update wallpaper */); + SetCustomWallpaper(account_id, wallpaper_files_id, "policy-controlled.jpeg", + wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, + user_manager::User::POLICY, user_image.image(), + true /* update wallpaper */); } } @@ -823,10 +856,13 @@ const gfx::ImageSkia& image, bool update_wallpaper, bool cryptohome_success, - const std::string& user_id_hash) { + const std::string& wallpaper_files_id_str) { if (!cryptohome_success) return; - SetCustomWallpaper(account_id, user_id_hash, "policy-controlled.jpeg", + const wallpaper::WallpaperFilesId wallpaper_files_id = + wallpaper::WallpaperFilesId::FromString(wallpaper_files_id_str); + SetKnownUserWallpaperFilesId(account_id, wallpaper_files_id); + SetCustomWallpaper(account_id, wallpaper_files_id, "policy-controlled.jpeg", wallpaper::WALLPAPER_LAYOUT_CENTER_CROPPED, user_manager::User::POLICY, image, update_wallpaper); } @@ -1101,4 +1137,9 @@ } } +wallpaper::WallpaperFilesId WallpaperManager::GetFilesId( + const user_manager::User& user) const { + return GetKnownUserWallpaperFilesId(user); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h index 8762763..69e94de2 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h
@@ -86,7 +86,7 @@ // local state preferences. If |update_wallpaper| is false, don't change // wallpaper but only update cache. void SetCustomWallpaper(const AccountId& account_id, - const std::string& user_id_hash, + const wallpaper::WallpaperFilesId& wallpaper_files_id, const std::string& file, wallpaper::WallpaperLayout layout, user_manager::User::WallpaperType type, @@ -128,6 +128,10 @@ // Returns queue size. size_t GetPendingListSizeForTesting() const override; + // Returns wallpaper files id for the user. + wallpaper::WallpaperFilesId GetFilesId( + const user_manager::User& user) const override; + // Overridden from user_manager::UserManager::UserSessionStateObserver: void UserChangedChildStatus(user_manager::User* user) override; @@ -152,12 +156,14 @@ void SetPolicyControlledWallpaper(const AccountId& account_id, const user_manager::UserImage& user_image); - // Calls SetCustomWallpaper() with |user_id_hash| received from cryptohome. - void SetCustomWallpaperOnSanitizedUsername(const AccountId& account_id, - const gfx::ImageSkia& image, - bool update_wallpaper, - bool cryptohome_success, - const std::string& user_id_hash); + // Calls SetCustomWallpaper() with |wallpaper_files_id_str| received from + // cryptohome. + void SetCustomWallpaperOnSanitizedUsername( + const AccountId& account_id, + const gfx::ImageSkia& image, + bool update_wallpaper, + bool cryptohome_success, + const std::string& wallpaper_files_id_str); // WallpaperManagerBase overrides: void InitializeRegisteredDeviceWallpaper() override;
diff --git a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc index 961f2ab..8b43b4c4 100644 --- a/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc +++ b/chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager_browsertest.cc
@@ -35,6 +35,7 @@ #include "components/signin/core/account_id/account_id.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" +#include "components/wallpaper/wallpaper_files_id.h" #include "content/public/test/test_utils.h" #include "ui/aura/env.h" #include "ui/gfx/geometry/point.h" @@ -100,13 +101,13 @@ protected: // Return custom wallpaper path. Create directory if not exist. - base::FilePath GetCustomWallpaperPath(const char* sub_dir, - const std::string& username_hash, - const std::string& id) { + base::FilePath GetCustomWallpaperPath( + const char* sub_dir, + const wallpaper::WallpaperFilesId& wallpaper_files_id, + const std::string& id) { base::FilePath wallpaper_path = WallpaperManager::Get()->GetCustomWallpaperPath(sub_dir, - username_hash, - id); + wallpaper_files_id, id); if (!base::DirectoryExists(wallpaper_path.DirName())) base::CreateDirectory(wallpaper_path.DirName()); @@ -165,6 +166,11 @@ const AccountId test_account_id1_ = AccountId::FromUserEmail(kTestUser1); const AccountId test_account_id2_ = AccountId::FromUserEmail(kTestUser2); + const wallpaper::WallpaperFilesId test_account1_wallpaper_files_id_ = + wallpaper::WallpaperFilesId::FromString(kTestUser1Hash); + const wallpaper::WallpaperFilesId test_account2_wallpaper_files_id_ = + wallpaper::WallpaperFilesId::FromString(kTestUser2Hash); + private: DISALLOW_COPY_AND_ASSIGN(WallpaperManagerBrowserTest); }; @@ -177,9 +183,9 @@ LogIn(test_account_id1_, kTestUser1Hash); std::string id = base::Int64ToString(base::Time::Now().ToInternalValue()); base::FilePath small_wallpaper_path = GetCustomWallpaperPath( - wallpaper::kSmallWallpaperSubDir, kTestUser1Hash, id); + wallpaper::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id); base::FilePath large_wallpaper_path = GetCustomWallpaperPath( - wallpaper::kLargeWallpaperSubDir, kTestUser1Hash, id); + wallpaper::kLargeWallpaperSubDir, test_account1_wallpaper_files_id_, id); // Saves the small/large resolution wallpapers to small/large custom // wallpaper paths. @@ -194,7 +200,8 @@ kLargeWallpaperHeight, wallpaper_manager_test_utils::kLargeDefaultWallpaperColor)); - std::string relative_path = base::FilePath(kTestUser1Hash).Append(id).value(); + std::string relative_path = + base::FilePath(test_account1_wallpaper_files_id_.id()).Append(id).value(); // Saves wallpaper info to local state for user |test_account_id1_|. WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED, user_manager::User::CUSTOMIZED, @@ -267,14 +274,15 @@ // Change wallpaper to a custom wallpaper. std::string id = base::Int64ToString(base::Time::Now().ToInternalValue()); base::FilePath small_wallpaper_path = GetCustomWallpaperPath( - wallpaper::kSmallWallpaperSubDir, kTestUser1Hash, id); + wallpaper::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id); ASSERT_TRUE(wallpaper_manager_test_utils::WriteJPEGFile( small_wallpaper_path, kSmallWallpaperWidth, kSmallWallpaperHeight, wallpaper_manager_test_utils::kSmallDefaultWallpaperColor)); - std::string relative_path = base::FilePath(kTestUser1Hash).Append(id).value(); + std::string relative_path = + base::FilePath(test_account1_wallpaper_files_id_.id()).Append(id).value(); // Saves wallpaper info to local state for user |test_account_id1_|. WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED, user_manager::User::CUSTOMIZED, @@ -481,9 +489,9 @@ std::string id = base::Int64ToString(base::Time::Now().ToInternalValue()); WallpaperManager* wallpaper_manager = WallpaperManager::Get(); base::FilePath small_wallpaper_path = GetCustomWallpaperPath( - wallpaper::kSmallWallpaperSubDir, kTestUser1Hash, id); + wallpaper::kSmallWallpaperSubDir, test_account1_wallpaper_files_id_, id); base::FilePath large_wallpaper_path = GetCustomWallpaperPath( - wallpaper::kLargeWallpaperSubDir, kTestUser1Hash, id); + wallpaper::kLargeWallpaperSubDir, test_account1_wallpaper_files_id_, id); // Saves the small/large resolution wallpapers to small/large custom // wallpaper paths. @@ -498,7 +506,8 @@ kLargeWallpaperHeight, wallpaper_manager_test_utils::kLargeDefaultWallpaperColor)); - std::string relative_path = base::FilePath(kTestUser1Hash).Append(id).value(); + std::string relative_path = + base::FilePath(test_account1_wallpaper_files_id_.id()).Append(id).value(); // Saves wallpaper info to local state for user |test_account_id1_|. WallpaperInfo info = {relative_path, WALLPAPER_LAYOUT_CENTER_CROPPED, user_manager::User::CUSTOMIZED, @@ -566,11 +575,11 @@ EXPECT_TRUE(cached_wallpaper.BackedBySameObjectAs(red_wallpaper)); gfx::ImageSkia green_wallpaper = CreateTestImage(SK_ColorGREEN); - wallpaper_manager->SetCustomWallpaper(test_account_id1_, kTestUser1Hash, - "dummy", // dummy file name - WALLPAPER_LAYOUT_CENTER, - user_manager::User::CUSTOMIZED, - green_wallpaper, true); + wallpaper_manager->SetCustomWallpaper( + test_account_id1_, test_account1_wallpaper_files_id_, + "dummy", // dummy file name + WALLPAPER_LAYOUT_CENTER, user_manager::User::CUSTOMIZED, green_wallpaper, + true); wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished(); // SetCustomWallpaper should also update wallpaper cache when multi-profile is // turned on. @@ -833,7 +842,8 @@ gfx::ImageSkia image = wallpaper_manager_test_utils::CreateTestImage( 640, 480, wallpaper_manager_test_utils::kCustomWallpaperColor); WallpaperManager::Get()->SetCustomWallpaper( - chromeos::login::StubAccountId(), "test_hash", "test-nofile.jpeg", + chromeos::login::StubAccountId(), + wallpaper::WallpaperFilesId::FromString("test_hash"), "test-nofile.jpeg", WALLPAPER_LAYOUT_STRETCH, user_manager::User::CUSTOMIZED, image, true); wallpaper_manager_test_utils::WaitAsyncWallpaperLoadFinished();
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc index 62b3284..2613d68 100644 --- a/chrome/browser/devtools/devtools_sanity_browsertest.cc +++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -771,7 +771,6 @@ content::WindowedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, content::Source<Browser>(browser())); - chrome::IncrementKeepAliveCount(); chrome::CloseAllBrowsers(); AcceptModalDialog(); AcceptModalDialog();
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn index 7c93c82..a512418 100644 --- a/chrome/browser/extensions/BUILD.gn +++ b/chrome/browser/extensions/BUILD.gn
@@ -85,6 +85,13 @@ "//url", ] + if (enable_task_manager) { + sources += rebase_path( + gypi_values.chrome_browser_extensions_task_manager_enabled_sources, + ".", + "//chrome") + } + if (is_chromeos) { sources += rebase_path(gypi_values.chrome_browser_extensions_chromeos_sources,
diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc index ae43fd23..77a49a02 100644 --- a/chrome/browser/extensions/api/processes/processes_api.cc +++ b/chrome/browser/extensions/api/processes/processes_api.cc
@@ -4,57 +4,57 @@ #include "chrome/browser/extensions/api/processes/processes_api.h" -#include <stddef.h> #include <stdint.h> #include <algorithm> -#include <utility> -#include "base/callback.h" -#include "base/json/json_writer.h" #include "base/lazy_instance.h" -#include "base/location.h" -#include "base/metrics/histogram.h" -#include "base/single_thread_task_runner.h" +#include "base/metrics/histogram_macros.h" +#include "base/process/process.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "base/thread_task_runner_handle.h" -#include "base/values.h" -#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" -#include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/task_manager/resource_provider.h" -#include "chrome/browser/task_manager/task_manager.h" +#include "chrome/browser/task_management/task_manager_interface.h" #include "chrome/common/extensions/api/processes.h" -#include "content/public/browser/browser_context.h" -#include "content/public/browser/notification_details.h" -#include "content/public/browser/notification_service.h" -#include "content/public/browser/notification_source.h" -#include "content/public/browser/notification_types.h" +#include "content/public/browser/browser_child_process_host.h" +#include "content/public/browser/child_process_data.h" #include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/render_widget_host.h" -#include "content/public/browser/render_widget_host_iterator.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/child_process_host.h" #include "content/public/common/result_codes.h" -#include "extensions/browser/event_router.h" -#include "extensions/browser/extension_function_registry.h" -#include "extensions/browser/extension_function_util.h" #include "extensions/common/error_utils.h" +#include "third_party/WebKit/public/web/WebCache.h" namespace extensions { namespace errors { const char kNotAllowedToTerminate[] = "Not allowed to terminate process: *."; const char kProcessNotFound[] = "Process not found: *."; -const char kInavlidArgument[] = "Invalid argument: *."; +const char kInvalidArgument[] = "Invalid argument: *."; } // namespace errors namespace { -#if defined(ENABLE_TASK_MANAGER) +base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI>> + g_processes_api_factory = LAZY_INSTANCE_INITIALIZER; + +int64_t GetRefreshTypesFlagOnlyEssentialData() { + // This is the only non-optional data in the Process as defined by the API in + // processes.idl. + return task_management::REFRESH_TYPE_NACL; +} + +// This does not include memory. The memory refresh flag will only be added once +// a listener to OnUpdatedWithMemory event is added. +int64_t GetRefreshTypesForProcessOptionalData() { + return task_management::REFRESH_TYPE_CPU | + task_management::REFRESH_TYPE_NETWORK_USAGE | + task_management::REFRESH_TYPE_SQLITE_MEMORY | + task_management::REFRESH_TYPE_V8_MEMORY | + task_management::REFRESH_TYPE_WEBCACHE_STATS; +} scoped_ptr<api::processes::Cache> CreateCacheData( const blink::WebCache::ResourceTypeStat& stat) { @@ -64,279 +64,232 @@ return cache; } -api::processes::ProcessType GetProcessType(TaskManagerModel* model, - int index) { - // Determine process type. - task_manager::Resource::Type resource_type = model->GetResourceType(index); - switch (resource_type) { - case task_manager::Resource::BROWSER: +api::processes::ProcessType GetProcessType( + task_management::Task::Type task_type) { + switch (task_type) { + case task_management::Task::BROWSER: return api::processes::PROCESS_TYPE_BROWSER; - case task_manager::Resource::RENDERER: + case task_management::Task::RENDERER: return api::processes::PROCESS_TYPE_RENDERER; - case task_manager::Resource::EXTENSION: - case task_manager::Resource::GUEST: + case task_management::Task::EXTENSION: + case task_management::Task::GUEST: return api::processes::PROCESS_TYPE_EXTENSION; - case task_manager::Resource::NOTIFICATION: - return api::processes::PROCESS_TYPE_NOTIFICATION; - - case task_manager::Resource::PLUGIN: + case task_management::Task::PLUGIN: return api::processes::PROCESS_TYPE_PLUGIN; - case task_manager::Resource::WORKER: + case task_management::Task::WORKER: return api::processes::PROCESS_TYPE_WORKER; - case task_manager::Resource::NACL: + case task_management::Task::NACL: return api::processes::PROCESS_TYPE_NACL; - case task_manager::Resource::UTILITY: + case task_management::Task::UTILITY: return api::processes::PROCESS_TYPE_UTILITY; - case task_manager::Resource::GPU: + case task_management::Task::GPU: return api::processes::PROCESS_TYPE_GPU; - case task_manager::Resource::ZYGOTE: - case task_manager::Resource::SANDBOX_HELPER: - case task_manager::Resource::UNKNOWN: + case task_management::Task::UNKNOWN: + case task_management::Task::ARC: + case task_management::Task::SANDBOX_HELPER: + case task_management::Task::ZYGOTE: return api::processes::PROCESS_TYPE_OTHER; } - NOTREACHED() << "Unknown resource type."; + NOTREACHED() << "Unknown task type."; return api::processes::PROCESS_TYPE_NONE; } -void FillTabsForProcess(int process_id, api::processes::Process* out_process) { +// Fills |out_process| with the data of the process in which the task with |id| +// is running. If |include_optional| is true, this function will fill the +// optional fields in |api::processes::Process| except for |private_memory|, +// which should be filled later if needed. +void FillProcessData( + task_management::TaskId id, + task_management::TaskManagerInterface* task_manager, + bool include_optional, + api::processes::Process* out_process) { DCHECK(out_process); - // The tabs list only makes sense for render processes, so if we don't find - // one, just return the empty list. - content::RenderProcessHost* rph = - content::RenderProcessHost::FromID(process_id); - if (!rph) - return; + out_process->id = task_manager->GetChildProcessUniqueId(id); + out_process->os_process_id = task_manager->GetProcessId(id); + out_process->type = GetProcessType(task_manager->GetType(id)); + out_process->profile = base::UTF16ToUTF8(task_manager->GetProfileName(id)); + out_process->nacl_debug_port = task_manager->GetNaClDebugStubPort(id); - int tab_id = -1; - // We need to loop through all the RVHs to ensure we collect the set of all - // tabs using this renderer process. - scoped_ptr<content::RenderWidgetHostIterator> widgets( - content::RenderWidgetHost::GetRenderWidgetHosts()); - while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { - if (widget->GetProcess()->GetID() != process_id) - continue; + // Collect the tab IDs of all the tasks sharing this renderer if any. + const task_management::TaskIdList tasks_on_process = + task_manager->GetIdsOfTasksSharingSameProcess(id); + for (const auto& task_id : tasks_on_process) { + linked_ptr<api::processes::TaskInfo> task_info( + new api::processes::TaskInfo()); + task_info->title = base::UTF16ToUTF8(task_manager->GetTitle(task_id)); + const int tab_id = task_manager->GetTabId(task_id); + if (tab_id != -1) + task_info->tab_id.reset(new int(tab_id)); - content::RenderViewHost* host = content::RenderViewHost::From(widget); - content::WebContents* contents = - content::WebContents::FromRenderViewHost(host); - if (contents) { - tab_id = ExtensionTabUtil::GetTabId(contents); - if (tab_id != -1) - out_process->tabs.push_back(tab_id); - } + out_process->tasks.push_back(task_info); } -} - -// This function fills |out_process| with the data of the process with -// |process_id|. For memory details, which are not added by this function, -// the callers need to use AddMemoryDetails. -void FillProcessData(int process_id, - TaskManagerModel* model, - int index, - bool include_optional, - api::processes::Process* out_process) { - DCHECK(out_process); - - out_process->id = process_id; - out_process->os_process_id = model->GetProcessId(index); - out_process->type = GetProcessType(model, index); - out_process->title = base::UTF16ToUTF8(model->GetResourceTitle(index)); - out_process->profile = - base::UTF16ToUTF8(model->GetResourceProfileName(index)); - out_process->nacl_debug_port = model->GetNaClDebugStubPort(index); - - FillTabsForProcess(process_id, out_process); // If we don't need to include the optional properties, just return now. if (!include_optional) return; - out_process->cpu.reset(new double(model->GetCPUUsage(index))); + out_process->cpu.reset(new double(task_manager->GetCpuUsage(id))); - size_t mem = 0; - if (model->GetV8Memory(index, &mem)) { + out_process->network.reset(new double(static_cast<double>( + task_manager->GetProcessTotalNetworkUsage(id)))); + + int64_t v8_allocated = 0; + int64_t v8_used = 0; + if (task_manager->GetV8Memory(id, &v8_allocated, &v8_used)) { out_process->js_memory_allocated.reset(new double(static_cast<double>( - mem))); + v8_allocated))); + out_process->js_memory_used.reset(new double(static_cast<double>(v8_used))); } - if (model->GetV8MemoryUsed(index, &mem)) - out_process->js_memory_used.reset(new double(static_cast<double>(mem))); - - if (model->GetSqliteMemoryUsedBytes(index, &mem)) - out_process->sqlite_memory.reset(new double(static_cast<double>(mem))); + const int64_t sqlite_bytes = task_manager->GetSqliteMemoryUsed(id); + if (sqlite_bytes != -1) { + out_process->sqlite_memory.reset(new double(static_cast<double>( + sqlite_bytes))); + } blink::WebCache::ResourceTypeStats cache_stats; - if (model->GetWebCoreCacheStats(index, &cache_stats)) { + if (task_manager->GetWebCacheStats(id, &cache_stats)) { out_process->image_cache = CreateCacheData(cache_stats.images); out_process->script_cache = CreateCacheData(cache_stats.scripts); out_process->css_cache = CreateCacheData(cache_stats.cssStyleSheets); } - - // Network is reported by the TaskManager per resource (tab), not per - // process, therefore we need to iterate through the group of resources - // and aggregate the data. - int64_t net = 0; - int length = model->GetGroupRangeForResource(index).second; - for (int i = 0; i < length; ++i) - net += model->GetNetworkUsage(index + i); - out_process->network.reset(new double(static_cast<double>(net))); } -// Since memory details are expensive to gather, we don't do it by default. -// This function is a helper to add memory details data to an existing -// Process object |out_process|. -void AddMemoryDetails(TaskManagerModel* model, - int index, - api::processes::Process* out_process) { - DCHECK(out_process); - - size_t mem; - int64_t pr_mem = - model->GetPrivateMemory(index, &mem) ? static_cast<int64_t>(mem) : -1; - out_process->private_memory.reset(new double(static_cast<double>(pr_mem))); -} - -#endif // defined(ENABLE_TASK_MANAGER) - } // namespace -ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context) - : browser_context_(context), listeners_(0), task_manager_listening_(false) { -#if defined(ENABLE_TASK_MANAGER) - model_ = TaskManager::GetInstance()->model(); - model_->AddObserver(this); +//////////////////////////////////////////////////////////////////////////////// +// ProcessesEventRouter: +//////////////////////////////////////////////////////////////////////////////// - registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, - content::NotificationService::AllSources()); - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::NotificationService::AllSources()); -#endif // defined(ENABLE_TASK_MANAGER) +ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context) + : task_management::TaskManagerObserver(base::TimeDelta::FromSeconds(1), + task_management::REFRESH_TYPE_NONE), + browser_context_(context), + listeners_(0) { } ProcessesEventRouter::~ProcessesEventRouter() { -#if defined(ENABLE_TASK_MANAGER) - registrar_.Remove(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, - content::NotificationService::AllSources()); - registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, - content::NotificationService::AllSources()); - - if (task_manager_listening_) - model_->StopListening(); - - model_->RemoveObserver(this); -#endif // defined(ENABLE_TASK_MANAGER) } void ProcessesEventRouter::ListenerAdded() { -#if defined(ENABLE_TASK_MANAGER) - // The task manager has its own ref count to balance other callers of - // StartUpdating/StopUpdating. - model_->StartUpdating(); -#endif // defined(ENABLE_TASK_MANAGER) - ++listeners_; + UpdateRefreshTypesFlagsBasedOnListeners(); + + if (listeners_++ == 0) { + // The first listener to be added. + task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this); + } } void ProcessesEventRouter::ListenerRemoved() { - DCHECK_GT(listeners_, 0); - --listeners_; -#if defined(ENABLE_TASK_MANAGER) - // The task manager has its own ref count to balance other callers of - // StartUpdating/StopUpdating. - model_->StopUpdating(); -#endif // defined(ENABLE_TASK_MANAGER) -} + UpdateRefreshTypesFlagsBasedOnListeners(); -void ProcessesEventRouter::StartTaskManagerListening() { -#if defined(ENABLE_TASK_MANAGER) - if (!task_manager_listening_) { - model_->StartListening(); - task_manager_listening_ = true; + if (--listeners_ == 0) { + // Last listener to be removed. + task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver( + this); } -#endif // defined(ENABLE_TASK_MANAGER) } -void ProcessesEventRouter::Observe( - int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - - switch (type) { - case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: - ProcessHangEvent( - content::Source<content::RenderWidgetHost>(source).ptr()); - break; - case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: - ProcessClosedEvent( - content::Source<content::RenderProcessHost>(source).ptr(), - content::Details<content::RenderProcessHost::RendererClosedDetails>( - details).ptr()); - break; - default: - NOTREACHED() << "Unexpected observe of type " << type; - } - return; -} - -void ProcessesEventRouter::OnItemsAdded(int start, int length) { -#if defined(ENABLE_TASK_MANAGER) - DCHECK_EQ(length, 1); +void ProcessesEventRouter::OnTaskAdded(task_management::TaskId id) { if (!HasEventListeners(api::processes::OnCreated::kEventName)) return; - // If the item being added is not the first one in the group, find the base - // index and use it for retrieving the process data. - if (!model_->IsResourceFirstInGroup(start)) - start = model_->GetGroupIndexForResource(start); + int child_process_host_id = 0; + if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id)) + return; api::processes::Process process; - FillProcessData(model_->GetUniqueChildProcessId(start), model_, start, - false /* include_optional */, &process); + FillProcessData(id, + observed_task_manager(), + false, // include_optional + &process); DispatchEvent(events::PROCESSES_ON_CREATED, api::processes::OnCreated::kEventName, api::processes::OnCreated::Create(process)); -#endif // defined(ENABLE_TASK_MANAGER) } -void ProcessesEventRouter::OnItemsChanged(int start, int length) { -#if defined(ENABLE_TASK_MANAGER) - // If we don't have any listeners, return immediately. - if (listeners_ == 0) +void ProcessesEventRouter::OnTaskToBeRemoved(task_management::TaskId id) { + if (!HasEventListeners(api::processes::OnExited::kEventName)) return; - if (!model_) + int child_process_host_id = 0; + if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id)) return; - // We need to know which type of onUpdated events to fire and whether to - // collect memory or not. - bool updated = HasEventListeners(api::processes::OnUpdated::kEventName); - bool updated_memory = + int exit_code = 0; + base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING; + observed_task_manager()->GetTerminationStatus(id, &status, &exit_code); + + DispatchEvent(events::PROCESSES_ON_EXITED, + api::processes::OnExited::kEventName, + api::processes::OnExited::Create(child_process_host_id, + status, + exit_code)); +} + +void ProcessesEventRouter::OnTasksRefreshedWithBackgroundCalculations( + const task_management::TaskIdList& task_ids) { + const bool has_on_updated_listeners = + HasEventListeners(api::processes::OnUpdated::kEventName); + const bool has_on_updated_with_memory_listeners = HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName); - if (!updated && !updated_memory) + + if (!has_on_updated_listeners && !has_on_updated_with_memory_listeners) return; + // Get the data of tasks sharing the same process only once. + std::set<base::ProcessId> seen_processes; base::DictionaryValue processes_dictionary; - for (int i = start; i < start + length; ++i) { - if (model_->IsResourceFirstInGroup(i)) { - int id = model_->GetUniqueChildProcessId(i); - api::processes::Process process; - FillProcessData(id, model_, i, true /* include_optional */, &process); - if (updated_memory) - AddMemoryDetails(model_, i, &process); - processes_dictionary.Set(base::IntToString(id), process.ToValue()); + for (const auto& task_id : task_ids) { + // We are not interested in tasks, but rather the processes on which they + // run. + const base::ProcessId proc_id = + observed_task_manager()->GetProcessId(task_id); + if (seen_processes.count(proc_id)) + continue; + + const int child_process_host_id = + observed_task_manager()->GetChildProcessUniqueId(task_id); + // Ignore tasks that don't have a valid child process host ID like ARC + // processes. We report the browser process info here though. + if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID) + continue; + + seen_processes.insert(proc_id); + api::processes::Process process; + FillProcessData(task_id, + observed_task_manager(), + true, // include_optional + &process); + + if (has_on_updated_with_memory_listeners) { + // Append the private memory usage to the process data. + const int64_t private_memory = + observed_task_manager()->GetPrivateMemoryUsage(task_id); + process.private_memory.reset(new double(static_cast<double>( + private_memory))); } + + // Store each process indexed by the string version of its ChildProcessHost + // ID. + processes_dictionary.Set(base::IntToString(child_process_host_id), + process.ToValue()); } - if (updated) { + // Done with data collection. Now dispatch the appropriate events according to + // the present listeners. + DCHECK(has_on_updated_listeners || has_on_updated_with_memory_listeners); + if (has_on_updated_listeners) { api::processes::OnUpdated::Processes processes; processes.additional_properties.MergeDictionary(&processes_dictionary); // NOTE: If there are listeners to the updates with memory as well, @@ -347,80 +300,33 @@ api::processes::OnUpdated::Create(processes)); } - if (updated_memory) { + if (has_on_updated_with_memory_listeners) { api::processes::OnUpdatedWithMemory::Processes processes; processes.additional_properties.MergeDictionary(&processes_dictionary); DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY, api::processes::OnUpdatedWithMemory::kEventName, - api::processes::OnUpdatedWithMemory::Create(processes));} -#endif // defined(ENABLE_TASK_MANAGER) + api::processes::OnUpdatedWithMemory::Create(processes)); + } } -void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { -#if defined(ENABLE_TASK_MANAGER) - DCHECK_EQ(length, 1); - - if (!HasEventListeners(api::processes::OnExited::kEventName)) - return; - - // Process exit for renderer processes has the data about exit code and - // termination status, therefore we will rely on notifications and not on - // the Task Manager data. We do use the rest of this method for non-renderer - // processes. - if (model_->GetResourceType(start) == task_manager::Resource::RENDERER) - return; - - DispatchEvent(events::PROCESSES_ON_EXITED, - api::processes::OnExited::kEventName, - api::processes::OnExited::Create( - model_->GetUniqueChildProcessId(start), - 0 /* exit_type */, - 0 /* exit_code */)); -#endif // defined(ENABLE_TASK_MANAGER) -} - -void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) { -#if defined(ENABLE_TASK_MANAGER) +void ProcessesEventRouter::OnTaskUnresponsive(task_management::TaskId id) { if (!HasEventListeners(api::processes::OnUnresponsive::kEventName)) return; - int count = model_->ResourceCount(); - int id = widget->GetProcess()->GetID(); - - for (int i = 0; i < count; ++i) { - if (model_->IsResourceFirstInGroup(i)) { - if (id == model_->GetUniqueChildProcessId(i)) { - api::processes::Process process; - FillProcessData(id, model_, i, false /* include_optional */, &process); - DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE, - api::processes::OnUnresponsive::kEventName, - api::processes::OnUnresponsive::Create(process)); - return; - } - } - } -#endif // defined(ENABLE_TASK_MANAGER) -} - -void ProcessesEventRouter::ProcessClosedEvent( - content::RenderProcessHost* rph, - content::RenderProcessHost::RendererClosedDetails* details) { -#if defined(ENABLE_TASK_MANAGER) - if (!HasEventListeners(api::processes::OnExited::kEventName)) - return; - - DispatchEvent(events::PROCESSES_ON_EXITED, - api::processes::OnExited::kEventName, - api::processes::OnExited::Create(rph->GetID(), - details->status, - details->exit_code)); -#endif // defined(ENABLE_TASK_MANAGER) + api::processes::Process process; + FillProcessData(id, + observed_task_manager(), + false, // include_optional + &process); + DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE, + api::processes::OnUnresponsive::kEventName, + api::processes::OnUnresponsive::Create(process)); } void ProcessesEventRouter::DispatchEvent( events::HistogramValue histogram_value, const std::string& event_name, - scoped_ptr<base::ListValue> event_args) { + scoped_ptr<base::ListValue> event_args) const { EventRouter* event_router = EventRouter::Get(browser_context_); if (event_router) { scoped_ptr<Event> event( @@ -429,11 +335,53 @@ } } -bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) { +bool ProcessesEventRouter::HasEventListeners( + const std::string& event_name) const { EventRouter* event_router = EventRouter::Get(browser_context_); return event_router && event_router->HasEventListener(event_name); } +bool ProcessesEventRouter::ShouldReportOnCreatedOrOnExited( + task_management::TaskId id, + int* out_child_process_host_id) const { + // Is it the first task to be created or the last one to be removed? + if (observed_task_manager()->GetNumberOfTasksOnSameProcess(id) != 1) + return false; + + // Ignore tasks that don't have a valid child process host ID like ARC + // processes, as well as the browser process (neither onCreated() nor + // onExited() shouldn't report the browser process). + *out_child_process_host_id = + observed_task_manager()->GetChildProcessUniqueId(id); + if (*out_child_process_host_id == + content::ChildProcessHost::kInvalidUniqueID || + *out_child_process_host_id == 0) { + return false; + } + + return true; +} + +void ProcessesEventRouter::UpdateRefreshTypesFlagsBasedOnListeners() { + int64_t refresh_types = task_management::REFRESH_TYPE_NONE; + if (HasEventListeners(api::processes::OnCreated::kEventName) || + HasEventListeners(api::processes::OnUnresponsive::kEventName)) { + refresh_types |= GetRefreshTypesFlagOnlyEssentialData(); + } + + if (HasEventListeners(api::processes::OnUpdated::kEventName)) + refresh_types |= GetRefreshTypesForProcessOptionalData(); + + if (HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName)) + refresh_types |= task_management::REFRESH_TYPE_MEMORY; + + SetRefreshTypesFlags(refresh_types); +} + +//////////////////////////////////////////////////////////////////////////////// +// ProcessesAPI: +//////////////////////////////////////////////////////////////////////////////// + ProcessesAPI::ProcessesAPI(content::BrowserContext* context) : browser_context_(context) { EventRouter* event_router = EventRouter::Get(browser_context_); @@ -449,19 +397,13 @@ } ProcessesAPI::~ProcessesAPI() { + // This object has already been unregistered as an observer in Shutdown(). } -void ProcessesAPI::Shutdown() { - EventRouter::Get(browser_context_)->UnregisterObserver(this); -} - -static base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI> > - g_factory = LAZY_INSTANCE_INITIALIZER; - // static BrowserContextKeyedAPIFactory<ProcessesAPI>* ProcessesAPI::GetFactoryInstance() { - return g_factory.Pointer(); + return g_processes_api_factory.Pointer(); } // static @@ -469,292 +411,280 @@ return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context); } -ProcessesEventRouter* ProcessesAPI::processes_event_router() { - if (!processes_event_router_) - processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); - return processes_event_router_.get(); +void ProcessesAPI::Shutdown() { + EventRouter::Get(browser_context_)->UnregisterObserver(this); } void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) { - // We lazily tell the TaskManager to start updating when listeners to the - // processes.onUpdated or processes.onUpdatedWithMemory events arrive. + // The ProcessesEventRouter will observe the TaskManager as long as there are + // listeners for the processes.onUpdated/.onUpdatedWithMemory/.onCreated ... + // etc. events. processes_event_router()->ListenerAdded(); } void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) { - // If a processes.onUpdated or processes.onUpdatedWithMemory event listener - // is removed (or a process with one exits), then we let the extension API - // know that it has one fewer listener. + // If a processes.onUpdated/.onUpdatedWithMemory/.onCreated ... etc. event + // listener is removed (or a process with one exits), then we let the + // extension API know that it has one fewer listener. processes_event_router()->ListenerRemoved(); } +ProcessesEventRouter* ProcessesAPI::processes_event_router() { + if (!processes_event_router_.get()) + processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); + return processes_event_router_.get(); +} + //////////////////////////////////////////////////////////////////////////////// // ProcessesGetProcessIdForTabFunction: //////////////////////////////////////////////////////////////////////////////// -ProcessesGetProcessIdForTabFunction::ProcessesGetProcessIdForTabFunction() - : tab_id_(-1) { -} - ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() { -#if defined(ENABLE_TASK_MANAGER) + // For this function, the task manager doesn't even need to be running. scoped_ptr<api::processes::GetProcessIdForTab::Params> params( - api::processes::GetProcessIdForTab::Params::Create(*args_)); + api::processes::GetProcessIdForTab::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - tab_id_ = params->tab_id; - if (tab_id_ < 0) { - return RespondNow(Error(errors::kInavlidArgument, - base::IntToString(tab_id_))); - } - - // Add a reference, which is balanced in GetProcessIdForTab to keep the object - // around and allow for the callback to be invoked. - AddRef(); - - // If the task manager is already listening, just post a task to execute - // which will invoke the callback once we have returned from this function. - // Otherwise, wait for the notification that the task manager is done with - // the data gathering. - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->is_task_manager_listening()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab, - this)); - } else { - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( - base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab, - this)); - - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->StartTaskManagerListening(); - } - - return RespondLater(); -#else - return RespondNow(Error(errors::kExtensionNotSupported)); -#endif // defined(ENABLE_TASK_MANAGER) -} - -void ProcessesGetProcessIdForTabFunction::GetProcessIdForTab() { - content::WebContents* contents = NULL; + const int tab_id = params->tab_id; + content::WebContents* contents = nullptr; int tab_index = -1; if (!ExtensionTabUtil::GetTabById( - tab_id_, + tab_id, Profile::FromBrowserContext(browser_context()), include_incognito(), nullptr, nullptr, &contents, &tab_index)) { - Respond(Error(tabs_constants::kTabNotFoundError, - base::IntToString(tab_id_))); - } else { - int process_id = contents->GetRenderProcessHost()->GetID(); - Respond(ArgumentList( - api::processes::GetProcessIdForTab::Results::Create(process_id))); + return RespondNow(Error(tabs_constants::kTabNotFoundError, + base::IntToString(tab_id))); } - // Balance the AddRef in the Run. - Release(); + const int process_id = contents->GetRenderProcessHost()->GetID(); + return RespondNow(ArgumentList( + api::processes::GetProcessIdForTab::Results::Create(process_id))); } //////////////////////////////////////////////////////////////////////////////// -// ProcessesTerminateFunction +// ProcessesTerminateFunction: //////////////////////////////////////////////////////////////////////////////// -ProcessesTerminateFunction::ProcessesTerminateFunction() : process_id_(-1) { -} - ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() { -#if defined(ENABLE_TASK_MANAGER) + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + // For this function, the task manager doesn't even need to be running. scoped_ptr<api::processes::Terminate::Params> params( api::processes::Terminate::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - process_id_ = params->process_id; - // Add a reference, which is balanced in TerminateProcess to keep the object - // around and allow for the callback to be invoked. - AddRef(); - - // If the task manager is already listening, just post a task to execute - // which will invoke the callback once we have returned from this function. - // Otherwise, wait for the notification that the task manager is done with - // the data gathering. - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->is_task_manager_listening()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::Bind(&ProcessesTerminateFunction::TerminateProcess, - this)); - } else { - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( - base::Bind(&ProcessesTerminateFunction::TerminateProcess, this)); - - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->StartTaskManagerListening(); + child_process_host_id_ = params->process_id; + if (child_process_host_id_ < 0) { + return RespondNow(Error(errors::kInvalidArgument, + base::IntToString(child_process_host_id_))); + } else if (child_process_host_id_ == 0) { + // Cannot kill the browser process. + return RespondNow(Error(errors::kNotAllowedToTerminate, + base::IntToString(child_process_host_id_))); } + // Check if it's a renderer. + auto* render_process_host = + content::RenderProcessHost::FromID(child_process_host_id_); + if (render_process_host) + return RespondNow(TerminateIfAllowed(render_process_host->GetHandle())); + + // This could be a non-renderer child process like a plugin or a nacl + // process. Try to get its handle from the BrowserChildProcessHost on the + // IO thread. + content::BrowserThread::PostTaskAndReplyWithResult( + content::BrowserThread::IO, + FROM_HERE, + base::Bind(&ProcessesTerminateFunction::GetProcessHandleOnIO, + this, + child_process_host_id_), + base::Bind(&ProcessesTerminateFunction::OnProcessHandleOnUI, this)); + + // Promise to respond later. return RespondLater(); -#else - return RespondNow(Error(errors::kExtensionNotSupported)); -#endif // defined(ENABLE_TASK_MANAGER) } -void ProcessesTerminateFunction::TerminateProcess() { -#if defined(ENABLE_TASK_MANAGER) - TaskManagerModel* model = TaskManager::GetInstance()->model(); +base::ProcessHandle ProcessesTerminateFunction::GetProcessHandleOnIO( + int child_process_host_id) const { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); - bool found = false; - for (int i = 0, count = model->ResourceCount(); i < count; ++i) { - if (model->IsResourceFirstInGroup(i) && - process_id_ == model->GetUniqueChildProcessId(i)) { - base::ProcessHandle process_handle = model->GetProcess(i); - if (process_handle == base::GetCurrentProcessHandle()) { - // Cannot kill the browser process. - // TODO(kalman): Are there other sensitive processes? - Respond(Error(errors::kNotAllowedToTerminate, - base::IntToString(process_id_))); - } else { - base::Process process = - base::Process::DeprecatedGetProcessFromHandle(process_handle); - bool did_terminate = - process.Terminate(content::RESULT_CODE_KILLED, true); - if (did_terminate) - UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); + auto* host = content::BrowserChildProcessHost::FromID(child_process_host_id); + if (host) + return host->GetData().handle; - Respond(ArgumentList( - api::processes::Terminate::Results::Create(did_terminate))); - } - found = true; - break; - } + return base::kNullProcessHandle; +} + +void ProcessesTerminateFunction::OnProcessHandleOnUI( + base::ProcessHandle handle) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + Respond(TerminateIfAllowed(handle)); +} + +ExtensionFunction::ResponseValue +ProcessesTerminateFunction::TerminateIfAllowed(base::ProcessHandle handle) { + if (handle == base::kNullProcessHandle) { + return Error(errors::kProcessNotFound, + base::IntToString(child_process_host_id_)); } - if (!found) - Respond(Error(errors::kProcessNotFound, base::IntToString(process_id_))); + if (handle == base::GetCurrentProcessHandle()) { + // Cannot kill the browser process. + return Error(errors::kNotAllowedToTerminate, + base::IntToString(child_process_host_id_)); + } - // Balance the AddRef in the Run. - Release(); -#endif // defined(ENABLE_TASK_MANAGER) + base::Process process = base::Process::Open(base::GetProcId(handle)); + if (!process.IsValid()) { + return Error(errors::kProcessNotFound, + base::IntToString(child_process_host_id_)); + } + + const bool did_terminate = + process.Terminate(content::RESULT_CODE_KILLED, true /* wait */); + if (did_terminate) + UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); + + return ArgumentList( + api::processes::Terminate::Results::Create(did_terminate)); } //////////////////////////////////////////////////////////////////////////////// -// ProcessesGetProcessInfoFunction +// ProcessesGetProcessInfoFunction: //////////////////////////////////////////////////////////////////////////////// ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction() -#if defined(ENABLE_TASK_MANAGER) - : memory_(false) -#endif - { + : task_management::TaskManagerObserver( + base::TimeDelta::FromSeconds(1), + GetRefreshTypesFlagOnlyEssentialData()) { } ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() { -#if defined(ENABLE_TASK_MANAGER) scoped_ptr<api::processes::GetProcessInfo::Params> params( api::processes::GetProcessInfo::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); if (params->process_ids.as_integer) - process_ids_.push_back(*params->process_ids.as_integer); + process_host_ids_.push_back(*params->process_ids.as_integer); else - process_ids_.swap(*params->process_ids.as_integers); + process_host_ids_.swap(*params->process_ids.as_integers); - memory_ = params->include_memory; + include_memory_ = params->include_memory; + if (include_memory_) + AddRefreshType(task_management::REFRESH_TYPE_MEMORY); - // Add a reference, which is balanced in GatherProcessInfo to keep the object - // around and allow for the callback to be invoked. + // Keep this object alive until the first of either OnTasksRefreshed() or + // OnTasksRefreshedWithBackgroundCalculations() is received depending on + // |include_memory_|. AddRef(); - // If the task manager is already listening, just post a task to execute - // which will invoke the callback once we have returned from this function. - // Otherwise, wait for the notification that the task manager is done with - // the data gathering. - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->is_task_manager_listening()) { - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this)); - } else { - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( - base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this)); - - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) - ->processes_event_router() - ->StartTaskManagerListening(); - } + // The task manager needs to be enabled for this function. + // Start observing the task manager and wait for the next refresh event. + task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this); return RespondLater(); -#else - return RespondNow(Error(errors::kExtensionNotSupported)); -#endif // defined(ENABLE_TASK_MANAGER) } -ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() { +void ProcessesGetProcessInfoFunction::OnTasksRefreshed( + const task_management::TaskIdList& task_ids) { + // Memory is background calculated and will be ready when + // OnTasksRefreshedWithBackgroundCalculations() is invoked. + if (include_memory_) + return; + + GatherDataAndRespond(task_ids); } -void ProcessesGetProcessInfoFunction::GatherProcessInfo() { -#if defined(ENABLE_TASK_MANAGER) - TaskManagerModel* model = TaskManager::GetInstance()->model(); - api::processes::GetProcessInfo::Results::Processes processes; +void +ProcessesGetProcessInfoFunction::OnTasksRefreshedWithBackgroundCalculations( + const task_management::TaskIdList& task_ids) { + if (!include_memory_) + return; + GatherDataAndRespond(task_ids); +} + +ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() {} + +void ProcessesGetProcessInfoFunction::GatherDataAndRespond( + const task_management::TaskIdList& task_ids) { // If there are no process IDs specified, it means we need to return all of // the ones we know of. - if (process_ids_.size() == 0) { - int resources = model->ResourceCount(); - for (int i = 0; i < resources; ++i) { - if (model->IsResourceFirstInGroup(i)) { - int id = model->GetUniqueChildProcessId(i); - api::processes::Process process; - FillProcessData(id, model, i, false, &process); - if (memory_) - AddMemoryDetails(model, i, &process); - processes.additional_properties.Set(base::IntToString(id), - process.ToValue()); - } - } - } else { - int resources = model->ResourceCount(); - for (int i = 0; i < resources; ++i) { - if (model->IsResourceFirstInGroup(i)) { - int id = model->GetUniqueChildProcessId(i); - std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), - process_ids_.end(), id); - if (proc_id != process_ids_.end()) { - api::processes::Process process; - FillProcessData(id, model, i, false, &process); - if (memory_) - AddMemoryDetails(model, i, &process); - processes.additional_properties.Set(base::IntToString(id), - process.ToValue()); + const bool specific_processes_requested = !process_host_ids_.empty(); + std::set<base::ProcessId> seen_processes; + // Create the results object as defined in the generated API from process.idl + // and fill it with the processes info. + api::processes::GetProcessInfo::Results::Processes processes; + for (const auto& task_id : task_ids) { + const base::ProcessId proc_id = + observed_task_manager()->GetProcessId(task_id); + if (seen_processes.count(proc_id)) + continue; - process_ids_.erase(proc_id); - if (process_ids_.size() == 0) - break; - } - } + const int child_process_host_id = + observed_task_manager()->GetChildProcessUniqueId(task_id); + // Ignore tasks that don't have a valid child process host ID like ARC + // processes. We report the browser process info here though. + if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID) + continue; + + if (specific_processes_requested) { + // Note: we can't use |!process_host_ids_.empty()| directly in the above + // condition as we will erase from |process_host_ids_| below. + auto itr = std::find(process_host_ids_.begin(), + process_host_ids_.end(), + child_process_host_id); + if (itr == process_host_ids_.end()) + continue; + + // If found, we remove it from |process_host_ids|, so that at the end if + // anything remains in |process_host_ids|, those were invalid arguments + // that will be reported on the console. + process_host_ids_.erase(itr); } - // If not all processes were found, log them to the extension's console to - // help the developer, but don't fail the API call. - for (int pid : process_ids_) { - WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, - ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, - base::IntToString(pid))); + + seen_processes.insert(proc_id); + + // We do not include the optional data in this function results. + api::processes::Process process; + FillProcessData(task_id, + observed_task_manager(), + false, // include_optional + &process); + + if (include_memory_) { + // Append the private memory usage to the process data. + const int64_t private_memory = + observed_task_manager()->GetPrivateMemoryUsage(task_id); + process.private_memory.reset(new double(static_cast<double>( + private_memory))); } + + // Store each process indexed by the string version of its + // ChildProcessHost ID. + processes.additional_properties.Set( + base::IntToString(child_process_host_id), + process.ToValue()); + } + + // Report the invalid host ids sent in the arguments. + for (const auto& host_id : process_host_ids_) { + WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, + ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, + base::IntToString(host_id))); } // Send the response. Respond(ArgumentList( api::processes::GetProcessInfo::Results::Create(processes))); - // Balance the AddRef in the Run. + // Stop observing the task manager, and balance the AddRef() in Run(). + task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(this); Release(); -#endif // defined(ENABLE_TASK_MANAGER) } } // namespace extensions
diff --git a/chrome/browser/extensions/api/processes/processes_api.h b/chrome/browser/extensions/api/processes/processes_api.h index f1a2477..5ea54b0 100644 --- a/chrome/browser/extensions/api/processes/processes_api.h +++ b/chrome/browser/extensions/api/processes/processes_api.h
@@ -5,35 +5,22 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_PROCESSES_PROCESSES_API_H__ #define CHROME_BROWSER_EXTENSIONS_API_PROCESSES_PROCESSES_API_H__ -#include <set> -#include <string> +#include <vector> #include "base/macros.h" -#include "base/memory/scoped_ptr.h" -#include "chrome/browser/extensions/chrome_extension_function.h" -#include "chrome/browser/task_manager/task_manager.h" -#include "components/keyed_service/core/keyed_service.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/render_process_host.h" -#include "content/public/browser/render_widget_host.h" +#include "chrome/browser/task_management/task_manager_observer.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/event_router.h" #include "extensions/browser/extension_event_histogram_value.h" +#include "extensions/browser/extension_function.h" -namespace base { -class ListValue; -} - -namespace content { -class BrowserContext; -} +class ProcessesApiTest; namespace extensions { // Observes the Task Manager and routes the notifications as events to the // extension system. -class ProcessesEventRouter : public TaskManagerModelObserver, - public content::NotificationObserver { +class ProcessesEventRouter : public task_management::TaskManagerObserver { public: explicit ProcessesEventRouter(content::BrowserContext* context); ~ProcessesEventRouter() override; @@ -44,58 +31,44 @@ // Called when an extension process with a listener exits or removes it. void ListenerRemoved(); - // Called on the first invocation of extension API function. This will call - // out to the Task Manager to start listening for notifications. Returns - // true if this was the first call and false if this has already been called. - void StartTaskManagerListening(); - - bool is_task_manager_listening() { return task_manager_listening_; } + // task_management::TaskManagerObserver: + void OnTaskAdded(task_management::TaskId id) override; + void OnTaskToBeRemoved(task_management::TaskId id) override; + void OnTasksRefreshed(const task_management::TaskIdList& task_ids) override {} + void OnTasksRefreshedWithBackgroundCalculations( + const task_management::TaskIdList& task_ids) override; + void OnTaskUnresponsive(task_management::TaskId id) override; private: - // content::NotificationObserver implementation. - void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) override; - - // TaskManagerModelObserver methods. - void OnItemsAdded(int start, int length) override; - void OnModelChanged() override {} - void OnItemsChanged(int start, int length) override; - void OnItemsRemoved(int start, int length) override {} - void OnItemsToBeRemoved(int start, int length) override; - - // Internal helpers for processing notifications. - void ProcessHangEvent(content::RenderWidgetHost* widget); - void ProcessClosedEvent( - content::RenderProcessHost* rph, - content::RenderProcessHost::RendererClosedDetails* details); + friend class ::ProcessesApiTest; void DispatchEvent(events::HistogramValue histogram_value, const std::string& event_name, - scoped_ptr<base::ListValue> event_args); + scoped_ptr<base::ListValue> event_args) const; // Determines whether there is a registered listener for the specified event. - // It helps to avoid collecing data if no one is interested in it. - bool HasEventListeners(const std::string& event_name); + // It helps to avoid collecting data if no one is interested in it. + bool HasEventListeners(const std::string& event_name) const; - // Used for tracking registrations to process related notifications. - content::NotificationRegistrar registrar_; + // Returns true if the task with the given |id| should be reported as created + // or removed. |out_child_process_host_id| will be filled with the valid ID of + // the process to report in the event. + bool ShouldReportOnCreatedOrOnExited(task_management::TaskId id, + int* out_child_process_host_id) const; + + // Updates the requested task manager refresh types flags depending on what + // events are being listened to by extensions. + void UpdateRefreshTypesFlagsBasedOnListeners(); content::BrowserContext* browser_context_; - // TaskManager to observe for updates. - TaskManagerModel* model_; - // Count of listeners, so we avoid sending updates if no one is interested. int listeners_; - // Indicator whether we've initialized the Task Manager listeners. This is - // done once for the lifetime of this object. - bool task_manager_listening_; - DISALLOW_COPY_AND_ASSIGN(ProcessesEventRouter); }; +//////////////////////////////////////////////////////////////////////////////// // The profile-keyed service that manages the processes extension API. class ProcessesAPI : public BrowserContextKeyedAPI, public EventRouter::Observer { @@ -103,35 +76,35 @@ explicit ProcessesAPI(content::BrowserContext* context); ~ProcessesAPI() override; - // KeyedService implementation. - void Shutdown() override; - - // BrowserContextKeyedAPI implementation. + // BrowserContextKeyedAPI: static BrowserContextKeyedAPIFactory<ProcessesAPI>* GetFactoryInstance(); // Convenience method to get the ProcessesAPI for a profile. static ProcessesAPI* Get(content::BrowserContext* context); - ProcessesEventRouter* processes_event_router(); + // KeyedService: + void Shutdown() override; - // EventRouter::Observer implementation. + // EventRouter::Observer: void OnListenerAdded(const EventListenerInfo& details) override; void OnListenerRemoved(const EventListenerInfo& details) override; + ProcessesEventRouter* processes_event_router(); + private: friend class BrowserContextKeyedAPIFactory<ProcessesAPI>; - content::BrowserContext* browser_context_; - - // BrowserContextKeyedAPI implementation. - static const char* service_name() { - return "ProcessesAPI"; - } + // BrowserContextKeyedAPI: + static const char* service_name() { return "ProcessesAPI"; } static const bool kServiceRedirectedInIncognito = true; static const bool kServiceIsNULLWhileTesting = true; + content::BrowserContext* browser_context_; + // Created lazily on first access. scoped_ptr<ProcessesEventRouter> processes_event_router_; + + DISALLOW_COPY_AND_ASSIGN(ProcessesAPI); }; //////////////////////////////////////////////////////////////////////////////// @@ -139,21 +112,14 @@ // currently in use by the specified Tab. class ProcessesGetProcessIdForTabFunction : public UIThreadExtensionFunction { public: - ProcessesGetProcessIdForTabFunction(); - // UIThreadExtensionFunction: ExtensionFunction::ResponseAction Run() override; + DECLARE_EXTENSION_FUNCTION("processes.getProcessIdForTab", + PROCESSES_GETPROCESSIDFORTAB); + private: ~ProcessesGetProcessIdForTabFunction() override {} - - void GetProcessIdForTab(); - - // Storage for the tab ID parameter. - int tab_id_; - - DECLARE_EXTENSION_FUNCTION("processes.getProcessIdForTab", - PROCESSES_GETPROCESSIDFORTAB) }; //////////////////////////////////////////////////////////////////////////////// @@ -164,46 +130,65 @@ // * guards against killing non-Chrome processes. class ProcessesTerminateFunction : public UIThreadExtensionFunction { public: - ProcessesTerminateFunction(); - // UIThreadExtensionFunction: ExtensionFunction::ResponseAction Run() override; + DECLARE_EXTENSION_FUNCTION("processes.terminate", PROCESSES_TERMINATE); + private: ~ProcessesTerminateFunction() override {} - void TerminateProcess(); + // Functions to get the process handle on the IO thread and post it back to + // the UI thread from processing. + base::ProcessHandle GetProcessHandleOnIO(int child_process_host_id) const; + void OnProcessHandleOnUI(base::ProcessHandle handle); - // Storage for the process ID parameter. - int process_id_; + // Terminates the process with |handle| if it's valid and is allowed to be + // terminated. Returns the response value of this extension function to be + // sent. + ExtensionFunction::ResponseValue TerminateIfAllowed( + base::ProcessHandle handle); - DECLARE_EXTENSION_FUNCTION("processes.terminate", - PROCESSES_TERMINATE) + // Caches the parameter of this function. To be accessed only on the UI + // thread. + int child_process_host_id_ = 0; }; //////////////////////////////////////////////////////////////////////////////// // Extension function which returns a set of Process objects, containing the // details corresponding to the process IDs supplied as input. -class ProcessesGetProcessInfoFunction : public UIThreadExtensionFunction { +class ProcessesGetProcessInfoFunction : + public UIThreadExtensionFunction, + public task_management::TaskManagerObserver { public: ProcessesGetProcessInfoFunction(); // UIThreadExtensionFunction: ExtensionFunction::ResponseAction Run() override; + // task_management::TaskManagerObserver: + void OnTaskAdded(task_management::TaskId id) override {} + void OnTaskToBeRemoved(task_management::TaskId id) override {} + void OnTasksRefreshed(const task_management::TaskIdList& task_ids) override; + void OnTasksRefreshedWithBackgroundCalculations( + const task_management::TaskIdList& task_ids) override; + + DECLARE_EXTENSION_FUNCTION("processes.getProcessInfo", + PROCESSES_GETPROCESSINFO); + private: ~ProcessesGetProcessInfoFunction() override; - void GatherProcessInfo(); + // Since we don't report optional process data like CPU usage in the results + // of this function, the only background calculations we want to watch is + // memory usage (which will be requested only when |include_memory_| is true). + // This function will be called by either OnTasksRefreshed() or + // OnTasksRefreshedWithBackgroundCalculations() depending on whether memory is + // requested. + void GatherDataAndRespond(const task_management::TaskIdList& task_ids); - // Member variables to store the function parameters - std::vector<int> process_ids_; -#if defined(ENABLE_TASK_MANAGER) - bool memory_; -#endif - - DECLARE_EXTENSION_FUNCTION("processes.getProcessInfo", - PROCESSES_GETPROCESSINFO) + std::vector<int> process_host_ids_; + bool include_memory_ = false; }; } // namespace extensions
diff --git a/chrome/browser/extensions/api/processes/processes_apitest.cc b/chrome/browser/extensions/api/processes/processes_apitest.cc index caf3dcc..23d95dc 100644 --- a/chrome/browser/extensions/api/processes/processes_apitest.cc +++ b/chrome/browser/extensions/api/processes/processes_apitest.cc
@@ -3,51 +3,68 @@ // found in the LICENSE file. #include "base/command_line.h" +#include "chrome/browser/extensions/api/processes/processes_api.h" #include "chrome/browser/extensions/extension_apitest.h" -#include "chrome/browser/task_manager/task_manager.h" -#include "chrome/browser/task_manager/task_manager_browsertest_util.h" +#include "chrome/browser/task_management/task_manager_interface.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_dialogs.h" #include "chrome/browser/ui/browser_window.h" #include "extensions/common/switches.h" #include "extensions/test/extension_test_message_listener.h" -using ProcessesApiTest = ExtensionApiTest; +class ProcessesApiTest : public ExtensionApiTest { + public: + ProcessesApiTest() {} + ~ProcessesApiTest() override {} -// Fails on some MSan bots crbug.com/591581. -IN_PROC_BROWSER_TEST_F(ProcessesApiTest, DISABLED_Processes) { + int GetListenersCount() { + return extensions::ProcessesAPI::Get(profile())-> + processes_event_router()->listeners_; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ProcessesApiTest); +}; + +IN_PROC_BROWSER_TEST_F(ProcessesApiTest, Processes) { ASSERT_TRUE(RunExtensionTest("processes/api")) << message_; } -IN_PROC_BROWSER_TEST_F(ProcessesApiTest, ProcessesVsTaskManager) { - // This test is for the old implementation of the task manager. We must - // explicitly disable the new one. - task_manager::browsertest_util::EnableOldTaskManager(); +IN_PROC_BROWSER_TEST_F(ProcessesApiTest, ProcessesApiListeners) { + EXPECT_EQ(0, GetListenersCount()); - // Ensure task manager is not yet updating - TaskManagerModel* model = TaskManager::GetInstance()->model(); - EXPECT_EQ(0, model->update_requests_); - EXPECT_EQ(TaskManagerModel::IDLE, model->update_state_); + // Load extension that adds a listener in background page + ExtensionTestMessageListener listener1("ready", false /* will_reply */); + const extensions::Extension* extension1 = LoadExtension( + test_data_dir_.AppendASCII("processes").AppendASCII("onupdated")); + ASSERT_TRUE(extension1); + ASSERT_TRUE(listener1.WaitUntilSatisfied()); - // Load extension that adds listener in background page - ExtensionTestMessageListener listener("ready", false); - ASSERT_TRUE(LoadExtension( - test_data_dir_.AppendASCII("processes").AppendASCII("onupdated"))); - ASSERT_TRUE(listener.WaitUntilSatisfied()); + // The memory refresh type of the task manager may or may not be enabled by + // now depending on the presence of other task manager observers. + // Ensure the listeners count has changed. + EXPECT_EQ(1, GetListenersCount()); - // Ensure the task manager has started updating - EXPECT_EQ(1, model->update_requests_); - EXPECT_EQ(TaskManagerModel::TASK_PENDING, model->update_state_); + // Load another extension that listen to the onUpdatedWithMemory. + ExtensionTestMessageListener listener2("ready", false /* will_reply */); + const extensions::Extension* extension2 = LoadExtension( + test_data_dir_.AppendASCII("processes").AppendASCII( + "onupdated_with_memory")); + ASSERT_TRUE(extension2); + ASSERT_TRUE(listener2.WaitUntilSatisfied()); - // Now show the task manager and wait for it to be ready - chrome::ShowTaskManager(browser()); + // The memory refresh type must be enabled now. + const task_management::TaskManagerInterface* task_manager = + task_management::TaskManagerInterface::GetTaskManager(); + EXPECT_EQ(2, GetListenersCount()); + EXPECT_TRUE(task_manager->IsResourceRefreshEnabled( + task_management::REFRESH_TYPE_MEMORY)); - EXPECT_EQ(2, model->update_requests_); - EXPECT_EQ(TaskManagerModel::TASK_PENDING, model->update_state_); - - // Unload the extension and check that listener count decreases - UnloadExtension(last_loaded_extension_id()); - EXPECT_EQ(1, model->update_requests_); + // Unload the extensions and make sure the listeners count is updated. + UnloadExtension(extension2->id()); + EXPECT_EQ(1, GetListenersCount()); + UnloadExtension(extension1->id()); + EXPECT_EQ(0, GetListenersCount()); } IN_PROC_BROWSER_TEST_F(ProcessesApiTest, CannotTerminateBrowserProcess) {
diff --git a/chrome/browser/extensions/api/tabs/tabs_api.cc b/chrome/browser/extensions/api/tabs/tabs_api.cc index 96cbd399..33b3ac7e 100644 --- a/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chrome/browser/extensions/api/tabs/tabs_api.cc
@@ -72,7 +72,6 @@ #include "extensions/browser/app_window/app_window.h" #include "extensions/browser/extension_api_frame_id_map.h" #include "extensions/browser/extension_function_dispatcher.h" -#include "extensions/browser/extension_function_util.h" #include "extensions/browser/extension_host.h" #include "extensions/browser/extension_zoom_request_client.h" #include "extensions/browser/file_reader.h"
diff --git a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc index 4466ade1..823ea85 100644 --- a/chrome/browser/extensions/extension_disabled_ui_browsertest.cc +++ b/chrome/browser/extensions/extension_disabled_ui_browsertest.cc
@@ -30,6 +30,8 @@ #include "extensions/common/extension.h" #include "extensions/test/extension_test_message_listener.h" #include "net/url_request/test_url_request_interceptor.h" +#include "sync/api/fake_sync_change_processor.h" +#include "sync/api/sync_error_factory_mock.h" #include "sync/protocol/extension_specifics.pb.h" #include "sync/protocol/sync.pb.h" @@ -213,6 +215,10 @@ GURL("http://localhost/autoupdate/v2.crx"), scoped_temp_dir_.path().AppendASCII("permissions2.crx")); + sync_service->MergeDataAndStartSyncing( + syncer::EXTENSIONS, syncer::SyncDataList(), + make_scoped_ptr(new syncer::FakeSyncChangeProcessor()), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); extensions::TestExtensionRegistryObserver install_observer(registry_); sync_service->ProcessSyncChanges( FROM_HERE, @@ -265,12 +271,16 @@ syncer::AttachmentIdList(), syncer::AttachmentServiceProxy()); + ExtensionSyncService* sync_service = ExtensionSyncService::Get(profile()); + sync_service->MergeDataAndStartSyncing( + syncer::EXTENSIONS, syncer::SyncDataList(), + make_scoped_ptr(new syncer::FakeSyncChangeProcessor()), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); extensions::TestExtensionRegistryObserver install_observer(registry_); - ExtensionSyncService::Get(profile())->ProcessSyncChanges( + sync_service->ProcessSyncChanges( FROM_HERE, syncer::SyncChangeList( - 1, syncer::SyncChange(FROM_HERE, - syncer::SyncChange::ACTION_ADD, + 1, syncer::SyncChange(FROM_HERE, syncer::SyncChange::ACTION_ADD, sync_data))); install_observer.WaitForExtensionWillBeInstalled();
diff --git a/chrome/browser/extensions/extension_service_sync_unittest.cc b/chrome/browser/extensions/extension_service_sync_unittest.cc index 2eb884b..a283a8e 100644 --- a/chrome/browser/extensions/extension_service_sync_unittest.cc +++ b/chrome/browser/extensions/extension_service_sync_unittest.cc
@@ -43,6 +43,7 @@ #include "extensions/common/permissions/permission_set.h" #include "extensions/common/value_builder.h" #include "sync/api/fake_sync_change_processor.h" +#include "sync/api/sync_change_processor_wrapper_for_test.h" #include "sync/api/sync_data.h" #include "sync/api/sync_error_factory_mock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -80,6 +81,81 @@ return SyncChangeList(1, SyncChange(FROM_HERE, change_type, sync_data)); } +// This is a FakeSyncChangeProcessor specialization that maintains a store of +// SyncData items in the superclass' data_ member variable, treating it like a +// map keyed by the extension id from the SyncData. Each instance of this class +// should only be used for one model type (which should be either extensions or +// apps) to match how the real sync system handles things. +class StatefulChangeProcessor : public syncer::FakeSyncChangeProcessor { + public: + explicit StatefulChangeProcessor(syncer::ModelType expected_type) + : expected_type_(expected_type) { + EXPECT_TRUE(expected_type == syncer::ModelType::EXTENSIONS || + expected_type == syncer::ModelType::APPS); + } + + ~StatefulChangeProcessor() override {} + + // We let our parent class, FakeSyncChangeProcessor, handle saving the + // changes for us, but in addition we "apply" these changes by treating + // the FakeSyncChangeProcessor's SyncDataList as a map keyed by extension + // id. + syncer::SyncError ProcessSyncChanges( + const tracked_objects::Location& from_here, + const syncer::SyncChangeList& change_list) override { + syncer::FakeSyncChangeProcessor::ProcessSyncChanges(from_here, change_list); + for (const auto& change : change_list) { + syncer::SyncData sync_data = change.sync_data(); + EXPECT_EQ(expected_type_, sync_data.GetDataType()); + + scoped_ptr<ExtensionSyncData> modified = + ExtensionSyncData::CreateFromSyncData(sync_data); + + // Start by removing any existing entry for this extension id. + syncer::SyncDataList& data_list = data(); + for (auto iter = data_list.begin(); iter != data_list.end(); ++iter) { + scoped_ptr<ExtensionSyncData> existing = + ExtensionSyncData::CreateFromSyncData(*iter); + if (existing->id() == modified->id()) { + data_list.erase(iter); + break; + } + } + + // Now add in the new data for this id, if appropriate. + if (change.change_type() == SyncChange::ACTION_ADD || + change.change_type() == SyncChange::ACTION_UPDATE) { + data_list.push_back(sync_data); + } else if (change.change_type() != SyncChange::ACTION_DELETE) { + ADD_FAILURE() << "Unexpected change type " << change.change_type(); + } + } + return syncer::SyncError(); + } + + // We override this to help catch the error of trying to use a single + // StatefulChangeProcessor to process changes for both extensions and apps + // sync data. + syncer::SyncDataList GetAllSyncData(syncer::ModelType type) const override { + EXPECT_EQ(expected_type_, type); + return FakeSyncChangeProcessor::GetAllSyncData(type); + } + + // This is a helper to vend a wrapped version of this object suitable for + // passing in to MergeDataAndStartSyncing, which takes a + // scoped_ptr<SyncChangeProcessor>, since in tests we typically don't want to + // give up ownership of a local change processor. + scoped_ptr<syncer::SyncChangeProcessor> GetWrapped() { + return make_scoped_ptr(new syncer::SyncChangeProcessorWrapperForTest(this)); + } + + protected: + // The expected ModelType of changes that this processor will see. + syncer::ModelType expected_type_; + + DISALLOW_COPY_AND_ASSIGN(StatefulChangeProcessor); +}; + } // namespace class ExtensionServiceSyncTest @@ -92,6 +168,16 @@ *model_type_passed_in = model_type; } + // Helper to call MergeDataAndStartSyncing with no server data and dummy + // change processor / error factory. + void StartSyncing(syncer::ModelType type) { + ASSERT_TRUE(type == syncer::EXTENSIONS || type == syncer::APPS); + extension_sync_service()->MergeDataAndStartSyncing( + type, syncer::SyncDataList(), + make_scoped_ptr(new syncer::FakeSyncChangeProcessor()), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + } + protected: // Paths to some of the fake extensions. base::FilePath good0_path() { @@ -608,6 +694,7 @@ syncer::EXTENSIONS, syncer::SyncDataList(), make_scoped_ptr(new syncer::FakeSyncChangeProcessor()), make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + StartSyncing(syncer::APPS); UninstallExtension(good_crx, false); EXPECT_TRUE( @@ -792,6 +879,8 @@ TEST_F(ExtensionServiceSyncTest, ProcessSyncDataWrongType) { InitializeEmptyExtensionService(); + StartSyncing(syncer::EXTENSIONS); + StartSyncing(syncer::APPS); // Install the extension. base::FilePath extension_path = data_dir().AppendASCII("good.crx"); @@ -1486,6 +1575,7 @@ ExtensionServiceInitParams params = CreateDefaultInitParams(); params.profile_is_supervised = profile_is_supervised; InitializeExtensionService(params); + StartSyncing(syncer::EXTENSIONS); supervised_user_service()->SetDelegate(this); supervised_user_service()->Init(); @@ -1833,6 +1923,7 @@ TEST_F(ExtensionServiceSyncTest, SyncExtensionHasAllhostsWithheld) { InitializeEmptyExtensionService(); + StartSyncing(syncer::EXTENSIONS); // Create an extension that needs all-hosts. const std::string kName("extension"); @@ -1879,3 +1970,96 @@ } #endif // defined(ENABLE_SUPERVISED_USERS) + +// Tests sync behavior in the case of an item that starts out as an app and +// gets updated to become an extension. +TEST_F(ExtensionServiceSyncTest, AppToExtension) { + InitializeEmptyExtensionService(); + service()->Init(); + ASSERT_TRUE(service()->is_ready()); + + // Install v1, which is an app. + const Extension* v1 = + InstallCRX(data_dir().AppendASCII("sync_datatypes").AppendASCII("v1.crx"), + INSTALL_NEW); + EXPECT_TRUE(v1->is_app()); + EXPECT_FALSE(v1->is_extension()); + std::string id = v1->id(); + + StatefulChangeProcessor extensions_processor(syncer::ModelType::EXTENSIONS); + StatefulChangeProcessor apps_processor(syncer::ModelType::APPS); + extension_sync_service()->MergeDataAndStartSyncing( + syncer::EXTENSIONS, syncer::SyncDataList(), + extensions_processor.GetWrapped(), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + extension_sync_service()->MergeDataAndStartSyncing( + syncer::APPS, syncer::SyncDataList(), apps_processor.GetWrapped(), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + + // Check the app/extension change processors to be sure the right data was + // added. + EXPECT_TRUE(extensions_processor.changes().empty()); + EXPECT_TRUE(extensions_processor.data().empty()); + EXPECT_EQ(1u, apps_processor.data().size()); + ASSERT_EQ(1u, apps_processor.changes().size()); + const SyncChange& app_change = apps_processor.changes()[0]; + EXPECT_EQ(SyncChange::ACTION_ADD, app_change.change_type()); + scoped_ptr<ExtensionSyncData> app_data = + ExtensionSyncData::CreateFromSyncData(app_change.sync_data()); + EXPECT_TRUE(app_data->is_app()); + EXPECT_EQ(id, app_data->id()); + EXPECT_EQ(*v1->version(), app_data->version()); + + // Update the app to v2, which is an extension. + const Extension* v2 = + InstallCRX(data_dir().AppendASCII("sync_datatypes").AppendASCII("v2.crx"), + INSTALL_UPDATED); + EXPECT_FALSE(v2->is_app()); + EXPECT_TRUE(v2->is_extension()); + EXPECT_EQ(id, v2->id()); + + // Make sure we saw an extension item added. + ASSERT_EQ(1u, extensions_processor.changes().size()); + const SyncChange& extension_change = extensions_processor.changes()[0]; + EXPECT_EQ(SyncChange::ACTION_ADD, extension_change.change_type()); + scoped_ptr<ExtensionSyncData> extension_data = + ExtensionSyncData::CreateFromSyncData(extension_change.sync_data()); + EXPECT_FALSE(extension_data->is_app()); + EXPECT_EQ(id, extension_data->id()); + EXPECT_EQ(*v2->version(), extension_data->version()); + + // Get the current data from the change processors to use as the input to + // the following call to MergeDataAndStartSyncing. This simulates what should + // happen with sync. + syncer::SyncDataList extensions_data = + extensions_processor.GetAllSyncData(syncer::EXTENSIONS); + syncer::SyncDataList apps_data = apps_processor.GetAllSyncData(syncer::APPS); + + // Stop syncing, then start again. + extension_sync_service()->StopSyncing(syncer::EXTENSIONS); + extension_sync_service()->StopSyncing(syncer::APPS); + extension_sync_service()->MergeDataAndStartSyncing( + syncer::EXTENSIONS, extensions_data, extensions_processor.GetWrapped(), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + extension_sync_service()->MergeDataAndStartSyncing( + syncer::APPS, apps_data, apps_processor.GetWrapped(), + make_scoped_ptr(new syncer::SyncErrorFactoryMock())); + + // Make sure we saw an app item deleted. + bool found_delete = false; + for (const auto& change : apps_processor.changes()) { + if (change.change_type() == SyncChange::ACTION_DELETE) { + scoped_ptr<ExtensionSyncData> data = + ExtensionSyncData::CreateFromSyncChange(change); + if (data->id() == id) { + found_delete = true; + break; + } + } + } + EXPECT_TRUE(found_delete); + + // Make sure there is one extension, and there are no more apps. + EXPECT_EQ(1u, extensions_processor.data().size()); + EXPECT_TRUE(apps_processor.data().empty()); +}
diff --git a/chrome/browser/extensions/extension_sync_service.cc b/chrome/browser/extensions/extension_sync_service.cc index 6d6b3af..a608f07 100644 --- a/chrome/browser/extensions/extension_sync_service.cc +++ b/chrome/browser/extensions/extension_sync_service.cc
@@ -319,24 +319,18 @@ : syncer::EXTENSIONS; const std::string& id = extension_sync_data.id(); SyncBundle* bundle = GetSyncBundle(type); + DCHECK(bundle->IsSyncing()); // Note: |extension| may be null if it hasn't been installed yet. const Extension* extension = ExtensionRegistry::Get(profile_)->GetInstalledExtension(id); - // TODO(bolms): we should really handle this better. The particularly bad - // case is where an app becomes an extension or vice versa, and we end up with - // a zombie extension that won't go away. - // TODO(treib): Is this still true? if (extension && !IsCorrectSyncType(*extension, type)) { - // Special hack: There was a bug where themes incorrectly ended up in the - // syncer::EXTENSIONS type. If we get incoming sync data for a theme, clean - // it up. crbug.com/558299 - // TODO(treib,devlin): Remove this after M52 or so. - if (extension->is_theme()) { - // First tell the bundle about the extension, so that it won't just ignore - // the deletion. - bundle->ApplySyncData(extension_sync_data); - bundle->PushSyncDeletion(id, extension_sync_data.GetSyncData()); - } + // The installed item isn't the same type as the sync data item, so we need + // to remove the sync data item; otherwise it will be a zombie that will + // keep coming back even if the installed item with this id is uninstalled. + // First tell the bundle about the extension, so that it won't just ignore + // the deletion, then push the deletion. + bundle->ApplySyncData(extension_sync_data); + bundle->PushSyncDeletion(id, extension_sync_data.GetSyncData()); return; } @@ -602,8 +596,13 @@ auto it = pending_updates_.find(extension->id()); if (it != pending_updates_.end()) { int compare_result = extension->version()->CompareTo(it->second.version); - if (compare_result == 0 && it->second.grant_permissions_and_reenable) + if (compare_result == 0 && it->second.grant_permissions_and_reenable) { + // The call to SyncExtensionChangeIfNeeded below will take care of syncing + // changes to this extension, so we don't want to trigger sync activity + // from the call to GrantPermissionsAndEnableExtension. + base::AutoReset<bool> ignore_updates(&ignore_updates_, true); extension_service()->GrantPermissionsAndEnableExtension(extension); + } if (compare_result >= 0) pending_updates_.erase(it); }
diff --git a/chrome/browser/lifetime/application_lifetime.cc b/chrome/browser/lifetime/application_lifetime.cc index 657c71b..fd55baa 100644 --- a/chrome/browser/lifetime/application_lifetime.cc +++ b/chrome/browser/lifetime/application_lifetime.cc
@@ -17,6 +17,7 @@ #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/download/download_service.h" #include "chrome/browser/lifetime/browser_close_manager.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/metrics/thread_watcher.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_manager.h" @@ -70,7 +71,6 @@ return true; } -int g_keep_alive_count = 0; bool g_disable_shutdown_for_testing = false; #endif // !defined(OS_ANDROID) @@ -113,7 +113,8 @@ // application, send the APP_TERMINATING action here. Otherwise, it will be // sent by RemoveBrowser() when the last browser has closed. if (chrome::GetTotalBrowserCount() == 0 && - (browser_shutdown::IsTryingToQuit() || !chrome::WillKeepAlive())) { + (browser_shutdown::IsTryingToQuit() || + !KeepAliveRegistry::GetInstance()->IsKeepingAlive())) { // Tell everyone that we are shutting down. browser_shutdown::SetTryingToQuit(true); @@ -275,18 +276,7 @@ base::Process::Current().Terminate(0, false); } -void IncrementKeepAliveCount() { - // Increment the browser process refcount as long as we're keeping the - // application alive. - if (!WillKeepAlive()) - g_browser_process->AddRefModule(); - ++g_keep_alive_count; -} - void CloseAllBrowsersIfNeeded() { - // If there are no browsers open and we aren't already shutting down, - // initiate a shutdown. Also skips shutdown if this is a unit test. - // (MessageLoop::current() == null or explicitly disabled). if (chrome::GetTotalBrowserCount() == 0 && !browser_shutdown::IsTryingToQuit() && base::MessageLoop::current() && !g_disable_shutdown_for_testing) { @@ -294,27 +284,6 @@ } } -void DecrementKeepAliveCount() { - DCHECK_GT(g_keep_alive_count, 0); - --g_keep_alive_count; - // Although we should have a browser process, if there is none, - // there is nothing to do. - if (!g_browser_process) return; - - // Allow the app to shutdown again. - if (!WillKeepAlive()) { - g_browser_process->ReleaseModule(); - CloseAllBrowsersIfNeeded(); - } -} - -int GetKeepAliveCountForTesting() { - return g_keep_alive_count; -} - -bool WillKeepAlive() { - return g_keep_alive_count > 0; -} #endif // !defined(OS_ANDROID) void NotifyAppTerminating() { @@ -377,7 +346,8 @@ void DisableShutdownForTesting(bool disable_shutdown_for_testing) { g_disable_shutdown_for_testing = disable_shutdown_for_testing; - if (!g_disable_shutdown_for_testing && !WillKeepAlive()) + if (!g_disable_shutdown_for_testing && + !KeepAliveRegistry::GetInstance()->IsKeepingAlive()) CloseAllBrowsersIfNeeded(); } #endif // !defined(OS_ANDROID)
diff --git a/chrome/browser/lifetime/application_lifetime.h b/chrome/browser/lifetime/application_lifetime.h index 4930c67..77af418 100644 --- a/chrome/browser/lifetime/application_lifetime.h +++ b/chrome/browser/lifetime/application_lifetime.h
@@ -56,26 +56,14 @@ // browser windows keeping it alive or the application is quitting. void CloseAllBrowsers(); +// If there are no browsers open and we aren't already shutting down, +// initiate a shutdown. Also skips shutdown if this is a unit test. +// (MessageLoop::current() == null or explicitly disabled). +void CloseAllBrowsersIfNeeded(); + // Begins shutdown of the application when the desktop session is ending. void SessionEnding(); -// Tells the BrowserList to keep the application alive after the last Browser -// closes. This is implemented as a count, so callers should pair their calls -// to IncrementKeepAliveCount() with matching calls to DecrementKeepAliveCount() -// when they no -// longer need to keep the application running. -void IncrementKeepAliveCount(); - -// Stops keeping the application alive after the last Browser is closed. -// Should match a previous call to IncrementKeepAliveCount(). -void DecrementKeepAliveCount(); - -// Returns the current keep alive count. -int GetKeepAliveCountForTesting(); - -// Returns true if application will continue running after the last Browser -// closes. -bool WillKeepAlive(); #endif // !defined(OS_ANDROID) // Emits APP_TERMINATING notification. It is guaranteed that the
diff --git a/chrome/browser/lifetime/application_lifetime_aura.cc b/chrome/browser/lifetime/application_lifetime_aura.cc index 12c0613..fd970ca 100644 --- a/chrome/browser/lifetime/application_lifetime_aura.cc +++ b/chrome/browser/lifetime/application_lifetime_aura.cc
@@ -7,6 +7,7 @@ #include "base/command_line.h" #include "build/build_config.h" #include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/common/chrome_switches.h" #include "ui/aura/client/capture_client.h" @@ -40,8 +41,8 @@ #if defined(OS_CHROMEOS) if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableZeroBrowsersOpenForTests)) { - // App is exiting, call DecrementKeepAliveCount() on behalf of Aura Shell. - DecrementKeepAliveCount(); + // App is exiting, release the keep alive on behalf of Aura Shell. + g_browser_process->platform_part()->UnregisterKeepAlive(); // Make sure we have notified the session manager that we are exiting. // This might be called from FastShutdown() or CloseAllBrowsers(), but not // if something prevents a browser from closing before SetTryingToQuit()
diff --git a/chrome/browser/lifetime/browser_close_manager_browsertest.cc b/chrome/browser/lifetime/browser_close_manager_browsertest.cc index 67db8a2..53bcbb9 100644 --- a/chrome/browser/lifetime/browser_close_manager_browsertest.cc +++ b/chrome/browser/lifetime/browser_close_manager_browsertest.cc
@@ -21,6 +21,8 @@ #include "chrome/browser/download/download_service.h" #include "chrome/browser/download/download_service_factory.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/net/url_request_mock_util.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" @@ -969,11 +971,13 @@ IN_PROC_BROWSER_TEST_P(BrowserCloseManagerWithBackgroundModeBrowserTest, CloseAllBrowsersWithBackgroundMode) { EXPECT_FALSE(IsBackgroundModeSuspended()); + scoped_ptr<ScopedKeepAlive> tmp_keep_alive; Profile* profile = browser()->profile(); { RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); - chrome::IncrementKeepAliveCount(); + tmp_keep_alive.reset(new ScopedKeepAlive(KeepAliveOrigin::PANEL_VIEW, + KeepAliveRestartOption::DISABLED)); chrome::CloseAllBrowsers(); close_observer.Wait(); } @@ -985,7 +989,7 @@ ui_test_utils::BrowserAddedObserver new_browser_observer; chrome::NewEmptyWindow(profile); new_browser_observer.WaitForSingleNewBrowser(); - chrome::DecrementKeepAliveCount(); + tmp_keep_alive.reset(); EXPECT_FALSE(IsBackgroundModeSuspended()); RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); @@ -1020,7 +1024,8 @@ RepeatedNotificationObserver close_observer( chrome::NOTIFICATION_BROWSER_CLOSED, 1); EXPECT_FALSE(IsBackgroundModeSuspended()); - chrome::IncrementKeepAliveCount(); + ScopedKeepAlive tmp_keep_alive(KeepAliveOrigin::PANEL_VIEW, + KeepAliveRestartOption::DISABLED); browser()->window()->Close(); close_observer.Wait(); EXPECT_FALSE(browser_shutdown::IsTryingToQuit());
diff --git a/chrome/browser/lifetime/keep_alive_registry.cc b/chrome/browser/lifetime/keep_alive_registry.cc index dbe7cbc2..e9800616 100644 --- a/chrome/browser/lifetime/keep_alive_registry.cc +++ b/chrome/browser/lifetime/keep_alive_registry.cc
@@ -4,6 +4,7 @@ #include "chrome/browser/lifetime/keep_alive_registry.h" +#include "chrome/browser/browser_process.h" #include "chrome/browser/lifetime/application_lifetime.h" #include "chrome/browser/lifetime/keep_alive_state_observer.h" #include "chrome/browser/lifetime/keep_alive_types.h" @@ -39,9 +40,8 @@ : registered_count_(0), restart_allowed_count_(0) {} KeepAliveRegistry::~KeepAliveRegistry() { - DCHECK_EQ(0, registered_count_); - DCHECK_EQ(0u, registered_keep_alives_.size()); - DCHECK_EQ(0, restart_allowed_count_); + DLOG_IF(ERROR, registered_count_ > 0 || registered_keep_alives_.size() > 0) + << "KeepAliveRegistry not empty at destruction time. State: " << *this; } void KeepAliveRegistry::Register(KeepAliveOrigin origin, @@ -96,12 +96,18 @@ } void KeepAliveRegistry::OnKeepingAliveChanged(bool new_keeping_alive) { + // Although we should have a browser process, if there is none, + // there is nothing to do. + if (!g_browser_process) + return; + if (new_keeping_alive) { DVLOG(1) << "KeepAliveRegistry is now keeping the browser alive."; - chrome::IncrementKeepAliveCount(); + g_browser_process->AddRefModule(); } else { DVLOG(1) << "KeepAliveRegistry stopped keeping the browser alive."; - chrome::DecrementKeepAliveCount(); + g_browser_process->ReleaseModule(); + chrome::CloseAllBrowsersIfNeeded(); } } @@ -114,8 +120,9 @@ #ifndef NDEBUG std::ostream& operator<<(std::ostream& out, const KeepAliveRegistry& registry) { - out << "{KeepingAlive=" << registry.IsKeepingAlive() - << ", RestartAllowed=" << registry.IsRestartAllowed() << ", KeepAlives=["; + out << "{registered_count_=" << registry.registered_count_ + << ", restart_allowed_count_=" << registry.restart_allowed_count_ + << ", KeepAlives=["; for (auto counts_per_origin_it : registry.registered_keep_alives_) { if (counts_per_origin_it != *registry.registered_keep_alives_.begin()) out << ", ";
diff --git a/chrome/browser/lifetime/keep_alive_registry.h b/chrome/browser/lifetime/keep_alive_registry.h index f504fa0..cd0d412 100644 --- a/chrome/browser/lifetime/keep_alive_registry.h +++ b/chrome/browser/lifetime/keep_alive_registry.h
@@ -21,8 +21,8 @@ // Methods to query the state of the registry. // TODO(dgn): This currently does not give a complete picture. It has no - // information about the many places that rely on IncrementKeepAliveCount and - // AddRefModule to keep the browser alive. Tracked by https://crbug.com/587926 + // information about the many places that rely on AddRefModule to keep the + // browser alive. Tracked by https://crbug.com/587926 bool IsKeepingAlive() const; bool IsRestartAllowed() const;
diff --git a/chrome/browser/lifetime/keep_alive_registry_unittest.cc b/chrome/browser/lifetime/keep_alive_registry_unittest.cc index b2916ec..f6a5704 100644 --- a/chrome/browser/lifetime/keep_alive_registry_unittest.cc +++ b/chrome/browser/lifetime/keep_alive_registry_unittest.cc
@@ -9,6 +9,7 @@ #include "chrome/browser/lifetime/keep_alive_state_observer.h" #include "chrome/browser/lifetime/keep_alive_types.h" #include "chrome/browser/lifetime/scoped_keep_alive.h" +#include "chrome/test/base/testing_browser_process.h" #include "testing/gtest/include/gtest/gtest.h" class KeepAliveRegistryTest : public testing::Test, @@ -45,7 +46,9 @@ // Test the IsKeepingAlive state and when we interact with the browser with // a KeepAlive registered. TEST_F(KeepAliveRegistryTest, BasicKeepAliveTest) { - const int base_keep_alive_count = chrome::GetKeepAliveCountForTesting(); + TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal(); + const unsigned int base_module_ref_count = + browser_process->module_ref_count(); KeepAliveRegistry* registry = KeepAliveRegistry::GetInstance(); EXPECT_FALSE(registry->IsKeepingAlive()); @@ -56,39 +59,41 @@ KeepAliveRestartOption::DISABLED); // We should require the browser to stay alive - EXPECT_EQ(base_keep_alive_count + 1, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count + 1, browser_process->module_ref_count()); EXPECT_TRUE(registry_->IsKeepingAlive()); } // We should be back to normal now. - EXPECT_EQ(base_keep_alive_count, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count, browser_process->module_ref_count()); EXPECT_FALSE(registry_->IsKeepingAlive()); } // Test the IsKeepingAlive state and when we interact with the browser with // more than one KeepAlive registered. TEST_F(KeepAliveRegistryTest, DoubleKeepAliveTest) { - const int base_keep_alive_count = chrome::GetKeepAliveCountForTesting(); + TestingBrowserProcess* browser_process = TestingBrowserProcess::GetGlobal(); + const unsigned int base_module_ref_count = + browser_process->module_ref_count(); scoped_ptr<ScopedKeepAlive> keep_alive_1, keep_alive_2; keep_alive_1.reset(new ScopedKeepAlive(KeepAliveOrigin::CHROME_APP_DELEGATE, KeepAliveRestartOption::DISABLED)); - EXPECT_EQ(base_keep_alive_count + 1, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count + 1, browser_process->module_ref_count()); EXPECT_TRUE(registry_->IsKeepingAlive()); keep_alive_2.reset(new ScopedKeepAlive(KeepAliveOrigin::CHROME_APP_DELEGATE, KeepAliveRestartOption::DISABLED)); // We should not increment the count twice - EXPECT_EQ(base_keep_alive_count + 1, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count + 1, browser_process->module_ref_count()); EXPECT_TRUE(registry_->IsKeepingAlive()); keep_alive_1.reset(); // We should not decrement the count before the last keep alive is released. - EXPECT_EQ(base_keep_alive_count + 1, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count + 1, browser_process->module_ref_count()); EXPECT_TRUE(registry_->IsKeepingAlive()); keep_alive_2.reset(); - EXPECT_EQ(base_keep_alive_count, chrome::GetKeepAliveCountForTesting()); + EXPECT_EQ(base_module_ref_count, browser_process->module_ref_count()); EXPECT_FALSE(registry_->IsKeepingAlive()); }
diff --git a/chrome/browser/lifetime/keep_alive_types.cc b/chrome/browser/lifetime/keep_alive_types.cc index a96050e..d1cd8f31 100644 --- a/chrome/browser/lifetime/keep_alive_types.cc +++ b/chrome/browser/lifetime/keep_alive_types.cc
@@ -8,16 +8,24 @@ #ifndef NDEBUG std::ostream& operator<<(std::ostream& out, const KeepAliveOrigin& origin) { switch (origin) { + case KeepAliveOrigin::APP_CONTROLLER: + return out << "APP_CONTROLLER"; + case KeepAliveOrigin::BROWSER_PROCESS_CHROMEOS: + return out << "BROWSER_PROCESS_CHROMEOS"; case KeepAliveOrigin::BACKGROUND_MODE_MANAGER: return out << "BACKGROUND_MODE_MANAGER"; case KeepAliveOrigin::BACKGROUND_MODE_MANAGER_STARTUP: return out << "BACKGROUND_MODE_MANAGER_STARTUP"; + case KeepAliveOrigin::LOGIN_DISPLAY_HOST_IMPL: + return out << "LOGIN_DISPLAY_HOST_IMPL"; case KeepAliveOrigin::APP_LIST_SERVICE_VIEWS: return out << "APP_LIST_SERVICE_VIEWS"; case KeepAliveOrigin::APP_LIST_SHOWER: return out << "APP_LIST_SHOWER"; case KeepAliveOrigin::CHROME_APP_DELEGATE: return out << "CHROME_APP_DELEGATE"; + case KeepAliveOrigin::PANEL: + return out << "PANEL"; case KeepAliveOrigin::PANEL_VIEW: return out << "PANEL_VIEW"; case KeepAliveOrigin::PROFILE_LOADER:
diff --git a/chrome/browser/lifetime/keep_alive_types.h b/chrome/browser/lifetime/keep_alive_types.h index e41d5c1c..59ec9100 100644 --- a/chrome/browser/lifetime/keep_alive_types.h +++ b/chrome/browser/lifetime/keep_alive_types.h
@@ -14,14 +14,22 @@ // Refers to the what the KeepAlive's lifetime is tied to, to help debugging. enum class KeepAliveOrigin { + // c/b + APP_CONTROLLER, + BROWSER_PROCESS_CHROMEOS, + // c/b/background BACKGROUND_MODE_MANAGER, BACKGROUND_MODE_MANAGER_STARTUP, + // c/b/chromeos + LOGIN_DISPLAY_HOST_IMPL, + // c/b/ui APP_LIST_SERVICE_VIEWS, APP_LIST_SHOWER, CHROME_APP_DELEGATE, + PANEL, PANEL_VIEW, PROFILE_LOADER, USER_MANAGER_VIEW
diff --git a/chrome/browser/media/webrtc_webcam_browsertest.cc b/chrome/browser/media/webrtc_webcam_browsertest.cc index 4423d65..edbd57f 100644 --- a/chrome/browser/media/webrtc_webcam_browsertest.cc +++ b/chrome/browser/media/webrtc_webcam_browsertest.cc
@@ -23,7 +23,7 @@ static const char* kTestConfigFlags[] = { #if defined(OS_WIN) - switches::kForceDirectShowVideoCapture, + NULL, // Media Foundation is only available in Windows versions >= 7, below that the // following flag has no effect; the test would run twice using DirectShow. switches::kForceMediaFoundationVideoCapture
diff --git a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc index 11b1c174..58f4af4a 100644 --- a/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc +++ b/chrome/browser/metrics/chrome_browser_main_extra_parts_metrics.cc
@@ -51,6 +51,7 @@ #endif // defined(USE_OZONE) || defined(USE_X11) #if defined(OS_WIN) +#include "base/win/windows_version.h" #include "chrome/installer/util/google_update_settings.h" #endif // defined(OS_WIN) @@ -140,6 +141,15 @@ void RecordStartupMetricsOnBlockingPool() { #if defined(OS_WIN) GoogleUpdateSettings::RecordChromeUpdatePolicyHistograms(); + + const base::win::OSInfo& os_info = *base::win::OSInfo::GetInstance(); + UMA_HISTOGRAM_ENUMERATION("Windows.GetVersionExVersion", os_info.version(), + base::win::VERSION_WIN_LAST); + UMA_HISTOGRAM_ENUMERATION("Windows.Kernel32Version", + os_info.Kernel32Version(), + base::win::VERSION_WIN_LAST); + UMA_HISTOGRAM_BOOLEAN("Windows.InCompatibilityMode", + os_info.version() != os_info.Kernel32Version()); #endif // defined(OS_WIN) #if defined(OS_MACOSX)
diff --git a/chrome/browser/prerender/prerender_manager.cc b/chrome/browser/prerender/prerender_manager.cc index 4bb07b23..f8093165 100644 --- a/chrome/browser/prerender/prerender_manager.cc +++ b/chrome/browser/prerender/prerender_manager.cc
@@ -1039,16 +1039,14 @@ // Grab a copy of the current PrerenderContents pointers, so that we // will not interfere with potential deletions of the list. - std::vector<PrerenderContents*> - prerender_contents(active_prerenders_.size()); - std::transform(active_prerenders_.begin(), active_prerenders_.end(), - prerender_contents.begin(), - std::mem_fun(&PrerenderData::contents)); + std::vector<PrerenderContents*> prerender_contents; + prerender_contents.reserve(active_prerenders_.size()); + for (auto* prerender : active_prerenders_) + prerender_contents.push_back(prerender->contents()); // And now check for prerenders using too much memory. - std::for_each(prerender_contents.begin(), prerender_contents.end(), - std::mem_fun( - &PrerenderContents::DestroyWhenUsingTooManyResources)); + for (auto* contents : prerender_contents) + contents->DestroyWhenUsingTooManyResources(); // Measure how long the resource checks took. http://crbug.com/305419. UMA_HISTOGRAM_TIMES("Prerender.PeriodicCleanupResourceCheckTime",
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher.js index dabc8320..cbc4fa7 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher.js +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/event_watcher.js
@@ -1151,7 +1151,8 @@ announceChange = true; } - if (announceChange && !cvox.ChromeVoxEventSuspender.areEventsSuspended()) { + if (newValue && announceChange && + !cvox.ChromeVoxEventSuspender.areEventsSuspended()) { cvox.ChromeVox.tts.speak(newValue, cvox.ChromeVoxEventWatcher.queueMode_(), null);
diff --git a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js index cb91944..345d6c8 100644 --- a/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js +++ b/chrome/browser/resources/chromeos/chromevox/common/editable_text_base.js
@@ -293,6 +293,9 @@ */ cvox.ChromeVoxEditableTextBase.prototype.speak = function(str, opt_triggeredByUser, opt_personality) { + if (!str) { + return; + } var queueMode = cvox.QueueMode.QUEUE; if (opt_triggeredByUser === true) { queueMode = cvox.QueueMode.FLUSH;
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index a279da8..1a1bc5c 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -302,6 +302,13 @@ * @return {boolean} True if the command should propagate. */ onGotCommand: function(command, opt_bypassModeCheck) { + // Check for loss of focus which results in us invalidating our current + // range. Note this call is synchronis. + chrome.automation.getFocus(function(focusedNode) { + if (!focusedNode) + this.currentRange_ = null; + }.bind(this)); + if (!this.currentRange_) return true;
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js index 93bea51..982b45e 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -311,7 +311,6 @@ if (syncEnabled) { // If sync theme is enabled, use values from chrome.storage.sync to sync // wallpaper changes. - WallpaperUtil.requestSyncFS(function() {}); if (changes[Constants.AccessSyncSurpriseMeEnabledKey]) { if (changes[Constants.AccessSyncSurpriseMeEnabledKey].newValue) { SurpriseWallpaper.getInstance().next();
diff --git a/chrome/browser/resources/md_history/history_item.js b/chrome/browser/resources/md_history/history_item.js index 1fc49eee..02906617 100644 --- a/chrome/browser/resources/md_history/history_item.js +++ b/chrome/browser/resources/md_history/history_item.js
@@ -120,6 +120,7 @@ onMenuButtonTap_: function(e) { this.fire('toggle-menu', { target: Polymer.dom(e).localTarget, + timestamp: this.timestamp, }); // Stops the 'tap' event from closing the menu when it opens.
diff --git a/chrome/browser/resources/md_history/history_list.js b/chrome/browser/resources/md_history/history_list.js index 8aaea2ec..6339f56 100644 --- a/chrome/browser/resources/md_history/history_list.js +++ b/chrome/browser/resources/md_history/history_list.js
@@ -64,7 +64,8 @@ */ toggleMenu_: function(e) { var target = e.detail.target; - /** @type {CrSharedMenuElement} */(this.$.sharedMenu).toggleMenu(target); + /** @type {CrSharedMenuElement} */(this.$.sharedMenu).toggleMenu( + target, e.detail.timestamp); }, /**
diff --git a/chrome/browser/resources/media_router/compiled_resources.gyp b/chrome/browser/resources/media_router/compiled_resources.gyp index 7d3ece1..614b3699 100644 --- a/chrome/browser/resources/media_router/compiled_resources.gyp +++ b/chrome/browser/resources/media_router/compiled_resources.gyp
@@ -43,6 +43,7 @@ 'elements/route_details/route_details.js', 'elements/media_router_header/media_router_header.js', 'elements/media_router_container/media_router_container.js', + 'elements/media_router_search_highlighter/media_router_search_highlighter.js', ], 'externs': [ '<(EXTERNS_DIR)/chrome_send.js',
diff --git a/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js b/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js index 8be96c8..317907f 100644 --- a/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js +++ b/chrome/browser/resources/media_router/elements/media_router_search_highlighter/media_router_search_highlighter.js
@@ -24,7 +24,7 @@ * null corresponds to an empty string when the arrays are being combined. * So both examples reproduce the text 'living room', but with different * words highlighted. - * @type {{highlightedText: Array<string>, plainText: Array<string>}} + * @type {{highlightedText: !Array<?string>, plainText: !Array<?string>}} */ data: { type: Object, @@ -36,7 +36,7 @@ * The text that this element is displaying as a plain string. The primary * purpose for this property is to make getting this element's textContent * easy for testing. - * @type {string} + * @type {?string} */ text: { type: String, @@ -52,7 +52,8 @@ * The order the strings are combined is plainText[0] highlightedText[0] * plainText[1] highlightedText[1] etc. * - * @param {{highlightedText: Array<string>, plainText: Array<string>}} data + * @param {{highlightedText: !Array<?string>, plainText: !Array<?string>}} + * data * Parameters in |data|: * highlightedText - Array of strings that should be displayed highlighted. * plainText - Array of strings that should be displayed normally. @@ -65,11 +66,13 @@ var text = ''; for (var i = 0; i < data.highlightedText.length; ++i) { if (data.plainText[i]) { - text += HTMLEscape(data.plainText[i]); + text += + HTMLEscape(/** @type {!string} */ (data.plainText[i])); } if (data.highlightedText[i]) { text += '<span class="highlight">' + - HTMLEscape(data.highlightedText[i]) + '</span>'; + HTMLEscape(/** @type {!string} */ (data.highlightedText[i])) + + '</span>'; } } this.$.text.innerHTML = text;
diff --git a/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chrome/browser/resources/settings/advanced_page/advanced_page.html index 29044ff3..369584e 100644 --- a/chrome/browser/resources/settings/advanced_page/advanced_page.html +++ b/chrome/browser/resources/settings/advanced_page/advanced_page.html
@@ -50,7 +50,6 @@ </settings-section> </template> </if> - <template is="dom-if" if="[[showPage(pageVisibility.passwordsAndForms)]]" restamp> <settings-section @@ -76,12 +75,9 @@ </settings-downloads-page> </settings-section> </template> - <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" restamp> - <settings-section page-title="[[i18n('resetPageTitle')]]" - current-route="[[currentRoute]]" section="reset"> - <settings-reset-page></settings-reset-page> - </settings-section> - </template> + + <!-- TODO(dschuyler): Add Google Cloud Print section here. --> + <if expr="chromeos"> <!-- TODO(dbeam): find somewhere to stuff "Add more accessibility features" on desktop. --> @@ -100,6 +96,12 @@ </settings-section> </template> </if> + <template is="dom-if" if="[[showPage(pageVisibility.reset)]]" restamp> + <settings-section page-title="[[i18n('resetPageTitle')]]" + current-route="[[currentRoute]]" section="reset"> + <settings-reset-page></settings-reset-page> + </settings-section> + </template> </template> <script src="chrome://md-settings/advanced_page/advanced_page.js"></script> </dom-module>
diff --git a/chrome/browser/resources/settings/basic_page/basic_page.html b/chrome/browser/resources/settings/basic_page/basic_page.html index 54971fa..70d0d4e 100644 --- a/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chrome/browser/resources/settings/basic_page/basic_page.html
@@ -24,13 +24,6 @@ <settings-reset-profile-banner on-reset-done="onResetDone_"> </settings-reset-profile-banner> </template> - <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp> - <settings-section page-title="[[i18n('peoplePageTitle')]]" - current-route="[[currentRoute]]" section="people"> - <settings-people-page prefs="{{prefs}}" current-route="{{currentRoute}}"> - </settings-people-page> - </settings-section> - </template> <if expr="chromeos"> <template is="dom-if" if="[[showPage(pageVisibility.internet)]]" restamp> <settings-section page-title="[[i18n('internetPageTitle')]]" @@ -40,6 +33,22 @@ </settings-section> </template> </if> + <template is="dom-if" if="[[showPage(pageVisibility.people)]]" restamp> + <settings-section page-title="[[i18n('peoplePageTitle')]]" + current-route="[[currentRoute]]" section="people"> + <settings-people-page prefs="{{prefs}}" + current-route="{{currentRoute}}"> + </settings-people-page> + </settings-section> + </template> + <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" restamp> + <settings-section page-title="[[i18n('onStartup')]]" + current-route="[[currentRoute]]" section="onStartup"> + <settings-on-startup-page prefs="{{prefs}}" + current-route="{{currentRoute}}"> + </settings-on-startup-page> + </settings-section> + </template> <template is="dom-if" if="[[showPage(pageVisibility.appearance)]]" restamp> <settings-section page-title="[[i18n('appearancePageTitle')]]" current-route="[[currentRoute]]" section="appearance"> @@ -58,14 +67,6 @@ </settings-section> </template> </if> - <template is="dom-if" if="[[showPage(pageVisibility.onStartup)]]" restamp> - <settings-section page-title="[[i18n('onStartup')]]" - current-route="[[currentRoute]]" section="onStartup"> - <settings-on-startup-page prefs="{{prefs}}" - current-route="{{currentRoute}}"> - </settings-on-startup-page> - </settings-section> - </template> <template is="dom-if" if="[[showPage(pageVisibility.search)]]" restamp> <settings-section page-title="[[i18n('searchPageTitle')]]" current-route="[[currentRoute]]" section="search">
diff --git a/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html new file mode 100644 index 0000000..18e3315 --- /dev/null +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html
@@ -0,0 +1,68 @@ +<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html"> +<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html"> +<link rel="import" href="chrome://md-settings/settings_dialog.html"> +<link rel="import" href="chrome://md-settings/settings_shared_css.html"> + +<dom-module id="settings-clear-browsing-data-dialog"> + <template> + <style include="settings-shared"></style> + <settings-dialog id="dialog" on-iron-overlay-closed="onDialogClosed_"> + <div class="title" i18n-content="clearBrowsingData"></div> + <div class="body"> + <div class="row"> + <span class="start" i18n-content="clearFollowingItemsFrom"></span> + <settings-dropdown-menu id="clearFrom" + pref="{{prefs.browser.clear_data.time_period}}" + menu-options="[[clearFromOptions_]]" no-label-float> + </settings-dropdown-menu> + </div> + <settings-checkbox id="browsingCheckbox" + pref="{{prefs.browser.clear_data.browsing_history}}" + i18n-values="label:clearBrowsingHistory"> + </settings-checkbox> + <settings-checkbox id="downloadCheckbox" + pref="{{prefs.browser.clear_data.download_history}}" + i18n-values="label:clearDownloadHistory"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.cache}}" + i18n-values="label:clearCache"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.cookies}}" + i18n-values="label:clearCookies"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.passwords}}" + i18n-values="label:clearPasswords"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.form_data}}" + i18n-values="label:clearFormData"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.hosted_apps_data}}" + i18n-values="label:clearHostedAppData"> + </settings-checkbox> + <settings-checkbox + pref="{{prefs.browser.clear_data.content_licenses}}" + i18n-values="label:clearDeauthorizeContentLicenses"> + </settings-checkbox> + </div> + <div class="button-container"> + <paper-button class="cancel-button" i18n-content="cancel" + dialog-dismiss></paper-button> + <paper-button class="action-button" id="clearDataButton" + i18n-content="clearBrowsingData" dialog-confirm> + </paper-button> + </div> + <div class="footer"> + <span i18n-content="warnAboutNonClearedData"></span> + <span i18n-content="clearsSyncedData"></span> + </div> + </settings-dialog> + </template> + <script src="clear_browsing_data_dialog.js"></script> +</dom-module>
diff --git a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js similarity index 85% rename from chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js rename to chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js index d5c56c6..0d9f4de 100644 --- a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.js +++ b/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.js
@@ -16,7 +16,7 @@ * </iron-animated-pages> */ Polymer({ - is: 'settings-clear-browsing-data-page', + is: 'settings-clear-browsing-data-dialog', properties: { /** @@ -72,8 +72,7 @@ /** @private */ doneClearing_: function() { - if (this.$) - this.$.clearDataButton.disabled = false; + // TODO(dschuyler): inform the user on whether clearing data was successful. }, /** @@ -92,9 +91,16 @@ } }, - /** @private */ - onPerformClearBrowsingDataTap_: function() { - this.$.clearDataButton.disabled = true; - chrome.send('performClearBrowserData'); + open: function() { + this.$.dialog.open(); + }, + + /** + * @param {!Event} event Tells us whether to perform an action or cancel. + * @private + */ + onDialogClosed_: function(event) { + if (event.detail.confirmed) + chrome.send('performClearBrowserData'); }, });
diff --git a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css deleted file mode 100644 index cfa79868..0000000 --- a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.css +++ /dev/null
@@ -1,4 +0,0 @@ -/* Copyright 2015 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ -
diff --git a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html b/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html deleted file mode 100644 index b377621..0000000 --- a/chrome/browser/resources/settings/clear_browsing_data_page/clear_browsing_data_page.html +++ /dev/null
@@ -1,62 +0,0 @@ -<link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://md-settings/controls/settings_checkbox.html"> -<link rel="import" href="chrome://md-settings/controls/settings_dropdown_menu.html"> -<link rel="import" href="chrome://md-settings/settings_shared_css.html"> - -<dom-module id="settings-clear-browsing-data-page"> - <link rel="import" type="css" href="clear_browsing_data_page.css"> - <template> - <style include="settings-shared"></style> - <div class="settings-box block"> - <span i18n-content="clearFollowingItemsFrom"></span> - <settings-dropdown-menu id="clearFrom" - pref="{{prefs.browser.clear_data.time_period}}" - menu-options="[[clearFromOptions_]]"> - </settings-dropdown-menu> - <settings-checkbox id="browsingCheckbox" - pref="{{prefs.browser.clear_data.browsing_history}}" - i18n-values="label:clearBrowsingHistory"> - </settings-checkbox> - <settings-checkbox id="downloadCheckbox" - pref="{{prefs.browser.clear_data.download_history}}" - i18n-values="label:clearDownloadHistory"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.cache}}" - i18n-values="label:clearCache"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.cookies}}" - i18n-values="label:clearCookies"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.passwords}}" - i18n-values="label:clearPasswords"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.form_data}}" - i18n-values="label:clearFormData"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.hosted_apps_data}}" - i18n-values="label:clearHostedAppData"> - </settings-checkbox> - <settings-checkbox - pref="{{prefs.browser.clear_data.content_licenses}}" - i18n-values="label:clearDeauthorizeContentLicenses"> - </settings-checkbox> - <!-- TODO(dbeam): <setting-box> is not a real thing. Fix this. --> - </settings-box> - <span i18n-content="warnAboutNonClearedData"></span> - <span i18n-content="clearsSyncedData"></span> - </settings-box> - <settings-box> - <paper-button id="clearDataButton" class="action-button" - on-tap="onPerformClearBrowsingDataTap_" - i18n-content="clearBrowsingData"> - </paper-button> - </div> - </template> - <script src="clear_browsing_data_page.js"></script> -</dom-module>
diff --git a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html index 1cf9c2c9..0b1d844 100644 --- a/chrome/browser/resources/settings/controls/settings_dropdown_menu.html +++ b/chrome/browser/resources/settings/controls/settings_dropdown_menu.html
@@ -9,7 +9,28 @@ <dom-module id="settings-dropdown-menu"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + paper-item { + color: var(--paper-grey-800); + font-size: inherit; + } + + paper-dropdown-menu { + --iron-icon-fill-color: { + var(--paper-grey-800); + }; + --iron-icon-stroke-color: { + var(--paper-grey-800); + }; + --paper-font-subhead: { + font-size: inherit; + }; + --paper-input-container-underline: { + background: var(--paper-grey-300); + }; + width: 160px; + } + </style> <paper-dropdown-menu id="dropdownMenu" label="[[menuLabel_]]" on-iron-select="onSelect_" no-label-float$="[[noLabelFloat]]" disabled="[[shouldDisableMenu_(disabled, menuOptions.*)]]">
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html index f874136..c759e5a 100644 --- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html +++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html
@@ -1,17 +1,26 @@ <link rel="import" href="chrome://resources/polymer/v1_0/polymer/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> +<link rel="import" href="chrome://resources/js/util.js"> <link rel="import" href="chrome://md-settings/settings_dialog.html"> <link rel="import" href="chrome://md-settings/settings_shared_css.html"> <dom-module id="settings-startup-urls-page"> <link rel="import" type="css" href="on_startup_shared.css"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + .favicon-image { + background-size: contain; + background-repeat: no-repeat; + height: 16px; + width: 16px; + } + </style> <div class="list-frame vertical-list"> <template is="dom-repeat" items="[[startupPages_]]"> <div class="list-item"> - <iron-icon class="secondary" icon="image:brightness-1" - item-icon></iron-icon> + <div class="favicon-image" + style="background-image: [[getIconSet_(item.url)]]"> + </div> <div class="middle"> <div class="text-elide">[[item.title]]</div> <div class="text-elide secondary">[[item.url]]</div>
diff --git a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js index 2352320..bdfa547 100644 --- a/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js +++ b/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js
@@ -60,6 +60,10 @@ chrome.send('onStartupPrefsPageLoad'); }, + getIconSet_: function(url) { + return getFaviconImageSet(url); + }, + /** @private */ updateStartupPages_: function(startupPages) { this.startupPages_ = startupPages;
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js index 1891c86..609c4f86 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js
@@ -16,6 +16,9 @@ /** @typedef {chrome.passwordsPrivate.PasswordUiEntry} */ PasswordManager.PasswordUiEntry; +/** @typedef {chrome.passwordsPrivate.LoginPair} */ +PasswordManager.LoginPair; + PasswordManager.prototype = { /** * Register a callback for when the list of passwords is updated. @@ -25,6 +28,13 @@ onSavedPasswordListChangedCallback: assertNotReached, /** + * Should remove the saved password and notify that the list has changed. + * @param {!PasswordManager.LoginPair} loginPair The saved password that + * should be removed from the list. No-op if |loginPair| is not found. + */ + removeSavedPassword: assertNotReached, + + /** * Register a callback for when the list of exceptions is updated. * Calling this function should trigger an update. * @param {function(!Array<!string>):void} callback @@ -56,6 +66,11 @@ }, /** @override */ + removeSavedPassword: function(loginPair) { + chrome.passwordsPrivate.removeSavedPassword(loginPair); + }, + + /** @override */ onExceptionListChangedCallback: function(callback) { chrome.passwordsPrivate.onPasswordExceptionsListChanged.addListener( callback); @@ -109,7 +124,8 @@ }, listeners: { - 'remove-password-exception': 'removePasswordException_' + 'remove-password-exception': 'removePasswordException_', + 'remove-saved-password': 'removeSavedPassword_', }, /** @override */ @@ -132,5 +148,14 @@ removePasswordException_: function(event) { this.passwordManager_.removePasswordException(event.detail); }, + + /** + * Listens for the remove-saved-password event, and calls the private API. + * @param {!Event} event + * @private + */ + removeSavedPassword_: function(event) { + this.passwordManager_.removeSavedPassword(event.detail); + }, }); })();
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html index e638bde..8173807 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html
@@ -25,15 +25,19 @@ <paper-input id="password" type="password" disabled value="[[getEmptyPassword_(item.numCharactersInPassword)]]"> </paper-input> - <paper-icon-button icon="more-vert" on-tap="toggleMenu_" - i18n-values="alt:passwordMenu" tabindex$="[[tabIndex]]"> + <paper-icon-button id="passwordMenu" icon="more-vert" + on-tap="onPasswordMenuTap_" i18n-values="alt:passwordMenu" + tabindex$="[[tabIndex]]"> </paper-icon-button> </div> </template> </iron-list> <cr-shared-menu id="menu"> - <div class="list-item menu-item" i18n-content="editPassword"></div> - <div class="list-item menu-item" i18n-content="removePassword"></div> + <div id="menuEditPassword" class="list-item menu-item" + i18n-content="editPassword"></div> + <div id="menuRemovePassword" class="list-item menu-item" + i18n-content="removePassword" on-tap="onMenuRemovePasswordTap_"> + </div> </cr-shared-menu> </div> <div class="list-frame"> @@ -43,8 +47,8 @@ <template> <div class="list-item two-line"> <div id="exception" class="start">[[item]]</div> - <paper-icon-button id="removeButton" icon="close" - on-tap="onRemovePasswordException_" tabindex$="[[tabIndex]]" + <paper-icon-button id="removeExceptionButton" icon="close" + on-tap="onRemoveExceptionButtonTap_" tabindex$="[[tabIndex]]" i18n-values="alt:deletePasswordException"></paper-icon-button> </div> </template>
diff --git a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js index d36fbcc..9558bb5 100644 --- a/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js +++ b/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js
@@ -7,6 +7,10 @@ * the list of saved passwords as well as the list of sites that will never * save any passwords. */ + +/** @typedef {!{model: !{item: !chrome.passwordsPrivate.PasswordUiEntry}}} */ +var PasswordUiEntryEvent; + (function() { 'use strict'; @@ -39,11 +43,21 @@ }, /** - * Fires an event that should delete the passwordException. + * Fires an event that should delete the saved password. + * @private + */ + onMenuRemovePasswordTap_: function() { + var menu = /** @type {CrSharedMenuElement} */(this.$.menu); + this.fire('remove-saved-password', menu.itemData); + menu.closeMenu(); + }, + + /** + * Fires an event that should delete the password exception. * @param {!{model: !{item: !string}}} e The polymer event. * @private */ - onRemovePasswordException_: function(e) { + onRemoveExceptionButtonTap_: function(e) { this.fire('remove-password-exception', e.model.item); }, @@ -57,13 +71,16 @@ /** * Toggles the overflow menu. - * @param {Event} e + * @param {!Event} e The polymer event. * @private */ - toggleMenu_: function(e) { - this.$.menu.toggleMenu(Polymer.dom(e).localTarget); - // Prevent the tap event from closing the menu. - e.stopPropagation(); + onPasswordMenuTap_: function(e) { + var menu = /** @type {CrSharedMenuElement} */(this.$.menu); + var target = /** @type {!Element} */(Polymer.dom(e).localTarget); + var passwordUiEntryEvent = /** @type {!PasswordUiEntryEvent} */(e); + + menu.toggleMenu(target, passwordUiEntryEvent.model.item.loginPair); + e.stopPropagation(); // Prevent the tap event from closing the menu. }, /** @@ -71,7 +88,7 @@ * @private */ closeMenu_: function() { - this.$.menu.closeMenu(); + /** @type {CrSharedMenuElement} */(this.$.menu).closeMenu(); }, }); })();
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html index 2894d39..59240d7 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -3,7 +3,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://md-settings/certificate_manager_page/certificate_manager_page.html"> -<link rel="import" href="chrome://md-settings/clear_browsing_data_page/clear_browsing_data_page.html"> +<link rel="import" href="chrome://md-settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html"> <link rel="import" href="chrome://md-settings/controls/settings_checkbox.html"> <link rel="import" href="chrome://md-settings/settings_page/settings_animated_pages.html"> <link rel="import" href="chrome://md-settings/settings_page/settings_subheader.html"> @@ -19,6 +19,8 @@ <settings-animated-pages id="pages" current-route="{{currentRoute}}" section="privacy"> <neon-animatable id="main"> + <settings-clear-browsing-data-dialog prefs="{{prefs}}"> + </settings-clear-browsing-data-dialog> <div class="settings-box block first"> <p class="privacy-explanation" i18n-values=".innerHTML:improveBrowsingExperience"> @@ -211,12 +213,6 @@ category-selected="{{categorySelected}}"> </site-details> </neon-animatable> - <neon-animatable id="clear-browsing-data"> - <settings-subheader i18n-values="page-title:clearBrowsingData"> - </settings-subheader> - <settings-clear-browsing-data-page prefs="{{prefs}}"> - </settings-clear-browsing-data-page> - </neon-animatable> </settings-animated-pages> </template> <script src="privacy_page.js"></script>
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chrome/browser/resources/settings/privacy_page/privacy_page.js index a6d821bb..c45ff8b 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.js +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.js
@@ -52,6 +52,6 @@ /** @private */ onClearBrowsingDataTap_: function() { - this.$.pages.setSubpageChain(['clear-browsing-data']); + this.$.pages.querySelector('settings-clear-browsing-data-dialog').open(); }, });
diff --git a/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chrome/browser/resources/settings/settings_menu/settings_menu.html index 1921c50..6f664bb3 100644 --- a/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chrome/browser/resources/settings/settings_menu/settings_menu.html
@@ -79,14 +79,21 @@ <span i18n-content="peoplePageTitle"></span> </div> <div> - <iron-icon icon="home" item-icon></iron-icon> - <span i18n-content="appearancePageTitle"></span> - </div> - <div> <iron-icon icon="image:brightness-1" item-icon></iron-icon> <span i18n-content="onStartup"></span> </div> <div> + <iron-icon icon="home" item-icon></iron-icon> + <span i18n-content="appearancePageTitle"></span> + </div> +<if expr="chromeos"> + <div> + <!-- TODO(dschuyler): replace brightness-1 placeholder icon --> + <iron-icon icon="image:brightness-1" item-icon></iron-icon> + <span i18n-content="devicePageTitle"></span> + </div> +</if> + <div> <iron-icon icon="search" item-icon></iron-icon> <span i18n-content="searchPageTitle"></span> </div> @@ -106,10 +113,6 @@ </iron-icon> </div> <paper-menu class="menu-content"> - <div> - <iron-icon icon="communication:location-on" item-icon></iron-icon> - <span i18n-content="siteSettingsLocation"></span> - </div> <if expr="chromeos"> <div> <iron-icon icon="device:access-time" item-icon></iron-icon> @@ -139,17 +142,32 @@ <span i18n-content="downloadsPageTitle"></span> </div> <div> - <iron-icon icon="settings-backup-restore" item-icon></iron-icon> - <span i18n-content="resetPageTitle"></span> + <!-- TODO(dschuyler): replace brightness-1 placeholder icon --> + <iron-icon icon="image:brightness-1" item-icon></iron-icon> + <span i18n-content="googleCloudPrint"></span> </div> -<if expr="chromeos"> <div> <iron-icon icon="accessibility" item-icon></iron-icon> <span i18n-content="a11yPageTitle"></span> </div> +<if expr="not chromeos"> + <div> + <!-- TODO(dschuyler): replace brightness-1 placeholder icon --> + <iron-icon icon="image:brightness-1" item-icon></iron-icon> + <span i18n-content="systemPageTitle"></span> + </div> </if> + <div> + <iron-icon icon="settings-backup-restore" item-icon></iron-icon> + <span i18n-content="resetPageTitle"></span> + </div> </paper-menu> </paper-submenu> + <paper-submenu on-tap="openPage_"> + <div class="menu-trigger"> + <span i18n-content="aboutProgram"></span> + </div> + </paper-submenu> </paper-menu> </template> <script src="settings_menu.js"></script>
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd index 58201e9..229578e 100644 --- a/chrome/browser/resources/settings/settings_resources.grd +++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -190,14 +190,11 @@ <structure name="IDR_SETTINGS_CERTIFICATES_CERTIFICATE_DELETE_CONFIRMATION_DIALOG_HTML" file="certificate_manager_page/certificate_delete_confirmation_dialog.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_CSS" - file="clear_browsing_data_page/clear_browsing_data_page.css" + <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_DIALOG_HTML" + file="clear_browsing_data_dialog/clear_browsing_data_dialog.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_HTML" - file="clear_browsing_data_page/clear_browsing_data_page.html" - type="chrome_html" /> - <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_PAGE_JS" - file="clear_browsing_data_page/clear_browsing_data_page.js" + <structure name="IDR_SETTINGS_CLEAR_BROWSING_DATA_DIALOG_JS" + file="clear_browsing_data_dialog/clear_browsing_data_dialog.js" type="chrome_html" /> <structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_HTML" file="controls/settings_checkbox.html"
diff --git a/chrome/browser/resources/settings/system_page/system_page.html b/chrome/browser/resources/settings/system_page/system_page.html index 05b47212..ecd10bdb 100644 --- a/chrome/browser/resources/settings/system_page/system_page.html +++ b/chrome/browser/resources/settings/system_page/system_page.html
@@ -19,7 +19,7 @@ </div> <div class="settings-box"> <div class="button-strip"> - <paper-button i18n-content="changeProxySettings" + <paper-button i18n-content="changeProxySettings" class="primary-button" on-tap="onChangeProxySettingsTap_"></paper-button> </div> </div>
diff --git a/chrome/browser/search_engines/search_provider_install_data.cc b/chrome/browser/search_engines/search_provider_install_data.cc index dcf0d7c1..78bd1c4b 100644 --- a/chrome/browser/search_engines/search_provider_install_data.cc +++ b/chrome/browser/search_engines/search_provider_install_data.cc
@@ -306,9 +306,8 @@ std::vector<base::Closure> closure_queue; closure_queue.swap(closure_queue_); - std::for_each(closure_queue.begin(), - closure_queue.end(), - std::mem_fun_ref(&base::Closure::Run)); + for (auto& closure : closure_queue) + closure.Run(); // Since we expect this request to be rare, clear out the information. This // also keeps the responses current as the search providers change.
diff --git a/chrome/browser/sessions/better_session_restore_browsertest.cc b/chrome/browser/sessions/better_session_restore_browsertest.cc index 39ccea2..d92d76c 100644 --- a/chrome/browser/sessions/better_session_restore_browsertest.cc +++ b/chrome/browser/sessions/better_session_restore_browsertest.cc
@@ -19,7 +19,8 @@ #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/defaults.h" #include "chrome/browser/infobars/infobar_service.h" -#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile_impl.h" @@ -317,8 +318,10 @@ bool close_all_windows) { Profile* profile = browser->profile(); + ScopedKeepAlive test_keep_alive(KeepAliveOrigin::PANEL_VIEW, + KeepAliveRestartOption::DISABLED); + // Close the browser. - chrome::IncrementKeepAliveCount(); if (close_all_windows) CloseAllBrowsers(); else @@ -334,7 +337,6 @@ ui_test_utils::BrowserAddedObserver window_observer; chrome::NewEmptyWindow(profile); Browser* new_browser = window_observer.WaitForSingleNewBrowser(); - chrome::DecrementKeepAliveCount(); return new_browser; }
diff --git a/chrome/browser/task_management/providers/arc/arc_process_task.cc b/chrome/browser/task_management/providers/arc/arc_process_task.cc index 7ef3926b..816757a 100644 --- a/chrome/browser/task_management/providers/arc/arc_process_task.cc +++ b/chrome/browser/task_management/providers/arc/arc_process_task.cc
@@ -8,6 +8,7 @@ #include "base/strings/utf_string_conversions.h" #include "chrome/grit/generated_resources.h" #include "components/arc/arc_bridge_service.h" +#include "content/public/common/child_process_host.h" #include "ui/base/l10n/l10n_util.h" namespace task_management { @@ -42,7 +43,7 @@ int ArcProcessTask::GetChildProcessUniqueID() const { // ARC process is not a child process of the browser. - return 0; + return content::ChildProcessHost::kInvalidUniqueID; } void ArcProcessTask::Kill() {
diff --git a/chrome/browser/task_management/providers/task.cc b/chrome/browser/task_management/providers/task.cc index f62b077..c9ad00b2 100644 --- a/chrome/browser/task_management/providers/task.cc +++ b/chrome/browser/task_management/providers/task.cc
@@ -86,10 +86,23 @@ current_byte_count_ += bytes_read; } +void Task::GetTerminationStatus(base::TerminationStatus* out_status, + int* out_error_code) const { + DCHECK(out_status); + DCHECK(out_error_code); + + *out_status = base::TERMINATION_STATUS_STILL_RUNNING; + *out_error_code = 0; +} + base::string16 Task::GetProfileName() const { return base::string16(); } +int Task::GetTabId() const { + return -1; +} + bool Task::ReportsSqliteMemory() const { return GetSqliteMemoryUsed() != -1; }
diff --git a/chrome/browser/task_management/providers/task.h b/chrome/browser/task_management/providers/task.h index 992f8bd..3899d20b 100644 --- a/chrome/browser/task_management/providers/task.h +++ b/chrome/browser/task_management/providers/task.h
@@ -10,6 +10,7 @@ #include <string> #include "base/macros.h" +#include "base/process/kill.h" #include "base/process/process_handle.h" #include "base/strings/string16.h" #include "base/time/time.h" @@ -85,9 +86,19 @@ // value is whatever unique IDs of their hosts in the browser process. virtual int GetChildProcessUniqueID() const = 0; + // If the process, in which this task is running, is terminated, this gets the + // termination status. Currently implemented only for Renderer processes. + virtual void GetTerminationStatus(base::TerminationStatus* out_status, + int* out_error_code) const; + // The name of the profile owning this task. virtual base::string16 GetProfileName() const; + // Returns the unique ID of the tab if this task represents a renderer + // WebContents used for a tab. Returns -1 if this task does not represent + // a renderer, or a contents of a tab. + virtual int GetTabId() const; + // Getting the Sqlite used memory (in bytes). Not all tasks reports Sqlite // memory, in this case a default invalid value of -1 will be returned. // Check for whether the task reports it or not first.
diff --git a/chrome/browser/task_management/providers/task_provider.cc b/chrome/browser/task_management/providers/task_provider.cc index 1d08d8d7..8523942 100644 --- a/chrome/browser/task_management/providers/task_provider.cc +++ b/chrome/browser/task_management/providers/task_provider.cc
@@ -36,4 +36,9 @@ observer_->TaskRemoved(task); } +void TaskProvider::NotifyObserverTaskUnresponsive(Task* task) const { + DCHECK(observer_); + observer_->TaskUnresponsive(task); +} + } // namespace task_management
diff --git a/chrome/browser/task_management/providers/task_provider.h b/chrome/browser/task_management/providers/task_provider.h index e4387cf..545e9a1 100644 --- a/chrome/browser/task_management/providers/task_provider.h +++ b/chrome/browser/task_management/providers/task_provider.h
@@ -45,10 +45,11 @@ protected: // Used by concrete task providers to notify the observer of tasks addition/ - // removal. These methods should only be called after StartUpdating() has been - // called and before StopUpdating() is called. + // removal/renderer unresponsive. These methods should only be called after + // StartUpdating() has been called and before StopUpdating() is called. void NotifyObserverTaskAdded(Task* task) const; void NotifyObserverTaskRemoved(Task* task) const; + void NotifyObserverTaskUnresponsive(Task* task) const; private: // This will be called once an observer is set for this provider. When it is
diff --git a/chrome/browser/task_management/providers/task_provider_observer.h b/chrome/browser/task_management/providers/task_provider_observer.h index 72f8696..db95bd2 100644 --- a/chrome/browser/task_management/providers/task_provider_observer.h +++ b/chrome/browser/task_management/providers/task_provider_observer.h
@@ -24,6 +24,10 @@ // the observer and references to it must not be kept. virtual void TaskRemoved(Task* task) = 0; + // This notifies of the event that |task| has become unresponsive. This event + // is only for tasks representing renderer processes. + virtual void TaskUnresponsive(Task* task) {} + private: DISALLOW_COPY_AND_ASSIGN(TaskProviderObserver); };
diff --git a/chrome/browser/task_management/providers/web_contents/renderer_task.cc b/chrome/browser/task_management/providers/web_contents/renderer_task.cc index c045de42..5dd4278 100644 --- a/chrome/browser/task_management/providers/web_contents/renderer_task.cc +++ b/chrome/browser/task_management/providers/web_contents/renderer_task.cc
@@ -13,6 +13,7 @@ #include "chrome/browser/favicon/favicon_utils.h" #include "chrome/browser/process_resource_usage.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/task_management/task_manager_observer.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/render_process_host.h" @@ -73,7 +74,9 @@ v8_memory_allocated_(0), v8_memory_used_(0), webcache_stats_(), - profile_name_(GetRendererProfileName(render_process_host_)) { + profile_name_(GetRendererProfileName(render_process_host_)), + termination_status_(base::TERMINATION_STATUS_STILL_RUNNING), + termination_error_code_(0) { // All renderer tasks are capable of reporting network usage, so the default // invalid value of -1 doesn't apply here. OnNetworkBytesRead(0); @@ -129,10 +132,23 @@ return render_process_id_; } +void RendererTask::GetTerminationStatus(base::TerminationStatus* out_status, + int* out_error_code) const { + DCHECK(out_status); + DCHECK(out_error_code); + + *out_status = termination_status_; + *out_error_code = termination_error_code_; +} + base::string16 RendererTask::GetProfileName() const { return profile_name_; } +int RendererTask::GetTabId() const { + return SessionTabHelper::IdForTab(web_contents_); +} + int64_t RendererTask::GetV8MemoryAllocated() const { return v8_memory_allocated_; }
diff --git a/chrome/browser/task_management/providers/web_contents/renderer_task.h b/chrome/browser/task_management/providers/web_contents/renderer_task.h index 0a9bdeb5..9d7dfb73 100644 --- a/chrome/browser/task_management/providers/web_contents/renderer_task.h +++ b/chrome/browser/task_management/providers/web_contents/renderer_task.h
@@ -54,7 +54,10 @@ int64_t refresh_flags) override; Type GetType() const override; int GetChildProcessUniqueID() const override; + void GetTerminationStatus(base::TerminationStatus* out_status, + int* out_error_code) const override; base::string16 GetProfileName() const override; + int GetTabId() const override; int64_t GetV8MemoryAllocated() const override; int64_t GetV8MemoryUsed() const override; bool ReportsWebCacheStats() const override; @@ -67,6 +70,14 @@ bool icon_url_changed, const gfx::Image& image) override; + void set_termination_status(base::TerminationStatus status) { + termination_status_ = status; + } + + void set_termination_error_code(int error_code) { + termination_error_code_ = error_code; + } + protected: // Returns the title of the given |web_contents|. static base::string16 GetTitleFromWebContents( @@ -114,6 +125,9 @@ // host. const base::string16 profile_name_; + base::TerminationStatus termination_status_; + int termination_error_code_; + DISALLOW_COPY_AND_ASSIGN(RendererTask); };
diff --git a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc index a80a9e57..3035ef4 100644 --- a/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc +++ b/chrome/browser/task_management/providers/web_contents/web_contents_task_provider.cc
@@ -11,10 +11,12 @@ #include "chrome/browser/task_management/providers/web_contents/web_contents_tags_manager.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_observer.h" using content::RenderFrameHost; +using content::RenderWidgetHost; using content::SiteInstance; using content::WebContents; @@ -52,6 +54,7 @@ void RenderViewReady() override; void WebContentsDestroyed() override; void RenderProcessGone(base::TerminationStatus status) override; + void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) override; void DidNavigateMainFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) override; @@ -113,6 +116,10 @@ FramesList& frames_list = pair.second; DCHECK(!frames_list.empty()); RendererTask* task = tasks_by_frames_[frames_list[0]]; + + task->set_termination_status(web_contents()->GetCrashedStatus()); + task->set_termination_error_code(web_contents()->GetCrashedErrorCode()); + if (notify_observer) provider_->NotifyObserverTaskRemoved(task); delete task; @@ -156,6 +163,18 @@ ClearAllTasks(true); } +void WebContentsEntry::OnRendererUnresponsive( + RenderWidgetHost* render_widget_host) { + auto itr = tasks_by_frames_.find(web_contents()->GetMainFrame()); + if (itr == tasks_by_frames_.end()) + return; + + DCHECK_EQ(render_widget_host->GetProcess(), + web_contents()->GetMainFrame()->GetProcess()); + + provider_->NotifyObserverTaskUnresponsive(itr->second); +} + void WebContentsEntry::DidNavigateMainFrame( const content::LoadCommittedDetails& details, const content::FrameNavigateParams& params) {
diff --git a/chrome/browser/task_management/sampling/task_group.cc b/chrome/browser/task_management/sampling/task_group.cc index 3787bd3..a2c72b09d 100644 --- a/chrome/browser/task_management/sampling/task_group.cc +++ b/chrome/browser/task_management/sampling/task_group.cc
@@ -17,6 +17,16 @@ namespace { +// A mask for the refresh types that are done in the background thread. +const int kBackgroundRefreshTypesMask = + REFRESH_TYPE_CPU | + REFRESH_TYPE_MEMORY | + REFRESH_TYPE_IDLE_WAKEUPS | +#if defined(OS_LINUX) + REFRESH_TYPE_FD_COUNT | +#endif // defined(OS_LINUX) + REFRESH_TYPE_PRIORITY; + inline bool IsResourceRefreshEnabled(RefreshType refresh_type, int refresh_flags) { return (refresh_flags & refresh_type) != 0; @@ -57,11 +67,14 @@ TaskGroup::TaskGroup( base::ProcessHandle proc_handle, base::ProcessId proc_id, + const base::Closure& on_background_calculations_done, const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner) : process_handle_(proc_handle), process_id_(proc_id), + on_background_calculations_done_(on_background_calculations_done), worker_thread_sampler_(nullptr), - tasks_(), + expected_on_bg_done_flags_(kBackgroundRefreshTypesMask), + current_on_bg_done_flags_(0), cpu_usage_(0.0), memory_usage_(), gpu_memory_(-1), @@ -123,6 +136,10 @@ int64_t refresh_flags) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + expected_on_bg_done_flags_ = refresh_flags & kBackgroundRefreshTypesMask; + // If a refresh type was recently disabled, we need to account for that too. + current_on_bg_done_flags_ &= expected_on_bg_done_flags_; + // First refresh the enabled non-expensive resources usages on the UI thread. // 1- Refresh all the tasks as well as the total network usage (if enabled). const bool network_usage_refresh_enabled = @@ -132,9 +149,8 @@ Task* task = task_pair.second; task->Refresh(update_interval, refresh_flags); - if (network_usage_refresh_enabled && task->ReportsNetworkUsage()) { + if (network_usage_refresh_enabled && task->ReportsNetworkUsage()) per_process_network_usage_ += task->network_usage(); - } } // 2- Refresh GPU memory (if enabled). @@ -179,6 +195,14 @@ return tasks_.at(task_id); } +void TaskGroup::ClearCurrentBackgroundCalculationsFlags() { + current_on_bg_done_flags_ = 0; +} + +bool TaskGroup::AreBackgroundCalculationsDone() const { + return expected_on_bg_done_flags_ == current_on_bg_done_flags_; +} + void TaskGroup::RefreshGpuMemory( const gpu::VideoMemoryUsageStats& gpu_memory_stats) { auto itr = gpu_memory_stats.process_map.find(process_id_); @@ -214,18 +238,21 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); cpu_usage_ = cpu_usage; + OnBackgroundRefreshTypeFinished(REFRESH_TYPE_CPU); } void TaskGroup::OnMemoryUsageRefreshDone(MemoryUsageStats memory_usage) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); memory_usage_ = memory_usage; + OnBackgroundRefreshTypeFinished(REFRESH_TYPE_MEMORY); } void TaskGroup::OnIdleWakeupsRefreshDone(int idle_wakeups_per_second) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); idle_wakeups_per_second_ = idle_wakeups_per_second; + OnBackgroundRefreshTypeFinished(REFRESH_TYPE_IDLE_WAKEUPS); } #if defined(OS_LINUX) @@ -233,6 +260,7 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); open_fd_count_ = open_fd_count; + OnBackgroundRefreshTypeFinished(REFRESH_TYPE_FD_COUNT); } #endif // defined(OS_LINUX) @@ -240,6 +268,15 @@ DCHECK_CURRENTLY_ON(content::BrowserThread::UI); is_backgrounded_ = is_backgrounded; + OnBackgroundRefreshTypeFinished(REFRESH_TYPE_PRIORITY); +} + +void TaskGroup::OnBackgroundRefreshTypeFinished(int64_t finished_refresh_type) { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + current_on_bg_done_flags_ |= finished_refresh_type; + if (AreBackgroundCalculationsDone()) + on_background_calculations_done_.Run(); } } // namespace task_management
diff --git a/chrome/browser/task_management/sampling/task_group.h b/chrome/browser/task_management/sampling/task_group.h index a9276fd..4d6eed2 100644 --- a/chrome/browser/task_management/sampling/task_group.h +++ b/chrome/browser/task_management/sampling/task_group.h
@@ -32,6 +32,7 @@ TaskGroup( base::ProcessHandle proc_handle, base::ProcessId proc_id, + const base::Closure& on_background_calculations_done, const scoped_refptr<base::SequencedTaskRunner>& blocking_pool_runner); ~TaskGroup(); @@ -50,6 +51,15 @@ Task* GetTaskById(TaskId task_id) const; + // This is to be called after the task manager had informed its observers with + // OnTasksRefreshedWithBackgroundCalculations() to begin another cycle for + // this notification type. + void ClearCurrentBackgroundCalculationsFlags(); + + // True if all enabled background operations calculating resource usage of the + // process represented by this TaskGroup have completed. + bool AreBackgroundCalculationsDone() const; + const base::ProcessHandle& process_handle() const { return process_handle_; } const base::ProcessId& process_id() const { return process_id_; } @@ -104,16 +114,27 @@ void OnProcessPriorityDone(bool is_backgrounded); + void OnBackgroundRefreshTypeFinished(int64_t finished_refresh_type); + // The process' handle and ID. base::ProcessHandle process_handle_; base::ProcessId process_id_; + // This is a callback into the TaskManagerImpl to inform it that the + // background calculations for this TaskGroup has finished. + const base::Closure on_background_calculations_done_; + scoped_refptr<TaskGroupSampler> worker_thread_sampler_; // Maps the Tasks by their IDs. // Tasks are not owned by the TaskGroup. They're owned by the TaskProviders. std::map<TaskId, Task*> tasks_; + // Flags will be used to determine when the background calculations has + // completed for the enabled refresh types for this TaskGroup. + int64_t expected_on_bg_done_flags_; + int64_t current_on_bg_done_flags_; + // The per process resources usages. double cpu_usage_; MemoryUsageStats memory_usage_;
diff --git a/chrome/browser/task_management/sampling/task_manager_impl.cc b/chrome/browser/task_management/sampling/task_manager_impl.cc index 9c2abab..c7e7c8d 100644 --- a/chrome/browser/task_management/sampling/task_manager_impl.cc +++ b/chrome/browser/task_management/sampling/task_manager_impl.cc
@@ -42,7 +42,10 @@ } // namespace TaskManagerImpl::TaskManagerImpl() - : blocking_pool_runner_(GetBlockingPoolRunner()), + : on_background_data_ready_callback_(base::Bind( + &TaskManagerImpl::OnTaskGroupBackgroundCalculationsDone, + base::Unretained(this))), + blocking_pool_runner_(GetBlockingPoolRunner()), is_running_(false) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -183,6 +186,20 @@ return GetTaskByTaskId(task_id)->GetType(); } +int TaskManagerImpl::GetTabId(TaskId task_id) const { + return GetTaskByTaskId(task_id)->GetTabId(); +} + +int TaskManagerImpl::GetChildProcessUniqueId(TaskId task_id) const { + return GetTaskByTaskId(task_id)->GetChildProcessUniqueID(); +} + +void TaskManagerImpl::GetTerminationStatus(TaskId task_id, + base::TerminationStatus* out_status, + int* out_error_code) const { + GetTaskByTaskId(task_id)->GetTerminationStatus(out_status, out_error_code); +} + int64_t TaskManagerImpl::GetNetworkUsage(TaskId task_id) const { return GetTaskByTaskId(task_id)->network_usage(); } @@ -244,6 +261,16 @@ return sorted_task_ids_; } +TaskIdList TaskManagerImpl::GetIdsOfTasksSharingSameProcess( + TaskId task_id) const { + DCHECK(is_running_) << "Task manager is not running. You must observe the " + "task manager for it to start running"; + + TaskIdList result; + GetTaskGroupByTaskId(task_id)->AppendSortedTaskIds(&result); + return result; +} + size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id) const { return GetTaskGroupByTaskId(task_id)->num_tasks(); } @@ -259,6 +286,7 @@ if (itr == task_groups_by_proc_id_.end()) { task_group = new TaskGroup(task->process_handle(), proc_id, + on_background_data_ready_callback_, blocking_pool_runner_); task_groups_by_proc_id_[proc_id] = task_group; } else { @@ -300,6 +328,11 @@ } } +void TaskManagerImpl::TaskUnresponsive(Task* task) { + DCHECK(task); + NotifyObserversOnTaskUnresponsive(task->task_id()); +} + void TaskManagerImpl::OnVideoMemoryUsageStatsUpdate( const gpu::VideoMemoryUsageStats& gpu_memory_stats) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); @@ -399,4 +432,18 @@ return GetTaskGroupByTaskId(task_id)->GetTaskById(task_id); } +void TaskManagerImpl::OnTaskGroupBackgroundCalculationsDone() { + // TODO(afakhry): There should be a better way for doing this! + bool are_all_processes_data_ready = true; + for (auto& groups_itr : task_groups_by_proc_id_) { + are_all_processes_data_ready &= + groups_itr.second->AreBackgroundCalculationsDone(); + } + if (are_all_processes_data_ready) { + NotifyObserversOnRefreshWithBackgroundCalculations(GetTaskIdsList()); + for (auto& groups_itr : task_groups_by_proc_id_) + groups_itr.second->ClearCurrentBackgroundCalculationsFlags(); + } +} + } // namespace task_management
diff --git a/chrome/browser/task_management/sampling/task_manager_impl.h b/chrome/browser/task_management/sampling/task_manager_impl.h index 0f0eedd48..0e92023 100644 --- a/chrome/browser/task_management/sampling/task_manager_impl.h +++ b/chrome/browser/task_management/sampling/task_manager_impl.h
@@ -60,6 +60,11 @@ const base::ProcessHandle& GetProcessHandle(TaskId task_id) const override; const base::ProcessId& GetProcessId(TaskId task_id) const override; Task::Type GetType(TaskId task_id) const override; + int GetTabId(TaskId task_id) const override; + int GetChildProcessUniqueId(TaskId task_id) const override; + void GetTerminationStatus(TaskId task_id, + base::TerminationStatus* out_status, + int* out_error_code) const override; int64_t GetNetworkUsage(TaskId task_id) const override; int64_t GetProcessTotalNetworkUsage(TaskId task_id) const override; int64_t GetSqliteMemoryUsed(TaskId task_id) const override; @@ -70,11 +75,13 @@ TaskId task_id, blink::WebCache::ResourceTypeStats* stats) const override; const TaskIdList& GetTaskIdsList() const override; + TaskIdList GetIdsOfTasksSharingSameProcess(TaskId task_id) const override; size_t GetNumberOfTasksOnSameProcess(TaskId task_id) const override; // task_management::TaskProviderObserver: void TaskAdded(Task* task) override; void TaskRemoved(Task* task) override; + void TaskUnresponsive(Task* task) override; // content::GpuDataManagerObserver: void OnVideoMemoryUsageStatsUpdate( @@ -104,6 +111,12 @@ TaskGroup* GetTaskGroupByTaskId(TaskId task_id) const; Task* GetTaskByTaskId(TaskId task_id) const; + // Called back by a TaskGroup when the resource calculations done on the + // background thread has completed. + void OnTaskGroupBackgroundCalculationsDone(); + + const base::Closure on_background_data_ready_callback_; + // Map TaskGroups by the IDs of the processes they represent. // Keys and values are unique (no duplicates). std::map<base::ProcessId, TaskGroup*> task_groups_by_proc_id_;
diff --git a/chrome/browser/task_management/task_manager_interface.cc b/chrome/browser/task_management/task_manager_interface.cc index 790cbd0d..5776968 100644 --- a/chrome/browser/task_management/task_manager_interface.cc +++ b/chrome/browser/task_management/task_manager_interface.cc
@@ -87,7 +87,7 @@ SetEnabledResourceFlags(flags); } -bool TaskManagerInterface::IsResourceRefreshEnabled(RefreshType type) { +bool TaskManagerInterface::IsResourceRefreshEnabled(RefreshType type) const { return (enabled_resources_flags_ & type) != 0; } @@ -115,6 +115,17 @@ OnTasksRefreshed(task_ids)); } +void TaskManagerInterface::NotifyObserversOnRefreshWithBackgroundCalculations( + const TaskIdList& task_ids) { + FOR_EACH_OBSERVER(TaskManagerObserver, + observers_, + OnTasksRefreshedWithBackgroundCalculations(task_ids)); +} + +void TaskManagerInterface::NotifyObserversOnTaskUnresponsive(TaskId id) { + FOR_EACH_OBSERVER(TaskManagerObserver, observers_, OnTaskUnresponsive(id)); +} + base::TimeDelta TaskManagerInterface::GetCurrentRefreshTime() const { return refresh_timer_->IsRunning() ? refresh_timer_->GetCurrentDelay() : base::TimeDelta::Max();
diff --git a/chrome/browser/task_management/task_manager_interface.h b/chrome/browser/task_management/task_manager_interface.h index d8dd95c..79d65e1 100644 --- a/chrome/browser/task_management/task_manager_interface.h +++ b/chrome/browser/task_management/task_manager_interface.h
@@ -12,6 +12,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" +#include "base/process/kill.h" #include "base/process/process_handle.h" #include "base/time/time.h" #include "base/timer/timer.h" @@ -118,6 +119,28 @@ // Returns the type of the task with |task_id|. virtual Task::Type GetType(TaskId task_id) const = 0; + // Gets the unique ID of the tab if the task with |task_id| represents a + // WebContents of a tab. Returns -1 otherwise. + virtual int GetTabId(TaskId task_id) const = 0; + + // Returns the unique ID of the BrowserChildProcessHost/RenderProcessHost on + // which the task with |task_id| is running. It is not the PID nor the handle + // of the process. + // For a task that represents the browser process, the return value is 0. + // For a task that doesn't have a host on the browser process, the return + // value is also 0. For other tasks that represent renderers and other child + // processes, the return value is whatever unique IDs of their hosts in the + // browser process. + virtual int GetChildProcessUniqueId(TaskId task_id) const = 0; + + // If the process, in which the task with |task_id| is running, is terminated + // this gets the termination status. Currently implemented only for Renderer + // processes. The values will only be valid if the process has actually + // terminated. + virtual void GetTerminationStatus(TaskId task_id, + base::TerminationStatus* out_status, + int* out_error_code) const = 0; + // Returns the network usage (in bytes per second) during the current refresh // cycle for the task with |task_id|. A value of -1 means no valid value is // currently available or that task has never been notified of any network @@ -154,6 +177,10 @@ // IDs on which the tasks are running, then by the task IDs themselves. virtual const TaskIdList& GetTaskIdsList() const = 0; + // Gets the list of task IDs of the tasks that run on the same process as the + // task with |task_id|. The returned list will at least include |task_id|. + virtual TaskIdList GetIdsOfTasksSharingSameProcess(TaskId task_id) const = 0; + // Gets the number of task-manager tasks running on the same process on which // the Task with |task_id| is running. virtual size_t GetNumberOfTasksOnSameProcess(TaskId task_id) const = 0; @@ -161,7 +188,7 @@ // Returns true if the resource |type| usage calculation is enabled and // the implementation should refresh its value (this means that at least one // of the observers require this value). False otherwise. - bool IsResourceRefreshEnabled(RefreshType type); + bool IsResourceRefreshEnabled(RefreshType type) const; protected: TaskManagerInterface(); @@ -171,6 +198,9 @@ void NotifyObserversOnTaskAdded(TaskId id); void NotifyObserversOnTaskToBeRemoved(TaskId id); void NotifyObserversOnRefresh(const TaskIdList& task_ids); + void NotifyObserversOnRefreshWithBackgroundCalculations( + const TaskIdList& task_ids); + void NotifyObserversOnTaskUnresponsive(TaskId id); // Refresh all the enabled resources usage of all the available tasks. virtual void Refresh() = 0;
diff --git a/chrome/browser/task_management/task_manager_observer.cc b/chrome/browser/task_management/task_manager_observer.cc index a0a1a65..f75d27f 100644 --- a/chrome/browser/task_management/task_manager_observer.cc +++ b/chrome/browser/task_management/task_manager_observer.cc
@@ -17,6 +17,8 @@ desired_resources_flags_(resources_flags) {} TaskManagerObserver::~TaskManagerObserver() { + if (observed_task_manager()) + observed_task_manager()->RemoveObserver(this); } void TaskManagerObserver::AddRefreshType(RefreshType type) { @@ -33,5 +35,11 @@ observed_task_manager_->RecalculateRefreshFlags(); } +void TaskManagerObserver::SetRefreshTypesFlags(int64_t flags) { + desired_resources_flags_ = flags; + + if (observed_task_manager_) + observed_task_manager_->RecalculateRefreshFlags(); +} } // namespace task_management
diff --git a/chrome/browser/task_management/task_manager_observer.h b/chrome/browser/task_management/task_manager_observer.h index 408d2a87..84f2c21 100644 --- a/chrome/browser/task_management/task_manager_observer.h +++ b/chrome/browser/task_management/task_manager_observer.h
@@ -86,6 +86,22 @@ // IDs themselves. virtual void OnTasksRefreshed(const TaskIdList& task_ids) = 0; + // Notifies the observer that the task manager has just finished a refresh + // cycle that calculated all the resource usage of all tasks whose IDs are in + // |task_ids| including the resource usages that are calculated in the + // background such CPU and memory (If those refresh types are enabled). + // This event can take longer to be fired, and can miss some changes that may + // happen to non-background calculations in-between two successive + // invocations. Listen to this ONLY if you must know when all the background + // resource calculations to be valid for all the available processes. + // |task_ids| will be sorted as specified in OnTasksRefreshed() above. + virtual void OnTasksRefreshedWithBackgroundCalculations( + const TaskIdList& task_ids) {} + + // Notifies the observer that the task with |id| is running on a renderer that + // has become unresponsive. + virtual void OnTaskUnresponsive(TaskId id) {} + const base::TimeDelta& desired_refresh_time() const { return desired_refresh_time_; } @@ -100,6 +116,7 @@ // Add or Remove a refresh |type|. void AddRefreshType(RefreshType type); void RemoveRefreshType(RefreshType type); + void SetRefreshTypesFlags(int64_t flags); private: friend class TaskManagerInterface;
diff --git a/chrome/browser/task_management/test_task_manager.cc b/chrome/browser/task_management/test_task_manager.cc index c49c5f1..9b71bf4 100644 --- a/chrome/browser/task_management/test_task_manager.cc +++ b/chrome/browser/task_management/test_task_manager.cc
@@ -97,6 +97,24 @@ return Task::UNKNOWN; } +int TestTaskManager::GetTabId(TaskId task_id) const { + return -1; +} + +int TestTaskManager::GetChildProcessUniqueId(TaskId task_id) const { + return 0; +} + +void TestTaskManager::GetTerminationStatus(TaskId task_id, + base::TerminationStatus* out_status, + int* out_error_code) const { + DCHECK(out_status); + DCHECK(out_error_code); + + *out_status = base::TERMINATION_STATUS_STILL_RUNNING; + *out_error_code = 0; +} + int64_t TestTaskManager::GetNetworkUsage(TaskId task_id) const { return -1; } @@ -125,6 +143,13 @@ return ids_; } +TaskIdList TestTaskManager::GetIdsOfTasksSharingSameProcess( + TaskId task_id) const { + TaskIdList result; + result.push_back(task_id); + return result; +} + size_t TestTaskManager::GetNumberOfTasksOnSameProcess(TaskId task_id) const { return 1; }
diff --git a/chrome/browser/task_management/test_task_manager.h b/chrome/browser/task_management/test_task_manager.h index b666bb0..e3a1838 100644 --- a/chrome/browser/task_management/test_task_manager.h +++ b/chrome/browser/task_management/test_task_manager.h
@@ -47,6 +47,11 @@ const base::ProcessHandle& GetProcessHandle(TaskId task_id) const override; const base::ProcessId& GetProcessId(TaskId task_id) const override; Task::Type GetType(TaskId task_id) const override; + int GetTabId(TaskId task_id) const override; + int GetChildProcessUniqueId(TaskId task_id) const override; + void GetTerminationStatus(TaskId task_id, + base::TerminationStatus* out_status, + int* out_error_code) const override; int64_t GetNetworkUsage(TaskId task_id) const override; int64_t GetProcessTotalNetworkUsage(TaskId task_id) const override; int64_t GetSqliteMemoryUsed(TaskId task_id) const override; @@ -57,6 +62,7 @@ TaskId task_id, blink::WebCache::ResourceTypeStats* stats) const override; const TaskIdList& GetTaskIdsList() const override; + TaskIdList GetIdsOfTasksSharingSameProcess(TaskId task_id) const override; size_t GetNumberOfTasksOnSameProcess(TaskId task_id) const override; base::TimeDelta GetRefreshTime();
diff --git a/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc b/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc index 298b624f..bd6fdec2 100644 --- a/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc +++ b/chrome/browser/ui/app_list/app_list_service_views_browsertest.cc
@@ -9,7 +9,7 @@ #include "base/run_loop.h" #include "build/build_config.h" #include "chrome/browser/extensions/extension_browsertest.h" -#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/ui/app_list/app_list_controller_delegate.h" #include "chrome/browser/ui/app_list/test/chrome_app_list_test_support.h" #include "chrome/browser/ui/browser.h" @@ -119,13 +119,13 @@ generator.PressKey(ui::VKEY_ESCAPE, 0); #if !defined(OS_CHROMEOS) - EXPECT_TRUE(chrome::WillKeepAlive()); + EXPECT_TRUE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); #endif base::RunLoop().RunUntilIdle(); #if !defined(OS_CHROMEOS) - EXPECT_FALSE(chrome::WillKeepAlive()); + EXPECT_FALSE(KeepAliveRegistry::GetInstance()->IsKeepingAlive()); #endif EXPECT_FALSE(service->GetAppListWindow()); }
diff --git a/chrome/browser/ui/ash/ash_init.cc b/chrome/browser/ui/ash/ash_init.cc index 007c7f5b..db3fad2 100644 --- a/chrome/browser/ui/ash/ash_init.cc +++ b/chrome/browser/ui/ash/ash_init.cc
@@ -26,6 +26,8 @@ #if defined(OS_CHROMEOS) #include "base/sys_info.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/accessibility/magnification_manager.h" #include "chrome/browser/ui/ash/ime_controller_chromeos.h" @@ -93,7 +95,7 @@ if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableZeroBrowsersOpenForTests)) { - chrome::IncrementKeepAliveCount(); + g_browser_process->platform_part()->RegisterKeepAlive(); } #endif ash::Shell::GetPrimaryRootWindow()->GetHost()->Show();
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc index c43d298..ce221ce 100644 --- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc +++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -349,8 +349,8 @@ multi_user_window_manager_->GetOwnersOfVisibleWindows(&owners); std::vector<std::string> owner_list; - std::transform(owners.begin(), owners.end(), std::back_inserter(owner_list), - std::mem_fun_ref(&AccountId::GetUserEmail)); + for (auto& owner : owners) + owner_list.push_back(owner.GetUserEmail()); return base::JoinString(owner_list, " "); }
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc index 6f94a621..1595e86 100644 --- a/chrome/browser/ui/browser.cc +++ b/chrome/browser/ui/browser.cc
@@ -61,6 +61,7 @@ #include "chrome/browser/history/top_sites_factory.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_registry.h" #include "chrome/browser/memory/tab_manager_web_contents_data.h" #include "chrome/browser/notifications/notification_ui_manager.h" #include "chrome/browser/pepper_broker_infobar_delegate.h" @@ -701,7 +702,8 @@ // AppController on the Mac, or BackgroundContentsService for background // pages). bool should_quit_if_last_browser = - browser_shutdown::IsTryingToQuit() || !chrome::WillKeepAlive(); + browser_shutdown::IsTryingToQuit() || + !KeepAliveRegistry::GetInstance()->IsKeepingAlive(); if (should_quit_if_last_browser && ShouldStartShutdown()) browser_shutdown::OnShutdownStarting(browser_shutdown::WINDOW_CLOSE);
diff --git a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm index 51f96a0d..a9c7a83 100644 --- a/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm +++ b/chrome/browser/ui/cocoa/javascript_app_modal_dialog_cocoa.mm
@@ -83,10 +83,14 @@ - (NSAlert*)alert { if (!alert_) { alert_.reset([[NSAlert alloc] init]); - // Set a blank icon. - NSImage* image = - [[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] autorelease]; - [alert_ setIcon:image]; + if (!nativeDialog_->dialog()->is_before_unload_dialog()) { + // Set a blank icon for dialogs with text provided by the page. + // "onbeforeunload" dialogs don't have text provided by the page, so it's + // OK to use the app icon. + NSImage* image = + [[[NSImage alloc] initWithSize:NSMakeSize(1, 1)] autorelease]; + [alert_ setIcon:image]; + } } return alert_; }
diff --git a/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc b/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc index ccaca98..167e1cd 100644 --- a/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc +++ b/chrome/browser/ui/extensions/extension_installed_bubble_browsertest.cc
@@ -6,11 +6,15 @@ #include "chrome/browser/extensions/extension_browsertest.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/ui/extensions/extension_installed_bubble.h" +#include "extensions/common/feature_switch.h" using ExtensionInstalledBubbleBrowserTest = ExtensionBrowserTest; IN_PROC_BROWSER_TEST_F(ExtensionInstalledBubbleBrowserTest, DoNotShowHowToUseForSynthesizedActions) { + extensions::FeatureSwitch::ScopedOverride enable_redesign( + extensions::FeatureSwitch::extension_action_redesign(), + true); const SkBitmap kEmptyBitmap; { scoped_refptr<const extensions::Extension> extension =
diff --git a/chrome/browser/ui/layout_constants.cc b/chrome/browser/ui/layout_constants.cc index 7fefe4e..229a1eb9 100644 --- a/chrome/browser/ui/layout_constants.cc +++ b/chrome/browser/ui/layout_constants.cc
@@ -11,7 +11,7 @@ int GetLayoutConstant(LayoutConstant constant) { const int kFindBarVerticalOffset[] = {1, 6, 6}; const int kIconLabelViewInternalPadding[] = {3, 2, 2}; - const int kIconLabelViewTrailingPadding[] = {2, 8, 8}; + const int kIconLabelViewTrailingPadding[] = {2, 3, 3}; const int kLocationBarBorderThickness[] = {2, 1, 1}; const int kLocationBarBubbleFontVerticalPadding[] = {1, 2, 4}; const int kLocationBarBubbleHorizontalPadding[] = {1, 4, 4};
diff --git a/chrome/browser/ui/panels/panel.cc b/chrome/browser/ui/panels/panel.cc index ca0541f..04f8182 100644 --- a/chrome/browser/ui/panels/panel.cc +++ b/chrome/browser/ui/panels/panel.cc
@@ -21,6 +21,8 @@ #include "chrome/browser/extensions/window_controller.h" #include "chrome/browser/extensions/window_controller_list.h" #include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/sessions/session_tab_helper.h" #include "chrome/browser/task_management/web_contents_tags.h" @@ -166,10 +168,6 @@ Panel::~Panel() { DCHECK(!collection_); -#if !defined(USE_AURA) - // Invoked by native panel destructor. Do not access native_panel_ here. - chrome::DecrementKeepAliveCount(); // Remove shutdown prevention. -#endif } PanelManager* Panel::manager() const { @@ -558,10 +556,13 @@ content::Source<ThemeService>( ThemeServiceFactory::GetForProfile(profile_))); +// TODO(dgn): Should keep_alive be always registered regardless of the platform +// here? (https://crbug.com/590173) #if !defined(USE_AURA) // Keep alive for AURA has been moved to panel_view. // Prevent the browser process from shutting down while this window is open. - chrome::IncrementKeepAliveCount(); + keep_alive_.reset(new ScopedKeepAlive(KeepAliveOrigin::PANEL, + KeepAliveRestartOption::DISABLED)); #endif UpdateAppIcon();
diff --git a/chrome/browser/ui/panels/panel.h b/chrome/browser/ui/panels/panel.h index c441902..898696e 100644 --- a/chrome/browser/ui/panels/panel.h +++ b/chrome/browser/ui/panels/panel.h
@@ -29,6 +29,7 @@ class PanelHost; class PanelManager; class Profile; +class ScopedKeepAlive; class StackedPanelCollection; namespace content { @@ -411,6 +412,8 @@ // Icon showed in the task bar. gfx::Image app_icon_; + scoped_ptr<ScopedKeepAlive> keep_alive_; + base::WeakPtrFactory<Panel> image_loader_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(Panel);
diff --git a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc index fbe2762..a7b03509 100644 --- a/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc +++ b/chrome/browser/ui/views/bookmarks/bookmark_bar_view.cc
@@ -94,6 +94,8 @@ #include "ui/gfx/vector_icons_public.h" #include "ui/resources/grit/ui_resources.h" #include "ui/views/animation/button_ink_drop_delegate.h" +#include "ui/views/animation/flood_fill_ink_drop_animation.h" +#include "ui/views/animation/ink_drop_hover.h" #include "ui/views/button_drag_utils.h" #include "ui/views/controls/button/label_button.h" #include "ui/views/controls/button/label_button_border.h" @@ -188,7 +190,7 @@ // BookmarkButtonBase ----------------------------------------------- -// Base class for buttons used on the bookmark bar. +// Base class for non-menu hosting buttons used on the bookmark bar. class BookmarkButtonBase : public views::LabelButton { public: @@ -227,9 +229,26 @@ event_utils::IsPossibleDispositionEvent(e); } + scoped_ptr<views::InkDropAnimation> CreateInkDropAnimation() const override { + return make_scoped_ptr(new views::FloodFillInkDropAnimation( + size(), GetInkDropCenter(), GetInkDropBaseColor())); + } + + scoped_ptr<views::InkDropHover> CreateInkDropHover() const override { + if (!ShouldShowInkDropHover()) + return nullptr; + return make_scoped_ptr(new views::InkDropHover( + size(), 0, GetInkDropCenter(), GetInkDropBaseColor())); + } + SkColor GetInkDropBaseColor() const override { - return GetThemeProvider()->GetColor( - ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON); + // TODO(bruthig): Inject the color instead of assuming a ThemeProvider is + // always available. Fall back on LabelButton::GetInkDropBaseColor() so as + // to avoid difficult to track down crashes. + return GetThemeProvider() + ? GetThemeProvider()->GetColor( + ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON) + : views::LabelButton::GetInkDropBaseColor(); } private: @@ -300,16 +319,55 @@ // static const char ShortcutButton::kViewClassName[] = "ShortcutButton"; +// BookmarkMenuButtonBase ----------------------------------------------------- + +// Base class for menu hosting buttons used on the bookmark bar. +class BookmarkMenuButtonBase : public views::MenuButton { + public: + BookmarkMenuButtonBase(const base::string16& title, + views::MenuButtonListener* menu_button_listener, + bool show_menu_marker) + : MenuButton(title, menu_button_listener, show_menu_marker), + ink_drop_delegate_(this, this) { + set_ink_drop_delegate(&ink_drop_delegate_); + } + + scoped_ptr<views::InkDropAnimation> CreateInkDropAnimation() const override { + return make_scoped_ptr(new views::FloodFillInkDropAnimation( + size(), GetInkDropCenter(), GetInkDropBaseColor())); + } + + scoped_ptr<views::InkDropHover> CreateInkDropHover() const override { + if (!ShouldShowInkDropHover()) + return nullptr; + return make_scoped_ptr(new views::InkDropHover( + size(), 0, GetInkDropCenter(), GetInkDropBaseColor())); + } + + SkColor GetInkDropBaseColor() const override { + return GetThemeProvider() + ? GetThemeProvider()->GetColor( + ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON) + : views::LabelButton::GetInkDropBaseColor(); + } + + private: + // Controls the visual feedback for the button state. + views::ButtonInkDropDelegate ink_drop_delegate_; + + DISALLOW_COPY_AND_ASSIGN(BookmarkMenuButtonBase); +}; + // BookmarkFolderButton ------------------------------------------------------- // Buttons used for folders on the bookmark bar, including the 'other folders' // button. -class BookmarkFolderButton : public views::MenuButton { +class BookmarkFolderButton : public BookmarkMenuButtonBase { public: BookmarkFolderButton(const base::string16& title, views::MenuButtonListener* menu_button_listener, bool show_menu_marker) - : MenuButton(title, menu_button_listener, show_menu_marker) { + : BookmarkMenuButtonBase(title, menu_button_listener, show_menu_marker) { SetElideBehavior(kElideBehavior); show_animation_.reset(new gfx::SlideAnimation(this)); if (!animations_enabled) { @@ -328,13 +386,23 @@ return !tooltip->empty(); } + bool OnMousePressed(const ui::MouseEvent& event) override { + if (event.IsOnlyLeftMouseButton()) { + // TODO(bruthig): The ACTION_PENDING triggering logic should be in + // MenuButton::OnPressed() however there is a bug with the pressed state + // logic in MenuButton. See http://crbug.com/567252. + ink_drop_delegate()->OnAction(views::InkDropState::ACTION_PENDING); + } + return MenuButton::OnMousePressed(event); + } + bool IsTriggerableEventType(const ui::Event& e) override { // Bookmark folders handle normal menu button events (i.e., left click) as // well as clicks to open bookmarks in new tabs that would otherwise be // ignored. - return views::MenuButton::IsTriggerableEventType(e) || + return BookmarkMenuButtonBase::IsTriggerableEventType(e) || (e.IsMouseEvent() && - ui::DispositionFromEventFlags(e.flags()) != CURRENT_TAB); + ui::DispositionFromEventFlags(e.flags()) != CURRENT_TAB); } private: @@ -345,14 +413,14 @@ // OverflowButton (chevron) -------------------------------------------------- -class OverflowButton : public views::MenuButton { +class OverflowButton : public BookmarkMenuButtonBase { public: explicit OverflowButton(BookmarkBarView* owner) - : MenuButton(base::string16(), owner, false), owner_(owner) {} + : BookmarkMenuButtonBase(base::string16(), owner, false), owner_(owner) {} bool OnMousePressed(const ui::MouseEvent& e) override { owner_->StopThrobbing(true); - return views::MenuButton::OnMousePressed(e); + return BookmarkMenuButtonBase::OnMousePressed(e); } private:
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc index a3b7640c..234c753 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.cc +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.cc
@@ -56,7 +56,9 @@ SetBackgroundImageGrid(kBackgroundImages); } - image()->SetHorizontalAlignment(views::ImageView::LEADING); + image()->SetHorizontalAlignment(base::i18n::IsRTL() + ? views::ImageView::TRAILING + : views::ImageView::LEADING); image()->set_interactive(true); image()->EnableCanvasFlippingForRTLUI(true); image()->SetAccessibilityFocusable(true); @@ -94,7 +96,8 @@ // the user. If this becomes a problem, we could design some sort of queueing // mechanism to show one after the other, but it doesn't seem important now. int string_id = content_setting_image_model_->explanatory_string_id(); - if (string_id && !ShouldShowBackground()) { + if (string_id && !label()->visible()) { + ink_drop_delegate_->OnAction(views::InkDropState::HIDDEN); SetLabel(l10n_util::GetStringUTF16(string_id)); label()->SetVisible(true); slide_animator_.Show(); @@ -113,7 +116,8 @@ } bool ContentSettingImageView::ShouldShowBackground() const { - return slide_animator_.is_animating() || pause_animation_; + return (!IsShrinking() || label()->width() > 0) && + (slide_animator_.is_animating() || pause_animation_); } double ContentSettingImageView::WidthMultiplier() const { @@ -132,6 +136,13 @@ return size_fraction; } +bool ContentSettingImageView::IsShrinking() const { + const double kOpenFraction = + static_cast<double>(kOpenTimeMS) / kAnimationDurationMS; + return (!pause_animation_ && slide_animator_.is_animating() && + slide_animator_.GetCurrentValue() > (1.0 - kOpenFraction)); +} + void ContentSettingImageView::AnimationEnded(const gfx::Animation* animation) { slide_animator_.Reset(); if (!pause_animation_) { @@ -184,10 +195,8 @@ return; } const bool activated = HitTestPoint(event.location()); - if (!label()->visible()) { - ink_drop_delegate_->OnAction(activated ? views::InkDropState::ACTIVATED - : views::InkDropState::HIDDEN); - } + if (!label()->visible() && !activated) + ink_drop_delegate_->OnAction(views::InkDropState::HIDDEN); if (activated) OnClick(); } @@ -196,17 +205,13 @@ if (event.key_code() != ui::VKEY_SPACE && event.key_code() != ui::VKEY_RETURN) return false; - ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); OnClick(); return true; } void ContentSettingImageView::OnGestureEvent(ui::GestureEvent* event) { - if (event->type() == ui::ET_GESTURE_TAP) { - if (!label()->visible()) - ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); + if (event->type() == ui::ET_GESTURE_TAP) OnClick(); - } if ((event->type() == ui::ET_GESTURE_TAP) || (event->type() == ui::ET_GESTURE_TAP_DOWN)) event->SetHandled(); @@ -242,7 +247,19 @@ void ContentSettingImageView::OnClick() { if (slide_animator_.is_animating()) { - if (!pause_animation_) { + // If the user clicks while we're animating, the bubble arrow will be + // pointing to the image, and if we allow the animation to keep running, the + // image will move away from the arrow (or we'll have to move the bubble, + // which is even worse). So we want to stop the animation. We have two + // choices: jump to the final post-animation state (no label visible), or + // pause the animation where we are and continue running after the bubble + // closes. The former looks more jerky, so we avoid it unless the animation + // hasn't even fully exposed the image yet, in which case pausing with half + // an image visible will look broken. + const int final_width = image()->GetPreferredSize().width() + + GetBubbleOuterPadding(true) + + GetBubbleOuterPadding(false); + if (!pause_animation_ && ShouldShowBackground() && width() > final_width) { pause_animation_ = true; pause_animation_state_ = slide_animator_.GetCurrentValue(); } @@ -264,8 +281,10 @@ // bubble doesn't need an arrow. If the user clicks during an animation, // the animation simply pauses and no other visible state change occurs, so // show the arrow in this case. - if (ui::MaterialDesignController::IsModeMaterial() && !pause_animation_) + if (ui::MaterialDesignController::IsModeMaterial() && !pause_animation_) { + ink_drop_delegate_->OnAction(views::InkDropState::ACTIVATED); bubble_view_->SetArrowPaintType(views::BubbleBorder::PAINT_TRANSPARENT); + } bubble_widget->Show(); } }
diff --git a/chrome/browser/ui/views/location_bar/content_setting_image_view.h b/chrome/browser/ui/views/location_bar/content_setting_image_view.h index a6beed4..814c303 100644 --- a/chrome/browser/ui/views/location_bar/content_setting_image_view.h +++ b/chrome/browser/ui/views/location_bar/content_setting_image_view.h
@@ -65,6 +65,7 @@ SkColor GetBorderColor() const override; bool ShouldShowBackground() const override; double WidthMultiplier() const override; + bool IsShrinking() const override; // gfx::AnimationDelegate: void AnimationEnded(const gfx::Animation* animation) override;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc index f51e30a..480e856 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -105,6 +105,10 @@ return 1.0; } +bool IconLabelBubbleView::IsShrinking() const { + return false; +} + int IconLabelBubbleView::GetImageAndPaddingWidth() const { const int image_width = image_->GetPreferredSize().width(); return image_width @@ -118,20 +122,53 @@ } void IconLabelBubbleView::Layout() { - // In MD mode, both extension icons and Chrome-provided icons are 16px, - // so it's not necessary to handle them differently. TODO(estade): clean - // this up when MD is on by default. - bool icon_has_enough_padding = - !is_extension_icon_ || ui::MaterialDesignController::IsModeMaterial(); - const int image_width = image_->GetPreferredSize().width(); - image_->SetBounds(std::min((width() - image_width) / 2, - GetBubbleOuterPadding(icon_has_enough_padding)), - 0, image_->GetPreferredSize().width(), height()); + // Compute the label bounds. The label gets whatever size is left over after + // accounting for the preferred image width and padding amounts. Note that if + // the label has zero size it doesn't actually matter what we compute its X + // value to be, since it won't be visible, so the X value can be "wrong" + // compared to where the right edge of the image is computed to be below. + // This means doing this layout doesn't doesn't depend on any of the layout + // below. That layout, however, may need for this layout to have already + // happened, since the value of ShouldShowBackground() we read below may + // depend on whether the label has nonzero size. Therefore, we do this first. + const int label_x = GetBubbleOuterPadding(true) + GetImageAndPaddingWidth(); + const int label_width = + std::max(0, width() - label_x - GetBubbleOuterPadding(false)); + label_->SetBounds(label_x, 0, label_width, height()); - int pre_label_width = GetBubbleOuterPadding(true) + GetImageAndPaddingWidth(); - label_->SetBounds(pre_label_width, 0, - width() - pre_label_width - GetBubbleOuterPadding(false), - height()); + // Now compute the image bounds. In non-MD, the leading padding depends on + // whether this is an extension icon, since extension icons and + // Chrome-provided icons are different sizes. In MD, these sizes are the + // same, so it's not necessary to handle the two types differently. + const bool icon_has_enough_padding = + !is_extension_icon_ || ui::MaterialDesignController::IsModeMaterial(); + int image_x = GetBubbleOuterPadding(icon_has_enough_padding); + const int image_preferred_width = image_->GetPreferredSize().width(); + int bubble_trailing_padding = GetBubbleOuterPadding(false); + + // If ShouldShowBackground() is true, then either we show a background in the + // steady state, or we're not yet in the last portion of the animation. In + // these cases, we leave the leading and trailing padding alone; we don't want + // to let the image overlap the edge of the background, as this looks glitchy. + // If this is false, however, then we're only showing the image, and either + // the view width is the image width, or it's animating downwards and getting + // close to it. In these cases, we want to shrink the trailing padding first, + // so the image slides all the way to the trailing edge before slowing or + // stopping; then we want to shrink the leading padding down to zero. + if (!ShouldShowBackground()) { + image_x = std::min(image_x, width() - image_preferred_width); + bubble_trailing_padding = std::min( + bubble_trailing_padding, width() - image_preferred_width - image_x); + } + + // Now that we've computed the padding values, give the image all the + // remaining width. This will be less than the image's preferred width during + // the first portion of the animation; during the very beginning there may not + // be enough room to show the image at all. + const int image_width = + std::min(image_preferred_width, + std::max(0, width() - image_x - bubble_trailing_padding)); + image_->SetBounds(image_x, 0, image_width, height()); } void IconLabelBubbleView::OnNativeThemeChanged( @@ -177,20 +214,41 @@ : parent_background_color_; } -gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int width) const { +gfx::Size IconLabelBubbleView::GetSizeForLabelWidth(int label_width) const { gfx::Size size(image_->GetPreferredSize()); - if (ShouldShowBackground()) { - const int non_label_width = GetBubbleOuterPadding(true) + - GetImageAndPaddingWidth() + - GetBubbleOuterPadding(false); - size = gfx::Size(WidthMultiplier() * (width + non_label_width), 0); - if (!ui::MaterialDesignController::IsModeMaterial()) - size.SetToMax(background_painter_->GetMinimumSize()); + bool shrinking = IsShrinking(); + // Animation continues for the last few pixels even after the label is not + // visible in order to slide the icon into its final position. Therefore it + // is necessary to animate |total_width| even when the background is hidden + // as long as the animation is still shrinking. + if (ShouldShowBackground() || shrinking) { + const int image_width = size.width(); + const int padding = GetLayoutConstant(ICON_LABEL_VIEW_INTERNAL_PADDING) + + GetBubbleOuterPadding(true) + + GetBubbleOuterPadding(false); + // |multiplier| grows from zero to one, stays equal to one and then shrinks + // to zero again. The view width should correspondingly grow from zero to + // fully showing both label and icon, stay there, then shrink to just large + // enough to show the icon. We don't want to shrink all the way back to + // zero, since this would mean the view would completely disappear and then + // pop back to an icon after the animation finishes. + int total_width = WidthMultiplier() * (label_width + image_width + padding); + if (shrinking) + total_width = std::max(total_width, image_width); + size.set_width(total_width); } - return size; } +int IconLabelBubbleView::GetBubbleOuterPadding(bool leading) const { + if (ui::MaterialDesignController::IsModeMaterial()) + return GetBubbleOuterPaddingMd(leading); + + return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - + GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + + (leading ? 0 : GetLayoutConstant(ICON_LABEL_VIEW_TRAILING_PADDING)); +} + void IconLabelBubbleView::SetLabelBackgroundColor( SkColor chip_background_color) { // The background images are painted atop |parent_background_color_|. @@ -205,15 +263,6 @@ SkColorGetA(chip_background_color))); } -int IconLabelBubbleView::GetBubbleOuterPadding(bool leading) const { - if (ui::MaterialDesignController::IsModeMaterial()) - return GetBubbleOuterPaddingMd(leading); - - return GetLayoutConstant(LOCATION_BAR_HORIZONTAL_PADDING) - - GetLayoutConstant(LOCATION_BAR_BUBBLE_HORIZONTAL_PADDING) + - (leading ? 0 : GetLayoutConstant(ICON_LABEL_VIEW_TRAILING_PADDING)); -} - int IconLabelBubbleView::GetBubbleOuterPaddingMd(bool leading) const { // When the image is empty, leading and trailing padding are equal. if (image_->GetPreferredSize().IsEmpty() || !leading)
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h index f1a58d69..9cefe0fe 100644 --- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -54,6 +54,7 @@ protected: views::ImageView* image() { return image_; } views::Label* label() { return label_; } + const views::Label* label() const { return label_; } // Gets the color for displaying text. virtual SkColor GetTextColor() const = 0; @@ -70,6 +71,9 @@ // full-width view and can be used to animate the width of the view. virtual double WidthMultiplier() const; + // Returns true when animation is in progress and is shrinking. + virtual bool IsShrinking() const; + // Returns the amount of horizontal space needed to draw the image and its // padding before the label. virtual int GetImageAndPaddingWidth() const; @@ -87,18 +91,18 @@ SkColor GetParentBackgroundColor() const; - gfx::Size GetSizeForLabelWidth(int width) const; + gfx::Size GetSizeForLabelWidth(int label_width) const; + + // Amount of padding from the edge of the icon / label to the outer edge of + // the bubble view. If |leading| is true, this is the padding at the + // beginning of the bubble (left in LTR), otherwise it's the trailing padding. + int GetBubbleOuterPadding(bool leading) const; private: // Sets a background color on |label_| based on |chip_background_color| and // the parent's bg color. void SetLabelBackgroundColor(SkColor chip_background_color); - // Amount of padding at the edges of the bubble. If |leading| is true, this - // is the padding at the beginning of the bubble (left in LTR), otherwise it's - // the end padding. - int GetBubbleOuterPadding(bool leading) const; - // As above, but for Material Design. TODO(estade): remove/replace the above. int GetBubbleOuterPaddingMd(bool leading) const;
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc new file mode 100644 index 0000000..36e1a4a --- /dev/null +++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc
@@ -0,0 +1,217 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/views/location_bar/icon_label_bubble_view.h" + +#include "base/strings/utf_string_conversions.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/views/controls/image_view.h" +#include "ui/views/test/views_test_base.h" + +namespace { + +const int kStayOpenTimeMS = 100; +const int kOpenTimeMS = 100; +const int kAnimationDurationMS = (kOpenTimeMS * 2) + kStayOpenTimeMS; +const int kImageSize = 15; +const SkColor kTestColor = SkColorSetRGB(64, 64, 64); +const int kNumberOfSteps = 300; + +class TestIconLabelBubbleView : public IconLabelBubbleView { + public: + enum State { + GROWING, + STEADY, + SHRINKING, + }; + + TestIconLabelBubbleView(const gfx::FontList& font_list, SkColor color) + : IconLabelBubbleView(0, font_list, color, false), value_(0) { + GetImageView()->SetImageSize(gfx::Size(kImageSize, kImageSize)); + SetLabel(base::ASCIIToUTF16("Label")); + } + + void SetCurrentAnimationValue(int value) { + value_ = value; + SizeToPreferredSize(); + } + + int width() { return bounds().width(); } + bool IsLabelVisible() const { return label()->visible(); } + void SetLabelVisible(bool visible) { label()->SetVisible(visible); } + const gfx::Rect& GetLabelBounds() const { return label()->bounds(); } + + State state() const { + const double kOpenFraction = + static_cast<double>(kOpenTimeMS) / kAnimationDurationMS; + double state = value_ / (double)kNumberOfSteps; + if (state < kOpenFraction) + return GROWING; + if (state > (1.0 - kOpenFraction)) + return SHRINKING; + return STEADY; + } + + protected: + // IconLabelBubbleView: + SkColor GetTextColor() const override { return kTestColor; } + SkColor GetBorderColor() const override { return kTestColor; } + + bool ShouldShowBackground() const override { + return !IsShrinking() || label()->width() > 0; + } + + double WidthMultiplier() const override { + const double kOpenFraction = + static_cast<double>(kOpenTimeMS) / kAnimationDurationMS; + double fraction = value_ / (double)kNumberOfSteps; + switch (state()) { + case GROWING: + return fraction / kOpenFraction; + case STEADY: + return 1.0; + case SHRINKING: + return (1.0 - fraction) / kOpenFraction; + } + NOTREACHED(); + return 1.0; + } + + bool IsShrinking() const override { return state() == SHRINKING; } + + private: + int value_; + DISALLOW_COPY_AND_ASSIGN(TestIconLabelBubbleView); +}; + +} // namespace + +class IconLabelBubbleViewTest : public views::ViewsTestBase { + public: + IconLabelBubbleViewTest() + : views::ViewsTestBase(), + steady_reached_(false), + shrinking_reached_(false), + minimum_size_reached_(false), + previous_width_(0), + initial_image_x_(0) {} + ~IconLabelBubbleViewTest() override {} + + protected: + // views::ViewsTestBase: + void SetUp() override { + views::ViewsTestBase::SetUp(); + gfx::FontList font_list; + view_.reset(new TestIconLabelBubbleView(font_list, kTestColor)); + } + + void VerifyWithAnimationStep(int step) { + Reset(); + for (int value = 0; value < kNumberOfSteps; value += step) { + SetValue(value); + VerifyAnimationStep(); + } + view_->SetLabelVisible(false); + } + + private: + void Reset() { + view_->SetLabelVisible(true); + SetValue(0); + steady_reached_ = false; + shrinking_reached_ = false; + minimum_size_reached_ = false; + previous_width_ = 0; + initial_image_x_ = GetImageBounds().x(); + EXPECT_NE(0, initial_image_x_); + } + + void VerifyAnimationStep() { + switch (state()) { + case TestIconLabelBubbleView::State::GROWING: { + EXPECT_GE(width(), previous_width_); + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_GE(GetImageBounds().x(), 0); + if (GetImageBounds().width() > 0) + EXPECT_LE(GetImageBounds().right(), width()); + EXPECT_TRUE(IsLabelVisible()); + if (GetLabelBounds().width() > 0) { + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + } + break; + } + case TestIconLabelBubbleView::State::STEADY: { + if (steady_reached_) + EXPECT_EQ(previous_width_, width()); + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_GT(GetImageBounds().x(), 0); + EXPECT_LT(GetImageBounds().right(), width()); + EXPECT_TRUE(IsLabelVisible()); + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + steady_reached_ = true; + break; + } + case TestIconLabelBubbleView::State::SHRINKING: { + if (shrinking_reached_) + EXPECT_LE(width(), previous_width_); + if (minimum_size_reached_) + EXPECT_EQ(previous_width_, width()); + + EXPECT_GE(GetImageBounds().x(), 0); + if (width() <= initial_image_x_ + kImageSize) { + EXPECT_EQ(width(), GetImageBounds().right()); + EXPECT_EQ(0, GetLabelBounds().width()); + } else { + EXPECT_EQ(initial_image_x_, GetImageBounds().x()); + EXPECT_LE(GetImageBounds().right(), width()); + } + if (GetLabelBounds().width() > 0) { + EXPECT_GT(GetLabelBounds().x(), GetImageBounds().right()); + EXPECT_LT(GetLabelBounds().right(), width()); + } + shrinking_reached_ = true; + if (width() == kImageSize) + minimum_size_reached_ = true; + break; + } + } + previous_width_ = width(); + } + + void SetValue(int value) { view_->SetCurrentAnimationValue(value); } + + TestIconLabelBubbleView::State state() const { return view_->state(); } + + int width() { return view_->width(); } + + bool IsLabelVisible() { return view_->IsLabelVisible(); } + + const gfx::Rect& GetLabelBounds() const { return view_->GetLabelBounds(); } + + const gfx::Rect& GetImageBounds() const { + return view_->GetImageView()->bounds(); + } + + scoped_ptr<TestIconLabelBubbleView> view_; + + bool steady_reached_; + bool shrinking_reached_; + bool minimum_size_reached_; + int previous_width_; + int initial_image_x_; +}; + +// Tests layout rules for IconLabelBubbleView while simulating animation. +// The animation is first growing the bubble from zero, then keeping its size +// constant and finally shrinking it down to its minimum size which is the image +// size. +// Various step sizes during animation simulate different possible timing. +TEST_F(IconLabelBubbleViewTest, AnimateLayout) { + VerifyWithAnimationStep(1); + VerifyWithAnimationStep(5); + VerifyWithAnimationStep(10); + VerifyWithAnimationStep(25); +}
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils.h b/chrome/browser/ui/webui/options/advanced_options_utils.h deleted file mode 100644 index 654df0b..0000000 --- a/chrome/browser/ui/webui/options/advanced_options_utils.h +++ /dev/null
@@ -1,31 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_UI_WEBUI_OPTIONS_ADVANCED_OPTIONS_UTILS_H_ -#define CHROME_BROWSER_UI_WEBUI_OPTIONS_ADVANCED_OPTIONS_UTILS_H_ - -#include "base/macros.h" - -namespace content { -class WebContents; -} - -namespace options { - -// Chrome advanced options utility methods. -class AdvancedOptionsUtilities { - public: - // Invoke UI for network proxy settings. - static void ShowNetworkProxySettings(content::WebContents*); - - // Invoke UI for SSL certificates. - static void ShowManageSSLCertificates(content::WebContents*); - - private: - DISALLOW_IMPLICIT_CONSTRUCTORS(AdvancedOptionsUtilities); -}; - -} // namespace options - -#endif // CHROME_BROWSER_UI_WEBUI_OPTIONS_ADVANCED_OPTIONS_UTILS_H_
diff --git a/chrome/browser/ui/webui/options/browser_options_handler.cc b/chrome/browser/ui/webui/options/browser_options_handler.cc index 1a3e725..6bd2743d 100644 --- a/chrome/browser/ui/webui/options/browser_options_handler.cc +++ b/chrome/browser/ui/webui/options/browser_options_handler.cc
@@ -105,7 +105,7 @@ #include "ui/base/webui/web_ui_util.h" #if !defined(OS_CHROMEOS) -#include "chrome/browser/ui/webui/options/advanced_options_utils.h" +#include "chrome/browser/ui/webui/settings_utils.h" #endif #if defined(OS_CHROMEOS) @@ -1063,7 +1063,8 @@ if (!arc::ArcBridgeService::GetEnabled( base::CommandLine::ForCurrentProcess()) || - arc::ArcAuthService::IsOptInVerificationDisabled()) { + arc::ArcAuthService::IsOptInVerificationDisabled() || + profile->IsLegacySupervised()) { web_ui()->CallJavascriptFunction("BrowserOptions.hideAndroidAppsSection"); } #endif @@ -1628,8 +1629,7 @@ void BrowserOptionsHandler::ShowNetworkProxySettings( const base::ListValue* args) { content::RecordAction(UserMetricsAction("Options_ShowProxySettings")); - AdvancedOptionsUtilities::ShowNetworkProxySettings( - web_ui()->GetWebContents()); + settings_utils::ShowNetworkProxySettings(web_ui()->GetWebContents()); } #endif @@ -1637,8 +1637,7 @@ void BrowserOptionsHandler::ShowManageSSLCertificates( const base::ListValue* args) { content::RecordAction(UserMetricsAction("Options_ManageSSLCertificates")); - AdvancedOptionsUtilities::ShowManageSSLCertificates( - web_ui()->GetWebContents()); + settings_utils::ShowManageSSLCertificates(web_ui()->GetWebContents()); } #endif
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc index 797b51a..089b8ee 100644 --- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc +++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -69,36 +69,46 @@ arraysize(localized_strings)); } -#if defined(OS_CHROMEOS) void AddA11yStrings(content::WebUIDataSource* html_source) { LocalizedString localized_strings[] = { - {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, - {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, - {"optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL}, - {"largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL}, - {"highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL}, - {"stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL}, - {"chromeVoxLabel", IDS_SETTINGS_CHROMEVOX_LABEL}, - {"screenMagnifierLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL}, - {"tapDraggingLabel", IDS_SETTINGS_TAP_DRAGGING_LABEL}, - {"clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL}, - {"delayBeforeClickLabel", IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL}, - {"delayBeforeClickExtremelyShort", - IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT}, - {"delayBeforeClickVeryShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT}, - {"delayBeforeClickShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT}, - {"delayBeforeClickLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG}, - {"delayBeforeClickVeryLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG}, - {"onScreenKeyboardLabel", IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL}, - {"a11yExplanation", IDS_SETTINGS_ACCESSIBILITY_EXPLANATION}, + {"a11yPageTitle", IDS_SETTINGS_ACCESSIBILITY}, +#if defined(OS_CHROMEOS) + {"moreFeaturesLink", IDS_SETTINGS_MORE_FEATURES_LINK}, + {"optionsInMenuLabel", IDS_SETTINGS_OPTIONS_IN_MENU_LABEL}, + {"largeMouseCursorLabel", IDS_SETTINGS_LARGE_MOUSE_CURSOR_LABEL}, + {"highContrastLabel", IDS_SETTINGS_HIGH_CONTRAST_LABEL}, + {"stickyKeysLabel", IDS_SETTINGS_STICKY_KEYS_LABEL}, + {"chromeVoxLabel", IDS_SETTINGS_CHROMEVOX_LABEL}, + {"screenMagnifierLabel", IDS_SETTINGS_SCREEN_MAGNIFIER_LABEL}, + {"tapDraggingLabel", IDS_SETTINGS_TAP_DRAGGING_LABEL}, + {"clickOnStopLabel", IDS_SETTINGS_CLICK_ON_STOP_LABEL}, + {"delayBeforeClickLabel", IDS_SETTINGS_DELAY_BEFORE_CLICK_LABEL}, + {"delayBeforeClickExtremelyShort", + IDS_SETTINGS_DELAY_BEFORE_CLICK_EXTREMELY_SHORT}, + {"delayBeforeClickVeryShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_SHORT}, + {"delayBeforeClickShort", IDS_SETTINGS_DELAY_BEFORE_CLICK_SHORT}, + {"delayBeforeClickLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_LONG}, + {"delayBeforeClickVeryLong", IDS_SETTINGS_DELAY_BEFORE_CLICK_VERY_LONG}, + {"onScreenKeyboardLabel", IDS_SETTINGS_ON_SCREEN_KEYBOARD_LABEL}, + {"a11yExplanation", IDS_SETTINGS_ACCESSIBILITY_EXPLANATION}, +#endif }; AddLocalizedStringsBulk(html_source, localized_strings, arraysize(localized_strings)); +#if defined(OS_CHROMEOS) html_source->AddString("a11yLearnMoreUrl", chrome::kChromeAccessibilityHelpURL); -} #endif +} + +void AddAboutStrings(content::WebUIDataSource* html_source) { + LocalizedString localized_strings[] = { + {"aboutProgram", IDS_SETTINGS_ABOUT_PROGRAM}, + }; + AddLocalizedStringsBulk(html_source, localized_strings, + arraysize(localized_strings)); +} #if defined(OS_CHROMEOS) void AddAccountUITweaksStrings(content::WebUIDataSource* html_source, @@ -247,6 +257,14 @@ arraysize(localized_strings)); } +void AddCloudPrintStrings(content::WebUIDataSource* html_source) { + LocalizedString localized_strings[] = { + {"googleCloudPrint", IDS_SETTINGS_GOOGLE_CLOUD_PRINT}, + }; + AddLocalizedStringsBulk(html_source, localized_strings, + arraysize(localized_strings)); +} + #if !defined(OS_CHROMEOS) void AddDefaultBrowserStrings(content::WebUIDataSource* html_source) { LocalizedString localized_strings[] = { @@ -784,8 +802,9 @@ Profile* profile) { AddCommonStrings(html_source); -#if defined(OS_CHROMEOS) AddA11yStrings(html_source); + AddAboutStrings(html_source); +#if defined(OS_CHROMEOS) AddAccountUITweaksStrings(html_source, profile); #endif AddAppearanceStrings(html_source); @@ -794,6 +813,7 @@ #endif AddCertificateManagerStrings(html_source); AddClearBrowsingDataStrings(html_source); + AddCloudPrintStrings(html_source); #if !defined(OS_CHROMEOS) AddDefaultBrowserStrings(html_source); #endif
diff --git a/chrome/browser/ui/webui/settings/system_handler.cc b/chrome/browser/ui/webui/settings/system_handler.cc index c7d9269..49835c5d 100644 --- a/chrome/browser/ui/webui/settings/system_handler.cc +++ b/chrome/browser/ui/webui/settings/system_handler.cc
@@ -10,6 +10,10 @@ #include "base/metrics/user_metrics_action.h" #include "content/public/browser/web_ui.h" +#if !defined(OS_CHROMEOS) +#include "chrome/browser/ui/webui/settings_utils.h" +#endif + namespace settings { SystemHandler::SystemHandler() {} @@ -24,8 +28,11 @@ void SystemHandler::HandleChangeProxySettings(const base::ListValue* /*args*/) { base::RecordAction(base::UserMetricsAction("Options_ShowProxySettings")); - // TODO(dbeam): port AdvancedOptionsUtilities::ShowNetworkProxySettings from - // advanced_options_utils.h to new, settings accessible place. +#if defined(OS_CHROMEOS) + NOTREACHED(); +#else + settings_utils::ShowNetworkProxySettings(web_ui()->GetWebContents()); +#endif } } // namespace settings
diff --git a/chrome/browser/ui/webui/settings_utils.h b/chrome/browser/ui/webui/settings_utils.h new file mode 100644 index 0000000..9f95aa4 --- /dev/null +++ b/chrome/browser/ui/webui/settings_utils.h
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_WEBUI_SETTINGS_UTILS_H_ +#define CHROME_BROWSER_UI_WEBUI_SETTINGS_UTILS_H_ + +#include "base/macros.h" + +namespace content { +class WebContents; +} + +namespace settings_utils { + +// Invoke UI for network proxy settings. +void ShowNetworkProxySettings(content::WebContents* web_contents); + +// Invoke UI for SSL certificates. +void ShowManageSSLCertificates(content::WebContents* web_contents); + +} // namespace settings_utils + +#endif // CHROME_BROWSER_UI_WEBUI_SETTINGS_UTILS_H_
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils_linux.cc b/chrome/browser/ui/webui/settings_utils_linux.cc similarity index 94% rename from chrome/browser/ui/webui/options/advanced_options_utils_linux.cc rename to chrome/browser/ui/webui/settings_utils_linux.cc index cd54152..5293048 100644 --- a/chrome/browser/ui/webui/options/advanced_options_utils_linux.cc +++ b/chrome/browser/ui/webui/settings_utils_linux.cc
@@ -1,10 +1,10 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. +// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #if !defined(OS_CHROMEOS) -#include "chrome/browser/ui/webui/options/advanced_options_utils.h" +#include "chrome/browser/ui/webui/settings_utils.h" #include <stddef.h> @@ -26,9 +26,8 @@ using content::BrowserThread; using content::OpenURLParams; using content::Referrer; -using content::WebContents; -namespace options { +namespace settings_utils { // Command used to configure GNOME 2 proxy settings. const char* kGNOME2ProxyConfigCommand[] = {"gnome-network-properties", NULL}; @@ -59,7 +58,7 @@ GURL(kLinuxProxyConfigUrl), Referrer(), NEW_FOREGROUND_TAB, ui::PAGE_TRANSITION_LINK, false); - WebContents* web_contents = + content::WebContents* web_contents = tab_util::GetWebContentsByID(render_process_id, render_view_id); if (web_contents) web_contents->OpenURL(params); @@ -157,14 +156,13 @@ } // anonymous namespace -void AdvancedOptionsUtilities::ShowNetworkProxySettings( - WebContents* web_contents) { +void ShowNetworkProxySettings(content::WebContents* web_contents) { BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&DetectAndStartProxyConfigUtil, web_contents->GetRenderProcessHost()->GetID(), web_contents->GetRenderViewHost()->GetRoutingID())); } -} // namespace options +} // namespace settings_utils #endif // !defined(OS_CHROMEOS)
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils_mac.mm b/chrome/browser/ui/webui/settings_utils_mac.mm similarity index 75% rename from chrome/browser/ui/webui/options/advanced_options_utils_mac.mm rename to chrome/browser/ui/webui/settings_utils_mac.mm index c294b86..1f68f49 100644 --- a/chrome/browser/ui/webui/options/advanced_options_utils_mac.mm +++ b/chrome/browser/ui/webui/settings_utils_mac.mm
@@ -1,21 +1,18 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #import <Cocoa/Cocoa.h> -#include "chrome/browser/ui/webui/options/advanced_options_utils.h" +#include "chrome/browser/ui/webui/settings_utils.h" #include "base/logging.h" #include "base/mac/mac_logging.h" #include "base/mac/scoped_aedesc.h" -using content::WebContents; +namespace settings_utils { -namespace options { - -void AdvancedOptionsUtilities::ShowNetworkProxySettings( - WebContents* web_contents) { +void ShowNetworkProxySettings(content::WebContents* web_contents) { NSArray* itemsToOpen = [NSArray arrayWithObject:[NSURL fileURLWithPath: @"/System/Library/PreferencePanes/Network.prefPane"]]; @@ -35,8 +32,7 @@ LSOpenFromURLSpec(&launchSpec, NULL); } -void AdvancedOptionsUtilities::ShowManageSSLCertificates( - WebContents* web_contents) { +void ShowManageSSLCertificates(content::WebContents* web_contents) { NSString* const kKeychainBundleId = @"com.apple.keychainaccess"; [[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:kKeychainBundleId @@ -45,4 +41,4 @@ launchIdentifier:nil]; } -} // namespace options +} // namespace settings_utils
diff --git a/chrome/browser/ui/webui/options/advanced_options_utils_win.cc b/chrome/browser/ui/webui/settings_utils_win.cc similarity index 91% rename from chrome/browser/ui/webui/options/advanced_options_utils_win.cc rename to chrome/browser/ui/webui/settings_utils_win.cc index 7c5c16c..69bc3c8 100644 --- a/chrome/browser/ui/webui/options/advanced_options_utils_win.cc +++ b/chrome/browser/ui/webui/settings_utils_win.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/webui/options/advanced_options_utils.h" +#include "chrome/browser/ui/webui/settings_utils.h" #include <windows.h> #include <cryptuiapi.h> @@ -23,9 +23,8 @@ #include "ui/views/win/hwnd_util.h" using content::BrowserThread; -using content::WebContents; -namespace options { +namespace settings_utils { namespace { @@ -96,16 +95,14 @@ SW_SHOWNORMAL); } -void AdvancedOptionsUtilities::ShowNetworkProxySettings( - WebContents* web_contents) { +void ShowNetworkProxySettings(content::WebContents* web_contents) { DCHECK(BrowserThread::IsMessageLoopValid(BrowserThread::FILE)); BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, base::Bind(&OpenConnectionDialogCallback)); } -void AdvancedOptionsUtilities::ShowManageSSLCertificates( - WebContents* web_contents) { +void ShowManageSSLCertificates(content::WebContents* web_contents) { HWND parent = views::HWNDForNativeWindow(web_contents->GetTopLevelNativeWindow()); @@ -115,4 +112,4 @@ base::Bind(&base::DeletePointer<ManageCertificatesDialog>, dialog)); } -} // namespace options +} // namespace settings_utils
diff --git a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc index bb820402..f52c3c60 100644 --- a/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc +++ b/chrome/browser/ui/window_sizer/window_sizer_ash_uitest.cc
@@ -11,7 +11,8 @@ #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "build/build_config.h" -#include "chrome/browser/lifetime/application_lifetime.h" +#include "chrome/browser/lifetime/keep_alive_types.h" +#include "chrome/browser/lifetime/scoped_keep_alive.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" @@ -85,7 +86,8 @@ IN_PROC_BROWSER_TEST_F(WindowSizerTest, MAYBE_OpenBrowserUsingShelfOnOtherDisplay) { // Don't shutdown when closing the last browser window. - chrome::IncrementKeepAliveCount(); + ScopedKeepAlive test_keep_alive(KeepAliveOrigin::BROWSER_PROCESS_CHROMEOS, + KeepAliveRestartOption::DISABLED); aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows(); @@ -116,9 +118,6 @@ EXPECT_EQ(root_windows[0], browser_list->get(0)->window()->GetNativeWindow()->GetRootWindow()); EXPECT_EQ(root_windows[0], ash::Shell::GetTargetRootWindow()); - - // Balanced with the chrome::IncrementKeepAliveCount above. - chrome::DecrementKeepAliveCount(); } namespace { @@ -171,7 +170,8 @@ IN_PROC_BROWSER_TEST_F(WindowSizerContextMenuTest, MAYBE_OpenBrowserUsingContextMenuOnOtherDisplay) { // Don't shutdown when closing the last browser window. - chrome::IncrementKeepAliveCount(); + ScopedKeepAlive test_keep_alive(KeepAliveOrigin::BROWSER_PROCESS_CHROMEOS, + KeepAliveRestartOption::DISABLED); views::MenuController::TurnOffMenuSelectionHoldForTest(); @@ -198,7 +198,4 @@ EXPECT_EQ(root_windows[0], browser_list->get(1)->window()->GetNativeWindow()->GetRootWindow()); EXPECT_EQ(root_windows[0], ash::Shell::GetTargetRootWindow()); - - // Balanced with the chrome::IncrementKeepAliveCount above. - chrome::DecrementKeepAliveCount(); }
diff --git a/chrome/chrome_browser_extensions.gypi b/chrome/chrome_browser_extensions.gypi index dfb1d74..3c22e8b 100644 --- a/chrome/chrome_browser_extensions.gypi +++ b/chrome/chrome_browser_extensions.gypi
@@ -435,8 +435,6 @@ 'browser/extensions/api/preferences_private/preferences_private_api.h', 'browser/extensions/api/principals_private/principals_private_api.cc', 'browser/extensions/api/principals_private/principals_private_api.h', - 'browser/extensions/api/processes/processes_api.cc', - 'browser/extensions/api/processes/processes_api.h', 'browser/extensions/api/proxy/proxy_api.cc', 'browser/extensions/api/proxy/proxy_api.h', 'browser/extensions/api/proxy/proxy_api_constants.cc', @@ -895,6 +893,10 @@ 'browser/web_applications/web_app_win.cc', 'browser/web_applications/web_app_win.h', ], + 'chrome_browser_extensions_task_manager_enabled_sources': [ + 'browser/extensions/api/processes/processes_api.cc', + 'browser/extensions/api/processes/processes_api.h', + ], 'chrome_browser_extensions_app_list_sources': [ 'browser/apps/drive/drive_app_converter.cc', 'browser/apps/drive/drive_app_converter.h', @@ -1017,6 +1019,11 @@ '<@(chrome_browser_extensions_enabled_sources)', ], 'conditions': [ + ['enable_task_manager==1', { + 'sources': [ + '<@(chrome_browser_extensions_task_manager_enabled_sources)', + ], + }], ['chromeos==1', { 'dependencies': [ '../build/linux/system.gyp:dbus',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index d6107d3..8cc8155 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi
@@ -1889,10 +1889,6 @@ 'browser/ui/webui/ntp/ntp_resource_cache.h', 'browser/ui/webui/ntp/ntp_resource_cache_factory.cc', 'browser/ui/webui/ntp/ntp_resource_cache_factory.h', - 'browser/ui/webui/options/advanced_options_utils.h', - 'browser/ui/webui/options/advanced_options_utils_linux.cc', - 'browser/ui/webui/options/advanced_options_utils_mac.mm', - 'browser/ui/webui/options/advanced_options_utils_win.cc', 'browser/ui/webui/options/autofill_options_handler.cc', 'browser/ui/webui/options/autofill_options_handler.h', 'browser/ui/webui/options/automatic_settings_reset_handler.cc', @@ -2039,6 +2035,10 @@ 'browser/ui/webui/settings/site_settings_handler.h', 'browser/ui/webui/settings/system_handler.cc', 'browser/ui/webui/settings/system_handler.h', + 'browser/ui/webui/settings_utils.h', + 'browser/ui/webui/settings_utils_linux.cc', + 'browser/ui/webui/settings_utils_mac.mm', + 'browser/ui/webui/settings_utils_win.cc', 'browser/ui/webui/signin/get_auth_frame.cc', 'browser/ui/webui/signin/get_auth_frame.h', 'browser/ui/webui/signin/login_ui_service.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi index b64dd6e83..44291f37 100644 --- a/chrome/chrome_common.gypi +++ b/chrome/chrome_common.gypi
@@ -62,6 +62,8 @@ 'common/multi_process_lock_linux.cc', 'common/multi_process_lock_mac.cc', 'common/multi_process_lock_win.cc', + 'common/origin_trials/origin_trial_key_manager.cc', + 'common/origin_trials/origin_trial_key_manager.h', 'common/partial_circular_buffer.cc', 'common/partial_circular_buffer.h', 'common/pref_names_util.cc',
diff --git a/chrome/chrome_public_test_apk.isolate b/chrome/chrome_public_test_apk.isolate index 74387f6d..101efbe 100644 --- a/chrome/chrome_public_test_apk.isolate +++ b/chrome/chrome_public_test_apk.isolate
@@ -19,6 +19,7 @@ '<(DEPTH)/chrome/test/data/push_messaging/', '<(DEPTH)/chrome/test/data/translate/', '<(DEPTH)/chrome/test/data/webapps/', + '<(DEPTH)/chrome/test/media_router/resources/', '<(DEPTH)/content/test/data/android/geolocation.html', '<(DEPTH)/content/test/data/android/media/', '<(DEPTH)/content/test/data/media/getusermedia.html',
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi index b63109a..1afaa0fa 100644 --- a/chrome/chrome_renderer.gypi +++ b/chrome/chrome_renderer.gypi
@@ -33,8 +33,6 @@ 'renderer/net/net_error_page_controller.h', 'renderer/net_benchmarking_extension.cc', 'renderer/net_benchmarking_extension.h', - 'renderer/origin_trials/origin_trial_key_manager.cc', - 'renderer/origin_trials/origin_trial_key_manager.h', 'renderer/page_load_histograms.cc', 'renderer/page_load_histograms.h', 'renderer/plugins/non_loadable_plugin_placeholder.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index cc4e592..17a8741 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -1371,6 +1371,7 @@ 'browser/ui/views/frame/test_with_browser_view.cc', 'browser/ui/views/frame/test_with_browser_view.h', 'browser/ui/views/frame/web_contents_close_handler_unittest.cc', + 'browser/ui/views/location_bar/icon_label_bubble_view_unittest.cc', 'browser/ui/views/omnibox/omnibox_view_views_unittest.cc', 'browser/ui/views/status_icons/status_tray_win_unittest.cc', 'browser/ui/views/sync/bubble_sync_promo_view_unittest.cc',
diff --git a/chrome/common/chrome_content_client.cc b/chrome/common/chrome_content_client.cc index f79b019..4a2456f 100644 --- a/chrome/common/chrome_content_client.cc +++ b/chrome/common/chrome_content_client.cc
@@ -642,3 +642,7 @@ return false; #endif } + +base::StringPiece ChromeContentClient::GetOriginTrialPublicKey() { + return origin_trial_key_manager_.GetPublicKey(); +}
diff --git a/chrome/common/chrome_content_client.h b/chrome/common/chrome_content_client.h index c5b7d2d..227f737d 100644 --- a/chrome/common/chrome_content_client.h +++ b/chrome/common/chrome_content_client.h
@@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "build/build_config.h" +#include "chrome/common/origin_trials/origin_trial_key_manager.h" #include "content/public/common/content_client.h" #if defined(ENABLE_PLUGINS) @@ -86,6 +87,10 @@ void AddServiceWorkerSchemes(std::set<std::string>* schemes) override; bool IsSupplementarySiteIsolationModeEnabled() override; + base::StringPiece GetOriginTrialPublicKey() override; + + private: + OriginTrialKeyManager origin_trial_key_manager_; }; #endif // CHROME_COMMON_CHROME_CONTENT_CLIENT_H_
diff --git a/chrome/common/extensions/api/processes.idl b/chrome/common/extensions/api/processes.idl index 556ba241..9e9808c 100644 --- a/chrome/common/extensions/api/processes.idl +++ b/chrome/common/extensions/api/processes.idl
@@ -18,6 +18,16 @@ gpu, other }; + + // An object that represents a Chrome task running on a process. Several tasks + // can share the same process. + dictionary TaskInfo { + // The title of the task. + DOMString title; + // Optional tab ID, if this task represents a tab running on a renderer + // process. + long? tabId; + }; // The Cache object contains information about the size and utilization of a // cache used by the browser. @@ -34,8 +44,6 @@ long id; // The ID of the process, as provided by the OS. long osProcessId; - // The title of the process as seen in the task manager. - DOMString title; // The type of process. ProcessType type; // The profile which the process is associated with. @@ -43,9 +51,8 @@ // The debugging port for Native Client processes. Zero for other process // types and for NaCl processes that do not have debugging enabled. long naclDebugPort; - // Array of Tab IDs that have a page rendered by this process. The list will - // be non-empty for renderer processes only. - long[] tabs; + // Array of TaskInfos representing the tasks running on this process. + TaskInfo[] tasks; // The most recent measurement of the process CPU usage, between 0 and 100. // Only available when receiving the object as part of a callback from // onUpdated or onUpdatedWithMemory. @@ -83,7 +90,7 @@ // or onUpdatedWithMemory. Cache? cssCache; }; - + // A callback to report the status of the termination. // |didTerminate|: True if terminating the process was successful, and false // otherwise.
diff --git a/chrome/common/extensions/api/schemas.gni b/chrome/common/extensions/api/schemas.gni index 54cc684..8fc28c2c 100644 --- a/chrome/common/extensions/api/schemas.gni +++ b/chrome/common/extensions/api/schemas.gni
@@ -14,6 +14,9 @@ # Common sources that are both bundled and compiled. sources = gypi_values.main_schema_files +if (enable_task_manager) { + sources += gypi_values.task_manager_dependent_schema_files +} if (is_chromeos) { sources += gypi_values.chromeos_schema_files } else if (is_linux || is_win) {
diff --git a/chrome/common/extensions/api/schemas.gypi b/chrome/common/extensions/api/schemas.gypi index eec30e0..39d61035 100644 --- a/chrome/common/extensions/api/schemas.gypi +++ b/chrome/common/extensions/api/schemas.gypi
@@ -66,7 +66,6 @@ 'passwords_private.idl', 'permissions.json', 'preferences_private.json', - 'processes.idl', 'resources_private.idl', 'screenlock_private.idl', 'sessions.json', @@ -145,6 +144,10 @@ 'cast_streaming_session.idl', 'cast_streaming_udp_transport.idl', ], + + 'task_manager_dependent_schema_files': [ + 'processes.idl', + ], # Input IME schema. 'input_ime_schema_file': [ @@ -168,6 +171,11 @@ # Disable schema compiler to generate model extension API code. # Only register the extension functions in extension system. 'conditions': [ + ['enable_task_manager==1', { + 'schema_files': [ + '<@(task_manager_dependent_schema_files)', + ], + }], ['chromeos==1', { 'schema_files': [ '<@(chromeos_schema_files)',
diff --git a/chrome/renderer/origin_trials/origin_trial_key_manager.cc b/chrome/common/origin_trials/origin_trial_key_manager.cc similarity index 92% rename from chrome/renderer/origin_trials/origin_trial_key_manager.cc rename to chrome/common/origin_trials/origin_trial_key_manager.cc index e074f40a..9277066 100644 --- a/chrome/renderer/origin_trials/origin_trial_key_manager.cc +++ b/chrome/common/origin_trials/origin_trial_key_manager.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/renderer/origin_trials/origin_trial_key_manager.h" +#include "chrome/common/origin_trials/origin_trial_key_manager.h" #include <stdint.h>
diff --git a/chrome/common/origin_trials/origin_trial_key_manager.h b/chrome/common/origin_trials/origin_trial_key_manager.h new file mode 100644 index 0000000..cd6b245 --- /dev/null +++ b/chrome/common/origin_trials/origin_trial_key_manager.h
@@ -0,0 +1,17 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_COMMON_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_ +#define CHROME_COMMON_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_ + +#include "base/strings/string_piece.h" + +// This class is instantiated on the main/ui thread, but its methods can be +// accessed from any thread. +class OriginTrialKeyManager { + public: + base::StringPiece GetPublicKey(); +}; + +#endif // CHROME_COMMON_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_
diff --git a/chrome/common/url_constants.cc b/chrome/common/url_constants.cc index b436d9da..d850d67 100644 --- a/chrome/common/url_constants.cc +++ b/chrome/common/url_constants.cc
@@ -380,7 +380,7 @@ #endif const char kUpgradeHelpCenterBaseURL[] = - "http://support.google.com/installer/?product=" + "https://support.google.com/installer/?product=" "{8A69D345-D564-463c-AFF1-A69D9E530F96}&error="; const char kSmartLockHelpPage[] = @@ -517,7 +517,7 @@ "https://support.google.com/chrome/?p=mobile_protected_content"; #endif -const char kChromiumProjectURL[] = "http://www.chromium.org/"; +const char kChromiumProjectURL[] = "https://www.chromium.org/"; const char kLearnMoreReportingURL[] = "https://support.google.com/chrome/?p=ui_usagestat"; @@ -760,7 +760,7 @@ // TODO(mark): Change to a Help Center URL when one is available. // https://crbug.com/555044 const char kMac10_678_DeprecationURL[] = - "http://chrome.blogspot.com/2015/11/updates-to-chrome-platform-support.html"; + "https://chrome.blogspot.com/2015/11/updates-to-chrome-platform-support.html"; #endif #if defined(OS_WIN)
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc index 93ef2c2..5fa4a895 100644 --- a/chrome/renderer/chrome_content_renderer_client.cc +++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -1422,7 +1422,3 @@ return true; #endif } - -base::StringPiece ChromeContentRendererClient::GetOriginTrialPublicKey() { - return origin_trial_key_manager_.GetPublicKey(); -}
diff --git a/chrome/renderer/chrome_content_renderer_client.h b/chrome/renderer/chrome_content_renderer_client.h index c56c2bbd..97ee060 100644 --- a/chrome/renderer/chrome_content_renderer_client.h +++ b/chrome/renderer/chrome_content_renderer_client.h
@@ -16,7 +16,6 @@ #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" -#include "chrome/renderer/origin_trials/origin_trial_key_manager.h" #include "content/public/renderer/content_renderer_client.h" #include "ipc/ipc_channel_proxy.h" #include "v8/include/v8.h" @@ -153,7 +152,6 @@ v8::Local<v8::Context> context, const GURL& url) override; bool ShouldEnforceWebRTCRoutingPreferences() override; - base::StringPiece GetOriginTrialPublicKey() override; #if defined(ENABLE_SPELLCHECK) // Sets a new |spellcheck|. Used for testing only. @@ -202,8 +200,6 @@ scoped_ptr<network_hints::PrescientNetworkingDispatcher> prescient_networking_dispatcher_; - OriginTrialKeyManager origin_trial_key_manager_; - #if defined(ENABLE_SPELLCHECK) scoped_ptr<SpellCheck> spellcheck_; #endif
diff --git a/chrome/renderer/origin_trials/origin_trial_key_manager.h b/chrome/renderer/origin_trials/origin_trial_key_manager.h deleted file mode 100644 index 18b01d8..0000000 --- a/chrome/renderer/origin_trials/origin_trial_key_manager.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright (c) 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_RENDERER_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_ -#define CHROME_RENDERER_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_ - -#include "base/strings/string_piece.h" - -class OriginTrialKeyManager { - public: - base::StringPiece GetPublicKey(); -}; - -#endif // CHROME_RENDERER_ORIGIN_TRIALS_ORIGIN_TRIAL_KEY_MANAGER_H_
diff --git a/chrome/test/android/cast_emulator/BUILD.gn b/chrome/test/android/cast_emulator/BUILD.gn index 9545047..9bba06b6 100644 --- a/chrome/test/android/cast_emulator/BUILD.gn +++ b/chrome/test/android/cast_emulator/BUILD.gn
@@ -16,6 +16,8 @@ "src/org/chromium/chrome/browser/media/remote/RemoteSessionManager.java", "src/org/chromium/chrome/browser/media/remote/TestMediaRouteProvider.java", "src/org/chromium/chrome/browser/media/remote/TestMediaRouteProviderService.java", + "src/org/chromium/chrome/browser/media/router/DummyMediaRouteProvider.java", + "src/org/chromium/chrome/browser/media/router/DummyMediaRouteProviderService.java", ] deps = [ "//base:base_java",
diff --git a/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProvider.java b/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProvider.java new file mode 100644 index 0000000..ca93df9 --- /dev/null +++ b/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProvider.java
@@ -0,0 +1,59 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.media.router; + +import android.content.Context; +import android.content.IntentFilter; +import android.support.v7.media.MediaRouteDescriptor; +import android.support.v7.media.MediaRouteProvider; +import android.support.v7.media.MediaRouteProviderDescriptor; + +import com.google.android.gms.cast.CastMediaControlIntent; + +import java.util.ArrayList; + +/** + * A dummy MRP that registers some dummy media sinks to the Android support library, so that these + * dummy sinks can be discovered and shown in the device selection dialog in media router tests. + * The Cast app id must be fixed to "CCCCCCCC" so that these sinks can be detected. + */ +final class DummyMediaRouteProvider extends MediaRouteProvider { + private static final String DUMMY_ROUTE_ID1 = "test_sink_id_1"; + private static final String DUMMY_ROUTE_ID2 = "test_sink_id_2"; + private static final String DUMMY_ROUTE_NAME1 = "test-sink-1"; + private static final String DUMMY_ROUTE_NAME2 = "test-sink-2"; + + public DummyMediaRouteProvider(Context context) { + super(context); + + publishRoutes(); + } + + private void publishRoutes() { + IntentFilter filter = new IntentFilter(); + filter.addCategory(CastMediaControlIntent.categoryForCast("CCCCCCCC")); + filter.addDataScheme("http"); + filter.addDataScheme("https"); + filter.addDataScheme("file"); + + ArrayList<IntentFilter> controlFilters = new ArrayList<IntentFilter>(); + controlFilters.add(filter); + + MediaRouteDescriptor testRouteDescriptor1 = new MediaRouteDescriptor.Builder( + DUMMY_ROUTE_ID1, DUMMY_ROUTE_NAME1) + .setDescription(DUMMY_ROUTE_NAME1).addControlFilters(controlFilters) + .build(); + MediaRouteDescriptor testRouteDescriptor2 = new MediaRouteDescriptor.Builder( + DUMMY_ROUTE_ID2, DUMMY_ROUTE_NAME2) + .setDescription(DUMMY_ROUTE_NAME2).addControlFilters(controlFilters) + .build(); + + MediaRouteProviderDescriptor providerDescriptor = new MediaRouteProviderDescriptor.Builder() + .addRoute(testRouteDescriptor1) + .addRoute(testRouteDescriptor2) + .build(); + setDescriptor(providerDescriptor); + } +}
diff --git a/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProviderService.java b/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProviderService.java new file mode 100644 index 0000000..59d8d5b --- /dev/null +++ b/chrome/test/android/cast_emulator/src/org/chromium/chrome/browser/media/router/DummyMediaRouteProviderService.java
@@ -0,0 +1,18 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.chrome.browser.media.router; + +import android.support.v7.media.MediaRouteProvider; +import android.support.v7.media.MediaRouteProviderService; + +/** + * Service for registering {@link DummyMediaRouteProvider} using the support library. + */ +public class DummyMediaRouteProviderService extends MediaRouteProviderService { + @Override + public MediaRouteProvider onCreateMediaRouteProvider() { + return new DummyMediaRouteProvider(this); + } +}
diff --git a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml index 0d60c71..f32414d 100644 --- a/chrome/test/android/chrome_public_test_support/AndroidManifest.xml +++ b/chrome/test/android/chrome_public_test_support/AndroidManifest.xml
@@ -16,5 +16,13 @@ <action android:name="android.media.MediaRouteProviderService" /> </intent-filter> </service> + <service android:name="org.chromium.chrome.browser.media.router.DummyMediaRouteProviderService" + android:label="dummyMediaRouteProviderService" + android:process=":mrp" + tools:ignore="ExportedService" > + <intent-filter> + <action android:name="android.media.MediaRouteProviderService" /> + </intent-filter> + </service> </application> </manifest>
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java index 128b8b4..1dbee5a 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/ApplicationTestUtils.java
@@ -21,6 +21,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Methods used for testing Chrome at the Application-level. */ @@ -106,13 +108,13 @@ /** Waits until Chrome is in the foreground. */ public static void waitUntilChromeInForeground() throws Exception { - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - int state = ApplicationStatus.getStateForApplication(); - return state == ApplicationState.HAS_RUNNING_ACTIVITIES; - } - }); + CriteriaHelper.pollForCriteria( + Criteria.equals(ApplicationState.HAS_RUNNING_ACTIVITIES, new Callable<Integer>() { + @Override + public Integer call() { + return ApplicationStatus.getStateForApplication(); + } + })); } /** Finishes all tasks Chrome has listed in Android's Overview. */ @@ -125,12 +127,12 @@ task.finishAndRemoveTask(); } - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getNumChromeTasks(context) == 0; + public Integer call() { + return getNumChromeTasks(context); } - }); + })); } /** Counts how many tasks Chrome has listed in Android's Overview. */
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java index 88839c7..a016b46 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/FullscreenTestUtils.java
@@ -15,6 +15,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Static methods for use in tests that require toggling persistent fullscreen. */ @@ -79,13 +81,13 @@ * @throws InterruptedException */ public static void waitForPersistentFullscreen(final TabWebContentsDelegateAndroid delegate, - final boolean state) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + boolean state) throws InterruptedException { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(state, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return state == delegate.isFullscreenForTabOrPending(); + public Boolean call() { + return delegate.isFullscreenForTabOrPending(); } - }); + })); } private static boolean isFlagSet(int flags, int flag) {
diff --git a/chrome/test/base/testing_browser_process.h b/chrome/test/base/testing_browser_process.h index 99e5dcfc..5c1f2b9 100644 --- a/chrome/test/base/testing_browser_process.h +++ b/chrome/test/base/testing_browser_process.h
@@ -141,6 +141,8 @@ void SetRapporService(rappor::RapporService* rappor_service); void ShutdownBrowserPolicyConnector(); + unsigned int module_ref_count() const { return module_ref_count_; } + private: // See CreateInstance() and DestoryInstance() above. TestingBrowserProcess();
diff --git a/chrome/test/data/android/contextmenu/context_menu_test.html b/chrome/test/data/android/contextmenu/context_menu_test.html index ab9418da..3c88f46 100644 --- a/chrome/test/data/android/contextmenu/context_menu_test.html +++ b/chrome/test/data/android/contextmenu/context_menu_test.html
@@ -31,7 +31,7 @@ width="16" height="14" alt="embedded folder icon" id="dataUrlIcon"><br /> <video id="videoDOMElement" controls> - <source src="../media/test.webm" type="video/webm"> + <source src="../media/test.mp4" type="video/mp4"> </video><br /> </body>
diff --git a/chrome/test/data/android/media/test.webm b/chrome/test/data/android/media/test.webm deleted file mode 100644 index f1a92fc..0000000 --- a/chrome/test/data/android/media/test.webm +++ /dev/null Binary files differ
diff --git a/chrome/test/data/extensions/api_test/processes/api/test.js b/chrome/test/data/extensions/api_test/processes/api/test.js index edd4f27..a4ceb52 100644 --- a/chrome/test/data/extensions/api_test/processes/api/test.js +++ b/chrome/test/data/extensions/api_test/processes/api/test.js
@@ -29,11 +29,15 @@ function dumpProcess(process) { console.log("id " + process.id); - console.log("title " + process.title); console.log("osProcId " + process.osProcessId); console.log("type " + process.type); console.log("profile " + process.profile); - console.log("tabs " + process.tabs); + console.log("tasks " + process.tasks); + for (var i = 0; i < process.tasks.length; ++i) { + console.log("task["+ i + "].title " + process.tasks[i].title); + if ("tabId" in process.tasks[i]) + console.log("task["+ i + "].tabId " + process.tasks[i].tabId); + } console.log("cpu " + process.cpu); console.log("privMem " + process.privateMemory); console.log("network " + process.network); @@ -58,12 +62,12 @@ function validateProcessProperties(process, updating, memory_included) { // Always present. assertTrue("id" in process); - assertTrue("title" in process); assertTrue("naclDebugPort" in process); assertTrue("osProcessId" in process); assertTrue("type" in process); assertTrue("profile" in process); - assertTrue("tabs" in process); + assertTrue("tasks" in process); + assertTrue("title" in process.tasks[0]); // Present if onUpdate(WithMemory) listener is registered. assertEq(("cpu" in process), updating); @@ -146,9 +150,9 @@ function (pl2) { var proc1 = pl1[pid1]; var proc2 = pl2[pid2]; - assertTrue(proc1.tabs.length == proc2.tabs.length); - for (var i = 0; i < proc1.tabs.length; ++i) { - assertEq(proc1.tabs[i], proc2.tabs[i]); + assertTrue(proc1.tasks.length == proc2.tasks.length); + for (var i = 0; i < proc1.tasks.length; ++i) { + assertEq(proc1.tasks[i], proc2.tasks[i]); } }); }); @@ -261,13 +265,15 @@ function testOnCreated() { listenOnce(chrome.processes.onCreated, function(process) { assertTrue("id" in process, "process doesn't have id property"); + // We don't report the creation of the browser process, hence process.id + // is expected to be > 0. assertTrue(process.id > 0, "id is not positive " + process.id); }); createTab(5, "chrome://newtab/"); }, // DISABLED: crbug.com/345411 - // Hangs consistently. + // Hangs consistently (On Windows). /* function testOnExited() { listenOnce(chrome.processes.onExited,
diff --git a/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/background.js b/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/background.js new file mode 100644 index 0000000..66ea6c1 --- /dev/null +++ b/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/background.js
@@ -0,0 +1,11 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Add a simple listener to onUpdatedWithMemory to ensure that the task +// manager's refresh types are updated correctly. +chrome.processes.onUpdatedWithMemory.addListener(function(processes) { + console.log("Received update with memory."); +}); + +chrome.test.sendMessage("ready"); \ No newline at end of file
diff --git a/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/manifest.json b/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/manifest.json new file mode 100644 index 0000000..1b20b3f --- /dev/null +++ b/chrome/test/data/extensions/api_test/processes/onupdated_with_memory/manifest.json
@@ -0,0 +1,10 @@ +{ + "name": "processes onupdated with memory test", + "description": "extension that listens to processes.onUpdatedWithMemory", + "version": "0.1", + "manifest_version": 2, + "background": { + "scripts": ["background.js"] + }, + "permissions": [ "tabs", "processes" ] +} \ No newline at end of file
diff --git a/chrome/test/data/extensions/sync_datatypes/key.pem b/chrome/test/data/extensions/sync_datatypes/key.pem new file mode 100644 index 0000000..5a29d65 --- /dev/null +++ b/chrome/test/data/extensions/sync_datatypes/key.pem
@@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCxF/hN3FoCig1c +YXyxHSweoZ8sbSPwipjhaSsQyeca4mXuf984W7LuMPvhMmwUaytnJXU294sT3nzj +83O7pBdbH0jWKDKajJPMlcOnSQGs8dT9ABzt8winILAJOpJw7nSgxvRZiZgbKp2I +VHydIJLCsBgvBCFPqCPAJirVeGm5D24cXjVChdcA6duoBJGWspDWiZ/LRkbM2ZuN +8NxlXC2N+C0HpHkZqOO+BbM/GApJdW85Ce70JKUK/Nu/9EZB56kTwmo3MXjXdE9Y +eK8qn2NqYFYMfzUe3uK1atRBiX8NobjrCnqu3LJrdPKxy/Mw+Y0YDaF/ZXXxSmHR +GMvTofEjAgMBAAECggEAYAypHsmphAEOOBGjyIgS+tYb98OGH5t8SZ15vxRSpREv +ychO8ElD5c5pfn2TgwuRMdNuHI7sPq2IPTY4igf4pvJz1btdntcp/mcoA94j64IK +S+I4zpHnGoYvFAJRlLCwTtc5hiqLdgiKAnwYTjxxfOh3ZWCvFH4UTc4lozw40yZ0 +k9uHIVNZkE9PAPHdUX3Oiv7kPpuaZAqoFyfyAXdfUEbGch9hgosPqFrwB8mAbJeh +DubTZkpMVlaMyIAFIgbYjvc8sXrvfHDu60qXNktFEDVQ7igSHHpwdHWtHtsIJ5vb +AOY+TWR/ScDBgqvCXXlKiExRI2W0NSHD/ftgStWQ4QKBgQDmrXOnlWgfpkCGuCQH +7R9iyBfogU9dQmjaVHhrxssHfPz2coZwDrHdESFxqYK9sHzLNfdz8bLyNdOZtNtf +jS6GDVcsAM9miEi9nkYuu1pb7z8OXNXXV4LYIm2NXUFYzFIGCXK1n2JvlxziO1Mo +9QhaWj0WmFkxfFjnDdaLk8VYcQKBgQDEiLEhgE0I+npSOFExEtN5IC/ohr6TwGB9 +zKcx7dS8Morpir2D0XdWghA8o2+wKML1XRBRVHbZzIFIGZi6Nfc45GIR6Cuo3Cuu +kCXDwtUkNPTzKmoxxuUGxa1UOeveTRgM9csGo3fzk0lpy4by+ZdjM03e/VNE2M7u +E/aa3YDM0wKBgQCMxk+tdv1rSy9Xx+qdN7WOuCP3DWscs9l/XEt9In1m3X0W/X9T +xXQAQGMTlWonTxxpe06/YEJflD/FLt0t69/3iQ6o2Pm5TfRuW7fi7w1Oy6vEnR0X +ZN2B/0iyG7Y0dcSc0IlDk7gj96l12tR+S0NEuItNTb4o+ATdRNGoro6h0QKBgFw1 +NcXeCEaaHiHNQmqfxpAhxdh2v5tauurKxfbq+tCBdiM0cM4TzMXNqAiLNa+UsEOm +Mi22TzzIci99suZKw37xyAFWyIUlJ2lzQASkuJOQNQyRbdmE05dlz3ig5EUcLpiG +CYdH0tN42wzD7MC60Yg9Xd+tQxAeGJgizaTDH9b5AoGBAMa5tbS4klwTQgHrDnu5 +vxqmTqE4Z5JT0Cj+aJvFAUtYtzrkH3DYvnBFDZvYXWuojqY3mA1+6wwhsyh3EfFO +CyOUfcpqJTLblQdY8gO3rtK2fH2/TTOCu+1A1yW2XQLO1K4NORczIHF7CAYYPzxO +S6UN7LQb/YUvm0czl0WbFDCf +-----END PRIVATE KEY-----
diff --git a/chrome/test/data/extensions/sync_datatypes/v1.crx b/chrome/test/data/extensions/sync_datatypes/v1.crx new file mode 100644 index 0000000..2412eb87 --- /dev/null +++ b/chrome/test/data/extensions/sync_datatypes/v1.crx Binary files differ
diff --git a/chrome/test/data/extensions/sync_datatypes/v2.crx b/chrome/test/data/extensions/sync_datatypes/v2.crx new file mode 100644 index 0000000..97375e7 --- /dev/null +++ b/chrome/test/data/extensions/sync_datatypes/v2.crx Binary files differ
diff --git a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js index 9266215..5cc6d8f 100644 --- a/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js +++ b/chrome/test/data/webui/settings/settings_passwords_section_browsertest.js
@@ -118,6 +118,19 @@ return passwordsSection; }, + + /** + * Helper method used to test for a url in a list of passwords. + * @param {!Array<!chrome.passwordsPrivate.PasswordUiEntry>} passwordList + * @param {!String} url The URL that is being searched for. + */ + listContainsUrl(passwordList, url) { + for (var i = 0; i < passwordList.length; ++i) { + if (passwordList[i].loginPair.originUrl == url) + return true; + } + return false; + }, }; /** @@ -128,23 +141,100 @@ suite('PasswordsSection', function() { test('verifySavedPasswordLength', function() { - assertEquals(self.browsePreload, document.location.href) + assertEquals(self.browsePreload, document.location.href); var passwordList = [ + self.createPasswordItem_('site1.com', 'luigi', 1), + self.createPasswordItem_('longwebsite.com', 'peach', 7), + self.createPasswordItem_('site2.com', 'mario', 70), + self.createPasswordItem_('site1.com', 'peach', 11), + self.createPasswordItem_('google.com', 'mario', 7), + self.createPasswordItem_('site2.com', 'luigi', 8), + ]; + + var passwordsSection = self.createPasswordsSection_(passwordList, []); + + // Assert that the data is passed into the iron list. If this fails, + // then other expectations will also fail. + assertEquals(passwordList, passwordsSection.$.passwordList.items); + + self.validatePasswordList( + self.getIronListChildren_(passwordsSection.$.passwordList), + passwordList); + }); + + // Test verifies that removing a password will update the elements. + test('verifyPasswordListRemove', function() { + var passwordList = [ self.createPasswordItem_('anotherwebsite.com', 'luigi', 1), self.createPasswordItem_('longwebsite.com', 'peach', 7), self.createPasswordItem_('website.com', 'mario', 70) ]; - var passwordSection = self.createPasswordsSection_(passwordList, []); - - // Assert that the data is passed into the iron list. If this fails, - // then other expectations will also fail. - assertEquals(passwordList, passwordSection.$.passwordList.items); + var passwordsSection = self.createPasswordsSection_(passwordList, []); self.validatePasswordList( - self.getIronListChildren_(passwordSection.$.passwordList), + self.getIronListChildren_(passwordsSection.$.passwordList), passwordList); + // Simulate 'longwebsite.com' being removed from the list. + passwordsSection.splice('savedPasswords', 1, 1); + Polymer.dom.flush(); + + assertFalse(self.listContainsUrl(passwordsSection.savedPasswords, + 'longwebsite.com')); + assertFalse(self.listContainsUrl(passwordList, 'longwebsite.com')); + + self.validatePasswordList( + self.getIronListChildren_(passwordsSection.$.passwordList), + passwordList); + }); + + // Test verifies that pressing the 'remove' button will trigger a remove + // event. Does not actually remove any passwords. + test('verifyPasswordItemRemoveButton', function(done) { + var passwordList = [ + self.createPasswordItem_('one', 'six', 5), + self.createPasswordItem_('two', 'five', 3), + self.createPasswordItem_('three', 'four', 1), + self.createPasswordItem_('four', 'three', 2), + self.createPasswordItem_('five', 'two', 4), + self.createPasswordItem_('six', 'one', 6), + ]; + + var passwordsSection = self.createPasswordsSection_(passwordList, []); + + var passwords = + self.getIronListChildren_(passwordsSection.$.passwordList); + + // The index of the button currently being checked. + var index = 0; + + var clickRemoveButton = function() { + passwords[index].querySelector('#passwordMenu').click(); + passwordsSection.$.menuRemovePassword.click(); + }; + + // Listen for the remove event. If this event isn't received, the test + // will time out and fail. + passwordsSection.addEventListener('remove-saved-password', + function(event) { + // Verify that the event matches the expected value. + assertTrue(index < passwordList.length); + assertEquals(passwordList[index].loginPair.originUrl, + event.detail.originUrl); + assertEquals(passwordList[index].loginPair.username, + event.detail.username); + + if (++index < passwordList.length) { + // Click 'remove' on all passwords, one by one. + window.setTimeout(clickRemoveButton, 0); + } else { + done(); + } + }); + + // Start removing. + clickRemoveButton(); }); test('verifyPasswordExceptions', function() { @@ -199,7 +289,7 @@ // Test verifies that pressing the 'remove' button will trigger a remove // event. Does not actually remove any exceptions. - test('verifyPasswordRemoveButton', function(done) { + test('verifyPasswordExceptionRemoveButton', function(done) { var exceptionList = [ 'docs.google.com', 'mail.com', @@ -218,7 +308,7 @@ var index = 0; var clickRemoveButton = function() { - exceptions[index].querySelector('#removeButton').click(); + exceptions[index].querySelector('#removeExceptionButton').click(); }; // Listen for the remove event. If this event isn't received, the test
diff --git a/chrome/test/media_router/media_router_perf_tests.isolate b/chrome/test/media_router/media_router_perf_tests.isolate index 0807f41..41ee089 100644 --- a/chrome/test/media_router/media_router_perf_tests.isolate +++ b/chrome/test/media_router/media_router_perf_tests.isolate
@@ -15,7 +15,7 @@ '--output-dir=${ISOLATED_OUTDIR}', ], 'files': [ - '<(PRODUCT_DIR)/mr_extension/', + '<(PRODUCT_DIR)/mr_extension/release/', '../../../third_party/catapult/', '../../../tools/perf/', '../../../tools/variations/fieldtrial_util.py',
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js index 1ec934c4..be92b2f2 100644 --- a/chrome/test/media_router/resources/common.js +++ b/chrome/test/media_router/resources/common.js
@@ -10,9 +10,18 @@ var startSessionPromise = null; var startedConnection = null; var reconnectedSession = null; -var presentationUrl = "http://www.google.com/#__testprovider__=true"; +var presentationUrl = null; +if (window.location.href.indexOf('__is_android__=true') >= 0) { + // For android, "google.com/cast" is required in presentation URL. + // TODO(zqzhang): this requirement may be removed in the future. + presentationUrl = "http://google.com/cast#__castAppId__=CCCCCCCC/"; +} else { + presentationUrl = "http://www.google.com/#__testprovider__=true"; +} var startSessionRequest = new PresentationRequest(presentationUrl); var defaultRequestSessionId = null; +var lastExecutionResult = null; +var useDomAutomationController = !!window.domAutomationController; window.navigator.presentation.defaultRequest = startSessionRequest; window.navigator.presentation.defaultRequest.onconnectionavailable = function(e) @@ -198,8 +207,15 @@ * fails. */ function sendResult(passed, errorMessage) { - window.domAutomationController.send(JSON.stringify({ - passed: passed, - errorMessage: errorMessage - })); + if (useDomAutomationController) { + window.domAutomationController.send(JSON.stringify({ + passed: passed, + errorMessage: errorMessage + })); + } else { + lastExecutionResult = JSON.stringify({ + passed: passed, + errorMessage: errorMessage + }); + } }
diff --git a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py index 4d9985e..3ce86a51 100644 --- a/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py +++ b/chrome/test/media_router/telemetry/benchmarks/media_router_benchmark.py
@@ -24,7 +24,7 @@ # TODO: find a better way to find extension location. options.AppendExtraBrowserArgs([ '--load-extension=' + os.path.join(path_util.GetChromiumSrcDir(), 'out', - 'Release', 'mr_extension'), + 'Release', 'mr_extension', 'release'), '--whitelisted-extension-id=enhhojjnijigcajfphajepfemndkmdlo', '--media-router=1', '--enable-stats-collection-bindings'
diff --git a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_pages.py b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_pages.py index af9d16d4..70135a1 100644 --- a/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_pages.py +++ b/chrome/test/media_router/telemetry/benchmarks/pagesets/media_router_pages.py
@@ -27,6 +27,8 @@ def RunPageInteractions(self, action_runner): with action_runner.CreateInteraction('LaunchDialog'): + # Wait for 5s after Chrome is opened in order to get consistent results. + action_runner.Wait(5) action_runner.TapElement(selector='#start_session_button') action_runner.Wait(5)
diff --git a/chrome/tools/build/win/create_installer_archive.py b/chrome/tools/build/win/create_installer_archive.py index d320363d..4c16945 100755 --- a/chrome/tools/build/win/create_installer_archive.py +++ b/chrome/tools/build/win/create_installer_archive.py
@@ -502,7 +502,9 @@ 'crcrypto.dll', 'icui18n.dll', 'icuuc.dll', - 'msvc*.dll' ] + 'msvc*.dll', + 'api-ms-win-*.dll', + 'vcruntime*.dll' ] for setup_component_dll_glob in setup_component_dll_globs: setup_component_dlls = glob.glob(os.path.join(build_dir, setup_component_dll_glob))
diff --git a/chromecast/common/media/cma_param_traits.cc b/chromecast/common/media/cma_param_traits.cc index f27043db..f0ddc49 100644 --- a/chromecast/common/media/cma_param_traits.cc +++ b/chromecast/common/media/cma_param_traits.cc
@@ -12,6 +12,7 @@ #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" #include "media/base/audio_decoder_config.h" +#include "media/base/encryption_scheme.h" #include "media/base/video_decoder_config.h" #include "ui/gfx/ipc/gfx_param_traits.h" @@ -29,6 +30,16 @@ namespace IPC { +template <> +struct ParamTraits<media::EncryptionScheme::Pattern> { + typedef media::EncryptionScheme::Pattern param_type; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + + void ParamTraits<media::AudioDecoderConfig>::Write( base::Pickle* m, const media::AudioDecoderConfig& p) { @@ -36,7 +47,7 @@ WriteParam(m, p.sample_format()); WriteParam(m, p.channel_layout()); WriteParam(m, p.samples_per_second()); - WriteParam(m, p.is_encrypted()); + WriteParam(m, p.encryption_scheme()); WriteParam(m, p.extra_data()); } @@ -48,15 +59,17 @@ media::SampleFormat sample_format; media::ChannelLayout channel_layout; int samples_per_second; - bool is_encrypted; + media::EncryptionScheme encryption_scheme; std::vector<uint8_t> extra_data; if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &sample_format) || !ReadParam(m, iter, &channel_layout) || !ReadParam(m, iter, &samples_per_second) || - !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data)) + !ReadParam(m, iter, &encryption_scheme) || + !ReadParam(m, iter, &extra_data)) return false; *r = media::AudioDecoderConfig(codec, sample_format, channel_layout, - samples_per_second, extra_data, is_encrypted); + samples_per_second, extra_data, + encryption_scheme); return true; } @@ -75,7 +88,7 @@ WriteParam(m, p.coded_size()); WriteParam(m, p.visible_rect()); WriteParam(m, p.natural_size()); - WriteParam(m, p.is_encrypted()); + WriteParam(m, p.encryption_scheme()); WriteParam(m, p.extra_data()); } @@ -90,17 +103,18 @@ gfx::Size coded_size; gfx::Rect visible_rect; gfx::Size natural_size; - bool is_encrypted; + media::EncryptionScheme encryption_scheme; std::vector<uint8_t> extra_data; if (!ReadParam(m, iter, &codec) || !ReadParam(m, iter, &profile) || !ReadParam(m, iter, &format) || !ReadParam(m, iter, &color_space) || !ReadParam(m, iter, &coded_size) || !ReadParam(m, iter, &visible_rect) || !ReadParam(m, iter, &natural_size) || - !ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data)) + !ReadParam(m, iter, &encryption_scheme) || + !ReadParam(m, iter, &extra_data)) return false; *r = media::VideoDecoderConfig(codec, profile, format, color_space, coded_size, visible_rect, natural_size, - extra_data, is_encrypted); + extra_data, encryption_scheme); return true; } @@ -109,4 +123,45 @@ l->append(base::StringPrintf("<VideoDecoderConfig>")); } +void ParamTraits<media::EncryptionScheme>::Write( + base::Pickle* m, const param_type& p) { + WriteParam(m, p.mode()); + WriteParam(m, p.pattern()); +} + +bool ParamTraits<media::EncryptionScheme>::Read( + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { + media::EncryptionScheme::CipherMode mode; + media::EncryptionScheme::Pattern pattern; + if (!ReadParam(m, iter, &mode) || !ReadParam(m, iter, &pattern)) + return false; + *r = media::EncryptionScheme(mode, pattern); + return true; +} + +void ParamTraits<media::EncryptionScheme>::Log( + const param_type& p, std::string* l) { + l->append(base::StringPrintf("<EncryptionScheme>")); +} + +void ParamTraits<media::EncryptionScheme::Pattern>::Write( + base::Pickle* m, const param_type& p) { + WriteParam(m, p.encrypt_blocks()); + WriteParam(m, p.skip_blocks()); +} + +bool ParamTraits<media::EncryptionScheme::Pattern>::Read( + const base::Pickle* m, base::PickleIterator* iter, param_type* r) { + uint32_t encrypt_blocks, skip_blocks; + if (!ReadParam(m, iter, &encrypt_blocks) || !ReadParam(m, iter, &skip_blocks)) + return false; + *r = media::EncryptionScheme::Pattern(encrypt_blocks, skip_blocks); + return true; +} + +void ParamTraits<media::EncryptionScheme::Pattern>::Log( + const param_type& p, std::string* l) { + l->append(base::StringPrintf("<Pattern>")); +} + } // namespace IPC
diff --git a/chromecast/common/media/cma_param_traits.h b/chromecast/common/media/cma_param_traits.h index c8609a5a..879bbf15 100644 --- a/chromecast/common/media/cma_param_traits.h +++ b/chromecast/common/media/cma_param_traits.h
@@ -10,6 +10,7 @@ namespace media { class AudioDecoderConfig; class VideoDecoderConfig; +class EncryptionScheme; } namespace IPC { @@ -34,6 +35,15 @@ static void Log(const param_type& p, std::string* l); }; +template <> +struct ParamTraits<media::EncryptionScheme> { + typedef media::EncryptionScheme param_type; + static void Write(base::Pickle* m, const param_type& p); + static bool Read(const base::Pickle* m, base::PickleIterator* iter, + param_type* r); + static void Log(const param_type& p, std::string* l); +}; + } // namespace IPC #endif // CHROMECAST_COMMON_MEDIA_CMA_PARAM_TRAITS_H_
diff --git a/chromecast/common/media/cma_param_traits_macros.h b/chromecast/common/media/cma_param_traits_macros.h index a25e53f..2aae996 100644 --- a/chromecast/common/media/cma_param_traits_macros.h +++ b/chromecast/common/media/cma_param_traits_macros.h
@@ -44,6 +44,8 @@ media::VideoCodec::kUnknownVideoCodec, media::VideoCodec::kVideoCodecMax) IPC_ENUM_TRAITS_MAX_VALUE(media::ColorSpace, media::COLOR_SPACE_MAX) +IPC_ENUM_TRAITS_MAX_VALUE(media::EncryptionScheme::CipherMode, + media::EncryptionScheme::CIPHER_MODE_MAX); IPC_STRUCT_TRAITS_BEGIN(media::PipelineStatistics) IPC_STRUCT_TRAITS_MEMBER(audio_bytes_decoded)
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc index ec415d75..fc91d50fa 100644 --- a/chromecast/media/audio/cast_audio_output_stream.cc +++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -47,7 +47,6 @@ audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8; audio_config.channel_number = audio_params.channels(); audio_config.samples_per_second = audio_params.sample_rate(); - audio_config.is_encrypted = false; if (!decoder->SetConfig(audio_config)) return nullptr;
diff --git a/chromecast/media/audio/cast_audio_output_stream_unittest.cc b/chromecast/media/audio/cast_audio_output_stream_unittest.cc index a8ad0f0..8402a6a 100644 --- a/chromecast/media/audio/cast_audio_output_stream_unittest.cc +++ b/chromecast/media/audio/cast_audio_output_stream_unittest.cc
@@ -385,7 +385,7 @@ const AudioConfig& audio_config = audio_decoder->config(); EXPECT_EQ(kCodecPCM, audio_config.codec); EXPECT_EQ(kSampleFormatS16, audio_config.sample_format); - EXPECT_FALSE(audio_config.is_encrypted); + EXPECT_FALSE(audio_config.encryption_scheme.is_encrypted()); CloseStream(stream); }
diff --git a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc index 7fd2d1d..c78af4ad 100644 --- a/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc +++ b/chromecast/media/cma/backend/audio_video_pipeline_device_unittest.cc
@@ -35,6 +35,7 @@ #include "media/base/audio_decoder_config.h" #include "media/base/audio_timestamp_helper.h" #include "media/base/decoder_buffer.h" +#include "media/base/encryption_scheme.h" #include "media/base/video_decoder_config.h" #include "testing/gtest/include/gtest/gtest.h" @@ -68,7 +69,7 @@ default_config.codec = kCodecH264; default_config.profile = kH264Main; default_config.additional_config = nullptr; - default_config.is_encrypted = false; + default_config.encryption_scheme = Unencrypted(); return default_config; } @@ -564,7 +565,7 @@ video_config.codec = kCodecH264; video_config.profile = kH264Main; video_config.additional_config = nullptr; - video_config.is_encrypted = false; + video_config.encryption_scheme = Unencrypted(); } else { base::FilePath file_path = GetTestDataFilePath(filename); DemuxResult demux_result = FFmpegDemuxForTest(file_path, false /* audio */); @@ -608,6 +609,7 @@ void AudioVideoPipelineDeviceTest::AddPause(base::TimeDelta delay, base::TimeDelta length) { + DCHECK_EQ(MediaPipelineDeviceParams::kModeSyncPts, sync_type_); pause_pattern_.push_back(PauseInfo(delay, length)); } @@ -645,6 +647,7 @@ void AudioVideoPipelineDeviceTest::SetPausePattern( const std::vector<PauseInfo> pattern) { + DCHECK_EQ(MediaPipelineDeviceParams::kModeSyncPts, sync_type_); pause_pattern_ = pattern; } @@ -951,7 +954,7 @@ TEST_F(AudioVideoPipelineDeviceTest, WebmPlaybackWithPause) { scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); - set_sync_type(MediaPipelineDeviceParams::kModeIgnorePts); + set_sync_type(MediaPipelineDeviceParams::kModeSyncPts); // Setup to pause for 100ms every 500ms AddPause(base::TimeDelta::FromMilliseconds(500), base::TimeDelta::FromMilliseconds(100)); @@ -1133,7 +1136,7 @@ TEST_F(AudioVideoPipelineDeviceTest, WebmPlaybackWithPause_WithEffectsStreams) { scoped_ptr<base::MessageLoop> message_loop(new base::MessageLoop()); - set_sync_type(MediaPipelineDeviceParams::kModeIgnorePts); + set_sync_type(MediaPipelineDeviceParams::kModeSyncPts); // Setup to pause for 100ms every 500ms AddPause(base::TimeDelta::FromMilliseconds(500), base::TimeDelta::FromMilliseconds(100));
diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc index 3a8ab39..24e8b41e 100644 --- a/chromecast/media/cma/base/decoder_config_adapter.cc +++ b/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -85,7 +85,7 @@ // Converts ::media::VideoCodecProfile to chromecast::media::VideoProfile. VideoProfile ToVideoProfile(const ::media::VideoCodecProfile codec_profile) { - switch(codec_profile) { + switch (codec_profile) { case ::media::H264PROFILE_BASELINE: return kH264Baseline; case ::media::H264PROFILE_MAIN: @@ -183,6 +183,62 @@ } } +::media::EncryptionScheme::CipherMode ToMediaCipherMode( + EncryptionScheme::CipherMode mode) { + switch (mode) { + case EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + return ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + case EncryptionScheme::CIPHER_MODE_AES_CTR: + return ::media::EncryptionScheme::CIPHER_MODE_AES_CTR; + case EncryptionScheme::CIPHER_MODE_AES_CBC: + return ::media::EncryptionScheme::CIPHER_MODE_AES_CBC; + default: + NOTREACHED(); + return ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + } +} + +EncryptionScheme::CipherMode ToCipherMode( + ::media::EncryptionScheme::CipherMode mode) { + switch (mode) { + case ::media::EncryptionScheme::CIPHER_MODE_UNENCRYPTED: + return EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + case ::media::EncryptionScheme::CIPHER_MODE_AES_CTR: + return EncryptionScheme::CIPHER_MODE_AES_CTR; + case ::media::EncryptionScheme::CIPHER_MODE_AES_CBC: + return EncryptionScheme::CIPHER_MODE_AES_CBC; + default: + NOTREACHED(); + return EncryptionScheme::CIPHER_MODE_UNENCRYPTED; + } +} + +EncryptionScheme::Pattern ToPatternSpec( + const ::media::EncryptionScheme::Pattern& pattern) { + return EncryptionScheme::Pattern( + pattern.encrypt_blocks(), pattern.skip_blocks()); +} + +::media::EncryptionScheme::Pattern ToMediaPatternSpec( + const EncryptionScheme::Pattern& pattern) { + return ::media::EncryptionScheme::Pattern( + pattern.encrypt_blocks, pattern.skip_blocks); +} + +EncryptionScheme ToEncryptionScheme( + const ::media::EncryptionScheme& scheme) { + return EncryptionScheme( + ToCipherMode(scheme.mode()), + ToPatternSpec(scheme.pattern())); +} + +::media::EncryptionScheme ToMediaEncryptionScheme( + const EncryptionScheme& scheme) { + return ::media::EncryptionScheme( + ToMediaCipherMode(scheme.mode), + ToMediaPatternSpec(scheme.pattern)); +} + } // namespace // static @@ -201,7 +257,8 @@ ::media::ChannelLayoutToChannelCount(config.channel_layout()), audio_config.samples_per_second = config.samples_per_second(); audio_config.extra_data = config.extra_data(); - audio_config.is_encrypted = config.is_encrypted(); + audio_config.encryption_scheme = ToEncryptionScheme( + config.encryption_scheme()); return audio_config; } @@ -212,7 +269,8 @@ ToMediaAudioCodec(config.codec), ToMediaSampleFormat(config.sample_format), ToMediaChannelLayout(config.channel_number), config.samples_per_second, - config.extra_data, config.is_encrypted); + config.extra_data, + ToMediaEncryptionScheme(config.encryption_scheme)); } // static @@ -228,7 +286,8 @@ video_config.codec = ToVideoCodec(config.codec()); video_config.profile = ToVideoProfile(config.profile()); video_config.extra_data = config.extra_data(); - video_config.is_encrypted = config.is_encrypted(); + video_config.encryption_scheme = ToEncryptionScheme( + config.encryption_scheme()); return video_config; }
diff --git a/chromecast/media/cma/base/demuxer_stream_for_test.cc b/chromecast/media/cma/base/demuxer_stream_for_test.cc index 9942545..32ee27b 100644 --- a/chromecast/media/cma/base/demuxer_stream_for_test.cc +++ b/chromecast/media/cma/base/demuxer_stream_for_test.cc
@@ -63,7 +63,7 @@ visible_rect, natural_size, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); } ::media::DemuxerStream::Type DemuxerStreamForTest::type() const {
diff --git a/chromecast/media/cma/ipc_streamer/BUILD.gn b/chromecast/media/cma/ipc_streamer/BUILD.gn index a3429d641..7d25f45 100644 --- a/chromecast/media/cma/ipc_streamer/BUILD.gn +++ b/chromecast/media/cma/ipc_streamer/BUILD.gn
@@ -14,6 +14,8 @@ "decoder_buffer_base_marshaller.h", "decrypt_config_marshaller.cc", "decrypt_config_marshaller.h", + "encryption_scheme_marshaller.cc", + "encryption_scheme_marshaller.h", "video_decoder_config_marshaller.cc", "video_decoder_config_marshaller.h", ]
diff --git a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc index 2798c6ba..031571a 100644 --- a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc +++ b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "chromecast/media/cma/ipc/media_message.h" +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" #include "media/base/audio_decoder_config.h" namespace chromecast { @@ -27,7 +28,7 @@ CHECK(msg->WritePod(config.channel_layout())); CHECK(msg->WritePod(config.samples_per_second())); CHECK(msg->WritePod(config.sample_format())); - CHECK(msg->WritePod(config.is_encrypted())); + EncryptionSchemeMarshaller::Write(config.encryption_scheme(), msg); CHECK(msg->WritePod(config.extra_data().size())); if (!config.extra_data().empty()) CHECK(msg->WriteBuffer(&config.extra_data()[0], @@ -41,15 +42,15 @@ ::media::SampleFormat sample_format; ::media::ChannelLayout channel_layout; int samples_per_second; - bool is_encrypted; size_t extra_data_size; std::vector<uint8_t> extra_data; + ::media::EncryptionScheme encryption_scheme; CHECK(msg->ReadPod(&codec)); CHECK(msg->ReadPod(&channel_layout)); CHECK(msg->ReadPod(&samples_per_second)); CHECK(msg->ReadPod(&sample_format)); - CHECK(msg->ReadPod(&is_encrypted)); + encryption_scheme = EncryptionSchemeMarshaller::Read(msg); CHECK(msg->ReadPod(&extra_data_size)); CHECK_GE(codec, ::media::kUnknownAudioCodec); @@ -67,7 +68,7 @@ return ::media::AudioDecoderConfig( codec, sample_format, channel_layout, samples_per_second, - extra_data, is_encrypted); + extra_data, encryption_scheme); } } // namespace media
diff --git a/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc new file mode 100644 index 0000000..a88cfc5 --- /dev/null +++ b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.cc
@@ -0,0 +1,54 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" + +#include <stdint.h> + +#include "base/logging.h" +#include "chromecast/media/cma/ipc/media_message.h" + +namespace chromecast { +namespace media { + +namespace { + +class PatternSpecMarshaller { + public: + static void Write(const ::media::EncryptionScheme::Pattern& pattern, + MediaMessage* msg) { + CHECK(msg->WritePod(pattern.encrypt_blocks())); + CHECK(msg->WritePod(pattern.skip_blocks())); + } + + static ::media::EncryptionScheme::Pattern Read(MediaMessage* msg) { + uint32_t encrypt_blocks; + uint32_t skip_blocks; + CHECK(msg->ReadPod(&encrypt_blocks)); + CHECK(msg->ReadPod(&skip_blocks)); + return ::media::EncryptionScheme::Pattern(encrypt_blocks, skip_blocks); + } +}; + +} // namespace + +// static +void EncryptionSchemeMarshaller::Write( + const ::media::EncryptionScheme& encryption_scheme, + MediaMessage* msg) { + CHECK(msg->WritePod(encryption_scheme.mode())); + PatternSpecMarshaller::Write(encryption_scheme.pattern(), msg); +} + +// static +::media::EncryptionScheme EncryptionSchemeMarshaller::Read(MediaMessage* msg) { + ::media::EncryptionScheme::CipherMode mode; + ::media::EncryptionScheme::Pattern pattern; + CHECK(msg->ReadPod(&mode)); + pattern = PatternSpecMarshaller::Read(msg); + return ::media::EncryptionScheme(mode, pattern); +} + +} // namespace media +} // namespace chromecast
diff --git a/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h new file mode 100644 index 0000000..0b3371b5 --- /dev/null +++ b/chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h
@@ -0,0 +1,27 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_ +#define CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_ + +#include "media/base/encryption_scheme.h" + +namespace chromecast { +namespace media { +class MediaMessage; + +class EncryptionSchemeMarshaller { + public: + // Writes the serialized structure of |encryption_scheme| into |msg|. + static void Write( + const ::media::EncryptionScheme& encryption_scheme, MediaMessage* msg); + + // Returns an EncryptionScheme from its serialized structure. + static ::media::EncryptionScheme Read(MediaMessage* msg); +}; + +} // namespace media +} // namespace chromecast + +#endif // CHROMECAST_MEDIA_CMA_IPC_STREAMER_ENCRYPTION_SCHEME_MARSHALLER_H_
diff --git a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc index b2e9aaa4..a471eb6 100644 --- a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc +++ b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
@@ -11,6 +11,7 @@ #include "base/logging.h" #include "chromecast/media/cma/ipc/media_message.h" +#include "chromecast/media/cma/ipc_streamer/encryption_scheme_marshaller.h" #include "media/base/video_decoder_config.h" #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" @@ -67,7 +68,7 @@ SizeMarshaller::Write(config.coded_size(), msg); RectMarshaller::Write(config.visible_rect(), msg); SizeMarshaller::Write(config.natural_size(), msg); - CHECK(msg->WritePod(config.is_encrypted())); + EncryptionSchemeMarshaller::Write(config.encryption_scheme(), msg); CHECK(msg->WritePod(config.extra_data().size())); if (!config.extra_data().empty()) CHECK(msg->WriteBuffer(&config.extra_data()[0], @@ -84,8 +85,8 @@ gfx::Size coded_size; gfx::Rect visible_rect; gfx::Size natural_size; - bool is_encrypted; size_t extra_data_size; + ::media::EncryptionScheme encryption_scheme; std::vector<uint8_t> extra_data; CHECK(msg->ReadPod(&codec)); @@ -95,7 +96,7 @@ coded_size = SizeMarshaller::Read(msg); visible_rect = RectMarshaller::Read(msg); natural_size = SizeMarshaller::Read(msg); - CHECK(msg->ReadPod(&is_encrypted)); + encryption_scheme = EncryptionSchemeMarshaller::Read(msg); CHECK(msg->ReadPod(&extra_data_size)); CHECK_GE(codec, ::media::kUnknownVideoCodec); @@ -115,7 +116,7 @@ return ::media::VideoDecoderConfig( codec, profile, format, color_space, coded_size, visible_rect, natural_size, - extra_data, is_encrypted); + extra_data, encryption_scheme); } } // namespace media
diff --git a/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc b/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc index 4b15bcc..a1cdf95 100644 --- a/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc +++ b/chromecast/media/cma/pipeline/audio_decoder_software_wrapper.cc
@@ -59,7 +59,7 @@ return true; } - if (config.is_encrypted || !CreateSoftwareDecoder(config)) + if (config.is_encrypted() || !CreateSoftwareDecoder(config)) return false; output_config_.codec = media::kCodecPCM; @@ -67,7 +67,7 @@ output_config_.channel_number = 2; output_config_.bytes_per_channel = 2; output_config_.samples_per_second = config.samples_per_second; - output_config_.is_encrypted = false; + output_config_.encryption_scheme = Unencrypted(); return backend_decoder_->SetConfig(output_config_); }
diff --git a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc index ab5478b..5148cb6 100644 --- a/chromecast/media/cma/pipeline/audio_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/audio_pipeline_impl.cc
@@ -84,6 +84,7 @@ delta_stats.audio_bytes_decoded = current_stats.audio_bytes_decoded - previous_stats_.audio_bytes_decoded; + bytes_decoded_since_last_update_ = delta_stats.audio_bytes_decoded; previous_stats_ = current_stats; client().statistics_cb.Run(delta_stats);
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc index bd747dd..eba1961 100644 --- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc +++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -66,7 +66,7 @@ ::media::AudioDecoderConfig audio_config( ::media::kCodecMP3, ::media::kSampleFormatS16, ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); AvPipelineClient client; client.eos_cb = base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this), STREAM_AUDIO); @@ -80,7 +80,7 @@ ::media::kCodecH264, ::media::H264PROFILE_MAIN, ::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED, gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480), - ::media::EmptyExtraData(), false)); + ::media::EmptyExtraData(), ::media::Unencrypted())); VideoPipelineClient client; client.av_pipeline_client.eos_cb = base::Bind(&AudioVideoPipelineImplTest::OnEos, base::Unretained(this),
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.cc b/chromecast/media/cma/pipeline/av_pipeline_impl.cc index 028fac4..815e8df 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.cc
@@ -37,7 +37,8 @@ AvPipelineImpl::AvPipelineImpl(MediaPipelineBackend::Decoder* decoder, const AvPipelineClient& client) - : decoder_(decoder), + : bytes_decoded_since_last_update_(0), + decoder_(decoder), client_(client), state_(kUninitialized), buffered_time_(::media::kNoTimestamp()),
diff --git a/chromecast/media/cma/pipeline/av_pipeline_impl.h b/chromecast/media/cma/pipeline/av_pipeline_impl.h index 4dfe091..ad44026 100644 --- a/chromecast/media/cma/pipeline/av_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/av_pipeline_impl.h
@@ -54,6 +54,10 @@ virtual void UpdateStatistics() = 0; + int bytes_decoded_since_last_update() const { + return bytes_decoded_since_last_update_; + } + protected: // Pipeline states. enum State { @@ -80,6 +84,7 @@ size_t max_frame_size); ::media::PipelineStatistics previous_stats_; + int bytes_decoded_since_last_update_; private: void OnFlushDone();
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.cc b/chromecast/media/cma/pipeline/media_pipeline_impl.cc index 73dc9ad1..d3e78cb 100644 --- a/chromecast/media/cma/pipeline/media_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/media_pipeline_impl.cc
@@ -14,7 +14,6 @@ #include "base/logging.h" #include "base/single_thread_task_runner.h" #include "base/thread_task_runner_handle.h" -#include "base/time/time.h" #include "chromecast/base/metrics/cast_metrics_helper.h" #include "chromecast/media/cdm/browser_cdm_cast.h" #include "chromecast/media/cma/base/buffering_controller.h" @@ -52,6 +51,24 @@ // kTimeUpdateInterval * kStatisticsUpdatePeriod. const int kStatisticsUpdatePeriod = 4; +void LogEstimatedBitrate(int decoded_bytes, + base::TimeDelta elapsed_time, + const char* tag, + const char* metric) { + int estimated_bitrate_in_kbps = + 8 * decoded_bytes / elapsed_time.InMilliseconds(); + + if (estimated_bitrate_in_kbps <= 0) + return; + + CMALOG(kLogControl) << "Estimated " << tag << " bitrate is " + << estimated_bitrate_in_kbps << " kbps"; + metrics::CastMetricsHelper* metrics_helper = + metrics::CastMetricsHelper::GetInstance(); + metrics_helper->RecordSimpleActionWithValue(metric, + estimated_bitrate_in_kbps); +} + } // namespace struct MediaPipelineImpl::FlushTask { @@ -68,6 +85,8 @@ video_decoder_(nullptr), pending_time_update_task_(false), statistics_rolling_counter_(0), + audio_bytes_for_bitrate_estimation_(0), + video_bytes_for_bitrate_estimation_(0), weak_factory_(this) { CMALOG(kLogControl) << __FUNCTION__; weak_this_ = weak_factory_.GetWeakPtr(); @@ -204,6 +223,7 @@ return; } backend_state_ = BACKEND_STATE_PLAYING; + ResetBitrateState(); metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( "Cast.Platform.Playing"); @@ -318,6 +338,7 @@ if (backend_state_ == BACKEND_STATE_PAUSED) { media_pipeline_backend_->Resume(); backend_state_ = BACKEND_STATE_PLAYING; + ResetBitrateState(); metrics::CastMetricsHelper::GetInstance()->RecordSimpleAction( "Cast.Platform.Playing"); } @@ -415,7 +436,31 @@ audio_pipeline_->UpdateStatistics(); if (video_pipeline_) video_pipeline_->UpdateStatistics(); + + if (backend_state_ == BACKEND_STATE_PLAYING) { + base::TimeTicks current_time = base::TimeTicks::Now(); + if (audio_pipeline_) + audio_bytes_for_bitrate_estimation_ += + audio_pipeline_->bytes_decoded_since_last_update(); + if (video_pipeline_) + video_bytes_for_bitrate_estimation_ += + video_pipeline_->bytes_decoded_since_last_update(); + elapsed_time_delta_ += current_time - last_sample_time_; + if (elapsed_time_delta_.InMilliseconds() > 5000) { + if (audio_pipeline_) + LogEstimatedBitrate(audio_bytes_for_bitrate_estimation_, + elapsed_time_delta_, "audio", + "Cast.Platform.AudioBitrate"); + if (video_pipeline_) + LogEstimatedBitrate(video_bytes_for_bitrate_estimation_, + elapsed_time_delta_, "video", + "Cast.Platform.VideoBitrate"); + ResetBitrateState(); + } + last_sample_time_ = current_time; + } } + statistics_rolling_counter_ = (statistics_rolling_counter_ + 1) % kStatisticsUpdatePeriod; @@ -468,5 +513,12 @@ client_.error_cb.Run(error); } +void MediaPipelineImpl::ResetBitrateState() { + elapsed_time_delta_ = base::TimeDelta::FromSeconds(0); + audio_bytes_for_bitrate_estimation_ = 0; + video_bytes_for_bitrate_estimation_ = 0; + last_sample_time_ = base::TimeTicks::Now(); +} + } // namespace media } // namespace chromecast
diff --git a/chromecast/media/cma/pipeline/media_pipeline_impl.h b/chromecast/media/cma/pipeline/media_pipeline_impl.h index 6773643..1b6660f 100644 --- a/chromecast/media/cma/pipeline/media_pipeline_impl.h +++ b/chromecast/media/cma/pipeline/media_pipeline_impl.h
@@ -13,6 +13,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread_checker.h" +#include "base/time/time.h" #include "chromecast/media/cma/pipeline/load_type.h" #include "chromecast/media/cma/pipeline/media_pipeline_client.h" #include "chromecast/public/media/media_pipeline_backend.h" @@ -82,6 +83,8 @@ void OnError(::media::PipelineStatus error); + void ResetBitrateState(); + base::ThreadChecker thread_checker_; MediaPipelineClient client_; scoped_ptr<BufferingController> buffering_controller_; @@ -108,6 +111,10 @@ // Used to make the statistics update period a multiplier of the time update // period. int statistics_rolling_counter_; + base::TimeTicks last_sample_time_; + base::TimeDelta elapsed_time_delta_; + int audio_bytes_for_bitrate_estimation_; + int video_bytes_for_bitrate_estimation_; base::WeakPtr<MediaPipelineImpl> weak_this_; base::WeakPtrFactory<MediaPipelineImpl> weak_factory_;
diff --git a/chromecast/media/cma/pipeline/video_pipeline_impl.cc b/chromecast/media/cma/pipeline/video_pipeline_impl.cc index 6b480c6..04b5046 100644 --- a/chromecast/media/cma/pipeline/video_pipeline_impl.cc +++ b/chromecast/media/cma/pipeline/video_pipeline_impl.cc
@@ -117,6 +117,7 @@ delta_stats.video_frames_dropped = current_stats.video_frames_dropped - previous_stats_.video_frames_dropped; + bytes_decoded_since_last_update_ = delta_stats.video_bytes_decoded; previous_stats_ = current_stats; client().statistics_cb.Run(delta_stats);
diff --git a/chromecast/media/cma/test/mock_frame_provider.cc b/chromecast/media/cma/test/mock_frame_provider.cc index fdab889..16d6393 100644 --- a/chromecast/media/cma/test/mock_frame_provider.cc +++ b/chromecast/media/cma/test/mock_frame_provider.cc
@@ -82,7 +82,7 @@ ::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN, ::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect, natural_size, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); audio_config = ::media::AudioDecoderConfig( ::media::kCodecAAC, @@ -90,7 +90,7 @@ ::media::CHANNEL_LAYOUT_STEREO, 44100, ::media::EmptyExtraData(), - false); + ::media::Unencrypted()); } read_cb.Run(buffer, audio_config, video_config);
diff --git a/chromecast/media/media.gyp b/chromecast/media/media.gyp index 6cabfc7..077ea0c 100644 --- a/chromecast/media/media.gyp +++ b/chromecast/media/media.gyp
@@ -229,6 +229,8 @@ 'cma/ipc_streamer/decoder_buffer_base_marshaller.h', 'cma/ipc_streamer/decrypt_config_marshaller.cc', 'cma/ipc_streamer/decrypt_config_marshaller.h', + 'cma/ipc_streamer/encryption_scheme_marshaller.cc', + 'cma/ipc_streamer/encryption_scheme_marshaller.h', 'cma/ipc_streamer/video_decoder_config_marshaller.cc', 'cma/ipc_streamer/video_decoder_config_marshaller.h', ],
diff --git a/chromecast/public/media/decoder_config.h b/chromecast/public/media/decoder_config.h index 261b3f1..b82c5c1 100644 --- a/chromecast/public/media/decoder_config.h +++ b/chromecast/public/media/decoder_config.h
@@ -93,13 +93,78 @@ kVideoProfileMax = kDolbyVisionNonCompatible_BL_EL_MD, }; -// TODO(erickung): Remove constructor once CMA backend implementation does't +// Specification of whether and how the stream is encrypted (in whole or part). +struct EncryptionScheme { + // Algorithm and mode that was used to encrypt the stream. + enum CipherMode { + CIPHER_MODE_UNENCRYPTED, + CIPHER_MODE_AES_CTR, + CIPHER_MODE_AES_CBC + }; + + // CENC 3rd Edition adds pattern encryption, through two new protection + // schemes: 'cens' (with AES-CTR) and 'cbcs' (with AES-CBC). + // The pattern applies independently to each 'encrypted' part of the frame (as + // defined by the relevant subsample entries), and reduces further the + // actual encryption applied through a repeating pattern of (encrypt:skip) + // 16 byte blocks. For example, in a (1:9) pattern, the first block is + // encrypted, and the next nine are skipped. This pattern is applied + // repeatedly until the end of the last 16-byte block in the subsample. + // Any remaining bytes are left clear. + // If either of encrypt_blocks or skip_blocks is 0, pattern encryption is + // disabled. + struct Pattern { + Pattern() {} + Pattern(uint32_t encrypt_blocks, uint32_t skip_blocks); + ~Pattern() {} + bool IsInEffect() const; + + uint32_t encrypt_blocks = 0; + uint32_t skip_blocks = 0; + }; + + EncryptionScheme() {} + EncryptionScheme(CipherMode mode, const Pattern& pattern); + ~EncryptionScheme() {} + bool is_encrypted() const { return mode != CIPHER_MODE_UNENCRYPTED; } + + CipherMode mode = CIPHER_MODE_UNENCRYPTED; + Pattern pattern; +}; + +inline EncryptionScheme::Pattern::Pattern(uint32_t encrypt_blocks, + uint32_t skip_blocks) + : encrypt_blocks(encrypt_blocks), skip_blocks(skip_blocks) { +} + +inline bool EncryptionScheme::Pattern::IsInEffect() const { + return encrypt_blocks != 0 && skip_blocks != 0; +} + +inline EncryptionScheme::EncryptionScheme(CipherMode mode, + const Pattern& pattern) + : mode(mode), pattern(pattern) { +} + +inline EncryptionScheme Unencrypted() { + return EncryptionScheme(); +} + +inline EncryptionScheme AesCtrEncryptionScheme() { + return EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CTR, + EncryptionScheme::Pattern()); +} + + +// TODO(erickung): Remove constructor once CMA backend implementation doesn't // create a new object to reset the configuration and use IsValidConfig() to // determine if the configuration is still valid or not. struct AudioConfig { AudioConfig(); ~AudioConfig(); + bool is_encrypted() const { return encryption_scheme.is_encrypted(); } + // Stream id. StreamId id; // Audio codec. @@ -114,8 +179,8 @@ int samples_per_second; // Extra data buffer for certain codec initialization. std::vector<uint8_t> extra_data; - // content is encrypted or not. - bool is_encrypted; + // Encryption scheme (if any) used for the content. + EncryptionScheme encryption_scheme; }; inline AudioConfig::AudioConfig() @@ -124,8 +189,7 @@ sample_format(kUnknownSampleFormat), bytes_per_channel(0), channel_number(0), - samples_per_second(0), - is_encrypted(false) { + samples_per_second(0) { } inline AudioConfig::~AudioConfig() { @@ -138,6 +202,8 @@ VideoConfig(); ~VideoConfig(); + bool is_encrypted() const { return encryption_scheme.is_encrypted(); } + // Stream Id. StreamId id; // Video codec. @@ -150,16 +216,15 @@ VideoConfig* additional_config; // Extra data buffer for certain codec initialization. std::vector<uint8_t> extra_data; - // content is encrypted or not. - bool is_encrypted; + // Encryption scheme (if any) used for the content. + EncryptionScheme encryption_scheme; }; inline VideoConfig::VideoConfig() : id(kPrimary), codec(kVideoCodecUnknown), profile(kVideoProfileUnknown), - additional_config(nullptr), - is_encrypted(false) { + additional_config(nullptr) { } inline VideoConfig::~VideoConfig() {
diff --git a/components/app_modal/javascript_dialog_manager.cc b/components/app_modal/javascript_dialog_manager.cc index ec47620..9bd127b3 100644 --- a/components/app_modal/javascript_dialog_manager.cc +++ b/components/app_modal/javascript_dialog_manager.cc
@@ -57,30 +57,15 @@ return extra_data->has_already_shown_a_dialog_; } -enum class DialogType { - JAVASCRIPT, - ON_BEFORE_UNLOAD, -}; - -void LogUMAMessageLengthStats(const base::string16& message, DialogType type) { - if (type == DialogType::JAVASCRIPT) { - UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageCharacters", - static_cast<int32_t>(message.length())); - } else { - UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfOnBeforeUnloadMessageCharacters", - static_cast<int32_t>(message.length())); - } +void LogUMAMessageLengthStats(const base::string16& message) { + UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageCharacters", + static_cast<int32_t>(message.length())); int32_t newline_count = std::count_if(message.begin(), message.end(), [](const base::char16& c) { return c == '\n'; }); - if (type == DialogType::JAVASCRIPT) { - UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageNewlines", - newline_count); - } else { - UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfOnBeforeUnloadMessageNewlines", - newline_count); - } + UMA_HISTOGRAM_COUNTS("JSDialogs.CountOfJSDialogMessageNewlines", + newline_count); } } // namespace @@ -172,7 +157,7 @@ extensions_client_->OnDialogOpened(web_contents); - LogUMAMessageLengthStats(message_text, DialogType::JAVASCRIPT); + LogUMAMessageLengthStats(message_text); AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( web_contents, &javascript_dialog_extra_data_, @@ -189,7 +174,6 @@ void JavaScriptDialogManager::RunBeforeUnloadDialog( content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { ChromeJavaScriptDialogExtraData* extra_data = @@ -202,23 +186,33 @@ return; } + // Build the dialog message. We explicitly do _not_ allow the webpage to + // specify the contents of this dialog, because most of the time nowadays it's + // used for scams. + // + // This does not violate the spec. Per + // https://html.spec.whatwg.org/#prompt-to-unload-a-document, step 7: + // + // "The prompt shown by the user agent may include the string of the + // returnValue attribute, or some leading subset thereof." + // + // The prompt MAY include the string. It doesn't any more. Scam web page + // authors have abused this, so we're taking away the toys from everyone. This + // is why we can't have nice things. + const base::string16 title = l10n_util::GetStringUTF16(is_reload ? IDS_BEFORERELOAD_MESSAGEBOX_TITLE : IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE); - const base::string16 footer = l10n_util::GetStringUTF16(is_reload ? - IDS_BEFORERELOAD_MESSAGEBOX_FOOTER : IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER); - - base::string16 full_message = - message_text + base::ASCIIToUTF16("\n\n") + footer; + const base::string16 message = + l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE); extensions_client_->OnDialogOpened(web_contents); - LogUMAMessageLengthStats(message_text, DialogType::ON_BEFORE_UNLOAD); AppModalDialogQueue::GetInstance()->AddDialog(new JavaScriptAppModalDialog( web_contents, &javascript_dialog_extra_data_, title, content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM, - full_message, + message, base::string16(), // default_prompt_text ShouldDisplaySuppressCheckbox(extra_data), true, // is_before_unload_dialog
diff --git a/components/app_modal/javascript_dialog_manager.h b/components/app_modal/javascript_dialog_manager.h index 22f2f796..66bfe7c 100644 --- a/components/app_modal/javascript_dialog_manager.h +++ b/components/app_modal/javascript_dialog_manager.h
@@ -52,7 +52,6 @@ const DialogClosedCallback& callback, bool* did_suppress_message) override; void RunBeforeUnloadDialog(content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override; bool HandleJavaScriptDialog(content::WebContents* web_contents,
diff --git a/components/app_modal_strings.grdp b/components/app_modal_strings.grdp index 09cd5ff6..ec4a2ac 100644 --- a/components/app_modal_strings.grdp +++ b/components/app_modal_strings.grdp
@@ -20,30 +20,27 @@ <!-- "Before Unload" Dialog Box strings --> <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog."> - Confirm Navigation + Do you want to leave this site? </message> - <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_FOOTER" desc="Text shown at the bottom of the dialog, after the message provided by the script."> - Are you sure you want to leave this page? + <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE" desc="Text shown as the message of the 'before unload' dialog."> + Changes you made may not be saved. </message> <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_OK_BUTTON_LABEL" desc="The text on the button which navigates the user away from the page."> - Leave this Page + Leave </message> <message name="IDS_BEFOREUNLOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL" desc="The text on the button which cancels the navigation away from the page."> - Stay on this Page + Stay </message> <!-- "Before Reload" Dialog Box strings (same as "Before Unload" but when reloading rather than unloading the page --> - <message name="IDS_BEFORERELOAD_MESSAGEBOX_TITLE" desc="Title for the 'before reload' dialog."> - Confirm Reload - </message> - <message name="IDS_BEFORERELOAD_MESSAGEBOX_FOOTER" desc="Text shown at the bottom of the dialog, after the message provided by the script."> - Are you sure you want to reload this page? + <message name="IDS_BEFORERELOAD_MESSAGEBOX_TITLE" desc="Title for the 'before unload' dialog for reloads."> + Do you want to reload this site? </message> <message name="IDS_BEFORERELOAD_MESSAGEBOX_OK_BUTTON_LABEL" desc="The text on the button which reloads the page."> - Reload this Page + Reload </message> <message name="IDS_BEFORERELOAD_MESSAGEBOX_CANCEL_BUTTON_LABEL" desc="The text on the button which cancels the page reload."> - Don't Reload + Don’t Reload </message> </grit-part>
diff --git a/components/cdm/browser/widevine_drm_delegate_android.cc b/components/cdm/browser/widevine_drm_delegate_android.cc index d4133ee..ba09143 100644 --- a/components/cdm/browser/widevine_drm_delegate_android.cc +++ b/components/cdm/browser/widevine_drm_delegate_android.cc
@@ -36,13 +36,9 @@ if (init_data_type != media::EmeInitDataType::CENC) return true; -#if defined(PROPRIETARY_CODECS) // Widevine MediaDrm plugin only accepts the "data" part of the PSSH box as // the init data when using MP4 container. return media::GetPsshData(init_data, GetUUID(), init_data_out); -#else - return false; -#endif } } // namespace cdm
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider.cc b/components/data_reduction_proxy/content/browser/content_lofi_decider.cc index 3380955..733a814 100644 --- a/components/data_reduction_proxy/content/browser/content_lofi_decider.cc +++ b/components/data_reduction_proxy/content/browser/content_lofi_decider.cc
@@ -6,11 +6,14 @@ #include <string> +#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "content/public/browser/resource_request_info.h" #include "net/base/load_flags.h" #include "net/http/http_request_headers.h" +#include "net/proxy/proxy_server.h" +#include "net/url_request/url_request.h" namespace data_reduction_proxy { @@ -35,7 +38,15 @@ bool ContentLoFiDecider::MaybeAddLoFiDirectiveToHeaders( const net::URLRequest& request, - net::HttpRequestHeaders* headers) const { + net::HttpRequestHeaders* headers, + const net::ProxyServer& proxy_server, + DataReductionProxyConfig* config) const { + if (!proxy_server.is_valid() || proxy_server.is_direct() || + proxy_server.host_port_pair().IsEmpty() || + !config->IsDataReductionProxy(proxy_server.host_port_pair(), nullptr)) { + return false; + } + const content::ResourceRequestInfo* request_info = content::ResourceRequestInfo::ForRequest(&request); @@ -85,7 +96,6 @@ headers->RemoveHeader(chrome_proxy_header()); header_value += ", "; } - header_value += chrome_proxy_lo_fi_experiment_directive(); headers->SetHeader(chrome_proxy_header(), header_value); }
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider.h b/components/data_reduction_proxy/content/browser/content_lofi_decider.h index 01e0377..4f82319b 100644 --- a/components/data_reduction_proxy/content/browser/content_lofi_decider.h +++ b/components/data_reduction_proxy/content/browser/content_lofi_decider.h
@@ -30,7 +30,9 @@ bool IsUsingLoFiMode(const net::URLRequest& request) const override; bool MaybeAddLoFiDirectiveToHeaders( const net::URLRequest& request, - net::HttpRequestHeaders* headers) const override; + net::HttpRequestHeaders* headers, + const net::ProxyServer& proxy_server, + DataReductionProxyConfig* config) const override; private: DISALLOW_COPY_AND_ASSIGN(ContentLoFiDecider);
diff --git a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc index 7ac2171..117a387 100644 --- a/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc +++ b/components/data_reduction_proxy/content/browser/content_lofi_decider_unittest.cc
@@ -108,12 +108,18 @@ } void NotifyBeforeSendProxyHeaders(net::HttpRequestHeaders* headers, - net::URLRequest* request) { + net::URLRequest* request, + bool use_data_reduction_proxy) { net::ProxyInfo data_reduction_proxy_info; - std::string data_reduction_proxy; - base::TrimString(test_context_->config()->test_params()->DefaultOrigin(), - "/", &data_reduction_proxy); - data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy); + + if (use_data_reduction_proxy) { + std::string data_reduction_proxy; + base::TrimString(test_context_->config()->test_params()->DefaultOrigin(), + "/", &data_reduction_proxy); + data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy); + } else { + data_reduction_proxy_info.UseNamedProxy("proxy.com"); + } data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( request, data_reduction_proxy_info, headers); @@ -139,17 +145,6 @@ std::string::npos); } - static void VerifyLoFiExperimentHeader( - bool expected_lofi_experiment_used, - const net::HttpRequestHeaders& headers) { - EXPECT_TRUE(headers.HasHeader(chrome_proxy_header())); - std::string header_value; - headers.GetHeader(chrome_proxy_header(), &header_value); - EXPECT_EQ(expected_lofi_experiment_used, - header_value.find(chrome_proxy_lo_fi_experiment_directive()) != - std::string::npos); - } - protected: base::MessageLoopForIO message_loop_; net::MockClientSocketFactory mock_socket_factory_; @@ -180,7 +175,7 @@ // No flags or field trials. The Lo-Fi header should not be added. net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(false, headers); VerifyLoFiPreviewHeader(false, headers); @@ -191,7 +186,7 @@ switches::kDataReductionProxyLoFiValueAlwaysOn); request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME); headers.Clear(); - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews, headers); VerifyLoFiPreviewHeader( @@ -201,7 +196,7 @@ // should be added. request->SetLoadFlags(0); headers.Clear(); - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews, headers); VerifyLoFiPreviewHeader(false, headers); @@ -212,7 +207,7 @@ switches::kDataReductionProxyLoFi, switches::kDataReductionProxyLoFiValueCellularOnly); headers.Clear(); - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews, headers); VerifyLoFiPreviewHeader(false, headers); @@ -223,7 +218,7 @@ switches::kDataReductionProxyLoFi, switches::kDataReductionProxyLoFiValueSlowConnectionsOnly); headers.Clear(); - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(tests[i].is_using_lofi && !tests[i].is_using_previews, headers); VerifyLoFiPreviewHeader(false, headers); @@ -244,7 +239,7 @@ for (size_t i = 0; i < arraysize(tests); ++i) { scoped_ptr<net::URLRequest> request = CreateRequest(tests[i].is_using_lofi); net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(tests[i].is_using_lofi, headers); VerifyLoFiPreviewHeader(false, headers); } @@ -264,7 +259,7 @@ for (size_t i = 0; i < arraysize(tests); ++i) { scoped_ptr<net::URLRequest> request = CreateRequest(tests[i].is_using_lofi); net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(false, headers); VerifyLoFiPreviewHeader(false, headers); } @@ -287,7 +282,7 @@ if (tests[i].is_main_frame) request->SetLoadFlags(request->load_flags() | net::LOAD_MAIN_FRAME); net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(false, headers); VerifyLoFiPreviewHeader(tests[i].is_using_lofi && tests[i].is_main_frame, headers); @@ -317,8 +312,6 @@ // trial and network is prohibitively slow. bool expect_lofi_header = tests[i].auto_lofi_enabled_group && tests[i].network_prohibitively_slow; - bool expect_lofi_experiment_header = - tests[i].auto_lofi_control_group && tests[i].network_prohibitively_slow; base::FieldTrialList field_trial_list(nullptr); if (tests[i].auto_lofi_enabled_group) { @@ -337,10 +330,9 @@ scoped_ptr<net::URLRequest> request = CreateRequest(tests[i].network_prohibitively_slow); net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(expect_lofi_header, headers); - VerifyLoFiExperimentHeader(expect_lofi_experiment_header, headers); } } @@ -388,10 +380,32 @@ scoped_ptr<net::URLRequest> request = CreateRequest(tests[i].network_prohibitively_slow); net::HttpRequestHeaders headers; - NotifyBeforeSendProxyHeaders(&headers, request.get()); + NotifyBeforeSendProxyHeaders(&headers, request.get(), true); VerifyLoFiHeader(expect_lofi_header, headers); } } +TEST_F(ContentLoFiDeciderTest, ProxyIsNotDataReductionProxy) { + base::FieldTrialList field_trial_list(nullptr); + base::FieldTrialList::CreateFieldTrial(params::GetLoFiFieldTrialName(), + "Enabled"); + // Enable Lo-Fi. + const struct { + bool is_using_lofi; + } tests[] = { + {false}, {true}, + }; + + for (size_t i = 0; i < arraysize(tests); ++i) { + scoped_ptr<net::URLRequest> request = CreateRequest(tests[i].is_using_lofi); + net::HttpRequestHeaders headers; + NotifyBeforeSendProxyHeaders(&headers, request.get(), false); + std::string header_value; + headers.GetHeader(chrome_proxy_header(), &header_value); + EXPECT_EQ(std::string::npos, + header_value.find(chrome_proxy_lo_fi_directive())); + } +} + } // namespace data_reduction_roxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc index af9bf55..52948d4 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.cc
@@ -118,40 +118,16 @@ void DataReductionProxyBypassStats::OnUrlRequestCompleted( const net::URLRequest* request, bool started) { - DataReductionProxyTypeInfo proxy_info; // Ignore requests that did not use the data reduction proxy. The check for // LOAD_BYPASS_PROXY is necessary because the proxy_server() in the |request| // might still be set to the data reduction proxy if |request| was retried // over direct and a network error occurred while retrying it. if (data_reduction_proxy_config_->WasDataReductionProxyUsed(request, - &proxy_info) && - (request->load_flags() & net::LOAD_BYPASS_PROXY) == 0) { - if (request->status().status() == net::URLRequestStatus::SUCCESS) { - successful_requests_through_proxy_count_++; - NotifyUnavailabilityIfChanged(); - } - - // Report any network errors that occurred for this request, including OK - // and ABORTED. - if (!proxy_info.is_fallback) { - UMA_HISTOGRAM_SPARSE_SLOWLY( - "DataReductionProxy.RequestCompletionErrorCodes.Primary", - std::abs(request->status().error())); - if (request->load_flags() & net::LOAD_MAIN_FRAME) { - UMA_HISTOGRAM_SPARSE_SLOWLY( - "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Primary", - std::abs(request->status().error())); - } - } else { - UMA_HISTOGRAM_SPARSE_SLOWLY( - "DataReductionProxy.RequestCompletionErrorCodes.Fallback", - std::abs(request->status().error())); - if (request->load_flags() & net::LOAD_MAIN_FRAME) { - UMA_HISTOGRAM_SPARSE_SLOWLY( - "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Fallback", - std::abs(request->status().error())); - } - } + nullptr) && + (request->load_flags() & net::LOAD_BYPASS_PROXY) == 0 && + request->status().status() == net::URLRequestStatus::SUCCESS) { + successful_requests_through_proxy_count_++; + NotifyUnavailabilityIfChanged(); } }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc index b6469baf6..bae7823c 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats_unittest.cc
@@ -441,103 +441,6 @@ } } -TEST_F(DataReductionProxyBypassStatsTest, RequestCompletionErrorCodes) { - const std::string kPrimaryHistogramName = - "DataReductionProxy.RequestCompletionErrorCodes.Primary"; - const std::string kFallbackHistogramName = - "DataReductionProxy.RequestCompletionErrorCodes.Fallback"; - const std::string kPrimaryMainFrameHistogramName = - "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Primary"; - const std::string kFallbackMainFrameHistogramName = - "DataReductionProxy.RequestCompletionErrorCodes.MainFrame.Fallback"; - - struct TestCase { - bool was_proxy_used; - bool is_load_bypass_proxy; - bool is_fallback; - bool is_main_frame; - net::Error net_error; - }; - - const TestCase test_cases[] = { - { false, true, false, true, net::OK }, - { false, true, false, false, net::ERR_TOO_MANY_REDIRECTS }, - { false, false, false, true, net::OK }, - { false, false, false, false, net::ERR_TOO_MANY_REDIRECTS }, - { true, false, false, true, net::OK }, - { true, false, false, true, net::ERR_TOO_MANY_REDIRECTS }, - { true, false, false, false, net::OK }, - { true, false, false, false, net::ERR_TOO_MANY_REDIRECTS }, - { true, false, true, true, net::OK }, - { true, false, true, true, net::ERR_TOO_MANY_REDIRECTS }, - { true, false, true, false, net::OK }, - { true, false, true, false, net::ERR_TOO_MANY_REDIRECTS } - }; - - for (size_t i = 0; i < arraysize(test_cases); ++i) { - base::HistogramTester histogram_tester; - scoped_ptr<DataReductionProxyBypassStats> bypass_stats = BuildBypassStats(); - - std::string response_headers( - "HTTP/1.1 200 OK\n" - "Via: 1.1 Chrome-Compression-Proxy\n"); - scoped_ptr<net::URLRequest> fake_request( - CreateURLRequestWithResponseHeaders(GURL("http://www.google.com/"), - response_headers)); - if (test_cases[i].is_load_bypass_proxy) { - fake_request->SetLoadFlags(fake_request->load_flags() | - net::LOAD_BYPASS_PROXY); - } - if (test_cases[i].is_main_frame) { - fake_request->SetLoadFlags(fake_request->load_flags() | - net::LOAD_MAIN_FRAME); - } - - int net_error_int = static_cast<int>(test_cases[i].net_error); - if (test_cases[i].net_error != net::OK) { - fake_request->CancelWithError(net_error_int); - } - - DataReductionProxyTypeInfo proxy_info; - proxy_info.is_fallback = test_cases[i].is_fallback; - EXPECT_CALL(*config(), WasDataReductionProxyUsed(fake_request.get(), - testing::NotNull())) - .WillRepeatedly(testing::DoAll(testing::SetArgPointee<1>(proxy_info), - Return(test_cases[i].was_proxy_used))); - - bypass_stats->OnUrlRequestCompleted(fake_request.get(), false); - - if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy && - !test_cases[i].is_fallback) { - histogram_tester.ExpectUniqueSample( - kPrimaryHistogramName, -net_error_int, 1); - } else { - histogram_tester.ExpectTotalCount(kPrimaryHistogramName, 0); - } - if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy && - test_cases[i].is_fallback) { - histogram_tester.ExpectUniqueSample( - kFallbackHistogramName, -net_error_int, 1); - } else { - histogram_tester.ExpectTotalCount(kFallbackHistogramName, 0); - } - if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy && - !test_cases[i].is_fallback && test_cases[i].is_main_frame) { - histogram_tester.ExpectUniqueSample( - kPrimaryMainFrameHistogramName, -net_error_int, 1); - } else { - histogram_tester.ExpectTotalCount(kPrimaryMainFrameHistogramName, 0); - } - if (test_cases[i].was_proxy_used && !test_cases[i].is_load_bypass_proxy && - test_cases[i].is_fallback && test_cases[i].is_main_frame) { - histogram_tester.ExpectUniqueSample( - kFallbackMainFrameHistogramName, -net_error_int, 1); - } else { - histogram_tester.ExpectTotalCount(kFallbackMainFrameHistogramName, 0); - } - } -} - // End-to-end tests for the DataReductionProxy.BypassedBytes histograms. class DataReductionProxyBypassStatsEndToEndTest : public testing::Test { public:
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index b5710ac..16467f14 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -159,11 +159,15 @@ net::HttpRequestHeaders* headers) { DCHECK(data_reduction_proxy_config_); + if (proxy_info.is_empty()) + return; + if (data_reduction_proxy_io_data_ && data_reduction_proxy_io_data_->lofi_decider() && request) { LoFiDecider* lofi_decider = data_reduction_proxy_io_data_->lofi_decider(); - bool is_using_lofi_mode = - lofi_decider->MaybeAddLoFiDirectiveToHeaders(*request, headers); + bool is_using_lofi_mode = lofi_decider->MaybeAddLoFiDirectiveToHeaders( + *request, headers, proxy_info.proxy_server(), + data_reduction_proxy_config_); if ((request->load_flags() & net::LOAD_MAIN_FRAME)) { // TODO(megjablon): Need to switch to per page.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index 2e83377..6b6de3c5 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -91,7 +91,9 @@ bool MaybeAddLoFiDirectiveToHeaders( const net::URLRequest& request, - net::HttpRequestHeaders* headers) const override { + net::HttpRequestHeaders* headers, + const net::ProxyServer& proxy_server, + DataReductionProxyConfig* config) const override { if (should_request_lofi_resource_) { const char kChromeProxyHeader[] = "Chrome-Proxy"; std::string header_value;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc index fa9b6da2..8ec2ad4f 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -31,7 +31,6 @@ const char kChromeProxyLoFiDirective[] = "q=low"; const char kChromeProxyLoFiPreviewDirective[] = "q=preview"; -const char kChromeProxyLoFiExperimentDirective[] = "exp=lofi_active_control"; const char kChromeProxyActionBlockOnce[] = "block-once"; const char kChromeProxyActionBlock[] = "block"; @@ -70,10 +69,6 @@ return kChromeProxyLoFiPreviewDirective; } -const char* chrome_proxy_lo_fi_experiment_directive() { - return kChromeProxyLoFiExperimentDirective; -} - bool GetDataReductionProxyActionValue( const net::HttpResponseHeaders* headers, const std::string& action_prefix,
diff --git a/components/data_reduction_proxy/core/common/lofi_decider.h b/components/data_reduction_proxy/core/common/lofi_decider.h index da63510..8247666 100644 --- a/components/data_reduction_proxy/core/common/lofi_decider.h +++ b/components/data_reduction_proxy/core/common/lofi_decider.h
@@ -6,14 +6,17 @@ #define COMPONENTS_DATA_REDUCTION_PROXY_CORE_BROWSER_LOFI_DECIDER_H_ #include "base/macros.h" -#include "net/url_request/url_request.h" namespace net { class HttpRequestHeaders; +class ProxyServer; +class URLRequest; } namespace data_reduction_proxy { +class DataReductionProxyConfig; + // Interface to determine if a request should be made for a low fidelity version // of the resource. class LoFiDecider { @@ -28,11 +31,14 @@ // |request| is using Lo-Fi mode, adds the "q=low" directive to the |headers|. // If the |request| is using Lo-Fi preview mode, and it is a main frame // request adds the "q=preview" and it is a main frame request directive to - // the |headers|. If the user is in the experiment control group and Lo-Fi is - // on, adds the experiment directive "exp=lofi_active_control". + // the |headers|. Only adds this header if the provided |proxy_server| is a + // data reduction proxy as identified by the given |config|. + virtual bool MaybeAddLoFiDirectiveToHeaders( const net::URLRequest& request, - net::HttpRequestHeaders* headers) const = 0; + net::HttpRequestHeaders* headers, + const net::ProxyServer& proxy_server, + DataReductionProxyConfig* config) const = 0; }; } // namespace data_reduction_proxy
diff --git a/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc b/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc index bc52b01..78ba075a9 100644 --- a/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc +++ b/components/dom_distiller/content/browser/distiller_page_web_contents_browsertest.cc
@@ -250,7 +250,7 @@ // A relative source/track should've been updated. EXPECT_THAT(distiller_result_->distilled_content().html(), - ContainsRegex("src=\"http://127.0.0.1:.*/relative_video.webm\"")); + ContainsRegex("src=\"http://127.0.0.1:.*/relative_video.mp4\"")); EXPECT_THAT( distiller_result_->distilled_content().html(), ContainsRegex("src=\"http://127.0.0.1:.*/relative_track_en.vtt\""));
diff --git a/components/gcm_driver/fake_gcm_driver.cc b/components/gcm_driver/fake_gcm_driver.cc index 390ca1a..f4ae620 100644 --- a/components/gcm_driver/fake_gcm_driver.cc +++ b/components/gcm_driver/fake_gcm_driver.cc
@@ -100,7 +100,7 @@ void FakeGCMDriver::WakeFromSuspendForHeartbeat(bool wake) { } -InstanceIDHandler* FakeGCMDriver::GetInstanceIDHandler() { +InstanceIDHandler* FakeGCMDriver::GetInstanceIDHandlerInternal() { return NULL; }
diff --git a/components/gcm_driver/fake_gcm_driver.h b/components/gcm_driver/fake_gcm_driver.h index 01a16c9..363e963 100644 --- a/components/gcm_driver/fake_gcm_driver.h +++ b/components/gcm_driver/fake_gcm_driver.h
@@ -40,7 +40,7 @@ base::Time GetLastTokenFetchTime() override; void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; - InstanceIDHandler* GetInstanceIDHandler() override; + InstanceIDHandler* GetInstanceIDHandlerInternal() override; void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; void RemoveHeartbeatInterval(const std::string& scope) override;
diff --git a/components/gcm_driver/gcm_driver.h b/components/gcm_driver/gcm_driver.h index c33890a..f87bc2a3d 100644 --- a/components/gcm_driver/gcm_driver.h +++ b/components/gcm_driver/gcm_driver.h
@@ -212,8 +212,8 @@ // to send a heartbeat message. virtual void WakeFromSuspendForHeartbeat(bool wake) = 0; - // Supports InstanceID handling. - virtual InstanceIDHandler* GetInstanceIDHandler() = 0; + // Supports InstanceID handling. Must only be used by the InstanceID system. + virtual InstanceIDHandler* GetInstanceIDHandlerInternal() = 0; // Adds or removes a custom client requested heartbeat interval. If multiple // components set that setting, the lowest setting will be used. If the
diff --git a/components/gcm_driver/gcm_driver_android.cc b/components/gcm_driver/gcm_driver_android.cc index 8f345423..7845bd992 100644 --- a/components/gcm_driver/gcm_driver_android.cc +++ b/components/gcm_driver/gcm_driver_android.cc
@@ -199,7 +199,7 @@ void GCMDriverAndroid::WakeFromSuspendForHeartbeat(bool wake) { } -InstanceIDHandler* GCMDriverAndroid::GetInstanceIDHandler() { +InstanceIDHandler* GCMDriverAndroid::GetInstanceIDHandlerInternal() { // Not supported for Android. return NULL; }
diff --git a/components/gcm_driver/gcm_driver_android.h b/components/gcm_driver/gcm_driver_android.h index dab0d14..5944b85 100644 --- a/components/gcm_driver/gcm_driver_android.h +++ b/components/gcm_driver/gcm_driver_android.h
@@ -74,7 +74,7 @@ base::Time GetLastTokenFetchTime() override; void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; - InstanceIDHandler* GetInstanceIDHandler() override; + InstanceIDHandler* GetInstanceIDHandlerInternal() override; void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; void RemoveHeartbeatInterval(const std::string& scope) override;
diff --git a/components/gcm_driver/gcm_driver_desktop.cc b/components/gcm_driver/gcm_driver_desktop.cc index 2c65b08e..171e4faf 100644 --- a/components/gcm_driver/gcm_driver_desktop.cc +++ b/components/gcm_driver/gcm_driver_desktop.cc
@@ -820,7 +820,7 @@ time)); } -InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandler() { +InstanceIDHandler* GCMDriverDesktop::GetInstanceIDHandlerInternal() { return this; }
diff --git a/components/gcm_driver/gcm_driver_desktop.h b/components/gcm_driver/gcm_driver_desktop.h index 51f002e8..f42bd052 100644 --- a/components/gcm_driver/gcm_driver_desktop.h +++ b/components/gcm_driver/gcm_driver_desktop.h
@@ -61,7 +61,7 @@ const scoped_refptr<base::SequencedTaskRunner>& blocking_task_runner); ~GCMDriverDesktop() override; - // GCMDriver overrides: + // GCMDriver implementation: void Shutdown() override; void OnSignedIn() override; void OnSignedOut() override; @@ -86,27 +86,10 @@ base::Time GetLastTokenFetchTime() override; void SetLastTokenFetchTime(const base::Time& time) override; void WakeFromSuspendForHeartbeat(bool wake) override; - InstanceIDHandler* GetInstanceIDHandler() override; + InstanceIDHandler* GetInstanceIDHandlerInternal() override; void AddHeartbeatInterval(const std::string& scope, int interval_ms) override; void RemoveHeartbeatInterval(const std::string& scope) override; - // InstanceIDHandler overrides: - void GetToken(const std::string& app_id, - const std::string& authorized_entity, - const std::string& scope, - const std::map<std::string, std::string>& options, - const GetTokenCallback& callback) override; - void DeleteToken(const std::string& app_id, - const std::string& authorized_entity, - const std::string& scope, - const DeleteTokenCallback& callback) override; - void AddInstanceIDData(const std::string& app_id, - const std::string& instance_id, - const std::string& extra_data) override; - void RemoveInstanceIDData(const std::string& app_id) override; - void GetInstanceIDData(const std::string& app_id, - const GetInstanceIDDataCallback& callback) override; - // Exposed for testing purpose. bool gcm_enabled() const { return gcm_enabled_; } GCMChannelStatusSyncer* gcm_channel_status_syncer_for_testing() { @@ -126,6 +109,23 @@ GCMEncryptionProvider::DecryptionResult result) override; + // InstanceIDHandler implementation: + void GetToken(const std::string& app_id, + const std::string& authorized_entity, + const std::string& scope, + const std::map<std::string, std::string>& options, + const GetTokenCallback& callback) override; + void DeleteToken(const std::string& app_id, + const std::string& authorized_entity, + const std::string& scope, + const DeleteTokenCallback& callback) override; + void AddInstanceIDData(const std::string& app_id, + const std::string& instance_id, + const std::string& extra_data) override; + void RemoveInstanceIDData(const std::string& app_id) override; + void GetInstanceIDData(const std::string& app_id, + const GetInstanceIDDataCallback& callback) override; + private: class IOWorker;
diff --git a/components/gcm_driver/gcm_driver_desktop_unittest.cc b/components/gcm_driver/gcm_driver_desktop_unittest.cc index 1c57cf6..9037b12 100644 --- a/components/gcm_driver/gcm_driver_desktop_unittest.cc +++ b/components/gcm_driver/gcm_driver_desktop_unittest.cc
@@ -1177,6 +1177,10 @@ const std::string& authorized_entity, const std::string& scope, WaitToFinish wait_to_finish); + void AddInstanceIDData(const std::string& app_id, + const std::string& instance_id, + const std::string& extra_data); + void RemoveInstanceIDData(const std::string& app_id); std::string instance_id() const { return instance_id_; } std::string extra_data() const { return extra_data_; } @@ -1205,9 +1209,9 @@ WaitToFinish wait_to_finish) { base::RunLoop run_loop; set_async_operation_completed_callback(run_loop.QuitClosure()); - driver()->GetInstanceIDData(app_id, - base::Bind(&GCMDriverInstanceIDTest::GetInstanceIDDataCompleted, - base::Unretained(this))); + driver()->GetInstanceIDHandlerInternal()->GetInstanceIDData( + app_id, base::Bind(&GCMDriverInstanceIDTest::GetInstanceIDDataCompleted, + base::Unretained(this))); if (wait_to_finish == WAIT) run_loop.Run(); } @@ -1227,12 +1231,9 @@ base::RunLoop run_loop; set_async_operation_completed_callback(run_loop.QuitClosure()); std::map<std::string, std::string> options; - driver()->GetToken(app_id, - authorized_entity, - scope, - options, - base::Bind(&GCMDriverTest::RegisterCompleted, - base::Unretained(this))); + driver()->GetInstanceIDHandlerInternal()->GetToken( + app_id, authorized_entity, scope, options, + base::Bind(&GCMDriverTest::RegisterCompleted, base::Unretained(this))); if (wait_to_finish == WAIT) run_loop.Run(); } @@ -1243,25 +1244,34 @@ WaitToFinish wait_to_finish) { base::RunLoop run_loop; set_async_operation_completed_callback(run_loop.QuitClosure()); - driver()->DeleteToken(app_id, - authorized_entity, - scope, - base::Bind(&GCMDriverTest::UnregisterCompleted, - base::Unretained(this))); + driver()->GetInstanceIDHandlerInternal()->DeleteToken( + app_id, authorized_entity, scope, + base::Bind(&GCMDriverTest::UnregisterCompleted, base::Unretained(this))); if (wait_to_finish == WAIT) run_loop.Run(); } +void GCMDriverInstanceIDTest::AddInstanceIDData(const std::string& app_id, + const std::string& instance_id, + const std::string& extra_data) { + driver()->GetInstanceIDHandlerInternal()->AddInstanceIDData( + app_id, instance_id, extra_data); +} + +void GCMDriverInstanceIDTest::RemoveInstanceIDData(const std::string& app_id) { + driver()->GetInstanceIDHandlerInternal()->RemoveInstanceIDData(app_id); +} + TEST_F(GCMDriverInstanceIDTest, InstanceIDData) { GetReady(); - driver()->AddInstanceIDData(kTestAppID1, kInstanceID1, "Foo"); + AddInstanceIDData(kTestAppID1, kInstanceID1, "Foo"); GetInstanceID(kTestAppID1, GCMDriverTest::WAIT); EXPECT_EQ(kInstanceID1, instance_id()); EXPECT_EQ("Foo", extra_data()); - driver()->RemoveInstanceIDData(kTestAppID1); + RemoveInstanceIDData(kTestAppID1); GetInstanceID(kTestAppID1, GCMDriverTest::WAIT); EXPECT_TRUE(instance_id().empty()); @@ -1280,9 +1290,9 @@ AddAppHandlers(); // All operations are on hold until GCMClient is ready. - driver()->AddInstanceIDData(kTestAppID1, kInstanceID1, "Foo"); - driver()->AddInstanceIDData(kTestAppID2, kInstanceID2, "Bar"); - driver()->RemoveInstanceIDData(kTestAppID1); + AddInstanceIDData(kTestAppID1, kInstanceID1, "Foo"); + AddInstanceIDData(kTestAppID2, kInstanceID2, "Bar"); + RemoveInstanceIDData(kTestAppID1); GetInstanceID(kTestAppID2, GCMDriverTest::DO_NOT_WAIT); PumpIOLoop(); PumpUILoop();
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc index b52c37d..b62270b1 100644 --- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc +++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.cc
@@ -20,7 +20,8 @@ FakeGCMDriverForInstanceID::~FakeGCMDriverForInstanceID() { } -gcm::InstanceIDHandler* FakeGCMDriverForInstanceID::GetInstanceIDHandler() { +gcm::InstanceIDHandler* +FakeGCMDriverForInstanceID::GetInstanceIDHandlerInternal() { return this; }
diff --git a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h index 9d6b77a..c8e9ab7e 100644 --- a/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h +++ b/components/gcm_driver/instance_id/fake_gcm_driver_for_instance_id.h
@@ -22,7 +22,7 @@ ~FakeGCMDriverForInstanceID() override; // FakeGCMDriver overrides: - gcm::InstanceIDHandler* GetInstanceIDHandler() override; + gcm::InstanceIDHandler* GetInstanceIDHandlerInternal() override; // InstanceIDHandler overrides: void GetToken(const std::string& app_id,
diff --git a/components/gcm_driver/instance_id/instance_id.cc b/components/gcm_driver/instance_id/instance_id.cc index 9e875a02..d89c997e 100644 --- a/components/gcm_driver/instance_id/instance_id.cc +++ b/components/gcm_driver/instance_id/instance_id.cc
@@ -6,8 +6,10 @@ namespace instance_id { -InstanceID::InstanceID(const std::string& app_id) - : app_id_(app_id) { +InstanceID::InstanceID(const std::string& app_id, + gcm::InstanceIDHandler* handler) + : handler_(handler), app_id_(app_id) { + DCHECK(handler_); } InstanceID::~InstanceID() {
diff --git a/components/gcm_driver/instance_id/instance_id.h b/components/gcm_driver/instance_id/instance_id.h index 9adf0e5..fb69a11 100644 --- a/components/gcm_driver/instance_id/instance_id.h +++ b/components/gcm_driver/instance_id/instance_id.h
@@ -14,7 +14,7 @@ #include "base/time/time.h" namespace gcm { -class GCMDriver; +class InstanceIDHandler; } // namespace gcm namespace instance_id { @@ -56,10 +56,10 @@ // Creator. // |app_id|: identifies the application that uses the Instance ID. - // |gcm_driver|: driver to access the GCM functionalities needed to support - // Instance ID. + // |handler|: provides the GCM functionality needed to support Instance ID. + // Must outlive this class. static scoped_ptr<InstanceID> Create(const std::string& app_id, - gcm::GCMDriver* gcm_driver); + gcm::InstanceIDHandler* handler); virtual ~InstanceID(); @@ -106,11 +106,17 @@ std::string app_id() const { return app_id_; } protected: - explicit InstanceID(const std::string& app_id); + InstanceID(const std::string& app_id, gcm::InstanceIDHandler* handler); void NotifyTokenRefresh(bool update_id); + gcm::InstanceIDHandler* handler() const { return handler_; } + private: + // Owned by GCMProfileServiceFactory, which is a dependency of + // InstanceIDProfileServiceFactory, which owns this. + gcm::InstanceIDHandler* handler_; + std::string app_id_; TokenRefreshCallback token_refresh_callback_;
diff --git a/components/gcm_driver/instance_id/instance_id_android.cc b/components/gcm_driver/instance_id/instance_id_android.cc index 86542ca8..9611567 100644 --- a/components/gcm_driver/instance_id/instance_id_android.cc +++ b/components/gcm_driver/instance_id/instance_id_android.cc
@@ -11,13 +11,13 @@ // static scoped_ptr<InstanceID> InstanceID::Create(const std::string& app_id, - gcm::GCMDriver* gcm_driver) { - return make_scoped_ptr(new InstanceIDAndroid(app_id)); + gcm::InstanceIDHandler* handler) { + return make_scoped_ptr(new InstanceIDAndroid(app_id, handler)); } -InstanceIDAndroid::InstanceIDAndroid(const std::string& app_id) - : InstanceID(app_id) { -} +InstanceIDAndroid::InstanceIDAndroid(const std::string& app_id, + gcm::InstanceIDHandler* handler) + : InstanceID(app_id, handler) {} InstanceIDAndroid::~InstanceIDAndroid() { }
diff --git a/components/gcm_driver/instance_id/instance_id_android.h b/components/gcm_driver/instance_id/instance_id_android.h index 7a6babf6..de0ff62d 100644 --- a/components/gcm_driver/instance_id/instance_id_android.h +++ b/components/gcm_driver/instance_id/instance_id_android.h
@@ -19,7 +19,7 @@ // InstanceID implementation for Android. class InstanceIDAndroid : public InstanceID { public: - InstanceIDAndroid(const std::string& app_id); + InstanceIDAndroid(const std::string& app_id, gcm::InstanceIDHandler* handler); ~InstanceIDAndroid() override; // InstanceID:
diff --git a/components/gcm_driver/instance_id/instance_id_driver.cc b/components/gcm_driver/instance_id/instance_id_driver.cc index 9ec01c4..374be22 100644 --- a/components/gcm_driver/instance_id/instance_id_driver.cc +++ b/components/gcm_driver/instance_id/instance_id_driver.cc
@@ -6,6 +6,7 @@ #include "base/metrics/field_trial.h" #include "build/build_config.h" +#include "components/gcm_driver/gcm_driver.h" #include "components/gcm_driver/instance_id/instance_id.h" namespace instance_id { @@ -41,7 +42,9 @@ if (iter != instance_id_map_.end()) return iter->second.get(); - scoped_ptr<InstanceID> instance_id = InstanceID::Create(app_id, gcm_driver_); + gcm::InstanceIDHandler* handler = gcm_driver_->GetInstanceIDHandlerInternal(); + + scoped_ptr<InstanceID> instance_id = InstanceID::Create(app_id, handler); InstanceID* instance_id_ptr = instance_id.get(); instance_id_map_.insert(std::make_pair(app_id, std::move(instance_id))); return instance_id_ptr;
diff --git a/components/gcm_driver/instance_id/instance_id_driver.h b/components/gcm_driver/instance_id/instance_id_driver.h index b7df4fc..e006f0d3 100644 --- a/components/gcm_driver/instance_id/instance_id_driver.h +++ b/components/gcm_driver/instance_id/instance_id_driver.h
@@ -42,7 +42,10 @@ bool ExistsInstanceID(const std::string& app_id) const; private: - gcm::GCMDriver* gcm_driver_; // Not owned. + // Owned by GCMProfileServiceFactory, which is a dependency of + // InstanceIDProfileServiceFactory, which owns this. + gcm::GCMDriver* gcm_driver_; + std::map<std::string, scoped_ptr<InstanceID>> instance_id_map_; DISALLOW_COPY_AND_ASSIGN(InstanceIDDriver);
diff --git a/components/gcm_driver/instance_id/instance_id_impl.cc b/components/gcm_driver/instance_id/instance_id_impl.cc index 9a99a79d..ee1ea35 100644 --- a/components/gcm_driver/instance_id/instance_id_impl.cc +++ b/components/gcm_driver/instance_id/instance_id_impl.cc
@@ -13,7 +13,7 @@ #include "base/memory/scoped_ptr.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_number_conversions.h" -#include "components/gcm_driver/gcm_driver_desktop.h" +#include "components/gcm_driver/gcm_driver.h" #include "crypto/random.h" namespace instance_id { @@ -48,19 +48,16 @@ // static scoped_ptr<InstanceID> InstanceID::Create(const std::string& app_id, - gcm::GCMDriver* gcm_driver) { - return make_scoped_ptr(new InstanceIDImpl(app_id, gcm_driver)); + gcm::InstanceIDHandler* handler) { + return make_scoped_ptr(new InstanceIDImpl(app_id, handler)); } InstanceIDImpl::InstanceIDImpl(const std::string& app_id, - gcm::GCMDriver* gcm_driver) - : InstanceID(app_id), - gcm_driver_(gcm_driver), - weak_ptr_factory_(this) { - GetInstanceIDHandler()->GetInstanceIDData( - app_id, - base::Bind(&InstanceIDImpl::GetInstanceIDDataCompleted, - weak_ptr_factory_.GetWeakPtr())); + gcm::InstanceIDHandler* handler) + : InstanceID(app_id, handler), weak_ptr_factory_(this) { + handler->GetInstanceIDData( + app_id, base::Bind(&InstanceIDImpl::GetInstanceIDDataCompleted, + weak_ptr_factory_.GetWeakPtr())); } InstanceIDImpl::~InstanceIDImpl() { @@ -129,14 +126,9 @@ const GetTokenCallback& callback) { EnsureIDGenerated(); - GetInstanceIDHandler()->GetToken( - app_id(), - authorized_entity, - scope, - options, - base::Bind(&InstanceIDImpl::OnGetTokenCompleted, - weak_ptr_factory_.GetWeakPtr(), - callback)); + handler()->GetToken(app_id(), authorized_entity, scope, options, + base::Bind(&InstanceIDImpl::OnGetTokenCompleted, + weak_ptr_factory_.GetWeakPtr(), callback)); } void InstanceIDImpl::DeleteToken(const std::string& authorized_entity, @@ -168,13 +160,9 @@ return; } - GetInstanceIDHandler()->DeleteToken( - app_id(), - authorized_entity, - scope, - base::Bind(&InstanceIDImpl::OnDeleteTokenCompleted, - weak_ptr_factory_.GetWeakPtr(), - callback)); + handler()->DeleteToken(app_id(), authorized_entity, scope, + base::Bind(&InstanceIDImpl::OnDeleteTokenCompleted, + weak_ptr_factory_.GetWeakPtr(), callback)); } void InstanceIDImpl::DeleteID(const DeleteIDCallback& callback) { @@ -196,13 +184,11 @@ return; } - GetInstanceIDHandler()->DeleteAllTokensForApp( - app_id(), - base::Bind(&InstanceIDImpl::OnDeleteIDCompleted, - weak_ptr_factory_.GetWeakPtr(), - callback)); + handler()->DeleteAllTokensForApp( + app_id(), base::Bind(&InstanceIDImpl::OnDeleteIDCompleted, + weak_ptr_factory_.GetWeakPtr(), callback)); - GetInstanceIDHandler()->RemoveInstanceIDData(app_id()); + handler()->RemoveInstanceIDData(app_id()); id_.clear(); creation_time_ = base::Time(); @@ -245,12 +231,6 @@ delayed_task_controller_.SetReady(); } -gcm::InstanceIDHandler* InstanceIDImpl::GetInstanceIDHandler() const { - gcm::InstanceIDHandler* handler = gcm_driver_->GetInstanceIDHandler(); - DCHECK(handler); - return handler; -} - void InstanceIDImpl::EnsureIDGenerated() { if (!id_.empty()) return; @@ -281,10 +261,8 @@ creation_time_ = base::Time::Now(); // Save to the persistent store. - GetInstanceIDHandler()->AddInstanceIDData( - app_id(), - id_, - base::Int64ToString(creation_time_.ToInternalValue())); + handler()->AddInstanceIDData( + app_id(), id_, base::Int64ToString(creation_time_.ToInternalValue())); } } // namespace instance_id
diff --git a/components/gcm_driver/instance_id/instance_id_impl.h b/components/gcm_driver/instance_id/instance_id_impl.h index 1f8749e..dd4569a 100644 --- a/components/gcm_driver/instance_id/instance_id_impl.h +++ b/components/gcm_driver/instance_id/instance_id_impl.h
@@ -18,7 +18,6 @@ #include "components/gcm_driver/instance_id/instance_id.h" namespace gcm { -class GCMDriver; class InstanceIDHandler; } // namespace gcm @@ -27,7 +26,7 @@ // InstanceID implementation for desktop and iOS. class InstanceIDImpl : public InstanceID { public: - InstanceIDImpl(const std::string& app_id, gcm::GCMDriver* gcm_driver); + InstanceIDImpl(const std::string& app_id, gcm::InstanceIDHandler* handler); ~InstanceIDImpl() override; // InstanceID: @@ -43,8 +42,6 @@ void DeleteID(const DeleteIDCallback& callback) override; private: - gcm::InstanceIDHandler* GetInstanceIDHandler() const; - void EnsureIDGenerated(); void OnGetTokenCompleted(const GetTokenCallback& callback, @@ -69,8 +66,6 @@ const DeleteTokenCallback& callback); void DoDeleteID(const DeleteIDCallback& callback); - gcm::GCMDriver* gcm_driver_; // Not owned. - gcm::GCMDelayedTaskController delayed_task_controller_; // The generated Instance ID.
diff --git a/components/metrics/BUILD.gn b/components/metrics/BUILD.gn index 6130dd5..c49e4a35 100644 --- a/components/metrics/BUILD.gn +++ b/components/metrics/BUILD.gn
@@ -2,6 +2,11 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +declare_args() { + # Overrides os name in uma metrics log to "Blimp". + metrics_use_blimp = false +} + # GYP version: components/metrics.gypi:metrics source_set("metrics") { sources = [ @@ -347,5 +352,14 @@ if (is_chromeos) { deps += [ ":leak_detector_unit_tests" ] } + + # These are only used by the blimp team, which has entirely migrated to gn, + # so this logic is not replicated in the gyp file. + if (metrics_use_blimp) { + defines = [ + "OVERRIDE_OS_NAME_TO_BLIMP", + "ENABLE_REPORTING_BLIMP", + ] + } } # TODO(GYP): metrics_chromeos
diff --git a/components/metrics/metrics_log.cc b/components/metrics/metrics_log.cc index 97774127..f0bf415b 100644 --- a/components/metrics/metrics_log.cc +++ b/components/metrics/metrics_log.cc
@@ -325,9 +325,14 @@ hardware->set_dll_base(reinterpret_cast<uint64_t>(&__ImageBase)); #endif +#if defined(OVERRIDE_OS_NAME_TO_BLIMP) + os->set_name("Blimp"); +#else SystemProfileProto::OS* os = system_profile->mutable_os(); std::string os_name = base::SysInfo::OperatingSystemName(); os->set_name(os_name); +#endif + os->set_version(base::SysInfo::OperatingSystemVersion()); #if defined(OS_ANDROID) os->set_fingerprint(
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn index 15ec984..c5439551 100644 --- a/components/mus/ws/BUILD.gn +++ b/components/mus/ws/BUILD.gn
@@ -161,6 +161,7 @@ "window_coordinate_conversions_unittest.cc", "window_finder_unittest.cc", "window_manager_client_unittest.cc", + "window_tree_client_unittest.cc", "window_tree_unittest.cc", ]
diff --git a/components/mus/ws/access_policy.h b/components/mus/ws/access_policy.h index 8ba6ff6..be3fdc9 100644 --- a/components/mus/ws/access_policy.h +++ b/components/mus/ws/access_policy.h
@@ -14,6 +14,7 @@ namespace mus { namespace ws { +class AccessPolicyDelegate; class ServerWindow; // AccessPolicy is used by WindowTree to determine what the WindowTree is @@ -22,6 +23,9 @@ public: virtual ~AccessPolicy() {} + virtual void Init(ConnectionSpecificId connection_id, + AccessPolicyDelegate* delegate) = 0; + // Unless otherwise mentioned all arguments have been validated. That is the // |window| arguments are non-null unless otherwise stated (eg CanSetWindow() // is allowed to take a NULL window).
diff --git a/components/mus/ws/connection_manager.cc b/components/mus/ws/connection_manager.cc index 6096d40..9d63c61 100644 --- a/components/mus/ws/connection_manager.cc +++ b/components/mus/ws/connection_manager.cc
@@ -13,6 +13,7 @@ #include "components/mus/ws/operation.h" #include "components/mus/ws/server_window.h" #include "components/mus/ws/window_coordinate_conversions.h" +#include "components/mus/ws/window_manager_access_policy.h" #include "components/mus/ws/window_manager_factory_service.h" #include "components/mus/ws/window_manager_state.h" #include "components/mus/ws/window_tree.h" @@ -69,8 +70,10 @@ WindowTree* ConnectionManager::EmbedAtWindow( ServerWindow* root, const UserId& user_id, - mojom::WindowTreeClientPtr client) { - scoped_ptr<WindowTree> tree_ptr(new WindowTree(this, user_id, root)); + mojom::WindowTreeClientPtr client, + scoped_ptr<AccessPolicy> access_policy) { + scoped_ptr<WindowTree> tree_ptr( + new WindowTree(this, user_id, root, std::move(access_policy))); WindowTree* tree = tree_ptr.get(); mojom::WindowTreePtr window_tree_ptr; @@ -101,7 +104,8 @@ mojom::DisplayPtr display_ptr = display->ToMojomDisplay(); mojom::WindowTreeClientPtr tree_client; factory->CreateWindowManager(std::move(display_ptr), GetProxy(&tree_client)); - scoped_ptr<WindowTree> tree_ptr(new WindowTree(this, user_id, root)); + scoped_ptr<WindowTree> tree_ptr(new WindowTree( + this, user_id, root, make_scoped_ptr(new WindowManagerAccessPolicy))); WindowTree* tree = tree_ptr.get(); scoped_ptr<DefaultWindowTreeBinding> binding(new DefaultWindowTreeBinding( tree_ptr.get(), this, std::move(tree_client)));
diff --git a/components/mus/ws/connection_manager.h b/components/mus/ws/connection_manager.h index fc4b185e..b4a10b47 100644 --- a/components/mus/ws/connection_manager.h +++ b/components/mus/ws/connection_manager.h
@@ -31,6 +31,7 @@ namespace mus { namespace ws { +class AccessPolicy; class ConnectionManagerDelegate; class DisplayManager; class ServerWindow; @@ -71,7 +72,8 @@ // |transport_window_id| is valid. WindowTree* EmbedAtWindow(ServerWindow* root, const UserId& user_id, - mojom::WindowTreeClientPtr client); + mojom::WindowTreeClientPtr client, + scoped_ptr<AccessPolicy> access_policy); // Adds |tree_impl_ptr| to the set of known trees. Use DestroyTree() to // destroy the tree.
diff --git a/components/mus/ws/default_access_policy.cc b/components/mus/ws/default_access_policy.cc index 77e3e8b..e1f9ab2f 100644 --- a/components/mus/ws/default_access_policy.cc +++ b/components/mus/ws/default_access_policy.cc
@@ -10,12 +10,16 @@ namespace mus { namespace ws { -DefaultAccessPolicy::DefaultAccessPolicy(ConnectionSpecificId connection_id, - AccessPolicyDelegate* delegate) - : connection_id_(connection_id), delegate_(delegate) {} +DefaultAccessPolicy::DefaultAccessPolicy() {} DefaultAccessPolicy::~DefaultAccessPolicy() {} +void DefaultAccessPolicy::Init(ConnectionSpecificId connection_id, + AccessPolicyDelegate* delegate) { + connection_id_ = connection_id; + delegate_ = delegate; +} + bool DefaultAccessPolicy::CanRemoveWindowFromParent( const ServerWindow* window) const { if (!WasCreatedByThisConnection(window))
diff --git a/components/mus/ws/default_access_policy.h b/components/mus/ws/default_access_policy.h index 8c1c5d0b4..17b47bf7 100644 --- a/components/mus/ws/default_access_policy.h +++ b/components/mus/ws/default_access_policy.h
@@ -18,11 +18,12 @@ // AccessPolicy for all connections, except the window manager. class DefaultAccessPolicy : public AccessPolicy { public: - DefaultAccessPolicy(ConnectionSpecificId connection_id, - AccessPolicyDelegate* delegate); + DefaultAccessPolicy(); ~DefaultAccessPolicy() override; // AccessPolicy: + void Init(ConnectionSpecificId connection_id, + AccessPolicyDelegate* delegate) override; bool CanRemoveWindowFromParent(const ServerWindow* window) const override; bool CanAddWindow(const ServerWindow* parent, const ServerWindow* child) const override; @@ -61,8 +62,8 @@ private: bool WasCreatedByThisConnection(const ServerWindow* window) const; - const ConnectionSpecificId connection_id_; - AccessPolicyDelegate* delegate_; + ConnectionSpecificId connection_id_ = 0u; + AccessPolicyDelegate* delegate_ = nullptr; DISALLOW_COPY_AND_ASSIGN(DefaultAccessPolicy); };
diff --git a/components/mus/ws/display_binding.cc b/components/mus/ws/display_binding.cc index 31ce695..20e788c 100644 --- a/components/mus/ws/display_binding.cc +++ b/components/mus/ws/display_binding.cc
@@ -6,6 +6,7 @@ #include "components/mus/ws/connection_manager.h" #include "components/mus/ws/display.h" +#include "components/mus/ws/window_manager_access_policy.h" #include "components/mus/ws/window_tree.h" #include "mojo/shell/public/interfaces/connector.mojom.h" @@ -25,8 +26,9 @@ DisplayBindingImpl::~DisplayBindingImpl() {} WindowTree* DisplayBindingImpl::CreateWindowTree(ServerWindow* root) { - WindowTree* tree = - connection_manager_->EmbedAtWindow(root, user_id_, std::move(client_)); + WindowTree* tree = connection_manager_->EmbedAtWindow( + root, user_id_, std::move(client_), + make_scoped_ptr(new WindowManagerAccessPolicy)); tree->ConfigureWindowManager(); return tree; }
diff --git a/components/mus/ws/window_manager_access_policy.cc b/components/mus/ws/window_manager_access_policy.cc index 16a215b..8a4a820 100644 --- a/components/mus/ws/window_manager_access_policy.cc +++ b/components/mus/ws/window_manager_access_policy.cc
@@ -10,16 +10,16 @@ namespace mus { namespace ws { -// TODO(sky): document why this differs from default for each case. Maybe want -// to subclass DefaultAccessPolicy. - -WindowManagerAccessPolicy::WindowManagerAccessPolicy( - ConnectionSpecificId connection_id, - AccessPolicyDelegate* delegate) - : connection_id_(connection_id), delegate_(delegate) {} +WindowManagerAccessPolicy::WindowManagerAccessPolicy() {} WindowManagerAccessPolicy::~WindowManagerAccessPolicy() {} +void WindowManagerAccessPolicy::Init(ConnectionSpecificId connection_id, + AccessPolicyDelegate* delegate) { + connection_id_ = connection_id; + delegate_ = delegate; +} + bool WindowManagerAccessPolicy::CanRemoveWindowFromParent( const ServerWindow* window) const { return true;
diff --git a/components/mus/ws/window_manager_access_policy.h b/components/mus/ws/window_manager_access_policy.h index 7cb062e..bb9a1fff8 100644 --- a/components/mus/ws/window_manager_access_policy.h +++ b/components/mus/ws/window_manager_access_policy.h
@@ -17,11 +17,12 @@ class WindowManagerAccessPolicy : public AccessPolicy { public: - WindowManagerAccessPolicy(ConnectionSpecificId connection_id, - AccessPolicyDelegate* delegate); + WindowManagerAccessPolicy(); ~WindowManagerAccessPolicy() override; // AccessPolicy: + void Init(ConnectionSpecificId connection_id, + AccessPolicyDelegate* delegate) override; bool CanRemoveWindowFromParent(const ServerWindow* window) const override; bool CanAddWindow(const ServerWindow* parent, const ServerWindow* child) const override; @@ -60,8 +61,8 @@ private: bool IsWindowKnown(const ServerWindow* window) const; - const ConnectionSpecificId connection_id_; - AccessPolicyDelegate* delegate_; + ConnectionSpecificId connection_id_ = 0u; + AccessPolicyDelegate* delegate_ = nullptr; DISALLOW_COPY_AND_ASSIGN(WindowManagerAccessPolicy); };
diff --git a/components/mus/ws/window_tree.cc b/components/mus/ws/window_tree.cc index 8016ad8..d3954a1 100644 --- a/components/mus/ws/window_tree.cc +++ b/components/mus/ws/window_tree.cc
@@ -19,7 +19,6 @@ #include "components/mus/ws/platform_display.h" #include "components/mus/ws/server_window.h" #include "components/mus/ws/server_window_observer.h" -#include "components/mus/ws/window_manager_access_policy.h" #include "components/mus/ws/window_manager_state.h" #include "components/mus/ws/window_tree_binding.h" #include "mojo/converters/geometry/geometry_type_converters.h" @@ -67,20 +66,18 @@ WindowTree::WindowTree(ConnectionManager* connection_manager, const UserId& user_id, - ServerWindow* root) + ServerWindow* root, + scoped_ptr<AccessPolicy> access_policy) : connection_manager_(connection_manager), user_id_(user_id), id_(connection_manager_->GetAndAdvanceNextConnectionId()), next_window_id_(1), + access_policy_(std::move(access_policy)), event_ack_id_(0), window_manager_internal_(nullptr) { if (root) roots_.insert(root); - // TODO(sky): pass in type rather than inferring it. - if (root && root->id().connection_id == kInvalidConnectionId) - access_policy_.reset(new WindowManagerAccessPolicy(id_, this)); - else - access_policy_.reset(new DefaultAccessPolicy(id_, this)); + access_policy_->Init(id_, this); } WindowTree::~WindowTree() { @@ -279,8 +276,8 @@ PrepareForEmbed(window); // When embedding we don't know the user id of where the TreeClient came // from. Use an invalid id, which limits what the client is able to do. - connection_manager_->EmbedAtWindow(window, InvalidUserId(), - std::move(client)); + connection_manager_->EmbedAtWindow(window, InvalidUserId(), std::move(client), + make_scoped_ptr(new DefaultAccessPolicy)); return true; }
diff --git a/components/mus/ws/window_tree.h b/components/mus/ws/window_tree.h index f84a38db..d671892 100644 --- a/components/mus/ws/window_tree.h +++ b/components/mus/ws/window_tree.h
@@ -64,7 +64,8 @@ public: WindowTree(ConnectionManager* connection_manager, const UserId& user_id, - ServerWindow* root); + ServerWindow* root, + scoped_ptr<AccessPolicy> access_policy); ~WindowTree() override; void Init(scoped_ptr<WindowTreeBinding> binding, mojom::WindowTreePtr tree);
diff --git a/components/mus/ws/window_tree_client_unittest.cc b/components/mus/ws/window_tree_client_unittest.cc index f98da25a..ac55ee6 100644 --- a/components/mus/ws/window_tree_client_unittest.cc +++ b/components/mus/ws/window_tree_client_unittest.cc
@@ -57,8 +57,7 @@ void EmbedCallbackImpl(base::RunLoop* run_loop, bool* result_cache, - bool result, - ConnectionSpecificId connection_id) { + bool result) { *result_cache = result; run_loop->Quit(); } @@ -276,8 +275,7 @@ void OnEmbed(ConnectionSpecificId connection_id, WindowDataPtr root, mojom::WindowTreePtr tree, - Id focused_window_id, - uint32_t access_policy) override { + Id focused_window_id) override { // TODO(sky): add coverage of |focused_window_id|. ASSERT_TRUE(root); root_window_id_ = root->window_id; @@ -545,7 +543,6 @@ scoped_ptr<TestWindowTreeClientImpl> EstablishConnectionViaEmbedWithPolicyBitmask(WindowTree* owner, Id root_id, - uint32_t policy_bitmask, int* connection_id) { if (!EmbedUrl(connector(), owner, test_name(), root_id)) { ADD_FAILURE() << "Embed() failed"; @@ -697,7 +694,7 @@ // Verifies once Embed() has been invoked the parent connection can't see any // children. -TEST_F(WindowTreeClientTest, CantAccessChildrenOfEmbeddedWindow) { +TEST_F(WindowTreeClientTest, DISABLED_CantAccessChildrenOfEmbeddedWindow) { ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); @@ -746,7 +743,7 @@ } // Verifies once Embed() has been invoked the parent can't mutate the children. -TEST_F(WindowTreeClientTest, CantModifyChildrenOfEmbeddedWindow) { +TEST_F(WindowTreeClientTest, DISABLED_CantModifyChildrenOfEmbeddedWindow) { ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); @@ -823,7 +820,7 @@ } // Verifies adding to root sends right notifications. -TEST_F(WindowTreeClientTest, AddToRoot) { +TEST_F(WindowTreeClientTest, DISABLED_AddToRoot) { // Create the embed point now so that the ids line up. Id window_1_1 = wt_client1()->NewWindow(1); ASSERT_TRUE(window_1_1); @@ -849,7 +846,7 @@ } // Verifies HierarchyChanged is correctly sent for various adds/removes. -TEST_F(WindowTreeClientTest, WindowHierarchyChangedWindows) { +TEST_F(WindowTreeClientTest, DISABLED_WindowHierarchyChangedWindows) { // Create the embed point now so that the ids line up. Id window_1_1 = wt_client1()->NewWindow(1); // 1,2->1,11. @@ -1123,7 +1120,7 @@ } // Assertions for GetWindowTree. -TEST_F(WindowTreeClientTest, GetWindowTree) { +TEST_F(WindowTreeClientTest, DISABLED_GetWindowTree) { ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); @@ -1627,7 +1624,7 @@ } } -TEST_F(WindowTreeClientTest, OnEmbeddedAppDisconnected) { +TEST_F(WindowTreeClientTest, DISABLED_OnEmbeddedAppDisconnected) { // Create connection 2 and 3. ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); @@ -1707,7 +1704,7 @@ SingleChangeToDescription(*client2.tracker()->changes())); } -TEST_F(WindowTreeClientTest, EmbedFailsFromOtherConnection) { +TEST_F(WindowTreeClientTest, DISABLED_EmbedFailsFromOtherConnection) { ASSERT_NO_FATAL_FAILURE(EstablishSecondConnection(true)); Id window_1_1 = BuildWindowId(connection_id_1(), 1); @@ -1744,7 +1741,7 @@ EXPECT_EQ(std::string(), SingleChangeToDescription(*changes2())); } -TEST_F(WindowTreeClientTest, CantEmbedFromConnectionRoot) { +TEST_F(WindowTreeClientTest, DISABLED_CantEmbedFromConnectionRoot) { // Shouldn't be able to embed into the root. ASSERT_FALSE(EmbedUrl(connector(), wt1(), test_name(), root_window_id()));
diff --git a/components/mus/ws/window_tree_factory.cc b/components/mus/ws/window_tree_factory.cc index e805ab6..53f1bba 100644 --- a/components/mus/ws/window_tree_factory.cc +++ b/components/mus/ws/window_tree_factory.cc
@@ -5,6 +5,7 @@ #include "components/mus/ws/window_tree_factory.h" #include "components/mus/ws/connection_manager.h" +#include "components/mus/ws/default_access_policy.h" #include "components/mus/ws/window_tree.h" #include "components/mus/ws/window_tree_binding.h" @@ -26,7 +27,8 @@ mojo::InterfaceRequest<mojom::WindowTree> tree_request, mojom::WindowTreeClientPtr client) { scoped_ptr<ws::WindowTree> service( - new ws::WindowTree(connection_manager_, user_id_, nullptr)); + new ws::WindowTree(connection_manager_, user_id_, nullptr, + make_scoped_ptr(new DefaultAccessPolicy))); scoped_ptr<ws::DefaultWindowTreeBinding> binding( new ws::DefaultWindowTreeBinding(service.get(), connection_manager_, std::move(tree_request),
diff --git a/components/mus/ws/window_tree_unittest.cc b/components/mus/ws/window_tree_unittest.cc index bd55e09..440c378f 100644 --- a/components/mus/ws/window_tree_unittest.cc +++ b/components/mus/ws/window_tree_unittest.cc
@@ -16,6 +16,7 @@ #include "components/mus/surfaces/surfaces_state.h" #include "components/mus/ws/connection_manager.h" #include "components/mus/ws/connection_manager_delegate.h" +#include "components/mus/ws/default_access_policy.h" #include "components/mus/ws/display_binding.h" #include "components/mus/ws/ids.h" #include "components/mus/ws/platform_display.h" @@ -25,6 +26,7 @@ #include "components/mus/ws/server_window_surface_manager_test_api.h" #include "components/mus/ws/test_change_tracker.h" #include "components/mus/ws/test_utils.h" +#include "components/mus/ws/window_manager_access_policy.h" #include "components/mus/ws/window_tree.h" #include "components/mus/ws/window_tree_binding.h" #include "mojo/converters/geometry/geometry_type_converters.h" @@ -107,7 +109,8 @@ WindowTree* CreateWindowTree(ServerWindow* root) override { return connection_manager_->EmbedAtWindow( root, mojo::shell::mojom::kRootUserID, - mus::mojom::WindowTreeClientPtr()); + mus::mojom::WindowTreeClientPtr(), + make_scoped_ptr(new WindowManagerAccessPolicy)); } Display* display_; @@ -224,7 +227,8 @@ WindowTree* CreateNewTree(const UserId& user_id, TestWindowTreeBinding** binding) { WindowTree* tree = - new WindowTree(connection_manager_.get(), user_id, nullptr); + new WindowTree(connection_manager_.get(), user_id, nullptr, + make_scoped_ptr(new DefaultAccessPolicy)); *binding = new TestWindowTreeBinding; connection_manager_->AddTree(make_scoped_ptr(tree), make_scoped_ptr(*binding), nullptr);
diff --git a/components/offline_pages.gypi b/components/offline_pages.gypi index 6ba8033..3ff83d83 100644 --- a/components/offline_pages.gypi +++ b/components/offline_pages.gypi
@@ -22,6 +22,8 @@ ], 'sources': [ 'offline_pages/offline_page_archiver.h', + 'offline_pages/offline_page_bookmark_bridge.h', + 'offline_pages/offline_page_bookmark_bridge.cc', 'offline_pages/offline_page_feature.cc', 'offline_pages/offline_page_feature.h', 'offline_pages/offline_page_item.cc',
diff --git a/components/offline_pages/BUILD.gn b/components/offline_pages/BUILD.gn index 1c2efd1..84a6601ba 100644 --- a/components/offline_pages/BUILD.gn +++ b/components/offline_pages/BUILD.gn
@@ -10,6 +10,8 @@ static_library("offline_pages") { sources = [ "offline_page_archiver.h", + "offline_page_bookmark_bridge.cc", + "offline_page_bookmark_bridge.h", "offline_page_item.cc", "offline_page_item.h", "offline_page_metadata_store.cc",
diff --git a/components/offline_pages/offline_page_bookmark_bridge.cc b/components/offline_pages/offline_page_bookmark_bridge.cc new file mode 100644 index 0000000..5c23260 --- /dev/null +++ b/components/offline_pages/offline_page_bookmark_bridge.cc
@@ -0,0 +1,85 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/offline_pages/offline_page_bookmark_bridge.h" + +#include "base/bind.h" +#include "base/logging.h" +#include "base/strings/string_number_conversions.h" +#include "components/bookmarks/browser/base_bookmark_model_observer.h" +#include "components/bookmarks/browser/bookmark_node.h" +#include "components/offline_pages/offline_page_item.h" +#include "components/offline_pages/offline_page_model.h" + +namespace offline_pages { + +namespace { +void EmptyDeleteCallback(OfflinePageModel::DeletePageResult /* result */) {} +} + +OfflinePageBookmarkBridge::OfflinePageBookmarkBridge( + OfflinePageModel* model, + bookmarks::BookmarkModel* bookmark_model) + : offline_model_(model), bookmark_model_(bookmark_model) {} + +void OfflinePageBookmarkBridge::BookmarkModelChanged() {} + +void OfflinePageBookmarkBridge::BookmarkNodeAdded( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int index) { + DCHECK_EQ(model, bookmark_model_); + const bookmarks::BookmarkNode* node = parent->GetChild(index); + DCHECK(node); + ClientId client_id(BOOKMARK_NAMESPACE, base::Int64ToString(node->id())); + std::vector<int64_t> ids = offline_model_->GetOfflineIdsForClientId( + client_id, true /* include_deleted */); + + for (const auto& id : ids) + offline_model_->UndoPageDeletion(id); +} + +void OfflinePageBookmarkBridge::BookmarkNodeRemoved( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int old_index, + const bookmarks::BookmarkNode* node, + const std::set<GURL>& removed_urls) { + DCHECK_EQ(model, bookmark_model_); + ClientId client_id; + client_id.name_space = BOOKMARK_NAMESPACE; + client_id.id = base::Int64ToString(node->id()); + std::vector<int64_t> ids = + offline_model_->GetOfflineIdsForClientId(client_id); + offline_model_->MarkPagesForDeletion(ids, base::Bind(&EmptyDeleteCallback)); +} + +void OfflinePageBookmarkBridge::BookmarkNodeChanged( + bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) { + DCHECK_EQ(model, bookmark_model_); + // BookmarkNodeChanged could be triggered if title or URL gets changed. If + // the latter, we need to invalidate the offline copy. + ClientId client_id; + client_id.name_space = BOOKMARK_NAMESPACE; + client_id.id = base::Int64ToString(node->id()); + std::vector<int64_t> ids = + offline_model_->GetOfflineIdsForClientId(client_id); + std::vector<int64_t> ids_to_delete; + for (const auto& id : ids) { + const OfflinePageItem* page = offline_model_->GetPageByOfflineId(id); + if (page != nullptr && page->url != node->url()) + ids_to_delete.push_back(id); + } + offline_model_->DeletePagesByOfflineId(ids_to_delete, + base::Bind(&EmptyDeleteCallback)); +} + +void OfflinePageBookmarkBridge::BookmarkModelBeingDeleted( + bookmarks::BookmarkModel* model) { + DCHECK_EQ(model, bookmark_model_); + delete this; +} + +} // namespace offline_pages
diff --git a/components/offline_pages/offline_page_bookmark_bridge.h b/components/offline_pages/offline_page_bookmark_bridge.h new file mode 100644 index 0000000..75cbc7e --- /dev/null +++ b/components/offline_pages/offline_page_bookmark_bridge.h
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_BOOKMARK_BRIDGE_H_ +#define COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_BOOKMARK_BRIDGE_H_ + +#include <set> + +#include "components/bookmarks/browser/base_bookmark_model_observer.h" + +namespace offline_pages { + +class OfflinePageModel; + +// A bridge that adapts the bookmark observer to the OfflinePageModel +class OfflinePageBookmarkBridge : public bookmarks::BaseBookmarkModelObserver { + public: + // constructor, does not take ownership of either pointer. + OfflinePageBookmarkBridge(OfflinePageModel* model, + bookmarks::BookmarkModel* bookmark_model); + + // Overridden from bookmarks::BaseBookmarkModelObserver + void BookmarkModelChanged() override; + // Invoked from the destructor of the BookmarkModel. + void BookmarkModelBeingDeleted(bookmarks::BookmarkModel* model) override; + + void BookmarkNodeAdded(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int index) override; + void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* parent, + int old_index, + const bookmarks::BookmarkNode* node, + const std::set<GURL>& removed_urls) override; + void BookmarkNodeChanged(bookmarks::BookmarkModel* model, + const bookmarks::BookmarkNode* node) override; + + private: + // Not owned. + OfflinePageModel* offline_model_; + bookmarks::BookmarkModel* bookmark_model_; + DISALLOW_COPY_AND_ASSIGN(OfflinePageBookmarkBridge); +}; +} // namespace offline_pages +#endif // COMPONENTS_OFFLINE_PAGES_OFFLINE_PAGE_BOOKMARK_BRIDGE_H_
diff --git a/components/offline_pages/offline_page_model.cc b/components/offline_pages/offline_page_model.cc index 2ab8537..9316a976 100644 --- a/components/offline_pages/offline_page_model.cc +++ b/components/offline_pages/offline_page_model.cc
@@ -89,9 +89,6 @@ } } -void EmptyDeleteCallback(OfflinePageModel::DeletePageResult /* result */) { -} - void FindPagesMissingArchiveFile( const std::vector<std::pair<int64_t, base::FilePath>>& id_path_pairs, std::vector<int64_t>* ids_of_pages_missing_archive_file) { @@ -129,7 +126,6 @@ archives_dir_(archives_dir), is_loaded_(false), task_runner_(task_runner), - scoped_observer_(this), weak_ptr_factory_(this) { task_runner_->PostTaskAndReply( FROM_HERE, base::Bind(EnsureArchivesDirCreated, archives_dir_), @@ -140,14 +136,6 @@ OfflinePageModel::~OfflinePageModel() { } -void OfflinePageModel::Start(bookmarks::BookmarkModel* model) { - scoped_observer_.Add(model); -} - -void OfflinePageModel::Shutdown() { - scoped_observer_.RemoveAll(); -} - void OfflinePageModel::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -250,6 +238,19 @@ void OfflinePageModel::DeletePagesByOfflineId( const std::vector<int64_t>& offline_ids, const DeletePageCallback& callback) { + if (!is_loaded_) { + delayed_tasks_.push_back( + base::Bind(&OfflinePageModel::DoDeletePagesByOfflineId, + weak_ptr_factory_.GetWeakPtr(), offline_ids, callback)); + + return; + } + DoDeletePagesByOfflineId(offline_ids, callback); +} + +void OfflinePageModel::DoDeletePagesByOfflineId( + const std::vector<int64_t>& offline_ids, + const DeletePageCallback& callback) { DCHECK(is_loaded_); std::vector<base::FilePath> paths_to_delete; @@ -328,16 +329,17 @@ } const std::vector<int64_t> OfflinePageModel::GetOfflineIdsForClientId( - const ClientId& cid) const { + const ClientId& client_id, + bool include_deleted) const { std::vector<int64_t> results; + // We want only all pages, including those marked for deletion. // TODO(bburns): actually use an index rather than linear scan. - const std::vector<OfflinePageItem> offline_pages = GetAllPages(); - - for (size_t i = 0; i < offline_pages.size(); i++) { - if (offline_pages[i].client_id.name_space == cid.name_space && - offline_pages[i].client_id.id == cid.id) { - results.push_back(offline_pages[i].offline_id); + for (const auto& id_page_pair : offline_pages_) { + if (id_page_pair.second.client_id == client_id) { + if (include_deleted || !id_page_pair.second.IsMarkedForDeletion()) { + results.push_back(id_page_pair.second.offline_id); + } } } return results; @@ -559,68 +561,6 @@ weak_ptr_factory_.GetWeakPtr(), offline_page_item)); } -void OfflinePageModel::BookmarkModelChanged() { -} - -void OfflinePageModel::BookmarkNodeAdded(bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* parent, - int index) { - const bookmarks::BookmarkNode* node = parent->GetChild(index); - DCHECK(node); - ClientId client_id(BOOKMARK_NAMESPACE, base::Int64ToString(node->id())); - std::vector<int64_t> ids; - // In this case we want only all pages, including those marked for deletion. - for (const auto& id_page_pair : offline_pages_) { - if (id_page_pair.second.client_id == client_id) { - ids.push_back(id_page_pair.second.offline_id); - } - } - - for (size_t i = 0; i < ids.size(); i++) { - UndoPageDeletion(ids[i]); - } -} - -void OfflinePageModel::BookmarkNodeRemoved( - bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* parent, - int old_index, - const bookmarks::BookmarkNode* node, - const std::set<GURL>& removed_urls) { - ClientId cid; - cid.name_space = BOOKMARK_NAMESPACE; - cid.id = base::Int64ToString(node->id()); - std::vector<int64_t> ids = GetOfflineIdsForClientId(cid); - if (!is_loaded_) { - for (size_t i = 0; i < ids.size(); i++) { - delayed_tasks_.push_back( - base::Bind(&OfflinePageModel::MarkPageForDeletion, - weak_ptr_factory_.GetWeakPtr(), ids[i], - base::Bind(&EmptyDeleteCallback))); - } - return; - } - for (size_t i = 0; i < ids.size(); i++) { - MarkPageForDeletion(ids[i], base::Bind(&EmptyDeleteCallback)); - } -} - -void OfflinePageModel::BookmarkNodeChanged( - bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* node) { - // BookmarkNodeChanged could be triggered if title or URL gets changed. If - // the latter, we need to invalidate the offline copy. - ClientId cid; - cid.name_space = BOOKMARK_NAMESPACE; - cid.id = base::Int64ToString(node->id()); - std::vector<int64_t> ids = GetOfflineIdsForClientId(cid); - for (size_t i = 0; i < ids.size(); i++) { - auto iter = offline_pages_.find(ids[i]); - if (iter != offline_pages_.end() && iter->second.url != node->url()) - DeletePageByOfflineId(ids[i], DeletePageCallback()); - } -} - void OfflinePageModel::OnEnsureArchivesDirCreatedDone() { store_->Load(base::Bind(&OfflinePageModel::OnLoadDone, weak_ptr_factory_.GetWeakPtr())); @@ -824,4 +764,19 @@ return base::RandGenerator(std::numeric_limits<int64_t>::max()) + 1; } +void OfflinePageModel::MarkPagesForDeletion( + const std::vector<int64_t>& offline_ids, + const DeletePageCallback& callback) { + if (!is_loaded_) { + for (size_t i = 0; i < offline_ids.size(); i++) { + delayed_tasks_.push_back( + base::Bind(&OfflinePageModel::MarkPageForDeletion, + weak_ptr_factory_.GetWeakPtr(), offline_ids[i], callback)); + } + return; + } + for (const auto& id : offline_ids) { + MarkPageForDeletion(id, callback); + } +} } // namespace offline_pages
diff --git a/components/offline_pages/offline_page_model.h b/components/offline_pages/offline_page_model.h index bae72ab5..e26b538f 100644 --- a/components/offline_pages/offline_page_model.h +++ b/components/offline_pages/offline_page_model.h
@@ -19,9 +19,7 @@ #include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" -#include "base/scoped_observer.h" #include "base/supports_user_data.h" -#include "components/bookmarks/browser/base_bookmark_model_observer.h" #include "components/keyed_service/core/keyed_service.h" #include "components/offline_pages/offline_page_archiver.h" #include "components/offline_pages/offline_page_metadata_store.h" @@ -32,9 +30,6 @@ class Time; class TimeDelta; } -namespace bookmarks { -class BookmarkModel; -} namespace offline_pages { @@ -63,9 +58,7 @@ // // TODO(fgorski): Things to describe: // * how to cancel requests and what to expect -class OfflinePageModel : public KeyedService, - public base::SupportsUserData, - public bookmarks::BaseBookmarkModelObserver { +class OfflinePageModel : public KeyedService, public base::SupportsUserData { public: // Result of saving a page offline. // A Java counterpart will be generated for this enum. @@ -145,15 +138,6 @@ const scoped_refptr<base::SequencedTaskRunner>& task_runner); ~OfflinePageModel() override; - // Starts the OfflinePageModel and registers it as a BookmarkModelObserver. - // Calling this method is optional, but offline pages will not be deleted - // when the bookmark is deleted, i.e. due to sync, until this method is - // called. - void Start(bookmarks::BookmarkModel* model); - - // KeyedService implementation. - void Shutdown() override; - void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -175,16 +159,19 @@ void MarkPageForDeletion(int64_t offline_id, const DeletePageCallback& callback); - // Deletes an offline page related to the passed |offline_id|. Requires that - // the model is loaded. + // Deletes an offline page related to the passed |offline_id|. void DeletePageByOfflineId(int64_t offline_id, const DeletePageCallback& callback); - // Deletes offline pages related to the passed |offline_ids|. Requires that - // the model is loaded. + // Deletes offline pages related to the passed |offline_ids|. void DeletePagesByOfflineId(const std::vector<int64_t>& offline_ids, const DeletePageCallback& callback); + // Marks pages for deletion. Actual delete is asynchronous. + // Works even if the model isn't loaded. + void MarkPagesForDeletion(const std::vector<int64_t>& offline_ids, + const DeletePageCallback& callback); + // Wipes out all the data by deleting all saved files and clearing the store. void ClearAll(const base::Closure& callback); @@ -199,8 +186,11 @@ const std::vector<OfflinePageItem> GetPagesToCleanUp() const; // Gets all offline ids where the offline page has the matching client id + // If |include_deleted| is true, include pages that are marked for deletion + // but not actually deleted yet. Default is false. const std::vector<int64_t> GetOfflineIdsForClientId( - const ClientId& cid) const; + const ClientId& client_id, + bool include_deleted = false) const; // Returns an offline page associated with a specified |offline_id|. nullptr // is returned if not found. @@ -231,6 +221,10 @@ int64_t free_space_bytes, bool reporting_after_delete); + // Undo a deletion of a page. Pages that are marked for deletion can + // be restored prior to when they are actually deleted. + void UndoPageDeletion(int64_t offline_id); + // Methods for testing only: OfflinePageMetadataStore* GetStoreForTesting(); @@ -238,23 +232,9 @@ private: FRIEND_TEST_ALL_PREFIXES(OfflinePageModelTest, MarkPageForDeletion); - FRIEND_TEST_ALL_PREFIXES(OfflinePageModelTest, BookmarkNodeChangesUrl); typedef ScopedVector<OfflinePageArchiver> PendingArchivers; - // BaseBookmarkModelObserver: - void BookmarkModelChanged() override; - void BookmarkNodeAdded(bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* parent, - int index) override; - void BookmarkNodeRemoved(bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* parent, - int old_index, - const bookmarks::BookmarkNode* node, - const std::set<GURL>& removed_urls) override; - void BookmarkNodeChanged(bookmarks::BookmarkModel* model, - const bookmarks::BookmarkNode* node) override; - // Callback for ensuring archive directory is created. void OnEnsureArchivesDirCreatedDone(); @@ -302,7 +282,6 @@ void FinalizePageDeletion(); // Steps for undoing an offline page deletion. - void UndoPageDeletion(int64_t offline_id); void OnUndoOfflinePageDone(const OfflinePageItem& offline_page, bool success); // Callbacks for checking if offline pages are missing archive files. @@ -323,6 +302,10 @@ void CacheLoadedData(const std::vector<OfflinePageItem>& offline_pages); + // Actually does the work of deleting, requires the model is loaded. + void DoDeletePagesByOfflineId(const std::vector<int64_t>& offline_ids, + const DeletePageCallback& callback); + // Persistent store for offline page metadata. scoped_ptr<OfflinePageMetadataStore> store_; @@ -345,9 +328,6 @@ // Delayed tasks that should be invoked after the loading is done. std::vector<base::Closure> delayed_tasks_; - ScopedObserver<bookmarks::BookmarkModel, bookmarks::BookmarkModelObserver> - scoped_observer_; - base::WeakPtrFactory<OfflinePageModel> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(OfflinePageModel);
diff --git a/components/offline_pages/offline_page_model_unittest.cc b/components/offline_pages/offline_page_model_unittest.cc index 31b3723..ab3a315 100644 --- a/components/offline_pages/offline_page_model_unittest.cc +++ b/components/offline_pages/offline_page_model_unittest.cc
@@ -27,6 +27,7 @@ #include "components/bookmarks/browser/bookmark_undo_delegate.h" #include "components/bookmarks/browser/bookmark_undo_provider.h" #include "components/bookmarks/test/test_bookmark_client.h" +#include "components/offline_pages/offline_page_bookmark_bridge.h" #include "components/offline_pages/offline_page_feature.h" #include "components/offline_pages/offline_page_item.h" #include "components/offline_pages/offline_page_switches.h" @@ -830,7 +831,8 @@ void OfflinePageModelBookmarkChangeTest::SetUp() { OfflinePageModelTest::SetUp(); - model()->Start(bookmark_model_.get()); + bookmark_model_->AddObserver( + new OfflinePageBookmarkBridge(model(), bookmark_model())); } void OfflinePageModelBookmarkChangeTest::TearDown() {
diff --git a/components/test/data/dom_distiller/video_article.html b/components/test/data/dom_distiller/video_article.html index 1ca2ce9..7fac7ae 100644 --- a/components/test/data/dom_distiller/video_article.html +++ b/components/test/data/dom_distiller/video_article.html
@@ -7,7 +7,7 @@ <p>Lorem ipsum dolor sit amet, at alia aliquip vel. Quas inani labore an vel. Sed an nemore minimum accusata. Sint inermis tacimates est ex, ad movet iracundia mei, delicata iracundia laboramus ei eos. Illud principes complectitur te nec, ius alienum insolens ea, cu quo oratio omnesque. <video width="500" height="400" controls> - <source src="relative_video.webm" type="video/webm"> + <source src="relative_video.mp4" type="video/mp4"> <source src="http://www.google.com/absolute_video.ogg" type="video/ogg"> <track src="relative_track_en.vtt" kind="chapters" srclang="en" label="English"> <track src="http://www.google.com/absolute_track_fr.vtt" kind="chapters" srclang="fr" label="French">
diff --git a/components/test_runner/web_frame_test_proxy.h b/components/test_runner/web_frame_test_proxy.h index 363f5e37..1cbe11f 100644 --- a/components/test_runner/web_frame_test_proxy.h +++ b/components/test_runner/web_frame_test_proxy.h
@@ -167,10 +167,9 @@ return true; } - bool runModalBeforeUnloadDialog(bool is_reload, - const blink::WebString& message) override { + bool runModalBeforeUnloadDialog(bool is_reload) override { base_proxy_->GetDelegate()->PrintMessage( - std::string("CONFIRM NAVIGATION: ") + message.utf8().data() + "\n"); + std::string("CONFIRM NAVIGATION\n")); return !base_proxy_->GetInterfaces() ->TestRunner() ->ShouldStayOnPageAfterHandlingBeforeUnload();
diff --git a/components/wallpaper.gypi b/components/wallpaper.gypi index 350117b..1cafb7e 100644 --- a/components/wallpaper.gypi +++ b/components/wallpaper.gypi
@@ -23,6 +23,8 @@ ], 'sources': [ 'wallpaper/wallpaper_layout.h', + 'wallpaper/wallpaper_files_id.cc', + 'wallpaper/wallpaper_files_id.h', 'wallpaper/wallpaper_resizer.cc', 'wallpaper/wallpaper_resizer.h', 'wallpaper/wallpaper_resizer_observer.h',
diff --git a/components/wallpaper/BUILD.gn b/components/wallpaper/BUILD.gn index 04cc0a15..cfb688a88 100644 --- a/components/wallpaper/BUILD.gn +++ b/components/wallpaper/BUILD.gn
@@ -4,6 +4,8 @@ component("wallpaper") { sources = [ + "wallpaper_files_id.cc", + "wallpaper_files_id.h", "wallpaper_layout.h", "wallpaper_resizer.cc", "wallpaper_resizer.h",
diff --git a/components/wallpaper/wallpaper_files_id.cc b/components/wallpaper/wallpaper_files_id.cc new file mode 100644 index 0000000..fce3c80d --- /dev/null +++ b/components/wallpaper/wallpaper_files_id.cc
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/wallpaper/wallpaper_files_id.h" + +namespace wallpaper { + +WallpaperFilesId::WallpaperFilesId() {} + +WallpaperFilesId::WallpaperFilesId(const std::string& id) : id_(id) {} + +// static +WallpaperFilesId WallpaperFilesId::FromString(const std::string& id) { + return WallpaperFilesId(id); +} + +bool WallpaperFilesId::is_valid() const { + return !id_.empty(); +} + +} // namespace wallpaper
diff --git a/components/wallpaper/wallpaper_files_id.h b/components/wallpaper/wallpaper_files_id.h new file mode 100644 index 0000000..00fb1d0 --- /dev/null +++ b/components/wallpaper/wallpaper_files_id.h
@@ -0,0 +1,33 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLPAPER_WALLPAPER_FILES_ID_H_ +#define COMPONENTS_WALLPAPER_WALLPAPER_FILES_ID_H_ + +#include <string> + +#include "components/wallpaper/wallpaper_export.h" + +namespace wallpaper { + +class WALLPAPER_EXPORT WallpaperFilesId { + public: + WallpaperFilesId(); + + // This should be used for deserialization only. + static WallpaperFilesId FromString(const std::string& data); + + const std::string& id() const { return id_; } + + // Returns true if id is not empty. + bool is_valid() const; + + private: + WallpaperFilesId(const std::string& id); + std::string id_; +}; + +} // namespace wallpaper + +#endif // COMPONENTS_WALLPAPER_WALLPAPER_FILES_ID_H_
diff --git a/components/wallpaper/wallpaper_manager_base.cc b/components/wallpaper/wallpaper_manager_base.cc index 23c74ce..eabe252c 100644 --- a/components/wallpaper/wallpaper_manager_base.cc +++ b/components/wallpaper/wallpaper_manager_base.cc
@@ -28,7 +28,9 @@ #include "components/user_manager/user_image/user_image.h" #include "components/user_manager/user_manager.h" #include "components/user_manager/user_type.h" +#include "components/wallpaper/wallpaper_files_id.h" #include "components/wallpaper/wallpaper_layout.h" +#include "components/wallpaper/wallpaper_manager_base.h" #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/geometry/safe_integer_conversions.h" @@ -93,24 +95,26 @@ } } -// Creates all new custom wallpaper directories for |user_id_hash| if not exist. +// Creates all new custom wallpaper directories for |wallpaper_files_id| if not +// exist. // static -void EnsureCustomWallpaperDirectories(const std::string& user_id_hash) { +void EnsureCustomWallpaperDirectories( + const wallpaper::WallpaperFilesId& wallpaper_files_id) { base::FilePath dir; dir = WallpaperManagerBase::GetCustomWallpaperDir(kSmallWallpaperSubDir); - dir = dir.Append(user_id_hash); + dir = dir.Append(wallpaper_files_id.id()); if (!base::PathExists(dir)) base::CreateDirectory(dir); dir = WallpaperManagerBase::GetCustomWallpaperDir(kLargeWallpaperSubDir); - dir = dir.Append(user_id_hash); + dir = dir.Append(wallpaper_files_id.id()); if (!base::PathExists(dir)) base::CreateDirectory(dir); dir = WallpaperManagerBase::GetCustomWallpaperDir(kOriginalWallpaperSubDir); - dir = dir.Append(user_id_hash); + dir = dir.Append(wallpaper_files_id.id()); if (!base::PathExists(dir)) base::CreateDirectory(dir); dir = WallpaperManagerBase::GetCustomWallpaperDir(kThumbnailWallpaperSubDir); - dir = dir.Append(user_id_hash); + dir = dir.Append(wallpaper_files_id.id()); if (!base::PathExists(dir)) base::CreateDirectory(dir); } @@ -464,10 +468,10 @@ // static base::FilePath WallpaperManagerBase::GetCustomWallpaperPath( const char* sub_dir, - const std::string& user_id_hash, + const wallpaper::WallpaperFilesId& wallpaper_files_id, const std::string& file) { base::FilePath custom_wallpaper_path = GetCustomWallpaperDir(sub_dir); - return custom_wallpaper_path.Append(user_id_hash).Append(file); + return custom_wallpaper_path.Append(wallpaper_files_id.id()).Append(file); } WallpaperManagerBase::WallpaperManagerBase() @@ -486,25 +490,25 @@ // static void WallpaperManagerBase::SaveCustomWallpaper( - const std::string& user_id_hash, + const WallpaperFilesId& wallpaper_files_id, const base::FilePath& original_path, WallpaperLayout layout, scoped_ptr<gfx::ImageSkia> image) { - base::DeleteFile( - GetCustomWallpaperDir(kOriginalWallpaperSubDir).Append(user_id_hash), - true /* recursive */); - base::DeleteFile( - GetCustomWallpaperDir(kSmallWallpaperSubDir).Append(user_id_hash), - true /* recursive */); - base::DeleteFile( - GetCustomWallpaperDir(kLargeWallpaperSubDir).Append(user_id_hash), - true /* recursive */); - EnsureCustomWallpaperDirectories(user_id_hash); + base::DeleteFile(GetCustomWallpaperDir(kOriginalWallpaperSubDir) + .Append(wallpaper_files_id.id()), + true /* recursive */); + base::DeleteFile(GetCustomWallpaperDir(kSmallWallpaperSubDir) + .Append(wallpaper_files_id.id()), + true /* recursive */); + base::DeleteFile(GetCustomWallpaperDir(kLargeWallpaperSubDir) + .Append(wallpaper_files_id.id()), + true /* recursive */); + EnsureCustomWallpaperDirectories(wallpaper_files_id); std::string file_name = original_path.BaseName().value(); - base::FilePath small_wallpaper_path = - GetCustomWallpaperPath(kSmallWallpaperSubDir, user_id_hash, file_name); - base::FilePath large_wallpaper_path = - GetCustomWallpaperPath(kLargeWallpaperSubDir, user_id_hash, file_name); + base::FilePath small_wallpaper_path = GetCustomWallpaperPath( + kSmallWallpaperSubDir, wallpaper_files_id, file_name); + base::FilePath large_wallpaper_path = GetCustomWallpaperPath( + kLargeWallpaperSubDir, wallpaper_files_id, file_name); // Re-encode orginal file to jpeg format and saves the result in case that // resized wallpaper is not generated (i.e. chrome shutdown before resized @@ -522,25 +526,29 @@ // static void WallpaperManagerBase::MoveCustomWallpapersOnWorker( const AccountId& account_id, - const std::string& user_id_hash, + const WallpaperFilesId& wallpaper_files_id, const scoped_refptr<base::SingleThreadTaskRunner>& reply_task_runner, base::WeakPtr<WallpaperManagerBase> weak_ptr) { + const std::string& temporary_wallpaper_dir = + account_id.GetUserEmail(); // Migrated if (MoveCustomWallpaperDirectory(kOriginalWallpaperSubDir, - account_id.GetUserEmail(), user_id_hash)) { + temporary_wallpaper_dir, + wallpaper_files_id.id())) { // Consider success if the original wallpaper is moved to the new directory. // Original wallpaper is the fallback if the correct resolution wallpaper // can not be found. reply_task_runner->PostTask( FROM_HERE, base::Bind(&WallpaperManagerBase::MoveCustomWallpapersSuccess, weak_ptr, - account_id, user_id_hash)); + account_id, wallpaper_files_id)); } - MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, account_id.GetUserEmail(), - user_id_hash); - MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, account_id.GetUserEmail(), - user_id_hash); + MoveCustomWallpaperDirectory(kLargeWallpaperSubDir, temporary_wallpaper_dir, + wallpaper_files_id.id()); + MoveCustomWallpaperDirectory(kSmallWallpaperSubDir, temporary_wallpaper_dir, + wallpaper_files_id.id()); MoveCustomWallpaperDirectory(kThumbnailWallpaperSubDir, - account_id.GetUserEmail(), user_id_hash); + temporary_wallpaper_dir, + wallpaper_files_id.id()); } // static @@ -564,11 +572,13 @@ if (!base::PathExists(valid_path)) { // Falls back to custom wallpaper that uses AccountId as part of its file // path. - // Note that account id is used instead of user_id_hash here. + // Note that account id is used instead of wallpaper_files_id here. LOG(ERROR) << "Failed to load custom wallpaper from its original fallback " "file path: " << valid_path.value(); - valid_path = GetCustomWallpaperPath( - kOriginalWallpaperSubDir, account_id.GetUserEmail(), info.location); + const std::string& old_path = account_id.GetUserEmail(); // Migrated + valid_path = GetCustomWallpaperPath(kOriginalWallpaperSubDir, + WallpaperFilesId::FromString(old_path), + info.location); } if (!base::PathExists(valid_path)) { @@ -830,13 +840,15 @@ void WallpaperManagerBase::MoveCustomWallpapersSuccess( const AccountId& account_id, - const std::string& user_id_hash) { + const wallpaper::WallpaperFilesId& wallpaper_files_id) { WallpaperInfo info; GetUserWallpaperInfo(account_id, &info); if (info.type == user_manager::User::CUSTOMIZED) { - // New file field should include user id hash in addition to file name. - // This is needed because at login screen, user id hash is not available. - info.location = base::FilePath(user_id_hash).Append(info.location).value(); + // New file field should include user wallpaper_files_id in addition to + // file name. This is needed because at login screen, wallpaper_files_id + // is not available. + info.location = + base::FilePath(wallpaper_files_id.id()).Append(info.location).value(); bool is_persistent = !user_manager::UserManager::Get()->IsUserNonCryptohomeDataEphemeral( account_id); @@ -851,10 +863,10 @@ if (logged_in_user) { task_runner_->PostTask( FROM_HERE, - base::Bind( - &WallpaperManagerBase::MoveCustomWallpapersOnWorker, - logged_in_user->GetAccountId(), logged_in_user->username_hash(), - base::ThreadTaskRunnerHandle::Get(), weak_factory_.GetWeakPtr())); + base::Bind(&WallpaperManagerBase::MoveCustomWallpapersOnWorker, + logged_in_user->GetAccountId(), GetFilesId(*logged_in_user), + base::ThreadTaskRunnerHandle::Get(), + weak_factory_.GetWeakPtr())); } }
diff --git a/components/wallpaper/wallpaper_manager_base.h b/components/wallpaper/wallpaper_manager_base.h index 500ec7f..80aa6b1 100644 --- a/components/wallpaper/wallpaper_manager_base.h +++ b/components/wallpaper/wallpaper_manager_base.h
@@ -68,7 +68,7 @@ ~WallpaperInfo(); // Either file name of migrated wallpaper including first directory level - // (corresponding to user id hash) or online wallpaper URL. + // (corresponding to user wallpaper_files_id) or online wallpaper URL. std::string location; WallpaperLayout layout; user_manager::User::WallpaperType type; @@ -119,6 +119,8 @@ // A dictionary pref that maps usernames to wallpaper properties. WALLPAPER_EXPORT extern const char kUserWallpapersProperties[]; +class WallpaperFilesId; + // This singleton class maintains wallpapers for users. class WALLPAPER_EXPORT WallpaperManagerBase { public: @@ -224,11 +226,13 @@ int preferred_height, gfx::ImageSkia* output_skia); - // Returns custom wallpaper path. Append |sub_dir|, |user_id_hash| and |file| + // Returns custom wallpaper path. Append |sub_dir|, |wallpaper_files_id| and + // |file| // to custom wallpaper directory. - static base::FilePath GetCustomWallpaperPath(const char* sub_dir, - const std::string& user_id_hash, - const std::string& file); + static base::FilePath GetCustomWallpaperPath( + const char* sub_dir, + const WallpaperFilesId& wallpaper_files_id, + const std::string& file); WallpaperManagerBase(); virtual ~WallpaperManagerBase(); @@ -260,7 +264,7 @@ // local state preferences. If |update_wallpaper| is false, don't change // wallpaper but only update cache. virtual void SetCustomWallpaper(const AccountId& account_id, - const std::string& user_id_hash, + const WallpaperFilesId& wallpaper_files_id, const std::string& file, WallpaperLayout layout, user_manager::User::WallpaperType type, @@ -342,6 +346,9 @@ // Returns queue size. virtual size_t GetPendingListSizeForTesting() const = 0; + // Ruturns files identifier for the user. + virtual WallpaperFilesId GetFilesId(const user_manager::User& user) const = 0; + protected: friend class TestApi; friend class WallpaperManagerBrowserTest; @@ -356,16 +363,16 @@ // Saves original custom wallpaper to |path| (absolute path) on filesystem // and starts resizing operation of the custom wallpaper if necessary. - static void SaveCustomWallpaper(const std::string& user_id_hash, + static void SaveCustomWallpaper(const WallpaperFilesId& wallpaper_files_id, const base::FilePath& path, WallpaperLayout layout, scoped_ptr<gfx::ImageSkia> image); - // Moves custom wallpapers from user email directory to |user_id_hash| - // directory. + // Moves custom wallpapers from user email directory to + // |wallpaper_files_id| directory. static void MoveCustomWallpapersOnWorker( const AccountId& account_id, - const std::string& user_id_hash, + const WallpaperFilesId& wallpaper_files_id, const scoped_refptr<base::SingleThreadTaskRunner>& reply_task_runner, base::WeakPtr<WallpaperManagerBase> weak_ptr); @@ -445,14 +452,14 @@ // Called when the original custom wallpaper is moved to the new place. // Updates the corresponding user wallpaper info. - virtual void MoveCustomWallpapersSuccess(const AccountId& account_id, - const std::string& user_id_hash); + virtual void MoveCustomWallpapersSuccess( + const AccountId& account_id, + const wallpaper::WallpaperFilesId& wallpaper_files_id); // Moves custom wallpaper to a new place. Email address was used as directory // name in the old system, this is not safe. New directory system uses - // user_id_hash instead of account_id. This must be called after user_id_hash - // is - // ready. + // wallpaper_files_id instead of e-mail. This must be called after + // wallpaper_files_id is ready. virtual void MoveLoggedInUserCustomWallpaper(); // Gets wallpaper information of |account_id| from Local State or memory.
diff --git a/components/web_contents_delegate_android/OWNERS b/components/web_contents_delegate_android/OWNERS index 561bf2779..48569ad0 100644 --- a/components/web_contents_delegate_android/OWNERS +++ b/components/web_contents_delegate_android/OWNERS
@@ -1,2 +1,2 @@ -mnaganov@chromium.org +sievers@chromium.org tedchoc@chromium.org
diff --git a/content/browser/appcache/appcache_service_impl.cc b/content/browser/appcache/appcache_service_impl.cc index 2fc5d94..537ca8e8 100644 --- a/content/browser/appcache/appcache_service_impl.cc +++ b/content/browser/appcache/appcache_service_impl.cc
@@ -412,9 +412,8 @@ AppCacheServiceImpl::~AppCacheServiceImpl() { DCHECK(backends_.empty()); - std::for_each(pending_helpers_.begin(), - pending_helpers_.end(), - std::mem_fun(&AsyncHelper::Cancel)); + for (auto* helper : pending_helpers_) + helper->Cancel(); STLDeleteElements(&pending_helpers_); if (quota_client_) quota_client_->NotifyAppCacheDestroyed();
diff --git a/content/browser/appcache/appcache_storage_impl.cc b/content/browser/appcache/appcache_storage_impl.cc index 2a255ed..fbb72905 100644 --- a/content/browser/appcache/appcache_storage_impl.cc +++ b/content/browser/appcache/appcache_storage_impl.cc
@@ -1419,12 +1419,10 @@ } AppCacheStorageImpl::~AppCacheStorageImpl() { - std::for_each(pending_quota_queries_.begin(), - pending_quota_queries_.end(), - std::mem_fun(&DatabaseTask::CancelCompletion)); - std::for_each(scheduled_database_tasks_.begin(), - scheduled_database_tasks_.end(), - std::mem_fun(&DatabaseTask::CancelCompletion)); + for (auto* task : pending_quota_queries_) + task->CancelCompletion(); + for (auto* task : scheduled_database_tasks_) + task->CancelCompletion(); if (database_ && !db_thread_->PostTask(
diff --git a/content/browser/cache_storage/cache_storage.cc b/content/browser/cache_storage/cache_storage.cc index c14a923..705894a4 100644 --- a/content/browser/cache_storage/cache_storage.cc +++ b/content/browser/cache_storage/cache_storage.cc
@@ -484,6 +484,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + CacheAndErrorCallback pending_callback = base::Bind(&CacheStorage::PendingCacheAndErrorCallback, weak_factory_.GetWeakPtr(), callback); @@ -499,6 +503,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + BoolAndErrorCallback pending_callback = base::Bind(&CacheStorage::PendingBoolAndErrorCallback, weak_factory_.GetWeakPtr(), callback); @@ -514,6 +522,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + BoolAndErrorCallback pending_callback = base::Bind(&CacheStorage::PendingBoolAndErrorCallback, weak_factory_.GetWeakPtr(), callback); @@ -528,6 +540,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + StringsAndErrorCallback pending_callback = base::Bind(&CacheStorage::PendingStringsAndErrorCallback, weak_factory_.GetWeakPtr(), callback); @@ -545,6 +561,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + CacheStorageCache::ResponseCallback pending_callback = base::Bind(&CacheStorage::PendingResponseCallback, weak_factory_.GetWeakPtr(), callback); @@ -561,6 +581,10 @@ if (!initialized_) LazyInit(); + quota_manager_proxy_->NotifyStorageAccessed( + storage::QuotaClient::kServiceWorkerCache, origin_, + storage::kStorageTypeTemporary); + CacheStorageCache::ResponseCallback pending_callback = base::Bind(&CacheStorage::PendingResponseCallback, weak_factory_.GetWeakPtr(), callback);
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc index 1f6411a..2551747c 100644 --- a/content/browser/cache_storage/cache_storage_manager_unittest.cc +++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -313,6 +313,15 @@ return callback_usage_; } + int64_t Size(const GURL& origin) { + base::RunLoop loop; + CacheStorage* cache_storage = CacheStorageForOrigin(origin); + cache_storage->Size(base::Bind(&CacheStorageManagerTest::UsageCallback, + base::Unretained(this), &loop)); + loop.Run(); + return callback_usage_; + } + protected: // Temporary directory must be allocated first so as to be destroyed last. base::ScopedTempDir temp_dir_; @@ -707,6 +716,56 @@ EXPECT_FALSE(base::DirectoryExists(unreferenced_path)); } +TEST_P(CacheStorageManagerTestP, OpenCacheStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_TRUE(Open(origin1_, "foo")); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, HasStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_FALSE(Has(origin1_, "foo")); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, DeleteStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_FALSE(Delete(origin1_, "foo")); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, KeysStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_TRUE(Keys(origin1_)); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, MatchCacheStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_FALSE(StorageMatch(origin1_, "foo", GURL("http://example.com/foo"))); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, MatchAllCachesStorageAccessed) { + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); + EXPECT_FALSE(StorageMatchAll(origin1_, GURL("http://example.com/foo"))); + EXPECT_EQ(1, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, SizeStorageAccessed) { + EXPECT_EQ(0, Size(origin1_)); + // Size is not part of the web API and should not notify the quota manager of + // an access. + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); +} + +TEST_P(CacheStorageManagerTestP, SizeThenCloseStorageAccessed) { + EXPECT_EQ(0, GetSizeThenCloseAllCaches(origin1_)); + // GetSizeThenCloseAllCaches is not part of the web API and should not notify + // the quota manager of an access. + EXPECT_EQ(0, quota_manager_proxy_->notify_storage_accessed_count()); +} + class CacheStorageMigrationTest : public CacheStorageManagerTest { protected: CacheStorageMigrationTest() : cache1_("foo"), cache2_("bar") {}
diff --git a/content/browser/cache_storage/cache_storage_unittest.cc b/content/browser/cache_storage/cache_storage_unittest.cc index f2d1e9a..9c0081b 100644 --- a/content/browser/cache_storage/cache_storage_unittest.cc +++ b/content/browser/cache_storage/cache_storage_unittest.cc
@@ -7,9 +7,12 @@ #include "base/bind.h" #include "base/callback.h" #include "base/files/scoped_temp_dir.h" +#include "base/memory/ref_counted.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/thread_task_runner_handle.h" +#include "content/browser/quota/mock_quota_manager_proxy.h" +#include "content/public/test/mock_special_storage_policy.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/url_request/url_request_context_getter.h" #include "storage/browser/quota/quota_manager_proxy.h" @@ -23,12 +26,14 @@ class TestCacheStorage : public CacheStorage { public: - explicit TestCacheStorage(const base::FilePath& file_path) + TestCacheStorage( + const base::FilePath& file_path, + scoped_refptr<storage::QuotaManagerProxy> quota_manager_proxy) : CacheStorage(file_path, false /* memory_only */, base::ThreadTaskRunnerHandle::Get().get(), scoped_refptr<net::URLRequestContextGetter>(), - scoped_refptr<storage::QuotaManagerProxy>(), + quota_manager_proxy, base::WeakPtr<storage::BlobStorageContext>(), GURL(kOrigin)), delay_preserved_cache_callback_(false) {} @@ -67,7 +72,17 @@ void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - test_cache_storage_.reset(new TestCacheStorage(temp_dir_.path())); + + quota_policy_ = new MockSpecialStoragePolicy; + mock_quota_manager_ = new MockQuotaManager( + false /* is incognito */, temp_dir_.path(), + base::ThreadTaskRunnerHandle::Get().get(), + base::ThreadTaskRunnerHandle::Get().get(), quota_policy_.get()); + quota_manager_proxy_ = new MockQuotaManagerProxy( + mock_quota_manager_.get(), base::ThreadTaskRunnerHandle::Get().get()); + + test_cache_storage_.reset( + new TestCacheStorage(temp_dir_.path(), quota_manager_proxy_)); } bool OpenCache(const std::string& cache_name) { @@ -90,6 +105,9 @@ base::ScopedTempDir temp_dir_; TestBrowserThreadBundle browser_thread_bundle_; + scoped_refptr<MockSpecialStoragePolicy> quota_policy_; + scoped_refptr<MockQuotaManager> mock_quota_manager_; + scoped_refptr<MockQuotaManagerProxy> quota_manager_proxy_; scoped_ptr<TestCacheStorage> test_cache_storage_; scoped_refptr<CacheStorageCache> callback_cache_;
diff --git a/content/browser/compositor/delegated_frame_host.cc b/content/browser/compositor/delegated_frame_host.cc index 15288bf..e6ab7bb 100644 --- a/content/browser/compositor/delegated_frame_host.cc +++ b/content/browser/compositor/delegated_frame_host.cc
@@ -69,6 +69,7 @@ last_output_surface_id_(0), pending_delegated_ack_count_(0), skipped_frames_(false), + background_color_(SK_ColorRED), current_scale_factor_(1.f), can_lock_compositor_(YES_CAN_LOCK), delegated_frame_evictor_(new DelegatedFrameEvictor(this)), @@ -256,6 +257,45 @@ !client_->DelegatedFrameHostIsVisible()) EvictDelegatedFrame(); MaybeCreateResizeLock(); + UpdateGutters(); +} + +void DelegatedFrameHost::UpdateGutters() { + if (surface_id_.is_null()) { + right_gutter_.reset(); + bottom_gutter_.reset(); + return; + } + if (current_frame_size_in_dip_.width() < + client_->DelegatedFrameHostDesiredSizeInDIP().width()) { + right_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); + right_gutter_->SetColor(background_color_); + int width = client_->DelegatedFrameHostDesiredSizeInDIP().width() - + current_frame_size_in_dip_.width(); + // The right gutter also includes the bottom-right corner, if necessary. + int height = client_->DelegatedFrameHostDesiredSizeInDIP().height(); + right_gutter_->SetBounds( + gfx::Rect(current_frame_size_in_dip_.width(), 0, width, height)); + + client_->DelegatedFrameHostGetLayer()->Add(right_gutter_.get()); + } else { + right_gutter_.reset(); + } + + if (current_frame_size_in_dip_.height() < + client_->DelegatedFrameHostDesiredSizeInDIP().height()) { + bottom_gutter_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR)); + bottom_gutter_->SetColor(background_color_); + int width = current_frame_size_in_dip_.width(); + int height = client_->DelegatedFrameHostDesiredSizeInDIP().height() - + current_frame_size_in_dip_.height(); + bottom_gutter_->SetBounds( + gfx::Rect(0, current_frame_size_in_dip_.height(), width, height)); + client_->DelegatedFrameHostGetLayer()->Add(bottom_gutter_.get()); + + } else { + bottom_gutter_.reset(); + } } gfx::Size DelegatedFrameHost::GetRequestedRendererSize() const { @@ -403,6 +443,8 @@ bool skip_frame = false; pending_delegated_ack_count_++; + background_color_ = frame->metadata.root_background_color; + if (frame_size.IsEmpty()) { DCHECK(frame_data->resource_list.empty()); EvictDelegatedFrame(); @@ -450,6 +492,8 @@ current_frame_size_in_dip_ = frame_size_in_dip; CheckResizeLock(); + UpdateGutters(); + if (!damage_rect_in_dip.IsEmpty()) client_->DelegatedFrameHostGetLayer()->OnDelegatedFrameDamage( damage_rect_in_dip); @@ -527,6 +571,7 @@ surface_id_ = cc::SurfaceId(); } delegated_frame_evictor_->DiscardedFrame(); + UpdateGutters(); } // static
diff --git a/content/browser/compositor/delegated_frame_host.h b/content/browser/compositor/delegated_frame_host.h index 5cb9301..e2f7ee5 100644 --- a/content/browser/compositor/delegated_frame_host.h +++ b/content/browser/compositor/delegated_frame_host.h
@@ -202,6 +202,10 @@ // Checks if the resize lock can be released because we received an new frame. void CheckResizeLock(); + // Update the layers for the resize gutters to the right and bottom of the + // surface layer. + void UpdateGutters(); + // Called after async thumbnailer task completes. Scales and crops the result // of the copy. static void CopyFromCompositingSurfaceHasResultForVideo( @@ -257,6 +261,12 @@ bool skipped_frames_; std::vector<ui::LatencyInfo> skipped_latency_info_list_; + scoped_ptr<ui::Layer> right_gutter_; + scoped_ptr<ui::Layer> bottom_gutter_; + + // This is the last root background color from a swapped frame. + SkColor background_color_; + // State for rendering into a Surface. scoped_ptr<cc::SurfaceIdAllocator> id_allocator_; scoped_ptr<cc::SurfaceFactory> surface_factory_;
diff --git a/content/browser/frame_host/frame_tree_node.cc b/content/browser/frame_host/frame_tree_node.cc index f9b793f..3a2f122 100644 --- a/content/browser/frame_host/frame_tree_node.cc +++ b/content/browser/frame_host/frame_tree_node.cc
@@ -14,6 +14,7 @@ #include "content/browser/frame_host/navigation_request.h" #include "content/browser/frame_host/navigator.h" #include "content/browser/frame_host/render_frame_host_impl.h" +#include "content/browser/frame_host/traced_frame_tree_node.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/common/frame_messages.h" #include "content/common/site_isolation_policy.h" @@ -105,6 +106,12 @@ g_frame_tree_node_id_map.Get().insert( std::make_pair(frame_tree_node_id_, this)); CHECK(result.second); + + TRACE_EVENT_OBJECT_CREATED_WITH_ID( + "navigation", "FrameTreeNode", + TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_)); + // Don't TraceSnapshot() until the RenderFrameHostManager is initialized and + // calls SetCurrentURL(). } FrameTreeNode::~FrameTreeNode() { @@ -116,6 +123,10 @@ opener_->RemoveObserver(opener_observer_.get()); g_frame_tree_node_id_map.Get().erase(frame_tree_node_id_); + + TRACE_EVENT_OBJECT_DELETED_WITH_ID( + "navigation", "FrameTreeNode", + TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_)); } void FrameTreeNode::AddObserver(Observer* observer) { @@ -172,6 +183,7 @@ void FrameTreeNode::ResetForNewProcess() { current_frame_host()->set_last_committed_url(GURL()); + TraceSnapshot(); // Remove child nodes from the tree, then delete them. This destruction // operation will notify observers. @@ -197,6 +209,7 @@ if (!has_committed_real_load_ && url != GURL(url::kAboutBlankURL)) has_committed_real_load_ = true; current_frame_host()->set_last_committed_url(url); + TraceSnapshot(); } void FrameTreeNode::SetCurrentOrigin(const url::Origin& origin) { @@ -448,4 +461,13 @@ } } +void FrameTreeNode::TraceSnapshot() const { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID( + "navigation", "FrameTreeNode", + TRACE_ID_WITH_SCOPE("FrameTreeNode", frame_tree_node_id_), + scoped_ptr<base::trace_event::ConvertableToTraceFormat>( + new TracedFrameTreeNode(*this))); +} + } // namespace content
diff --git a/content/browser/frame_host/frame_tree_node.h b/content/browser/frame_host/frame_tree_node.h index c108da5..f806856 100644 --- a/content/browser/frame_host/frame_tree_node.h +++ b/content/browser/frame_host/frame_tree_node.h
@@ -272,6 +272,8 @@ void set_parent(FrameTreeNode* parent) { parent_ = parent; } + void TraceSnapshot() const; + // The next available browser-global FrameTreeNode ID. static int next_frame_tree_node_id_;
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h index 355ee601..1ce4b781 100644 --- a/content/browser/frame_host/render_frame_host_delegate.h +++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -81,7 +81,6 @@ IPC::Message* reply_msg) {} virtual void RunBeforeUnloadConfirm(RenderFrameHost* render_frame_host, - const base::string16& message, bool is_reload, IPC::Message* reply_msg) {}
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc index cb35604..10615f4 100644 --- a/content/browser/frame_host/render_frame_host_impl.cc +++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1441,14 +1441,13 @@ void RenderFrameHostImpl::OnRunBeforeUnloadConfirm( const GURL& frame_url, - const base::string16& message, bool is_reload, IPC::Message* reply_msg) { // While a JS beforeunload dialog is showing, tabs in the same process // shouldn't process input events. GetProcess()->SetIgnoreInputEvents(true); render_view_host_->GetWidget()->StopHangMonitorTimeout(); - delegate_->RunBeforeUnloadConfirm(this, message, is_reload, reply_msg); + delegate_->RunBeforeUnloadConfirm(this, is_reload, reply_msg); } void RenderFrameHostImpl::OnTextSurroundingSelectionResponse(
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h index b52ab74..35195ba83 100644 --- a/content/browser/frame_host/render_frame_host_impl.h +++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -623,7 +623,6 @@ JavaScriptMessageType type, IPC::Message* reply_msg); void OnRunBeforeUnloadConfirm(const GURL& frame_url, - const base::string16& message, bool is_reload, IPC::Message* reply_msg); void OnTextSurroundingSelectionResponse(const base::string16& content,
diff --git a/content/browser/frame_host/render_frame_host_manager_unittest.cc b/content/browser/frame_host/render_frame_host_manager_unittest.cc index b09d9456..f66c758 100644 --- a/content/browser/frame_host/render_frame_host_manager_unittest.cc +++ b/content/browser/frame_host/render_frame_host_manager_unittest.cc
@@ -669,16 +669,16 @@ // without showing an actual dialog. MockRenderProcessHost* ntp_process_host = ntp_rfh->GetProcess(); ntp_process_host->sink().ClearMessages(); - const base::string16 msg = base::ASCIIToUTF16("Message"); bool result = false; base::string16 unused; FrameHostMsg_RunBeforeUnloadConfirm before_unload_msg( - ntp_rfh->GetRoutingID(), kChromeURL, msg, false, &result, &unused); + ntp_rfh->GetRoutingID(), kChromeURL, false, &result, &unused); EXPECT_TRUE(ntp_rfh->OnMessageReceived(before_unload_msg)); EXPECT_TRUE(ntp_process_host->sink().GetUniqueMessageMatching(IPC_REPLY_ID)); // Also test RunJavaScriptMessage. ntp_process_host->sink().ClearMessages(); + const base::string16 msg = base::ASCIIToUTF16("Message"); FrameHostMsg_RunJavaScriptMessage js_msg( ntp_rfh->GetRoutingID(), msg, msg, kChromeURL, JAVASCRIPT_MESSAGE_TYPE_CONFIRM, &result, &unused);
diff --git a/content/browser/frame_host/traced_frame_tree_node.cc b/content/browser/frame_host/traced_frame_tree_node.cc new file mode 100644 index 0000000..0141b38e --- /dev/null +++ b/content/browser/frame_host/traced_frame_tree_node.cc
@@ -0,0 +1,69 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/frame_host/traced_frame_tree_node.h" + +#include "base/command_line.h" +#include "base/json/json_writer.h" +#include "base/strings/stringprintf.h" +#include "content/browser/frame_host/frame_tree.h" +#include "content/public/common/content_switches.h" +#include "url/gurl.h" + +namespace content { + +TracedFrameTreeNode::TracedFrameTreeNode(const FrameTreeNode& node) + : parent_node_id_(-1), + process_id_(-1), + routing_id_(-1) { + FrameTreeNode* parent = node.parent(); + if (parent) + parent_node_id_ = parent->frame_tree_node_id(); + + RenderFrameHostImpl* current_frame_host = node.current_frame_host(); + + if (current_frame_host->last_committed_url().is_valid()) + url_ = current_frame_host->last_committed_url().spec(); + + // On Windows, |rph->GetHandle()| does not duplicate ownership + // of the process handle and the render host still retains it. Therefore, we + // cannot create a base::Process object, which provides a proper way to get a + // process id, from the handle. For a stopgap, we use this deprecated + // function that does not require the ownership (http://crbug.com/417532). + process_id_ = base::GetProcId(current_frame_host->GetProcess()->GetHandle()); + + routing_id_ = current_frame_host->GetRoutingID(); + DCHECK_NE(routing_id_, MSG_ROUTING_NONE); +} + +TracedFrameTreeNode::~TracedFrameTreeNode() { +} + +void TracedFrameTreeNode::AppendAsTraceFormat(std::string* out) const { + scoped_ptr<base::DictionaryValue> value(new base::DictionaryValue()); + + if (parent_node_id_ >= 0) { + scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue()); + ref->SetString("id_ref", base::StringPrintf("0x%x", parent_node_id_)); + ref->SetString("scope", "FrameTreeNode"); + value->Set("parent", std::move(ref)); + } + + if (process_id_ >= 0) { + scoped_ptr<base::DictionaryValue> ref(new base::DictionaryValue()); + ref->SetInteger("pid_ref", process_id_); + ref->SetString("id_ref", base::StringPrintf("0x%x", routing_id_)); + ref->SetString("scope", "RenderFrame"); + value->Set("RenderFrame", std::move(ref)); + } + + if (!url_.empty()) + value->SetString("url", url_); + + std::string tmp; + base::JSONWriter::Write(*value, &tmp); + *out += tmp; +} + +} // content
diff --git a/content/browser/frame_host/traced_frame_tree_node.h b/content/browser/frame_host/traced_frame_tree_node.h new file mode 100644 index 0000000..79c2a80 --- /dev/null +++ b/content/browser/frame_host/traced_frame_tree_node.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/macros.h" +#include "base/memory/scoped_vector.h" +#include "base/trace_event/trace_event_impl.h" +#include "base/values.h" +#include "content/common/content_export.h" + +namespace content { + +class FrameTree; +class FrameTreeNode; + +// This is a temporary container used when tracing snapshots of FrameTree +// objects. When a snapshot of a FrameTree is taken, a TracedFrameTreeNode is +// created and stored by the tracing system until the trace is dumped. +class CONTENT_EXPORT TracedFrameTreeNode : + public base::trace_event::ConvertableToTraceFormat { + public: + TracedFrameTreeNode(const FrameTreeNode& node); + void AppendAsTraceFormat(std::string* out) const override; + + private: + ~TracedFrameTreeNode() override; + + int parent_node_id_; + std::string url_; + int process_id_; + int routing_id_; + + DISALLOW_COPY_AND_ASSIGN(TracedFrameTreeNode); +}; + +} // content
diff --git a/content/browser/loader/async_resource_handler.cc b/content/browser/loader/async_resource_handler.cc index 8f02d3f..599767b0 100644 --- a/content/browser/loader/async_resource_handler.cc +++ b/content/browser/loader/async_resource_handler.cc
@@ -450,6 +450,8 @@ if (!sent_data_buffer_msg_) { base::SharedMemoryHandle handle = base::SharedMemory::DuplicateHandle( buffer_->GetSharedMemory().handle()); + if (!base::SharedMemory::IsHandleValid(handle)) + return false; filter->Send(new ResourceMsg_SetDataBuffer( GetRequestID(), handle, buffer_->GetSharedMemory().mapped_size(), filter->peer_pid()));
diff --git a/content/browser/media/media_canplaytype_browsertest.cc b/content/browser/media/media_canplaytype_browsertest.cc index 1a3af5a3..0b70f41 100644 --- a/content/browser/media/media_canplaytype_browsertest.cc +++ b/content/browser/media/media_canplaytype_browsertest.cc
@@ -42,8 +42,8 @@ const char* kTheoraProbably = kNot; const char* kOggOpusProbably = kNot; const char* kMpeg2AacProbably = kNot; // https://crbug.com/544268. -const char* kHlsProbably = kPropProbably; -const char* kHlsMaybe = kPropMaybe; +const char* kHlsProbably = kProbably; +const char* kHlsMaybe = kMaybe; #endif // !OS_ANDROID #if BUILDFLAG(ENABLE_HEVC_DEMUXING)
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc index 19b53fa..91fdf545 100644 --- a/content/browser/mojo/mojo_shell_context.cc +++ b/content/browser/mojo/mojo_shell_context.cc
@@ -25,6 +25,8 @@ #include "content/public/common/service_registry.h" #include "mojo/public/cpp/bindings/interface_request.h" #include "mojo/public/cpp/bindings/string.h" +#include "mojo/services/catalog/owner.h" +#include "mojo/services/catalog/store.h" #include "mojo/shell/connect_params.h" #include "mojo/shell/loader.h" #include "mojo/shell/native_runner.h" @@ -205,8 +207,9 @@ scoped_ptr<mojo::shell::NativeRunnerFactory> native_runner_factory( new mojo::shell::InProcessNativeRunnerFactory( BrowserThread::GetBlockingPool())); + catalog_.reset(new catalog::Owner(file_task_runner.get(), nullptr)); shell_.reset(new mojo::shell::Shell(std::move(native_runner_factory), - file_task_runner.get(), nullptr)); + catalog_->TakeShellClient())); shell_->set_default_loader( scoped_ptr<mojo::shell::Loader>(new DefaultLoader));
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h index 90bda832..bc71c96e 100644 --- a/content/browser/mojo/mojo_shell_context.h +++ b/content/browser/mojo/mojo_shell_context.h
@@ -16,6 +16,10 @@ #include "mojo/shell/public/interfaces/connector.mojom.h" #include "mojo/shell/shell.h" +namespace catalog { +class Owner; +} + namespace mojo { class ShellClient; } @@ -58,6 +62,7 @@ static base::LazyInstance<scoped_ptr<Proxy>> proxy_; + scoped_ptr<catalog::Owner> catalog_; scoped_ptr<mojo::shell::Shell> shell_; DISALLOW_COPY_AND_ASSIGN(MojoShellContext);
diff --git a/content/browser/renderer_host/ime_adapter_android.cc b/content/browser/renderer_host/ime_adapter_android.cc index 95c1241..233c042 100644 --- a/content/browser/renderer_host/ime_adapter_android.cc +++ b/content/browser/renderer_host/ime_adapter_android.cc
@@ -48,7 +48,7 @@ // as a key press of character \r. NativeWebKeyboardEvent NativeWebKeyboardEventFromKeyEvent( JNIEnv* env, - jobject java_key_event, + const base::android::JavaRef<jobject>& java_key_event, int action, int modifiers, long time_ms, @@ -63,8 +63,9 @@ type = blink::WebInputEvent::KeyUp; else NOTREACHED() << "Invalid Android key event action: " << action; - return NativeWebKeyboardEvent(java_key_event, type, modifiers, - time_ms / 1000.0, key_code, scan_code, unicode_char, is_system_key); + return NativeWebKeyboardEvent(env, java_key_event, type, modifiers, + time_ms / 1000.0, key_code, scan_code, + unicode_char, is_system_key); } } // anonymous namespace
diff --git a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc index abed148..ee11929 100644 --- a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc +++ b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
@@ -33,6 +33,11 @@ namespace { +// This value has to be larger than the height of the device this test is +// executed on, otherwise the device will be unable to scroll thus failing +// tests. +const int kWebsiteHeight = 10000; + const char kNonBlockingEventDataURL[] = "data:text/html;charset=utf-8," "<!DOCTYPE html>" @@ -41,7 +46,7 @@ "html, body {" " margin: 0;" "}" - ".spacer { height: 1000px; }" + ".spacer { height: 10000px; }" "</style>" "<div class=spacer></div>" "<script>" @@ -110,7 +115,7 @@ int scrollHeight = ExecuteScriptAndExtractInt("document.documentElement.scrollHeight"); - EXPECT_EQ(1000, scrollHeight); + EXPECT_EQ(kWebsiteHeight, scrollHeight); scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher()); frame_watcher->AttachTo(shell()->web_contents()); @@ -135,7 +140,7 @@ int scrollHeight = ExecuteScriptAndExtractInt("document.documentElement.scrollHeight"); - EXPECT_EQ(1000, scrollHeight); + EXPECT_EQ(kWebsiteHeight, scrollHeight); scoped_refptr<FrameWatcher> frame_watcher(new FrameWatcher()); frame_watcher->AttachTo(shell()->web_contents());
diff --git a/content/browser/renderer_host/input/web_input_event_builders_android.cc b/content/browser/renderer_host/input/web_input_event_builders_android.cc index 4aa2449a..6ccde311 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_android.cc +++ b/content/browser/renderer_host/input/web_input_event_builders_android.cc
@@ -4,8 +4,11 @@ #include "content/browser/renderer_host/input/web_input_event_builders_android.h" +#include <android/input.h> + #include "base/logging.h" #include "content/browser/renderer_host/input/web_input_event_util.h" +#include "ui/events/android/key_event_utils.h" #include "ui/events/android/motion_event_android.h" #include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/keycode_converter.h" @@ -26,7 +29,37 @@ namespace { -ui::DomKey GetDomKeyFromEvent(int keycode, int unicode_character) { +int WebInputEventToAndroidModifier(int web_modifier) { + int android_modifier = 0; + // Currently only Shift, CapsLock are used, add other modifiers if required. + if (web_modifier & WebInputEvent::ShiftKey) + android_modifier |= AMETA_SHIFT_ON; + if (web_modifier & WebInputEvent::CapsLockOn) + android_modifier |= AMETA_CAPS_LOCK_ON; + return android_modifier; +} + +ui::DomKey GetDomKeyFromEvent( + JNIEnv* env, + const base::android::JavaRef<jobject>& android_key_event, + int keycode, + int modifiers, + int unicode_character) { + if (!unicode_character && env) { + // According to spec |kAllowedModifiers| should be Shift and AltGr, however + // Android doesn't have AltGr key and ImeAdapter::getModifiers won't pass it + // either. + // According to discussion we want to honor CapsLock and possibly NumLock as + // well. https://github.com/w3c/uievents/issues/70 + const int kAllowedModifiers = + WebInputEvent::ShiftKey | WebInputEvent::CapsLockOn; + int fallback_modifiers = + WebInputEventToAndroidModifier(modifiers & kAllowedModifiers); + + unicode_character = ui::events::android::GetKeyEventUnicodeChar( + env, android_key_event, fallback_modifiers); + } + ui::DomKey key = ui::GetDomKeyFromAndroidEvent(keycode, unicode_character); if (key != ui::DomKey::NONE) return key; @@ -35,13 +68,16 @@ } // namespace -WebKeyboardEvent WebKeyboardEventBuilder::Build(WebInputEvent::Type type, - int modifiers, - double time_sec, - int keycode, - int scancode, - int unicode_character, - bool is_system_key) { +WebKeyboardEvent WebKeyboardEventBuilder::Build( + JNIEnv* env, + const base::android::JavaRef<jobject>& android_key_event, + WebInputEvent::Type type, + int modifiers, + double time_sec, + int keycode, + int scancode, + int unicode_character, + bool is_system_key) { DCHECK(WebInputEvent::isKeyboardEventType(type)); WebKeyboardEvent result; @@ -56,7 +92,8 @@ result.modifiers |= DomCodeToWebInputEventModifiers(dom_code); result.nativeKeyCode = keycode; result.domCode = static_cast<int>(dom_code); - result.domKey = GetDomKeyFromEvent(keycode, unicode_character); + result.domKey = GetDomKeyFromEvent(env, android_key_event, keycode, modifiers, + unicode_character); result.unmodifiedText[0] = unicode_character; if (result.windowsKeyCode == ui::VKEY_RETURN) { // This is the same behavior as GTK:
diff --git a/content/browser/renderer_host/input/web_input_event_builders_android.h b/content/browser/renderer_host/input/web_input_event_builders_android.h index 50063cf..b6bcf44 100644 --- a/content/browser/renderer_host/input/web_input_event_builders_android.h +++ b/content/browser/renderer_host/input/web_input_event_builders_android.h
@@ -7,6 +7,8 @@ #include <jni.h> +#include "base/android/scoped_java_ref.h" +#include "content/common/content_export.h" #include "third_party/WebKit/public/web/WebInputEvent.h" namespace ui { @@ -38,15 +40,18 @@ int window_y); }; -class WebKeyboardEventBuilder { +class CONTENT_EXPORT WebKeyboardEventBuilder { public: - static blink::WebKeyboardEvent Build(blink::WebInputEvent::Type type, - int modifiers, - double time_sec, - int keycode, - int scancode, - int unicode_character, - bool is_system_key); + static blink::WebKeyboardEvent Build( + JNIEnv* env, + const base::android::JavaRef<jobject>& android_key_event, + blink::WebInputEvent::Type type, + int modifiers, + double time_sec, + int keycode, + int scancode, + int unicode_character, + bool is_system_key); }; class WebGestureEventBuilder {
diff --git a/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc b/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc new file mode 100644 index 0000000..586ea755 --- /dev/null +++ b/content/browser/renderer_host/input/web_input_event_builders_android_unittest.cc
@@ -0,0 +1,141 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/renderer_host/input/web_input_event_builders_android.h" + +#include <android/input.h> +#include <android/keycodes.h> + +#include "base/android/jni_android.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "ui/events/android/key_event_utils.h" +#include "ui/events/gesture_detection/motion_event.h" +#include "ui/events/keycodes/dom/dom_key.h" +#include "ui/events/keycodes/dom/keycode_converter.h" + +using base::android::AttachCurrentThread; +using base::android::ScopedJavaLocalRef; +using blink::WebKeyboardEvent; + +namespace { + +const int kCombiningAccent = 0x80000000; +const int kCombiningAccentMask = 0x7fffffff; + +WebKeyboardEvent CreateFakeWebKeyboardEvent(JNIEnv* env, + int key_code, + int web_modifier, + int unicode_character) { + ScopedJavaLocalRef<jobject> keydown_event = + ui::events::android::CreateKeyEvent(env, ui::MotionEvent::ACTION_DOWN, + key_code); + + WebKeyboardEvent web_event = content::WebKeyboardEventBuilder::Build( + env, keydown_event, WebKeyboardEvent::KeyDown, web_modifier, 0, key_code, + 0, unicode_character, false); + return web_event; +} + +} // anonymous namespace + +class WebInputEventBuilderAndroidTest : public testing::Test {}; + +// This test case is based on VirtualKeyboard layout. +// https://github.com/android/platform_frameworks_base/blob/master/data/keyboards/Virtual.kcm +TEST(WebInputEventBuilderAndroidTest, DomKeyCtrlShift) { + JNIEnv* env = AttachCurrentThread(); + + struct DomKeyTestCase { + int key_code; + int character; + int shift_character; + } table[] = { + {AKEYCODE_0, '0', ')'}, {AKEYCODE_1, '1', '!'}, {AKEYCODE_2, '2', '@'}, + {AKEYCODE_3, '3', '#'}, {AKEYCODE_4, '4', '$'}, {AKEYCODE_5, '5', '%'}, + {AKEYCODE_6, '6', '^'}, {AKEYCODE_7, '7', '&'}, {AKEYCODE_8, '8', '*'}, + {AKEYCODE_9, '9', '('}, {AKEYCODE_A, 'a', 'A'}, {AKEYCODE_B, 'b', 'B'}, + {AKEYCODE_C, 'c', 'C'}, {AKEYCODE_D, 'd', 'D'}, {AKEYCODE_E, 'e', 'E'}, + {AKEYCODE_F, 'f', 'F'}, {AKEYCODE_G, 'g', 'G'}, {AKEYCODE_H, 'h', 'H'}, + {AKEYCODE_I, 'i', 'I'}, {AKEYCODE_J, 'j', 'J'}, {AKEYCODE_K, 'k', 'K'}, + {AKEYCODE_L, 'l', 'L'}, {AKEYCODE_M, 'm', 'M'}, {AKEYCODE_N, 'n', 'N'}, + {AKEYCODE_O, 'o', 'O'}, {AKEYCODE_P, 'p', 'P'}, {AKEYCODE_Q, 'q', 'Q'}, + {AKEYCODE_R, 'r', 'R'}, {AKEYCODE_S, 's', 'S'}, {AKEYCODE_T, 't', 'T'}, + {AKEYCODE_U, 'u', 'U'}, {AKEYCODE_V, 'v', 'V'}, {AKEYCODE_W, 'w', 'W'}, + {AKEYCODE_X, 'x', 'X'}, {AKEYCODE_Y, 'y', 'Y'}, {AKEYCODE_Z, 'z', 'Z'}}; + + for (const DomKeyTestCase& entry : table) { + // Tests DomKey without modifier. + WebKeyboardEvent web_event = + CreateFakeWebKeyboardEvent(env, entry.key_code, 0, entry.character); + EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey) + << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey); + + // Tests DomKey with Ctrl. + web_event = CreateFakeWebKeyboardEvent(env, entry.key_code, + WebKeyboardEvent::ControlKey, 0); + EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey) + << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey); + + // Tests DomKey with Ctrl and Shift. + web_event = CreateFakeWebKeyboardEvent( + env, entry.key_code, + WebKeyboardEvent::ControlKey | WebKeyboardEvent::ShiftKey, 0); + EXPECT_EQ(ui::DomKey::FromCharacter(entry.shift_character), + web_event.domKey) + << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey); + } +} + +// This test case is based on VirtualKeyboard layout. +// https://github.com/android/platform_frameworks_base/blob/master/data/keyboards/Virtual.kcm +TEST(WebInputEventBuilderAndroidTest, DomKeyCtrlAlt) { + JNIEnv* env = AttachCurrentThread(); + + struct DomKeyTestCase { + int key_code; + int character; + int alt_character; + } table[] = {{AKEYCODE_0, '0', 0}, {AKEYCODE_1, '1', 0}, + {AKEYCODE_2, '2', 0}, {AKEYCODE_3, '3', 0}, + {AKEYCODE_4, '4', 0}, {AKEYCODE_5, '5', 0}, + {AKEYCODE_6, '6', 0}, {AKEYCODE_7, '7', 0}, + {AKEYCODE_8, '8', 0}, {AKEYCODE_9, '9', 0}, + {AKEYCODE_A, 'a', 0}, {AKEYCODE_B, 'b', 0}, + {AKEYCODE_C, 'c', u'\u00e7'}, {AKEYCODE_D, 'd', 0}, + {AKEYCODE_E, 'e', u'\u0301'}, {AKEYCODE_F, 'f', 0}, + {AKEYCODE_G, 'g', 0}, {AKEYCODE_H, 'h', 0}, + {AKEYCODE_I, 'i', u'\u0302'}, {AKEYCODE_J, 'j', 0}, + {AKEYCODE_K, 'k', 0}, {AKEYCODE_L, 'l', 0}, + {AKEYCODE_M, 'm', 0}, {AKEYCODE_N, 'n', u'\u0303'}, + {AKEYCODE_O, 'o', 0}, {AKEYCODE_P, 'p', 0}, + {AKEYCODE_Q, 'q', 0}, {AKEYCODE_R, 'r', 0}, + {AKEYCODE_S, 's', u'\u00df'}, {AKEYCODE_T, 't', 0}, + {AKEYCODE_U, 'u', u'\u0308'}, {AKEYCODE_V, 'v', 0}, + {AKEYCODE_W, 'w', 0}, {AKEYCODE_X, 'x', 0}, + {AKEYCODE_Y, 'y', 0}, {AKEYCODE_Z, 'z', 0}}; + + for (const DomKeyTestCase& entry : table) { + // Tests DomKey with Alt. + WebKeyboardEvent web_event = CreateFakeWebKeyboardEvent( + env, entry.key_code, WebKeyboardEvent::AltKey, entry.alt_character); + ui::DomKey expected_alt_dom_key; + if (entry.alt_character == 0) + expected_alt_dom_key = ui::DomKey::FromCharacter(entry.character); + else if (entry.alt_character & kCombiningAccent) + expected_alt_dom_key = ui::DomKey::DeadKeyFromCombiningCharacter( + entry.alt_character & kCombiningAccentMask); + else + expected_alt_dom_key = ui::DomKey::FromCharacter(entry.alt_character); + EXPECT_EQ(expected_alt_dom_key, web_event.domKey) + << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey); + + // Tests DomKey with Ctrl and Alt. + web_event = CreateFakeWebKeyboardEvent( + env, entry.key_code, + WebKeyboardEvent::ControlKey | WebKeyboardEvent::AltKey, 0); + EXPECT_EQ(ui::DomKey::FromCharacter(entry.character), web_event.domKey) + << ui::KeycodeConverter::DomKeyToKeyString(web_event.domKey); + } +}
diff --git a/content/browser/renderer_host/native_web_keyboard_event_android.cc b/content/browser/renderer_host/native_web_keyboard_event_android.cc index fb32d70..696bb0d 100644 --- a/content/browser/renderer_host/native_web_keyboard_event_android.cc +++ b/content/browser/renderer_host/native_web_keyboard_event_android.cc
@@ -29,25 +29,46 @@ skip_in_browser(false) { } -NativeWebKeyboardEvent::NativeWebKeyboardEvent( - blink::WebInputEvent::Type type, - int modifiers, double time_secs, int keycode, int scancode, - int unicode_character, bool is_system_key) - : WebKeyboardEvent(WebKeyboardEventBuilder::Build( - type, modifiers, time_secs, keycode, scancode, unicode_character, - is_system_key)) { +NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type, + int modifiers, + double time_secs, + int keycode, + int scancode, + int unicode_character, + bool is_system_key) + : WebKeyboardEvent(WebKeyboardEventBuilder::Build(nullptr, + nullptr, + type, + modifiers, + time_secs, + keycode, + scancode, + unicode_character, + is_system_key)) { os_event = NULL; skip_in_browser = false; } NativeWebKeyboardEvent::NativeWebKeyboardEvent( - jobject android_key_event, blink::WebInputEvent::Type type, - int modifiers, double time_secs, int keycode, int scancode, - int unicode_character, bool is_system_key) - : WebKeyboardEvent(WebKeyboardEventBuilder::Build( - type, modifiers, time_secs, keycode, scancode, unicode_character, - is_system_key)) { - os_event = NewGlobalRefForKeyEvent(android_key_event); + JNIEnv* env, + const base::android::JavaRef<jobject>& android_key_event, + blink::WebInputEvent::Type type, + int modifiers, + double time_secs, + int keycode, + int scancode, + int unicode_character, + bool is_system_key) + : WebKeyboardEvent(WebKeyboardEventBuilder::Build(env, + android_key_event, + type, + modifiers, + time_secs, + keycode, + scancode, + unicode_character, + is_system_key)) { + os_event = NewGlobalRefForKeyEvent(android_key_event.obj()); skip_in_browser = false; }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc index e2169e7..dbd378b 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura_unittest.cc
@@ -277,7 +277,7 @@ FakeRenderWidgetHostViewAura(RenderWidgetHost* widget, bool is_guest_view_hack) : RenderWidgetHostViewAura(widget, is_guest_view_hack), - has_resize_lock_(false) {} + can_create_resize_lock_(true) {} void UseFakeDispatcher() { dispatcher_ = new FakeWindowEventDispatcher(window()->GetHost()); @@ -294,7 +294,9 @@ new FakeResizeLock(desired_size, defer_compositor_lock)); } - bool DelegatedFrameCanCreateResizeLock() const override { return true; } + bool DelegatedFrameCanCreateResizeLock() const override { + return can_create_resize_lock_; + } void RunOnCompositingDidCommit() { GetDelegatedFrameHost()->OnCompositingDidCommitForTesting( @@ -338,7 +340,7 @@ return pointer_state(); } - bool has_resize_lock_; + bool can_create_resize_lock_; gfx::Size last_frame_size_; scoped_ptr<cc::CopyOutputRequest> last_copy_request_; FakeWindowEventDispatcher* dispatcher_; @@ -1686,6 +1688,54 @@ } } +// If the view size is larger than the compositor frame then extra layers +// should be created to fill the gap. +TEST_F(RenderWidgetHostViewAuraTest, DelegatedFrameGutter) { + gfx::Size large_size(100, 100); + gfx::Size small_size(40, 45); + gfx::Size medium_size(40, 95); + + // Prevent the DelegatedFrameHost from skipping frames. + view_->can_create_resize_lock_ = false; + + view_->InitAsChild(NULL); + aura::client::ParentWindowWithContext( + view_->GetNativeView(), parent_view_->GetNativeView()->GetRootWindow(), + gfx::Rect()); + view_->SetSize(large_size); + view_->Show(); + scoped_ptr<cc::CompositorFrame> frame = + MakeDelegatedFrame(1.f, small_size, gfx::Rect(small_size)); + frame->metadata.root_background_color = SK_ColorRED; + view_->OnSwapCompositorFrame(0, std::move(frame)); + + ui::Layer* parent_layer = view_->GetNativeView()->layer(); + + ASSERT_EQ(2u, parent_layer->children().size()); + EXPECT_EQ(gfx::Rect(40, 0, 60, 100), parent_layer->children()[0]->bounds()); + EXPECT_EQ(SK_ColorRED, parent_layer->children()[0]->background_color()); + EXPECT_EQ(gfx::Rect(0, 45, 40, 55), parent_layer->children()[1]->bounds()); + EXPECT_EQ(SK_ColorRED, parent_layer->children()[1]->background_color()); + + view_->SetSize(medium_size); + + // Right gutter is unnecessary. + ASSERT_EQ(1u, parent_layer->children().size()); + EXPECT_EQ(gfx::Rect(0, 45, 40, 50), parent_layer->children()[0]->bounds()); + + frame = MakeDelegatedFrame(1.f, medium_size, gfx::Rect(medium_size)); + view_->OnSwapCompositorFrame(0, std::move(frame)); + EXPECT_EQ(0u, parent_layer->children().size()); + + view_->SetSize(large_size); + ASSERT_EQ(2u, parent_layer->children().size()); + + // This should evict the frame and remove the gutter layers. + view_->Hide(); + view_->SetSize(small_size); + ASSERT_EQ(0u, parent_layer->children().size()); +} + TEST_F(RenderWidgetHostViewAuraTest, Resize) { gfx::Size size1(100, 100); gfx::Size size2(200, 200);
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc index debd06a6..039a331e 100644 --- a/content/browser/site_per_process_browsertest.cc +++ b/content/browser/site_per_process_browsertest.cc
@@ -4591,8 +4591,14 @@ } // namespace anonymous +// Flaky under TSan. https://crbug.com/592320 +#if defined(THREAD_SANITIZER) +#define MAYBE_SubframeGestureEventRouting DISABLED_SubframeGestureEventRouting +#else +#define MAYBE_SubframeGestureEventRouting SubframeGestureEventRouting +#endif IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, - SubframeGestureEventRouting) { + MAYBE_SubframeGestureEventRouting) { GURL main_url(embedded_test_server()->GetURL( "/frame_tree/page_with_positioned_nested_frames.html")); EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index 17e4875d..feed3fe 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -1163,6 +1163,10 @@ return crashed_status_; } +int WebContentsImpl::GetCrashedErrorCode() const { + return crashed_error_code_; +} + bool WebContentsImpl::IsBeingDestroyed() const { return is_being_destroyed_; } @@ -3878,7 +3882,6 @@ void WebContentsImpl::RunBeforeUnloadConfirm( RenderFrameHost* render_frame_host, - const base::string16& message, bool is_reload, IPC::Message* reply_msg) { RenderFrameHostImpl* rfhi = @@ -3899,7 +3902,7 @@ is_showing_before_unload_dialog_ = true; dialog_manager_ = delegate_->GetJavaScriptDialogManager(this); dialog_manager_->RunBeforeUnloadDialog( - this, message, is_reload, + this, is_reload, base::Bind(&WebContentsImpl::OnDialogClosed, base::Unretained(this), render_frame_host->GetProcess()->GetID(), render_frame_host->GetRoutingID(), reply_msg, @@ -4409,6 +4412,9 @@ void WebContentsImpl::RendererUnresponsive( RenderWidgetHostImpl* render_widget_host) { + FOR_EACH_OBSERVER(WebContentsObserver, observers_, + OnRendererUnresponsive(render_widget_host)); + // Don't show hung renderer dialog for a swapped out RVH. if (render_widget_host != GetRenderViewHost()->GetWidget()) return;
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index 7e0da7d3..9907baa 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -290,6 +290,7 @@ bool IsCrashed() const override; void SetIsCrashed(base::TerminationStatus status, int error_code) override; base::TerminationStatus GetCrashedStatus() const override; + int GetCrashedErrorCode() const override; bool IsBeingDestroyed() const override; void NotifyNavigationStateChanged(InvalidateTypes changed_flags) override; base::TimeTicks GetLastActiveTime() const override; @@ -418,7 +419,6 @@ JavaScriptMessageType type, IPC::Message* reply_msg) override; void RunBeforeUnloadConfirm(RenderFrameHost* render_frame_host, - const base::string16& message, bool is_reload, IPC::Message* reply_msg) override; void DidAccessInitialDocument() override;
diff --git a/content/browser/web_contents/web_contents_impl_unittest.cc b/content/browser/web_contents/web_contents_impl_unittest.cc index e95c853..a96c322 100644 --- a/content/browser/web_contents/web_contents_impl_unittest.cc +++ b/content/browser/web_contents/web_contents_impl_unittest.cc
@@ -3408,7 +3408,6 @@ }; void RunBeforeUnloadDialog(WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override {}
diff --git a/content/common/content_switches_internal.cc b/content/common/content_switches_internal.cc index 9200e7f..5e73d4f3 100644 --- a/content/common/content_switches_internal.cc +++ b/content/common/content_switches_internal.cc
@@ -25,11 +25,7 @@ #endif bool IsUseZoomForDSFEnabledByDefault() { -#if defined(OS_CHROMEOS) - return true; -#else return false; -#endif } } // namespace
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h index ec76ea6..69c22468 100644 --- a/content/common/frame_messages.h +++ b/content/common/frame_messages.h
@@ -1256,9 +1256,8 @@ // Displays a dialog to confirm that the user wants to navigate away from the // page. Replies true if yes, and false otherwise. The reply string is ignored, // but is included so that we can use OnJavaScriptMessageBoxClosed. -IPC_SYNC_MESSAGE_ROUTED3_2(FrameHostMsg_RunBeforeUnloadConfirm, +IPC_SYNC_MESSAGE_ROUTED2_2(FrameHostMsg_RunBeforeUnloadConfirm, GURL, /* in - originating frame URL */ - base::string16 /* in - alert message */, bool /* in - is a reload */, bool /* out - success */, base::string16 /* out - This is ignored.*/)
diff --git a/content/common/gpu/client/gpu_channel_host.cc b/content/common/gpu/client/gpu_channel_host.cc index ebf552c9..3f0b0de 100644 --- a/content/common/gpu/client/gpu_channel_host.cc +++ b/content/common/gpu/client/gpu_channel_host.cc
@@ -189,15 +189,15 @@ flush_info->flushed_stream_flush_id = flush_info->flush_id; } -scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateViewCommandBuffer( +scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateCommandBuffer( gpu::SurfaceHandle surface_handle, + const gfx::Size& size, CommandBufferProxyImpl* share_group, int32_t stream_id, GpuStreamPriority stream_priority, const std::vector<int32_t>& attribs, const GURL& active_url, gfx::GpuPreference gpu_preference) { - DCHECK_NE(gpu::kNullSurfaceHandle, surface_handle); DCHECK(!share_group || (stream_id == share_group->stream_id())); TRACE_EVENT1("gpu", "GpuChannelHost::CreateViewCommandBuffer", "surface_handle", surface_handle); @@ -216,7 +216,7 @@ // TODO(vadimt): Remove ScopedTracker below once crbug.com/125248 is fixed. tracked_objects::ScopedTracker tracking_profile( FROM_HERE_WITH_EXPLICIT_FUNCTION( - "125248 BrowserGpuChannelHostFactory::CreateViewCommandBuffer")); + "125248 GpuChannelHost::CreateCommandBuffer")); // We're blocking the UI thread, which is generally undesirable. // In this case we need to wait for this before we can show any UI /anyway/, @@ -224,57 +224,14 @@ // TODO(piman): Make this asynchronous (http://crbug.com/125248). bool succeeded = false; - if (!Send(new GpuChannelMsg_CreateViewCommandBuffer( - surface_handle, init_params, route_id, &succeeded))) { - LOG(ERROR) << "Failed to send GpuChannelMsg_CreateViewCommandBuffer."; + if (!Send(new GpuChannelMsg_CreateCommandBuffer( + surface_handle, size, init_params, route_id, &succeeded))) { + LOG(ERROR) << "Failed to send GpuChannelMsg_CreateCommandBuffer."; return nullptr; } if (!succeeded) { - LOG(ERROR) - << "GpuChannelMsg_CreateOffscreenCommandBuffer returned failure."; - return nullptr; - } - - scoped_ptr<CommandBufferProxyImpl> command_buffer = - make_scoped_ptr(new CommandBufferProxyImpl(this, route_id, stream_id)); - AddRoute(route_id, command_buffer->AsWeakPtr()); - - return command_buffer; -} - -scoped_ptr<CommandBufferProxyImpl> GpuChannelHost::CreateOffscreenCommandBuffer( - const gfx::Size& size, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference) { - DCHECK(!share_group || (stream_id == share_group->stream_id())); - TRACE_EVENT0("gpu", "GpuChannelHost::CreateOffscreenCommandBuffer"); - - GPUCreateCommandBufferConfig init_params; - init_params.share_group_id = - share_group ? share_group->route_id() : MSG_ROUTING_NONE; - init_params.stream_id = stream_id; - init_params.stream_priority = stream_priority; - init_params.attribs = attribs; - init_params.active_url = active_url; - init_params.gpu_preference = gpu_preference; - - int32_t route_id = GenerateRouteID(); - - bool succeeded = false; - if (!Send(new GpuChannelMsg_CreateOffscreenCommandBuffer( - size, init_params, route_id, &succeeded))) { - LOG(ERROR) << "Failed to send GpuChannelMsg_CreateOffscreenCommandBuffer."; - return nullptr; - } - - if (!succeeded) { - LOG(ERROR) - << "GpuChannelMsg_CreateOffscreenCommandBuffer returned failure."; + LOG(ERROR) << "GpuChannelMsg_CreateCommandBuffer returned failure."; return nullptr; }
diff --git a/content/common/gpu/client/gpu_channel_host.h b/content/common/gpu/client/gpu_channel_host.h index ce9284e..06d4742b 100644 --- a/content/common/gpu/client/gpu_channel_host.h +++ b/content/common/gpu/client/gpu_channel_host.h
@@ -113,17 +113,8 @@ void FlushPendingStream(int32_t stream_id); // Create and connect to a command buffer in the GPU process. - scoped_ptr<CommandBufferProxyImpl> CreateViewCommandBuffer( + scoped_ptr<CommandBufferProxyImpl> CreateCommandBuffer( gpu::SurfaceHandle surface_handle, - CommandBufferProxyImpl* share_group, - int32_t stream_id, - GpuStreamPriority stream_priority, - const std::vector<int32_t>& attribs, - const GURL& active_url, - gfx::GpuPreference gpu_preference); - - // Create and connect to a command buffer in the GPU process. - scoped_ptr<CommandBufferProxyImpl> CreateOffscreenCommandBuffer( const gfx::Size& size, CommandBufferProxyImpl* share_group, int32_t stream_id,
diff --git a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc index 4b5ddb2a..3a1745f 100644 --- a/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc +++ b/content/common/gpu/client/webgraphicscontext3d_command_buffer_impl.cc
@@ -24,7 +24,6 @@ #include "base/profiler/scoped_tracker.h" #include "base/trace_event/trace_event.h" #include "content/common/gpu/client/gpu_channel_host.h" -#include "content/public/common/content_constants.h" #include "content/public/common/content_switches.h" #include "gpu/GLES2/gl2extchromium.h" #include "gpu/command_buffer/client/gles2_cmd_helper.h" @@ -182,19 +181,10 @@ attribs_for_gles2.Serialize(&attribs); // Create a proxy to a command buffer in the GPU process. - if (surface_handle_ != gpu::kNullSurfaceHandle) { - command_buffer_ = host_->CreateViewCommandBuffer( - surface_handle_, share_group_command_buffer, - GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, attribs, active_url_, - gpu_preference_); - } else { - command_buffer_ = host_->CreateOffscreenCommandBuffer( - gfx::Size(1, 1), share_group_command_buffer, - GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, attribs, active_url_, - gpu_preference_); - } + command_buffer_ = host_->CreateCommandBuffer( + surface_handle_, gfx::Size(), share_group_command_buffer, + GpuChannelHost::kDefaultStreamId, GpuChannelHost::kDefaultStreamPriority, + attribs, active_url_, gpu_preference_); if (!command_buffer_) { DLOG(ERROR) << "GpuChannelHost failed to create command buffer.";
diff --git a/content/common/gpu/gpu_channel.cc b/content/common/gpu/gpu_channel.cc index 68cac78..77a373d 100644 --- a/content/common/gpu/gpu_channel.cc +++ b/content/common/gpu/gpu_channel.cc
@@ -756,10 +756,8 @@ bool GpuChannel::OnControlMessageReceived(const IPC::Message& msg) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(GpuChannel, msg) - IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateViewCommandBuffer, - OnCreateViewCommandBuffer) - IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateOffscreenCommandBuffer, - OnCreateOffscreenCommandBuffer) + IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateCommandBuffer, + OnCreateCommandBuffer) IPC_MESSAGE_HANDLER(GpuChannelMsg_DestroyCommandBuffer, OnDestroyCommandBuffer) IPC_MESSAGE_UNHANDLED(handled = false) @@ -904,68 +902,52 @@ } #endif -void GpuChannel::OnCreateViewCommandBuffer( +void GpuChannel::OnCreateCommandBuffer( gpu::SurfaceHandle surface_handle, + const gfx::Size& size, const GPUCreateCommandBufferConfig& init_params, int32_t route_id, bool* succeeded) { - TRACE_EVENT1("gpu", "GpuChannel::CreateViewCommandBuffer", "route_id", - route_id); + TRACE_EVENT2("gpu", "GpuChannel::OnCreateCommandBuffer", "route_id", route_id, + "offscreen", (surface_handle == gpu::kNullSurfaceHandle)); *succeeded = false; - if (allow_view_command_buffers_ && - surface_handle != gpu::kNullSurfaceHandle) { - *succeeded = - CreateCommandBuffer(surface_handle, gfx::Size(), init_params, route_id); + if (surface_handle != gpu::kNullSurfaceHandle && + !allow_view_command_buffers_) { + DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): attempt to create a " + "view context on a non-priviledged channel"; + return; } -} -void GpuChannel::OnCreateOffscreenCommandBuffer( - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - bool* succeeded) { - TRACE_EVENT1("gpu", "GpuChannel::OnCreateOffscreenCommandBuffer", "route_id", - route_id); - *succeeded = - CreateCommandBuffer(gpu::kNullSurfaceHandle, size, init_params, route_id); -} - -bool GpuChannel::CreateCommandBuffer( - gpu::SurfaceHandle surface_handle, - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id) { int32_t share_group_id = init_params.share_group_id; GpuCommandBufferStub* share_group = stubs_.get(share_group_id); if (!share_group && share_group_id != MSG_ROUTING_NONE) { - DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): invalid share group id"; - return false; + DLOG(ERROR) + << "GpuChannel::OnCreateCommandBuffer(): invalid share group id"; + return; } int32_t stream_id = init_params.stream_id; if (share_group && stream_id != share_group->stream_id()) { - DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): stream id does not " + DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): stream id does not " "match share group stream id"; - return false; + return; } GpuStreamPriority stream_priority = init_params.stream_priority; if (!allow_real_time_streams_ && stream_priority == GpuStreamPriority::REAL_TIME) { - DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): real time stream " + DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): real time stream " "priority not allowed"; - return false; + return; } - bool offscreen = (surface_handle == gpu::kNullSurfaceHandle); scoped_ptr<GpuCommandBufferStub> stub(new GpuCommandBufferStub( this, sync_point_manager_, task_runner_.get(), share_group, surface_handle, mailbox_manager_.get(), preempted_flag_.get(), subscription_ref_set_.get(), pending_valuebuffer_state_.get(), size, disallowed_features_, init_params.attribs, init_params.gpu_preference, - init_params.stream_id, route_id, offscreen, watchdog_, - init_params.active_url)); + init_params.stream_id, route_id, watchdog_, init_params.active_url)); scoped_refptr<GpuChannelMessageQueue> queue = LookupStream(stream_id); if (!queue) @@ -973,12 +955,12 @@ if (!AddRoute(route_id, stream_id, stub.get())) { DestroyStreamIfNecessary(queue); - DLOG(ERROR) << "GpuChannel::CreateCommandBuffer(): failed to add route"; - return false; + DLOG(ERROR) << "GpuChannel::OnCreateCommandBuffer(): failed to add route"; + return; } stubs_.set(route_id, std::move(stub)); - return true; + *succeeded = true; } void GpuChannel::OnDestroyCommandBuffer(int32_t route_id) {
diff --git a/content/common/gpu/gpu_channel.h b/content/common/gpu/gpu_channel.h index 6bcf5987..4160c7eb 100644 --- a/content/common/gpu/gpu_channel.h +++ b/content/common/gpu/gpu_channel.h
@@ -209,22 +209,13 @@ void RemoveRouteFromStream(int32_t route_id); // Message handlers for control messages. - void OnCreateViewCommandBuffer( - gpu::SurfaceHandle surface_handle, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - bool* succeeded); - void OnCreateOffscreenCommandBuffer( - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id, - bool* succeeded); + void OnCreateCommandBuffer(gpu::SurfaceHandle surface_handle, + const gfx::Size& size, + const GPUCreateCommandBufferConfig& init_params, + int32_t route_id, + bool* succeeded); void OnDestroyCommandBuffer(int32_t route_id); - bool CreateCommandBuffer(gpu::SurfaceHandle surface_handle, - const gfx::Size& size, - const GPUCreateCommandBufferConfig& init_params, - int32_t route_id); // The lifetime of objects of this class is managed by a GpuChannelManager. // The GpuChannelManager destroy all the GpuChannels that they own when they
diff --git a/content/common/gpu/gpu_channel_unittest.cc b/content/common/gpu/gpu_channel_unittest.cc index 6968adb..1705af4 100644 --- a/content/common/gpu/gpu_channel_unittest.cc +++ b/content/common/gpu/gpu_channel_unittest.cc
@@ -85,9 +85,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateViewCommandBuffer( - surface_handle, init_params, kRouteId, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + surface_handle, gfx::Size(), init_params, kRouteId, + &succeeded)); EXPECT_TRUE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); @@ -113,9 +113,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateViewCommandBuffer( - surface_handle, init_params, kRouteId, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + surface_handle, gfx::Size(), init_params, kRouteId, + &succeeded)); EXPECT_FALSE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); @@ -136,9 +136,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId, &succeeded)); EXPECT_TRUE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); @@ -161,9 +161,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId1, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId1, &succeeded)); EXPECT_TRUE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); @@ -180,9 +180,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId2, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId2, &succeeded)); EXPECT_FALSE(succeeded); stub = channel->LookupCommandBuffer(kRouteId2); @@ -206,9 +206,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId1, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId1, &succeeded)); EXPECT_TRUE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId1); @@ -230,9 +230,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId2, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId2, &succeeded)); EXPECT_TRUE(succeeded); stub = channel->LookupCommandBuffer(kRouteId2); @@ -257,9 +257,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId, &succeeded)); EXPECT_FALSE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId); @@ -284,9 +284,9 @@ init_params.active_url = GURL(); init_params.gpu_preference = gfx::PreferIntegratedGpu; bool succeeded = false; - HandleMessage(channel, - new GpuChannelMsg_CreateOffscreenCommandBuffer( - gfx::Size(1, 1), init_params, kRouteId, &succeeded)); + HandleMessage(channel, new GpuChannelMsg_CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(1, 1), + init_params, kRouteId, &succeeded)); EXPECT_TRUE(succeeded); GpuCommandBufferStub* stub = channel->LookupCommandBuffer(kRouteId);
diff --git a/content/common/gpu/gpu_command_buffer_stub.cc b/content/common/gpu/gpu_command_buffer_stub.cc index 275ab6ea3..d036d0d 100644 --- a/content/common/gpu/gpu_command_buffer_stub.cc +++ b/content/common/gpu/gpu_command_buffer_stub.cc
@@ -177,7 +177,6 @@ gfx::GpuPreference gpu_preference, int32_t stream_id, int32_t route_id, - bool offscreen, GpuWatchdog* watchdog, const GURL& active_url) : channel_(channel), @@ -193,7 +192,6 @@ command_buffer_id_(GetCommandBufferID(channel->client_id(), route_id)), stream_id_(stream_id), route_id_(route_id), - offscreen_(offscreen), last_flush_count_(0), surface_format_(gfx::GLSurface::SURFACE_DEFAULT), watchdog_(watchdog), @@ -249,7 +247,7 @@ use_virtualized_gl_context_ = false; #endif - if (offscreen && initial_size_.IsEmpty()) { + if ((surface_handle_ == gpu::kNullSurfaceHandle) && initial_size_.IsEmpty()) { // If we're an offscreen surface with zero width and/or height, set to a // non-zero size so that we have a complete framebuffer for operations like // glClear. @@ -612,7 +610,8 @@ } // Initialize the decoder with either the view or pbuffer GLContext. - if (!decoder_->Initialize(surface_, context, offscreen_, initial_size_, + bool offscreen = (surface_handle_ == gpu::kNullSurfaceHandle); + if (!decoder_->Initialize(surface_, context, offscreen, initial_size_, disallowed_features_, requested_attribs_)) { DLOG(ERROR) << "Failed to initialize decoder."; OnInitializeFailed(reply_message);
diff --git a/content/common/gpu/gpu_command_buffer_stub.h b/content/common/gpu/gpu_command_buffer_stub.h index 5c6ec8fb..311a9eda 100644 --- a/content/common/gpu/gpu_command_buffer_stub.h +++ b/content/common/gpu/gpu_command_buffer_stub.h
@@ -91,7 +91,6 @@ gfx::GpuPreference gpu_preference, int32_t stream_id, int32_t route_id, - bool offscreen, GpuWatchdog* watchdog, const GURL& active_url); @@ -253,7 +252,6 @@ const gpu::CommandBufferId command_buffer_id_; const int32_t stream_id_; const int32_t route_id_; - const bool offscreen_; uint32_t last_flush_count_; scoped_ptr<gpu::CommandBufferService> command_buffer_;
diff --git a/content/common/gpu/gpu_host_messages.h b/content/common/gpu/gpu_host_messages.h index 21d6c000..9a18a822 100644 --- a/content/common/gpu/gpu_host_messages.h +++ b/content/common/gpu/gpu_host_messages.h
@@ -11,7 +11,6 @@ #include "content/common/gpu/establish_channel_params.h" #include "content/common/gpu/gpu_memory_uma_stats.h" #include "content/common/gpu/gpu_process_launch_causes.h" -#include "content/public/common/common_param_traits.h" #include "gpu/command_buffer/common/sync_token.h" #include "gpu/command_buffer/common/value_state.h" #include "gpu/command_buffer/service/gpu_preferences.h"
diff --git a/content/common/gpu/gpu_messages.h b/content/common/gpu/gpu_messages.h index 314d69d..3f004276 100644 --- a/content/common/gpu/gpu_messages.h +++ b/content/common/gpu/gpu_messages.h
@@ -173,22 +173,18 @@ // GPU Channel Messages // These are messages from a renderer process to the GPU process. -// Tells the GPU process to create a new command buffer that renders directly -// to a native view. A corresponding GpuCommandBufferStub is created. -IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateViewCommandBuffer, - gpu::SurfaceHandle, /* surface_handle */ - GPUCreateCommandBufferConfig, /* init_params */ +// Tells the GPU process to create a new command buffer. A corresponding +// GpuCommandBufferStub is created. if |surface_handle| is non-null, |size| is +// ignored, and it will render directly to the native surface (only the browser +// process is allowed to create those). Otherwise it will create an offscreen +// backbuffer of dimensions |size|. +IPC_SYNC_MESSAGE_CONTROL4_1(GpuChannelMsg_CreateCommandBuffer, + gpu::SurfaceHandle /* surface_handle */, + gfx::Size /* size */, + GPUCreateCommandBufferConfig /* init_params */, int32_t /* route_id */, bool /* succeeded */) -// Tells the GPU process to create a new command buffer that renders to an -// offscreen frame buffer. -IPC_SYNC_MESSAGE_CONTROL3_1(GpuChannelMsg_CreateOffscreenCommandBuffer, - gfx::Size, /* size */ - GPUCreateCommandBufferConfig, /* init_params */ - int32_t, /* route_id */ - bool /* succeeded */) - // The CommandBufferProxy sends this to the GpuCommandBufferStub in its // destructor, so that the stub deletes the actual CommandBufferService // object that it's hosting.
diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc index fc27cc1..d0a4981 100644 --- a/content/common/gpu/media/video_encode_accelerator_unittest.cc +++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -670,11 +670,13 @@ if (IsVP8(profile_)) config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat, media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, - natural_size, media::EmptyExtraData(), false); + natural_size, media::EmptyExtraData(), + media::Unencrypted()); else if (IsH264(profile_)) config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat, media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size, - natural_size, media::EmptyExtraData(), false); + natural_size, media::EmptyExtraData(), + media::Unencrypted()); else LOG_ASSERT(0) << "Invalid profile " << profile_;
diff --git a/content/renderer/origin_trials/trial_token.cc b/content/common/origin_trials/trial_token.cc similarity index 98% rename from content/renderer/origin_trials/trial_token.cc rename to content/common/origin_trials/trial_token.cc index 2cd9f186..e44f6f0 100644 --- a/content/renderer/origin_trials/trial_token.cc +++ b/content/common/origin_trials/trial_token.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/origin_trials/trial_token.h" +#include "content/common/origin_trials/trial_token.h" #include <openssl/curve25519.h>
diff --git a/content/renderer/origin_trials/trial_token.h b/content/common/origin_trials/trial_token.h similarity index 95% rename from content/renderer/origin_trials/trial_token.h rename to content/common/origin_trials/trial_token.h index 216c9b9..3109240 100644 --- a/content/renderer/origin_trials/trial_token.h +++ b/content/common/origin_trials/trial_token.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_H_ -#define CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_H_ +#ifndef CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_ +#define CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_ #include <string> @@ -106,4 +106,4 @@ } // namespace content -#endif // CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_H_ +#endif // CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_H_
diff --git a/content/renderer/origin_trials/trial_token_unittest.cc b/content/common/origin_trials/trial_token_unittest.cc similarity index 99% rename from content/renderer/origin_trials/trial_token_unittest.cc rename to content/common/origin_trials/trial_token_unittest.cc index e7e52e7e..dd83508 100644 --- a/content/renderer/origin_trials/trial_token_unittest.cc +++ b/content/common/origin_trials/trial_token_unittest.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/origin_trials/trial_token.h" +#include "content/common/origin_trials/trial_token.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h"
diff --git a/content/common/origin_trials/trial_token_validator.cc b/content/common/origin_trials/trial_token_validator.cc new file mode 100644 index 0000000..b7d61fec --- /dev/null +++ b/content/common/origin_trials/trial_token_validator.cc
@@ -0,0 +1,28 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/origin_trials/trial_token_validator.h" + +#include "base/time/time.h" +#include "content/common/origin_trials/trial_token.h" +#include "content/public/common/content_client.h" + +namespace content { + +bool TrialTokenValidator::ValidateToken(const std::string& token, + const url::Origin& origin, + base::StringPiece featureName) { + scoped_ptr<TrialToken> trial_token = TrialToken::Parse(token); + + // TODO(iclelland): Allow for multiple signing keys, and iterate over all + // active keys here. https://crbug.com/543220 + ContentClient* content_client = GetContentClient(); + base::StringPiece public_key = content_client->GetOriginTrialPublicKey(); + + return !public_key.empty() && trial_token && + trial_token->IsAppropriate(origin, featureName) && + trial_token->IsValid(base::Time::Now(), public_key); +} + +} // namespace content
diff --git a/content/common/origin_trials/trial_token_validator.h b/content/common/origin_trials/trial_token_validator.h new file mode 100644 index 0000000..d19c112 --- /dev/null +++ b/content/common/origin_trials/trial_token_validator.h
@@ -0,0 +1,26 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ +#define CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ + +#include <string> +#include "base/strings/string_piece.h" +#include "content/common/content_export.h" +#include "url/origin.h" + +namespace content { + +namespace TrialTokenValidator { + +// This method is thread-safe. +CONTENT_EXPORT bool ValidateToken(const std::string& token, + const url::Origin& origin, + base::StringPiece featureName); + +} // namespace TrialTokenValidator + +} // namespace content + +#endif // CONTENT_COMMON_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_
diff --git a/content/renderer/origin_trials/trial_token_validator_unittest.cc b/content/common/origin_trials/trial_token_validator_unittest.cc similarity index 85% rename from content/renderer/origin_trials/trial_token_validator_unittest.cc rename to content/common/origin_trials/trial_token_validator_unittest.cc index 858aa6f..9a2d27c 100644 --- a/content/renderer/origin_trials/trial_token_validator_unittest.cc +++ b/content/common/origin_trials/trial_token_validator_unittest.cc
@@ -2,14 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/renderer/origin_trials/trial_token_validator.h" +#include "content/common/origin_trials/trial_token_validator.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string_util.h" #include "base/test/simple_test_clock.h" #include "base/time/time.h" -#include "content/public/renderer/content_renderer_client.h" +#include "content/public/common/content_client.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h" @@ -71,7 +71,7 @@ const char kUnparsableToken[] = "abcde"; -class TestContentRendererClient : public content::ContentRendererClient { +class TestContentClient : public ContentClient { public: base::StringPiece GetOriginTrialPublicKey() override { return base::StringPiece(reinterpret_cast<const char*>(key_), @@ -90,57 +90,58 @@ inappropriate_origin_(GURL(kInappropriateOrigin)), insecure_origin_(GURL(kInsecureOrigin)) { SetPublicKey(kTestPublicKey); - SetRendererClientForTesting(&test_content_renderer_client_); + SetContentClient(&test_content_client_); } + ~TrialTokenValidatorTest() override { SetContentClient(nullptr); } + void SetPublicKey(const uint8_t* key) { - test_content_renderer_client_.SetOriginTrialPublicKey(key); + test_content_client_.SetOriginTrialPublicKey(key); } - TrialTokenValidator trial_token_validator_; const url::Origin appropriate_origin_; const url::Origin inappropriate_origin_; const url::Origin insecure_origin_; private: - TestContentRendererClient test_content_renderer_client_; + TestContentClient test_content_client_; }; TEST_F(TrialTokenValidatorTest, ValidateValidToken) { - EXPECT_TRUE(trial_token_validator_.validateToken( + EXPECT_TRUE(TrialTokenValidator::ValidateToken( kSampleToken, appropriate_origin_, kAppropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateInappropriateOrigin) { - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kSampleToken, inappropriate_origin_, kAppropriateFeatureName)); - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kSampleToken, insecure_origin_, kAppropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateInappropriateFeature) { - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kSampleToken, appropriate_origin_, kInappropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateInvalidSignature) { - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kInvalidSignatureToken, appropriate_origin_, kAppropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateUnparsableToken) { - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kUnparsableToken, appropriate_origin_, kAppropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateExpiredToken) { - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kExpiredToken, appropriate_origin_, kAppropriateFeatureName)); } TEST_F(TrialTokenValidatorTest, ValidateValidTokenWithIncorrectKey) { SetPublicKey(kTestPublicKey2); - EXPECT_FALSE(TrialTokenValidator().validateToken( + EXPECT_FALSE(TrialTokenValidator::ValidateToken( kSampleToken, appropriate_origin_, kAppropriateFeatureName)); }
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 3029054..a41971a 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -781,6 +781,8 @@ 'browser/frame_host/render_widget_host_view_child_frame.h', 'browser/frame_host/render_widget_host_view_guest.cc', 'browser/frame_host/render_widget_host_view_guest.h', + 'browser/frame_host/traced_frame_tree_node.cc', + 'browser/frame_host/traced_frame_tree_node.h', 'browser/gamepad/gamepad_consumer.h', 'browser/gamepad/gamepad_data_fetcher.cc', 'browser/gamepad/gamepad_data_fetcher.h',
diff --git a/content/content_common.gypi b/content/content_common.gypi index 6fb7d99..da15942 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -538,6 +538,10 @@ 'common/notification_constants.h', 'common/one_writer_seqlock.cc', 'common/one_writer_seqlock.h', + 'common/origin_trials/trial_token.cc', + 'common/origin_trials/trial_token.h', + 'common/origin_trials/trial_token_validator.cc', + 'common/origin_trials/trial_token_validator.h', 'common/origin_util.cc', 'common/p2p_messages.h', 'common/page_state_serialization.cc',
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi index adf3d1d..5c039754 100644 --- a/content/content_renderer.gypi +++ b/content/content_renderer.gypi
@@ -373,10 +373,8 @@ 'renderer/net_info_helper.h', 'renderer/notification_permission_dispatcher.cc', 'renderer/notification_permission_dispatcher.h', - 'renderer/origin_trials/trial_token.cc', - 'renderer/origin_trials/trial_token.h', - 'renderer/origin_trials/trial_token_validator.cc', - 'renderer/origin_trials/trial_token_validator.h', + 'renderer/origin_trials/web_trial_token_validator_impl.cc', + 'renderer/origin_trials/web_trial_token_validator_impl.h', 'renderer/peripheral_content_heuristic.cc', 'renderer/peripheral_content_heuristic.h', 'renderer/presentation/presentation_connection_client.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 3f2ff07..f5f1358e 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -553,6 +553,7 @@ 'browser/renderer_host/input/touch_action_filter_unittest.cc', 'browser/renderer_host/input/touch_emulator_unittest.cc', 'browser/renderer_host/input/touch_event_queue_unittest.cc', + 'browser/renderer_host/input/web_input_event_builders_android_unittest.cc', 'browser/renderer_host/input/web_input_event_builders_mac_unittest.mm', 'browser/renderer_host/input/web_input_event_unittest.cc', 'browser/renderer_host/input/web_input_event_util_unittest.cc', @@ -681,6 +682,8 @@ 'common/mac/attributed_string_coder_unittest.mm', 'common/mac/font_descriptor_unittest.mm', 'common/one_writer_seqlock_unittest.cc', + 'common/origin_trials/trial_token_unittest.cc', + 'common/origin_trials/trial_token_validator_unittest.cc', 'common/origin_util_unittest.cc', 'common/page_state_serialization_unittest.cc', 'common/page_zoom_unittest.cc', @@ -720,8 +723,6 @@ 'renderer/media/video_capture_impl_unittest.cc', 'renderer/media/video_capture_message_filter_unittest.cc', 'renderer/media/webmediaplayer_ms_unittest.cc', - 'renderer/origin_trials/trial_token_unittest.cc', - 'renderer/origin_trials/trial_token_validator_unittest.cc', 'renderer/peripheral_content_heuristic_unittest.cc', 'renderer/raster_worker_pool_unittest.cc', 'renderer/render_thread_impl_unittest.cc',
diff --git a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java index 899d48f0..4180cac 100644 --- a/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java +++ b/content/public/android/java/src/org/chromium/content/common/ContentSwitches.java
@@ -63,6 +63,10 @@ public static final String DISABLE_GESTURE_REQUIREMENT_FOR_MEDIA_PLAYBACK = "disable-gesture-requirement-for-media-playback"; + // Native switch kDisableGestureRequirementForPresentation + public static final String DISABLE_GESTURE_REQUIREMENT_FOR_PRESENTATION = + "disable-gesture-requirement-for-presentation"; + // Native switch kRendererProcessLimit public static final String RENDER_PROCESS_LIMIT = "renderer-process-limit";
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java index d2b9ed2..bdff26a7 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ChildProcessLauncherTest.java
@@ -16,6 +16,8 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; + /** * Instrumentation tests for ChildProcessLauncher. */ @@ -43,22 +45,20 @@ ChildProcessLauncher.allocateBoundConnectionForTesting(context); // Verify that the connection is not considered as allocated. - CriteriaHelper.pollForCriteria(new Criteria( - "Failed connection wasn't released from the allocator.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { + public Integer call() { return ChildProcessLauncher.allocatedConnectionsCountForTesting( - appContext) == 0; + appContext); } - }); + })); - CriteriaHelper.pollForCriteria(new Criteria( - "Failed connection wasn't released from ChildProcessLauncher.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 0; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); } /** @@ -83,22 +83,20 @@ assertTrue(connection.crashServiceForTesting()); // Verify that the connection gets cleaned-up. - CriteriaHelper.pollForCriteria(new Criteria( - "Crashed connection wasn't released from the allocator.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { + public Integer call() { return ChildProcessLauncher.allocatedConnectionsCountForTesting( - appContext) == 0; + appContext); } - }); + })); - CriteriaHelper.pollForCriteria(new Criteria( - "Crashed connection wasn't released from ChildProcessLauncher.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 0; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); } /** @@ -118,13 +116,12 @@ triggerConnectionSetup(connection); // Verify that the connection completes the setup. - CriteriaHelper.pollForCriteria(new Criteria( - "The connection wasn't registered in ChildProcessLauncher after setup.") { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 1; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); CriteriaHelper.pollForCriteria( new Criteria("The connection failed to get a pid in setup.") { @@ -138,22 +135,20 @@ assertTrue(connection.crashServiceForTesting()); // Verify that the connection gets cleaned-up. - CriteriaHelper.pollForCriteria(new Criteria( - "Crashed connection wasn't released from the allocator.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { + public Integer call() { return ChildProcessLauncher.allocatedConnectionsCountForTesting( - appContext) == 0; + appContext); } - }); + })); - CriteriaHelper.pollForCriteria(new Criteria( - "Crashed connection wasn't released from ChildProcessLauncher.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 0; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); // Verify that the connection pid remains set after termination. assertTrue(connection.getPid() != 0); @@ -182,13 +177,12 @@ // Verify that the connection completes the setup. CriteriaHelper.pollForCriteria( - new Criteria( - "The connection wasn't registered in ChildProcessLauncher after setup.") { + Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 1; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); CriteriaHelper.pollForCriteria( new Criteria("The connection failed to get a pid in setup.") { @@ -202,30 +196,29 @@ assertTrue(connection.crashServiceForTesting()); // Verify that a new service is started for the pending spawn. - CriteriaHelper.pollForCriteria(new Criteria("Failed to spawn from queue.") { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.pendingSpawnsCountForTesting() == 0; + public Integer call() { + return ChildProcessLauncher.pendingSpawnsCountForTesting(); } - }); + })); CriteriaHelper.pollForCriteria( - new Criteria("The connection wasn't allocated for the pending spawn.") { + Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { + public Integer call() { return ChildProcessLauncher.allocatedConnectionsCountForTesting( - appContext) == 1; + appContext); } - }); + })); // Verify that the connection completes the setup for the pending spawn. - CriteriaHelper.pollForCriteria(new Criteria( - "The connection wasn't registered in ChildProcessLauncher after setup.") { + CriteriaHelper.pollForCriteria(Criteria.equals(1, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return ChildProcessLauncher.connectedServicesCountForTesting() == 1; + public Integer call() { + return ChildProcessLauncher.connectedServicesCountForTesting(); } - }); + })); } private ChildProcessConnectionImpl startConnection() throws InterruptedException {
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java index 7a739095..359d8e9f 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewCoreSelectionTest.java
@@ -468,12 +468,13 @@ assertEquals(mContentViewCore.getSelectedText(), "SampleTextArea"); hideSelectActionMode(); waitForSelectActionBarVisible(false); - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - return "SampleTextArea".equals(getTextBeforeCursor(50, 0)); - } - }); + CriteriaHelper.pollForCriteria( + Criteria.equals("SampleTextArea", new Callable<CharSequence>() { + @Override + public CharSequence call() { + return getTextBeforeCursor(50, 0); + } + })); } @SmallTest @@ -659,12 +660,12 @@ private void waitForSelectActionBarVisible( final boolean visible) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(visible, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return visible == mContentViewCore.isSelectActionBarShowing(); + public Boolean call() { + return mContentViewCore.isSelectActionBarShowing(); } - }); + })); } private void setVisibileOnUiThread(final boolean show) { @@ -714,11 +715,11 @@ } private void waitForPastePopupStatus(final boolean show) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(show, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return show == mContentViewCore.isPastePopupShowing(); + public Boolean call() { + return mContentViewCore.isPastePopupShowing(); } - }); + })); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java index 8e626c9..4ed740b 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewLocationTest.java
@@ -15,6 +15,8 @@ import org.chromium.content_public.browser.LoadUrlParams; import org.chromium.content_shell_apk.ContentShellTestBase; +import java.util.concurrent.Callable; + /** * Test suite for ensureing that Geolocation interacts as expected * with ContentView APIs - e.g. that it's started and stopped as the @@ -71,12 +73,12 @@ } private void ensureGeolocationRunning(final boolean running) throws Exception { - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(running, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return mMockLocationProvider.isRunning() == running; + public Boolean call() { + return mMockLocationProvider.isRunning(); } - }); + })); } @Override
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java index 4ad685a..71af0b8 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/InterstitialPageTest.java
@@ -64,14 +64,13 @@ } private void waitForInterstitial(final boolean shouldBeShown) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria( - shouldBeShown ? "Interstitial never shown." : "Interstitial never hidden.") { - @Override - public boolean isSatisfied() { - return shouldBeShown - == getWebContents().isShowingInterstitialPage(); - } - }); + CriteriaHelper.pollForUIThreadCriteria( + Criteria.equals(shouldBeShown, new Callable<Boolean>() { + @Override + public Boolean call() { + return getWebContents().isShowingInterstitialPage(); + } + })); } /**
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java index 7792b4e6..5b88806 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/MediaSessionTest.java
@@ -17,6 +17,8 @@ import org.chromium.content.common.ContentSwitches; import org.chromium.content_shell_apk.ContentShellTestBase; +import java.util.concurrent.Callable; + /** * Tests for MediaSession. */ @@ -65,13 +67,13 @@ mAudioFocusState = AudioManager.AUDIOFOCUS_LOSS; } - public void waitForFocusStateChange(final int focusType) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria() { + public void waitForFocusStateChange(int focusType) throws InterruptedException { + CriteriaHelper.pollForCriteria(Criteria.equals(focusType, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return getAudioFocusState() == focusType; + public Integer call() { + return getAudioFocusState(); } - }); + })); } }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java index 905e24c..1aea5a9 100644 --- a/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java +++ b/content/public/android/javatests/src/org/chromium/content/browser/input/ImeTest.java
@@ -272,14 +272,12 @@ private void waitForKeyboardStates(int show, int hide, int restart, Integer[] history) throws InterruptedException { final String expected = stringifyKeyboardStates(show, hide, restart, history); - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(expected, new Callable<String>() { @Override - public boolean isSatisfied() { - updateFailureReason( - "Expected: {" + expected + "}, Actual: {" + getKeyboardStates() + "}"); - return expected.equals(getKeyboardStates()); + public String call() { + return getKeyboardStates(); } - }); + })); } private void resetAllStates() { @@ -392,12 +390,12 @@ // hide status of IME, so we will just check whether showIme() has been triggered. DOMUtils.longPressNode(this, mContentViewCore, "input_text"); final int newCount = showCount + 2; - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(newCount, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return newCount == mInputMethodManagerWrapper.getShowSoftInputCounter(); + public Integer call() { + return mInputMethodManagerWrapper.getShowSoftInputCounter(); } - }); + })); } private void attachPhysicalKeyboard() { @@ -939,14 +937,12 @@ private void waitUntilGetCharacterBeforeCursorBecomes(final String expectedText) throws InterruptedException { - pollForCriteriaOnThread(new Criteria() { + pollForCriteriaOnThread(Criteria.equals(expectedText, new Callable<String>() { @Override - public boolean isSatisfied() { - String actualText = (String) mConnection.getTextBeforeCursor(1, 0); - updateFailureReason("actualText: " + actualText); - return expectedText.equals(actualText); + public String call() { + return (String) mConnection.getTextBeforeCursor(1, 0); } - }); + })); } private void pollForCriteriaOnThread(final Criteria criteria) throws InterruptedException { @@ -1105,12 +1101,12 @@ private void assertWaitForSelectActionBarStatus( final boolean show) throws InterruptedException { - CriteriaHelper.pollForUIThreadCriteria(new Criteria() { + CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(show, new Callable<Boolean>() { @Override - public boolean isSatisfied() { - return show == mContentViewCore.isSelectActionBarShowing(); + public Boolean call() { + return mContentViewCore.isSelectActionBarShowing(); } - }); + })); } private void waitAndVerifyUpdateSelection(final int index, final int selectionStart, @@ -1350,16 +1346,12 @@ throws InterruptedException, TimeoutException { DOMUtils.focusNode(mWebContents, id); assertWaitForKeyboardStatus(shouldShowKeyboard); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(id, new Callable<String>() { @Override - public boolean isSatisfied() { - try { - return id.equals(DOMUtils.getFocusedNode(mWebContents)); - } catch (Exception e) { - return false; - } + public String call() throws Exception { + return DOMUtils.getFocusedNode(mWebContents); } - }); + })); // When we focus another element, the connection may be recreated. mConnection = getInputConnection(); }
diff --git a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java index 29a9060..a093583 100644 --- a/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java +++ b/content/public/android/javatests/src/org/chromium/content/common/CleanupReferenceTest.java
@@ -12,6 +12,7 @@ import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; +import java.util.concurrent.Callable; import java.util.concurrent.atomic.AtomicInteger; /** Test suite for {@link CleanupReference}. */ @@ -66,12 +67,12 @@ // Ensure compiler / instrumentation does not strip out the assignment. assertTrue(instance == null); collectGarbage(); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return sObjectCount.get() == 0; + public Integer call() { + return sObjectCount.get(); } - }); + })); } @SuppressFBWarnings("UC_USELESS_OBJECT") @@ -95,12 +96,12 @@ // to be GC'ed only when building using GN. assertTrue(sObjectCount.get() != -1); collectGarbage(); - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(0, new Callable<Integer>() { @Override - public boolean isSatisfied() { - return sObjectCount.get() == 0; + public Integer call() { + return sObjectCount.get(); } - }); + })); } }
diff --git a/content/public/browser/javascript_dialog_manager.h b/content/public/browser/javascript_dialog_manager.h index 114418cf..2342543 100644 --- a/content/public/browser/javascript_dialog_manager.h +++ b/content/public/browser/javascript_dialog_manager.h
@@ -40,7 +40,6 @@ // Displays a dialog asking the user if they want to leave a page. virtual void RunBeforeUnloadDialog(WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) = 0;
diff --git a/content/public/browser/native_web_keyboard_event.h b/content/public/browser/native_web_keyboard_event.h index 45a6707..7f593df 100644 --- a/content/public/browser/native_web_keyboard_event.h +++ b/content/public/browser/native_web_keyboard_event.h
@@ -12,6 +12,10 @@ #include "third_party/WebKit/public/web/WebInputEvent.h" #include "ui/gfx/native_widget_types.h" +#if defined(OS_ANDROID) +#include "base/android/scoped_java_ref.h" +#endif + namespace ui { class KeyEvent; } @@ -34,14 +38,16 @@ int unicode_character, bool is_system_key); // Takes ownership of android_key_event. - NativeWebKeyboardEvent(jobject android_key_event, - blink::WebInputEvent::Type type, - int modifiers, - double time_secs, - int keycode, - int scancode, - int unicode_character, - bool is_system_key); + NativeWebKeyboardEvent( + JNIEnv* env, + const base::android::JavaRef<jobject>& android_key_event, + blink::WebInputEvent::Type type, + int modifiers, + double time_secs, + int keycode, + int scancode, + int unicode_character, + bool is_system_key); #else explicit NativeWebKeyboardEvent(const ui::KeyEvent& key_event); #if defined(USE_AURA)
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index bbee142..1662c395 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -368,6 +368,7 @@ virtual void SetIsCrashed(base::TerminationStatus status, int error_code) = 0; virtual base::TerminationStatus GetCrashedStatus() const = 0; + virtual int GetCrashedErrorCode() const = 0; // Whether the tab is in the process of being destroyed. virtual bool IsBeingDestroyed() const = 0;
diff --git a/content/public/browser/web_contents_observer.h b/content/public/browser/web_contents_observer.h index 29c2c1e..2ad466e 100644 --- a/content/public/browser/web_contents_observer.h +++ b/content/public/browser/web_contents_observer.h
@@ -27,6 +27,7 @@ class NavigationHandle; class RenderFrameHost; class RenderViewHost; +class RenderWidgetHost; class WebContents; class WebContentsImpl; struct AXEventNotificationDetails; @@ -121,6 +122,10 @@ virtual void RenderViewHostChanged(RenderViewHost* old_host, RenderViewHost* new_host) {} + // This method is invoked when the process for the current main + // RenderFrameHost becomes unresponsive. + virtual void OnRendererUnresponsive(RenderWidgetHost* render_widget_host) {} + // Navigation related events ------------------------------------------------ // Called when a navigation started in the WebContents. |navigation_handle|
diff --git a/content/public/common/content_client.cc b/content/public/common/content_client.cc index 75ed9979f..34350d5 100644 --- a/content/public/common/content_client.cc +++ b/content/public/common/content_client.cc
@@ -120,4 +120,8 @@ return false; } +base::StringPiece ContentClient::GetOriginTrialPublicKey() { + return base::StringPiece(); +} + } // namespace content
diff --git a/content/public/common/content_client.h b/content/public/common/content_client.h index eabd3da..ba15b3e 100644 --- a/content/public/common/content_client.h +++ b/content/public/common/content_client.h
@@ -156,6 +156,10 @@ // model decisions. virtual bool IsSupplementarySiteIsolationModeEnabled(); + // Returns the public key to be used for origin trials, or an empty string if + // origin trials are not enabled in this context. + virtual base::StringPiece GetOriginTrialPublicKey(); + private: friend class ContentClientInitializer; // To set these pointers. friend class InternalTestInitializer;
diff --git a/content/public/renderer/content_renderer_client.cc b/content/public/renderer/content_renderer_client.cc index f928d33..d32ecccb 100644 --- a/content/public/renderer/content_renderer_client.cc +++ b/content/public/renderer/content_renderer_client.cc
@@ -225,8 +225,4 @@ return true; } -base::StringPiece ContentRendererClient::GetOriginTrialPublicKey() { - return base::StringPiece(); -} - } // namespace content
diff --git a/content/public/renderer/content_renderer_client.h b/content/public/renderer/content_renderer_client.h index 52b397f..880550cb 100644 --- a/content/public/renderer/content_renderer_client.h +++ b/content/public/renderer/content_renderer_client.h
@@ -327,10 +327,6 @@ // Whether this renderer should enforce preferences related to the WebRTC // routing logic, i.e. allowing multiple routes and non-proxied UDP. virtual bool ShouldEnforceWebRTCRoutingPreferences(); - - // Returns the public key to be used for origin trials, or an empty string if - // origin trials are not enabled in this context. - virtual base::StringPiece GetOriginTrialPublicKey(); }; } // namespace content
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java index 55c5f27b..be776c4 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/Criteria.java
@@ -4,6 +4,8 @@ package org.chromium.content.browser.test.util; +import java.util.concurrent.Callable; + /** * Provides a means for validating whether some condition/criteria has been met. * <p> @@ -52,4 +54,32 @@ mFailureReason = reason; } + /** + * Constructs a Criteria that will determine the equality of two items. + * + * <p> + * <pre> + * Sample Usage: + * <code> + * public void waitForTabTitle(final Tab tab, String title) { + * CriteriaHelper.pollForUIThreadCriteria(Criteria.equals(title, new Callable<String>() { + * {@literal @}Override + * public String call() { + * return tab.getTitle(); + * } + * })); + * } + * </code> + * </pre> + * + * @param <T> The type of value whose equality will be tested. + * @param expectedValue The value that is expected to determine the success of the criteria. + * @param actualValueCallable A {@link Callable} that provides a way of getting the current + * actual value. + * @return A Criteria that will check the equality of the passed in data. + */ + public static <T> Criteria equals(T expectedValue, Callable<T> actualValueCallable) { + return new EqualityCriteria<T>(expectedValue, actualValueCallable); + } + }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java index 4039835..32df58b 100644 --- a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/CriteriaHelper.java
@@ -26,13 +26,16 @@ * <pre> * Sample Usage: * <code> - * public void waitForTabTitle(final Tab tab, final String title) { + * public void waitForTabFullyLoaded(final Tab tab) { * CriteriaHelper.pollForUIThreadCriteria(new Criteria() { * {@literal @}Override * public boolean isSatisified() { - * updateFailureReason("Tab title did not match -- expected: " + title - * + ", actual: " + tab.getTitle()); - * return TextUtils.equals(tab.getTitle(), title); + * if (tab.getWebContents() == null) { + * updateFailureReason("Tab has no web contents"); + * return false; + * } + * updateFailureReason("Tab not fully loaded"); + * return tab.isLoading(); * } * }); * }
diff --git a/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/EqualityCriteria.java b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/EqualityCriteria.java new file mode 100644 index 0000000..4c96eb5 --- /dev/null +++ b/content/public/test/android/javatests/src/org/chromium/content/browser/test/util/EqualityCriteria.java
@@ -0,0 +1,46 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +package org.chromium.content.browser.test.util; + +import java.util.concurrent.Callable; + +/** + * Extension of the Criteria that handles object equality while providing a standard error message. + * + * @param <T> The type of value whose equality will be tested. + */ +class EqualityCriteria<T> extends Criteria { + + private final T mExpectedValue; + private final Callable<T> mActualValueCallable; + + /** + * Construct the EqualityCriteria with the given expected value. + * @param expectedValue The value that is expected to determine the success of the criteria. + */ + public EqualityCriteria(T expectedValue, Callable<T> actualValueCallable) { + mExpectedValue = expectedValue; + mActualValueCallable = actualValueCallable; + } + + @Override + public final boolean isSatisfied() { + T actualValue = null; + try { + actualValue = mActualValueCallable.call(); + } catch (Exception ex) { + updateFailureReason("Exception occurred: " + ex.getMessage()); + ex.printStackTrace(); + return false; + } + + updateFailureReason( + "Values did not match. Expected: " + mExpectedValue + ", actual: " + actualValue); + if (mExpectedValue == null) { + return actualValue == null; + } + return mExpectedValue.equals(actualValue); + } +}
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index 9e84f2d..89e650c 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -1511,21 +1511,24 @@ encrypted_client_->didResumePlaybackBlockedForKey(); } -void WebMediaPlayerAndroid::OnHidden(bool must_suspend) { +void WebMediaPlayerAndroid::OnHidden() { if (base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisableMediaSuspend)) { return; } - // If we're idle or playing video, pause and release resources; audio only - // players are allowed to continue playing in the background unless indicated - // otherwise by the call. - if (must_suspend || (paused() && playback_completed_) || hasVideo()) - SuspendAndReleaseResources(); + OnSuspendRequested(false); } void WebMediaPlayerAndroid::OnShown() {} +void WebMediaPlayerAndroid::OnSuspendRequested(bool must_suspend) { + // If we're idle or playing video, pause and release resources; audio only + // players are allowed to continue unless indicated otherwise by the call. + if (must_suspend || (paused() && playback_completed_) || hasVideo()) + SuspendAndReleaseResources(); +} + void WebMediaPlayerAndroid::OnPlay() { play(); client_->playbackStateChanged();
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 932b521..626b176 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -245,8 +245,9 @@ void OnWaitingForDecryptionKey() override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden(bool must_suspend) override; + void OnHidden() override; void OnShown() override; + void OnSuspendRequested(bool must_suspend) override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override;
diff --git a/content/renderer/media/canvas_capture_handler.cc b/content/renderer/media/canvas_capture_handler.cc index 15ebf05..fd6e55f2 100644 --- a/content/renderer/media/canvas_capture_handler.cc +++ b/content/renderer/media/canvas_capture_handler.cc
@@ -194,9 +194,10 @@ } const bool isOpaque = image->isOpaque(); + const base::TimeTicks timestamp = base::TimeTicks::Now(); scoped_refptr<media::VideoFrame> video_frame = frame_pool_.CreateFrame( isOpaque ? media::PIXEL_FORMAT_I420 : media::PIXEL_FORMAT_YV12A, size, - gfx::Rect(size), size, base::TimeTicks::Now() - base::TimeTicks()); + gfx::Rect(size), size, timestamp - base::TimeTicks()); DCHECK(video_frame); // TODO(emircan): Use https://code.google.com/p/libyuv/issues/detail?id=572 @@ -218,8 +219,7 @@ FROM_HERE, base::Bind(&CanvasCaptureHandler::CanvasCaptureHandlerDelegate:: SendNewFrameOnIOThread, - delegate_->GetWeakPtrForIOThread(), video_frame, - base::TimeTicks::Now())); + delegate_->GetWeakPtrForIOThread(), video_frame, timestamp)); } void CanvasCaptureHandler::AddVideoCapturerSourceToVideoTrack(
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.cc b/content/renderer/media/renderer_webmediaplayer_delegate.cc index 9966382..310c9bb 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.cc +++ b/content/renderer/media/renderer_webmediaplayer_delegate.cc
@@ -18,13 +18,8 @@ : RenderFrameObserver(render_frame), default_tick_clock_(new base::DefaultTickClock()), tick_clock_(default_tick_clock_.get()) { -#if defined(OS_ANDROID) - // On Android the idle cleanup timer is enabled by default. - // TODO(dalecurtis): Eventually this should be enabled on all platforms. - idle_cleanup_enabled_ = true; idle_cleanup_interval_ = base::TimeDelta::FromSeconds(5); idle_timeout_ = base::TimeDelta::FromSeconds(15); -#endif } RendererWebMediaPlayerDelegate::~RendererWebMediaPlayerDelegate() {} @@ -56,8 +51,7 @@ void RendererWebMediaPlayerDelegate::DidPause(int delegate_id, bool reached_end_of_stream) { DCHECK(id_map_.Lookup(delegate_id)); - if (reached_end_of_stream) - AddIdleDelegate(delegate_id); + AddIdleDelegate(delegate_id); Send(new MediaPlayerDelegateHostMsg_OnMediaPaused(routing_id(), delegate_id, reached_end_of_stream)); } @@ -75,7 +69,7 @@ void RendererWebMediaPlayerDelegate::WasHidden() { for (IDMap<Observer>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) - it.GetCurrentValue()->OnHidden(false); + it.GetCurrentValue()->OnHidden(); } void RendererWebMediaPlayerDelegate::WasShown() { @@ -98,10 +92,9 @@ return handled; } -void RendererWebMediaPlayerDelegate::EnableInstantIdleCleanupForTesting( +void RendererWebMediaPlayerDelegate::SetIdleCleanupParamsForTesting( base::TimeDelta idle_timeout, base::TickClock* tick_clock) { - idle_cleanup_enabled_ = true; idle_cleanup_interval_ = base::TimeDelta(); idle_timeout_ = idle_timeout; tick_clock_ = tick_clock; @@ -121,7 +114,7 @@ void RendererWebMediaPlayerDelegate::OnMediaDelegateSuspendAllMediaPlayers() { for (IDMap<Observer>::iterator it(&id_map_); !it.IsAtEnd(); it.Advance()) - it.GetCurrentValue()->OnHidden(true); + it.GetCurrentValue()->OnSuspendRequested(true); } void RendererWebMediaPlayerDelegate::OnMediaDelegateVolumeMultiplierUpdate( @@ -133,9 +126,6 @@ } void RendererWebMediaPlayerDelegate::AddIdleDelegate(int delegate_id) { - if (!idle_cleanup_enabled_) - return; - idle_delegate_map_[delegate_id] = tick_clock_->NowTicks(); if (!idle_cleanup_timer_.IsRunning()) { idle_cleanup_timer_.Start( @@ -145,9 +135,6 @@ } void RendererWebMediaPlayerDelegate::RemoveIdleDelegate(int delegate_id) { - if (!idle_cleanup_enabled_) - return; - // To avoid invalidating the iterator, just mark the delegate for deletion // using a sentinel value of an empty TimeTicks. if (idle_cleanup_running_) { @@ -166,9 +153,14 @@ // validity we set |idle_cleanup_running_| to true and defer deletions. base::AutoReset<bool> scoper(&idle_cleanup_running_, true); const base::TimeTicks now = tick_clock_->NowTicks(); - for (const auto& kv : idle_delegate_map_) { - if (now - kv.second > idle_timeout_) - id_map_.Lookup(kv.first)->OnHidden(true); + for (auto& idle_delegate_entry : idle_delegate_map_) { + if (now - idle_delegate_entry.second > idle_timeout_) { + id_map_.Lookup(idle_delegate_entry.first)->OnSuspendRequested(false); + + // Whether or not the player accepted the suspension, mark it for removal + // from future polls to avoid running the timer forever. + idle_delegate_entry.second = base::TimeTicks(); + } } // Take care of any removals that happened during the above iteration.
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate.h b/content/renderer/media/renderer_webmediaplayer_delegate.h index 2ca3d46..0a7813e 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate.h +++ b/content/renderer/media/renderer_webmediaplayer_delegate.h
@@ -53,11 +53,11 @@ void WasShown() override; bool OnMessageReceived(const IPC::Message& msg) override; - // Sets |idle_cleanup_enabled_| to true, zeros out |idle_cleanup_interval_|, - // and sets |idle_timeout_| to |idle_timeout|. A zero cleanup interval will - // cause the idle timer to run with each run of the message loop. - void EnableInstantIdleCleanupForTesting(base::TimeDelta idle_timeout, - base::TickClock* tick_clock); + // Zeros out |idle_cleanup_interval_|, and sets |idle_timeout_| to + // |idle_timeout|. A zero cleanup interval will cause the idle timer to run + // with each run of the message loop. + void SetIdleCleanupParamsForTesting(base::TimeDelta idle_timeout, + base::TickClock* tick_clock); bool IsIdleCleanupTimerRunningForTesting() const { return idle_cleanup_timer_.IsRunning(); } @@ -86,10 +86,6 @@ std::map<int, base::TimeTicks> idle_delegate_map_; base::RepeatingTimer idle_cleanup_timer_; - // Controls whether cleanup of idle delegates is enabled or not as well as the - // polling interval and timeout period for delegates; overridden for testing. - bool idle_cleanup_enabled_ = false; - // Amount of time allowed to elapse after a delegate enters the paused before // the delegate is suspended. base::TimeDelta idle_timeout_;
diff --git a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc index 8ab298ae..eb4ecd6 100644 --- a/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc +++ b/content/renderer/media/renderer_webmediaplayer_delegate_browsertest.cc
@@ -28,8 +28,9 @@ ~MockWebMediaPlayerDelegateObserver() {} // WebMediaPlayerDelegate::Observer implementation. - MOCK_METHOD1(OnHidden, void(bool)); + MOCK_METHOD0(OnHidden, void()); MOCK_METHOD0(OnShown, void()); + MOCK_METHOD1(OnSuspendRequested, void(bool)); MOCK_METHOD0(OnPlay, void()); MOCK_METHOD0(OnPause, void()); MOCK_METHOD1(OnVolumeMultiplierUpdate, void(double)); @@ -123,7 +124,7 @@ testing::StrictMock<MockWebMediaPlayerDelegateObserver> observer; const int delegate_id = delegate_manager_->AddObserver(&observer); - EXPECT_CALL(observer, OnHidden(false)); + EXPECT_CALL(observer, OnHidden()); delegate_manager_->WasHidden(); EXPECT_CALL(observer, OnShown()); @@ -143,7 +144,7 @@ kTestMultiplier); delegate_manager_->OnMessageReceived(volume_msg); - EXPECT_CALL(observer, OnHidden(true)); + EXPECT_CALL(observer, OnSuspendRequested(true)); MediaPlayerDelegateMsg_SuspendAllMediaPlayers suspend_msg(0); delegate_manager_->OnMessageReceived(suspend_msg); @@ -156,8 +157,7 @@ tick_clock.Advance(base::TimeDelta::FromSeconds(1234)); const base::TimeDelta kIdleTimeout = base::TimeDelta::FromSeconds(2); - delegate_manager_->EnableInstantIdleCleanupForTesting(kIdleTimeout, - &tick_clock); + delegate_manager_->SetIdleCleanupParamsForTesting(kIdleTimeout, &tick_clock); EXPECT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); testing::StrictMock<MockWebMediaPlayerDelegateObserver> observer_1; @@ -175,7 +175,7 @@ // Adding the observer should instantly queue the timeout task, once run the // second delegate should be expired while the first is kept alive. { - EXPECT_CALL(observer_2, OnHidden(true)) + EXPECT_CALL(observer_2, OnSuspendRequested(false)) .WillOnce(RunClosure(base::Bind( &RendererWebMediaPlayerDelegate::PlayerGone, base::Unretained(delegate_manager_.get()), delegate_id_2))); @@ -185,7 +185,8 @@ run_loop.Run(); } - // Pausing should not count as idle if playback didn't reach end of stream. + // Pausing should count as idle if playback didn't reach end of stream, but + // in this case the player will not remove the MediaSession. delegate_manager_->DidPause(delegate_id_1, false /* reached_end_of_stream */); testing::StrictMock<MockWebMediaPlayerDelegateObserver> observer_3; const int delegate_id_3 = delegate_manager_->AddObserver(&observer_3); @@ -195,6 +196,8 @@ // Adding the observer should instantly queue the timeout task, once run no // delegates should have been expired. { + EXPECT_CALL(observer_1, OnSuspendRequested(false)) + .Times(testing::AtLeast(1)); base::RunLoop run_loop; base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); @@ -210,7 +213,7 @@ // Once the timeout task runs the first delegate should be expired while the // third is kept alive. { - EXPECT_CALL(observer_1, OnHidden(true)) + EXPECT_CALL(observer_1, OnSuspendRequested(false)) .WillOnce(RunClosure(base::Bind( &RendererWebMediaPlayerDelegate::PlayerGone, base::Unretained(delegate_manager_.get()), delegate_id_1))); @@ -226,4 +229,31 @@ EXPECT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); } +TEST_F(RendererWebMediaPlayerDelegateTest, IdleDelegatesIgnoresSuspendRequest) { + // Start the tick clock off at a non-null value. + base::SimpleTestTickClock tick_clock; + tick_clock.Advance(base::TimeDelta::FromSeconds(1234)); + + const base::TimeDelta kIdleTimeout = base::TimeDelta::FromSeconds(2); + delegate_manager_->SetIdleCleanupParamsForTesting(kIdleTimeout, &tick_clock); + EXPECT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); + + testing::StrictMock<MockWebMediaPlayerDelegateObserver> observer_1; + const int delegate_id_1 = delegate_manager_->AddObserver(&observer_1); + EXPECT_TRUE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); + + // Adding the observer should instantly queue the timeout task, once run the + // second delegate should be expired while the first is kept alive. + EXPECT_CALL(observer_1, OnSuspendRequested(false)); + base::RunLoop run_loop; + base::MessageLoop::current()->PostTask(FROM_HERE, run_loop.QuitClosure()); + tick_clock.Advance(kIdleTimeout + base::TimeDelta::FromMicroseconds(1)); + run_loop.Run(); + + // Even though the player did not call PlayerGone() it should be removed from + // future idle cleanup polls. + EXPECT_FALSE(delegate_manager_->IsIdleCleanupTimerRunningForTesting()); + delegate_manager_->RemoveObserver(delegate_id_1); +} + } // namespace media
diff --git a/content/renderer/media/webmediaplayer_ms.cc b/content/renderer/media/webmediaplayer_ms.cc index 4134b847..90c6f45ce 100644 --- a/content/renderer/media/webmediaplayer_ms.cc +++ b/content/renderer/media/webmediaplayer_ms.cc
@@ -67,7 +67,7 @@ : url::Origin(security_origin)), volume_(1.0), volume_multiplier_(1.0), - paused_on_hidden_(false) { + should_play_upon_shown_(false) { DVLOG(1) << __FUNCTION__; DCHECK(client); if (delegate_) @@ -164,7 +164,7 @@ // Don't allow rendering to start while hidden; for either video or audio // since this may steal focus from a foreground player. if (delegate_ && delegate_->IsHidden()) { - paused_on_hidden_ = true; + should_play_upon_shown_ = true; return; } #endif @@ -182,7 +182,7 @@ media::kInfiniteDuration()); } - paused_on_hidden_ = false; + should_play_upon_shown_ = false; paused_ = false; } @@ -190,9 +190,7 @@ DVLOG(1) << __FUNCTION__; DCHECK(thread_checker_.CalledOnValidThread()); - // Always clear |paused_on_hidden_| since manual pause() should clear it and - // an OnHidden() pause will set it appropriately after this call. - paused_on_hidden_ = false; + should_play_upon_shown_ = false; media_log_->AddEvent(media_log_->CreateEvent(media::MediaLogEvent::PAUSE)); if (paused_) return; @@ -380,7 +378,7 @@ return 0; } -void WebMediaPlayerMS::OnHidden(bool must_suspend) { +void WebMediaPlayerMS::OnHidden() { #if defined(OS_ANDROID) DCHECK(thread_checker_.CalledOnValidThread()); @@ -392,18 +390,8 @@ // can't rely on |render_frame_suspended_| being false here. render_frame_suspended_ = true; - if (must_suspend) { - if (!paused_) { - pause(); - paused_on_hidden_ = true; - } - - if (delegate_) - delegate_->PlayerGone(delegate_id_); - } else if (!paused_) { - // pause() will make its own copy in the block above otherwise. + if (!paused_) compositor_->ReplaceCurrentFrameWithACopy(); - } #endif // defined(OS_ANDROID) } @@ -413,19 +401,36 @@ render_frame_suspended_ = false; - // Resume playback on visibility. play() clears |paused_on_hidden_|. - if (paused_on_hidden_) + // Resume playback on visibility. play() clears |should_play_upon_shown_|. + if (should_play_upon_shown_) play(); #endif // defined(OS_ANDROID) } +void WebMediaPlayerMS::OnSuspendRequested(bool must_suspend) { +#if defined(OS_ANDROID) + if (!must_suspend) + return; + + if (!paused_) { + pause(); + should_play_upon_shown_ = true; + } + + if (delegate_) + delegate_->PlayerGone(delegate_id_); + + render_frame_suspended_ = true; +#endif +} + void WebMediaPlayerMS::OnPlay() { play(); client_->playbackStateChanged(); } void WebMediaPlayerMS::OnPause() { - const bool was_playing = !paused_ || paused_on_hidden_; + const bool was_playing = !paused_ || should_play_upon_shown_; pause(); client_->playbackStateChanged(); @@ -433,7 +438,7 @@ // starts playing audio, in this case we want to track this so that when // OnShown() is called, we resume into the right state. if (was_playing && delegate_ && delegate_->IsHidden()) - paused_on_hidden_ = true; + should_play_upon_shown_ = true; } void WebMediaPlayerMS::OnVolumeMultiplierUpdate(double multiplier) {
diff --git a/content/renderer/media/webmediaplayer_ms.h b/content/renderer/media/webmediaplayer_ms.h index 28e7a160..8e1379b 100644 --- a/content/renderer/media/webmediaplayer_ms.h +++ b/content/renderer/media/webmediaplayer_ms.h
@@ -135,8 +135,9 @@ size_t videoDecodedByteCount() const override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden(bool must_suspend) override; + void OnHidden() override; void OnShown() override; + void OnSuspendRequested(bool must_suspend) override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override; @@ -223,8 +224,9 @@ double volume_; double volume_multiplier_; - // True if the delegate forced a pause during the last OnHidden() call. - bool paused_on_hidden_; + // True if playback should be started upon the next call to OnShown(). Only + // used on Android. + bool should_play_upon_shown_; DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerMS); };
diff --git a/content/renderer/media/webmediaplayer_ms_compositor.cc b/content/renderer/media/webmediaplayer_ms_compositor.cc index ac82084..bbc2586 100644 --- a/content/renderer/media/webmediaplayer_ms_compositor.cc +++ b/content/renderer/media/webmediaplayer_ms_compositor.cc
@@ -31,14 +31,11 @@ namespace { -// This function copies |frame| to a new I420 media::VideoFrame. -scoped_refptr<media::VideoFrame> CopyFrameToI420( +// This function copies |frame| to a new I420 or YV12A media::VideoFrame. +scoped_refptr<media::VideoFrame> CopyFrame( const scoped_refptr<media::VideoFrame>& frame, media::SkCanvasVideoRenderer* video_renderer) { - const scoped_refptr<media::VideoFrame> new_frame = - media::VideoFrame::CreateFrame(media::PIXEL_FORMAT_YV12, - frame->coded_size(), frame->visible_rect(), - frame->natural_size(), frame->timestamp()); + scoped_refptr<media::VideoFrame> new_frame; const gfx::Size& size = frame->coded_size(); if (frame->HasTextures()) { @@ -47,6 +44,9 @@ frame->format() == media::PIXEL_FORMAT_I420 || frame->format() == media::PIXEL_FORMAT_UYVY || frame->format() == media::PIXEL_FORMAT_NV12); + new_frame = media::VideoFrame::CreateFrame( + media::PIXEL_FORMAT_I420, frame->coded_size(), frame->visible_rect(), + frame->natural_size(), frame->timestamp()); SkBitmap bitmap; bitmap.allocN32Pixels(frame->visible_rect().width(), frame->visible_rect().height()); @@ -75,7 +75,13 @@ } else { DCHECK(frame->IsMappable()); DCHECK(frame->format() == media::PIXEL_FORMAT_YV12 || + frame->format() == media::PIXEL_FORMAT_YV12A || frame->format() == media::PIXEL_FORMAT_I420); + new_frame = media::VideoFrame::CreateFrame( + media::IsOpaque(frame->format()) ? media::PIXEL_FORMAT_I420 + : media::PIXEL_FORMAT_YV12A, + frame->coded_size(), frame->visible_rect(), frame->natural_size(), + frame->timestamp()); libyuv::I420Copy(frame->data(media::VideoFrame::kYPlane), frame->stride(media::VideoFrame::kYPlane), frame->data(media::VideoFrame::kUPlane), @@ -89,6 +95,14 @@ new_frame->data(media::VideoFrame::kVPlane), new_frame->stride(media::VideoFrame::kVPlane), size.width(), size.height()); + if (frame->format() == media::PIXEL_FORMAT_YV12A) { + libyuv::CopyPlane(frame->data(media::VideoFrame::kAPlane), + frame->stride(media::VideoFrame::kAPlane), + new_frame->data(media::VideoFrame::kAPlane), + new_frame->stride(media::VideoFrame::kAPlane), + size.width(), + size.height()); + } } // Transfer metadata keys. @@ -336,7 +350,7 @@ // there might be a finite number of available buffers. E.g, video that // originates from a video camera. current_frame_ = - CopyFrameToI420(current_frame_, player_->GetSkCanvasVideoRenderer()); + CopyFrame(current_frame_, player_->GetSkCanvasVideoRenderer()); } bool WebMediaPlayerMSCompositor::MapTimestampsToRenderTimeTicks(
diff --git a/content/renderer/media/webmediaplayer_ms_unittest.cc b/content/renderer/media/webmediaplayer_ms_unittest.cc index 2718231..b198fec 100644 --- a/content/renderer/media/webmediaplayer_ms_unittest.cc +++ b/content/renderer/media/webmediaplayer_ms_unittest.cc
@@ -128,7 +128,8 @@ void Pause() override; // Methods for test use - void QueueFrames(const std::vector<int>& timestamps_or_frame_type); + void QueueFrames(const std::vector<int>& timestamps_or_frame_type, + bool opaque_frame = true); bool Started() { return started_; } bool Paused() { return paused_; } @@ -184,7 +185,8 @@ } void MockVideoFrameProvider::QueueFrames( - const std::vector<int>& timestamp_or_frame_type) { + const std::vector<int>& timestamp_or_frame_type, + bool opaque_frame) { for (const int token : timestamp_or_frame_type) { if (token < static_cast<int>(FrameType::MIN_TYPE)) { CHECK(false) << "Unrecognized frame type: " << token; @@ -199,8 +201,9 @@ if (token >= 0) { gfx::Size natural_size = media::TestVideoConfig::NormalCodedSize(); auto frame = media::VideoFrame::CreateZeroInitializedFrame( - media::PIXEL_FORMAT_YV12, natural_size, gfx::Rect(natural_size), - natural_size, base::TimeDelta::FromMilliseconds(token)); + opaque_frame ? media::PIXEL_FORMAT_YV12 : media::PIXEL_FORMAT_YV12A, + natural_size, gfx::Rect(natural_size), natural_size, + base::TimeDelta::FromMilliseconds(token)); frame->metadata()->SetTimeTicks( media::VideoFrameMetadata::Key::REFERENCE_TIME, @@ -329,7 +332,7 @@ // WebMediaPlayerMSCompositor. // 7. When WebMediaPlayerMS::play gets called, evething paused in step 6 should // be resumed. -class WebMediaPlayerMSTest : public testing::Test, +class WebMediaPlayerMSTest : public testing::TestWithParam<bool>, public blink::WebMediaPlayerClient, public cc::VideoFrameProvider::Client { public: @@ -568,7 +571,8 @@ EXPECT_CALL(*this, DoStopRendering()); } -TEST_F(WebMediaPlayerMSTest, PlayThenPause) { +TEST_P(WebMediaPlayerMSTest, PlayThenPause) { + const bool opaque_frame = GetParam(); // In the middle of this test, WebMediaPlayerMS::pause will be called, and we // are going to verify that during the pause stage, a frame gets freezed, and // cc::VideoFrameProviderClient should also be paused. @@ -578,7 +582,7 @@ int tokens[] = {0, 33, 66, 100, 133, kTestBrake, 166, 200, 233, 266, 300, 333, 366, 400, 433, 466, 500, 533, 566, 600}; std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); - provider->QueueFrames(timestamps); + provider->QueueFrames(timestamps, opaque_frame); EXPECT_CALL(*this, DoSetWebLayer(true)); EXPECT_CALL(*this, DoStartRendering()); @@ -603,7 +607,8 @@ EXPECT_CALL(*this, DoSetWebLayer(false)); } -TEST_F(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { +TEST_P(WebMediaPlayerMSTest, PlayThenPauseThenPlay) { + const bool opaque_frame = GetParam(); // Similary to PlayAndPause test above, this one focuses on testing that // WebMediaPlayerMS can be resumed after a period of paused status. MockVideoFrameProvider* provider = LoadAndGetFrameProvider(false); @@ -613,7 +618,7 @@ 200, 233, 266, 300, 333, 366, 400, 433, kTestBrake, 466, 500, 533, 566, 600}; std::vector<int> timestamps(tokens, tokens + sizeof(tokens) / sizeof(int)); - provider->QueueFrames(timestamps); + provider->QueueFrames(timestamps, opaque_frame); EXPECT_CALL(*this, DoSetWebLayer(true)); EXPECT_CALL(*this, DoStartRendering()); @@ -649,6 +654,8 @@ EXPECT_CALL(*this, DoStopRendering()); } +INSTANTIATE_TEST_CASE_P(, WebMediaPlayerMSTest, ::testing::Bool()); + TEST_F(WebMediaPlayerMSTest, BackgroudRendering) { // During this test, we will switch to background rendering mode, in which // WebMediaPlayerMS::pause does not get called, but @@ -718,7 +725,7 @@ // A hidden event should not pause the player. delegate_.set_hidden(true); - player_.OnHidden(false); + player_.OnHidden(); EXPECT_FALSE(player_.paused()); // OnPause() should pause the player. @@ -735,13 +742,15 @@ player_.play(); EXPECT_FALSE(player_.paused()); - // An OnHidden() with forced suspension should pause playback. - delegate_.set_hidden(true); - player_.OnHidden(true); + // An OnSuspendRequested() without forced suspension should do nothing. + player_.OnSuspendRequested(false); + EXPECT_FALSE(player_.paused()); + + // An OnSuspendRequested() with forced suspension should pause playback. + player_.OnSuspendRequested(true); EXPECT_TRUE(player_.paused()); // OnShown() should restart after a forced suspension. - delegate_.set_hidden(false); player_.OnShown(); EXPECT_FALSE(player_.paused()); EXPECT_CALL(*this, DoSetWebLayer(false));
diff --git a/content/renderer/origin_trials/trial_token_validator.cc b/content/renderer/origin_trials/trial_token_validator.cc deleted file mode 100644 index f34afd1..0000000 --- a/content/renderer/origin_trials/trial_token_validator.cc +++ /dev/null
@@ -1,33 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "content/renderer/origin_trials/trial_token_validator.h" - -#include "base/time/time.h" -#include "content/public/common/content_client.h" -#include "content/public/renderer/content_renderer_client.h" -#include "content/renderer/origin_trials/trial_token.h" - -namespace content { - -TrialTokenValidator::TrialTokenValidator() {} -TrialTokenValidator::~TrialTokenValidator() {} - -bool TrialTokenValidator::validateToken(const blink::WebString& token, - const blink::WebSecurityOrigin& origin, - const blink::WebString& featureName) { - scoped_ptr<TrialToken> trial_token = TrialToken::Parse(token.utf8()); - - ContentClient* content_client = GetContentClient(); - CHECK(content_client); - - base::StringPiece public_key = - content_client->renderer()->GetOriginTrialPublicKey(); - - return !public_key.empty() && trial_token && - trial_token->IsAppropriate(origin, featureName.utf8()) && - trial_token->IsValid(base::Time::Now(), public_key); -} - -} // namespace content
diff --git a/content/renderer/origin_trials/web_trial_token_validator_impl.cc b/content/renderer/origin_trials/web_trial_token_validator_impl.cc new file mode 100644 index 0000000..01078ed --- /dev/null +++ b/content/renderer/origin_trials/web_trial_token_validator_impl.cc
@@ -0,0 +1,22 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/renderer/origin_trials/web_trial_token_validator_impl.h" + +#include "content/common/origin_trials/trial_token_validator.h" + +namespace content { + +WebTrialTokenValidatorImpl::WebTrialTokenValidatorImpl() {} +WebTrialTokenValidatorImpl::~WebTrialTokenValidatorImpl() {} + +bool WebTrialTokenValidatorImpl::validateToken( + const blink::WebString& token, + const blink::WebSecurityOrigin& origin, + const blink::WebString& featureName) { + return TrialTokenValidator::ValidateToken(token.utf8(), origin, + featureName.utf8()); +} + +} // namespace content
diff --git a/content/renderer/origin_trials/trial_token_validator.h b/content/renderer/origin_trials/web_trial_token_validator_impl.h similarity index 67% rename from content/renderer/origin_trials/trial_token_validator.h rename to content/renderer/origin_trials/web_trial_token_validator_impl.h index 4d877fc..ad20a1c 100644 --- a/content/renderer/origin_trials/trial_token_validator.h +++ b/content/renderer/origin_trials/web_trial_token_validator_impl.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ -#define CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ +#ifndef CONTENT_RENDERER_ORIGIN_TRIALS_WEB_TRIAL_TOKEN_VALIDATOR_IMPL_H_ +#define CONTENT_RENDERER_ORIGIN_TRIALS_WEB_TRIAL_TOKEN_VALIDATOR_IMPL_H_ #include <string> #include "content/common/content_export.h" @@ -15,11 +15,11 @@ // to validate tokens to enable experimental features. // // This class is thread-safe. -class CONTENT_EXPORT TrialTokenValidator +class CONTENT_EXPORT WebTrialTokenValidatorImpl : public NON_EXPORTED_BASE(blink::WebTrialTokenValidator) { public: - TrialTokenValidator(); - ~TrialTokenValidator() override; + WebTrialTokenValidatorImpl(); + ~WebTrialTokenValidatorImpl() override; // blink::WebTrialTokenValidator implementation bool validateToken(const blink::WebString& token, @@ -27,9 +27,9 @@ const blink::WebString& featureName) override; private: - DISALLOW_COPY_AND_ASSIGN(TrialTokenValidator); + DISALLOW_COPY_AND_ASSIGN(WebTrialTokenValidatorImpl); }; } // namespace content -#endif // CONTENT_RENDERER_ORIGIN_TRIALS_TRIAL_TOKEN_VALIDATOR_H_ +#endif // CONTENT_RENDERER_ORIGIN_TRIALS_WEB_TRIAL_TOKEN_VALIDATOR_IMPL_H_
diff --git a/content/renderer/pepper/pepper_video_encoder_host.cc b/content/renderer/pepper/pepper_video_encoder_host.cc index b78131d..46216e6 100644 --- a/content/renderer/pepper/pepper_video_encoder_host.cc +++ b/content/renderer/pepper/pepper_video_encoder_host.cc
@@ -503,10 +503,10 @@ return false; std::vector<int32_t> attribs(1, PP_GRAPHICS3DATTRIB_NONE); - command_buffer_ = channel_->CreateOffscreenCommandBuffer( - gfx::Size(), nullptr, GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, attribs, GURL::EmptyGURL(), - gfx::PreferIntegratedGpu); + command_buffer_ = channel_->CreateCommandBuffer( + gpu::kNullSurfaceHandle, gfx::Size(), nullptr, + GpuChannelHost::kDefaultStreamId, GpuChannelHost::kDefaultStreamPriority, + attribs, GURL::EmptyGURL(), gfx::PreferIntegratedGpu); if (!command_buffer_) { Close(); return false;
diff --git a/content/renderer/pepper/ppb_graphics_3d_impl.cc b/content/renderer/pepper/ppb_graphics_3d_impl.cc index c999fad4..4486f99 100644 --- a/content/renderer/pepper/ppb_graphics_3d_impl.cc +++ b/content/renderer/pepper/ppb_graphics_3d_impl.cc
@@ -252,7 +252,7 @@ gfx::Size surface_size; std::vector<int32_t> attribs; gfx::GpuPreference gpu_preference = gfx::PreferDiscreteGpu; - // TODO(alokp): Change GpuChannelHost::CreateOffscreenCommandBuffer() + // TODO(alokp): Change GpuChannelHost::CreateCommandBuffer() // interface to accept width and height in the attrib_list so that // we do not need to filter for width and height here. if (attrib_list) { @@ -290,10 +290,10 @@ share_buffer = share_graphics->GetCommandBufferProxy(); } - command_buffer_ = channel_->CreateOffscreenCommandBuffer( - surface_size, share_buffer, GpuChannelHost::kDefaultStreamId, - GpuChannelHost::kDefaultStreamPriority, attribs, GURL::EmptyGURL(), - gpu_preference); + command_buffer_ = channel_->CreateCommandBuffer( + gpu::kNullSurfaceHandle, surface_size, share_buffer, + GpuChannelHost::kDefaultStreamId, GpuChannelHost::kDefaultStreamPriority, + attribs, GURL::EmptyGURL(), gpu_preference); if (!command_buffer_) return false; if (!command_buffer_->Initialize())
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc index fbbca2e..92ffcdb 100644 --- a/content/renderer/pepper/video_decoder_shim.cc +++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -899,7 +899,7 @@ gfx::Size(32, 24), // Small sizes that won't fail. gfx::Rect(32, 24), gfx::Size(32, 24), // TODO(bbudge): Verify extra data isn't needed. - media::EmptyExtraData(), false /* decryption */); + media::EmptyExtraData(), media::Unencrypted()); media_task_runner_->PostTask( FROM_HERE,
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 69c7e94f..5ea20a24 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -3627,9 +3627,7 @@ return ok; } -bool RenderFrameImpl::runModalBeforeUnloadDialog( - bool is_reload, - const blink::WebString& message) { +bool RenderFrameImpl::runModalBeforeUnloadDialog(bool is_reload) { // If we are swapping out, we have already run the beforeunload handler. // TODO(creis): Fix OnSwapOut to clear the frame without running beforeunload // at all, to avoid running it twice. @@ -3647,7 +3645,7 @@ base::string16 ignored_result; render_view()->SendAndRunNestedMessageLoop( new FrameHostMsg_RunBeforeUnloadConfirm( - routing_id_, frame_->document().url(), message, is_reload, + routing_id_, frame_->document().url(), is_reload, &success, &ignored_result)); return success; }
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h index f57b159..0d7a3fa 100644 --- a/content/renderer/render_frame_impl.h +++ b/content/renderer/render_frame_impl.h
@@ -522,8 +522,7 @@ bool runModalPromptDialog(const blink::WebString& message, const blink::WebString& default_value, blink::WebString* actual_value) override; - bool runModalBeforeUnloadDialog(bool is_reload, - const blink::WebString& message) override; + bool runModalBeforeUnloadDialog(bool is_reload) override; void showContextMenu(const blink::WebContextMenuData& data) override; void clearContextMenu() override; void willSendRequest(blink::WebLocalFrame* frame,
diff --git a/content/renderer/renderer_blink_platform_impl.h b/content/renderer/renderer_blink_platform_impl.h index 90e644d4..6fc81555d 100644 --- a/content/renderer/renderer_blink_platform_impl.h +++ b/content/renderer/renderer_blink_platform_impl.h
@@ -16,7 +16,7 @@ #include "cc/blink/web_compositor_support_impl.h" #include "content/child/blink_platform_impl.h" #include "content/common/content_export.h" -#include "content/renderer/origin_trials/trial_token_validator.h" +#include "content/renderer/origin_trials/web_trial_token_validator_impl.h" #include "content/renderer/webpublicsuffixlist_impl.h" #include "device/vibration/vibration_manager.mojom.h" #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" @@ -294,7 +294,7 @@ scheduler::RendererScheduler* renderer_scheduler_; // NOT OWNED - TrialTokenValidator trial_token_validator_; + WebTrialTokenValidatorImpl trial_token_validator_; scoped_ptr<LocalStorageCachedAreas> local_storage_cached_areas_;
diff --git a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java index d5e54857..f2f363cb 100644 --- a/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java +++ b/content/shell/android/javatests/src/org/chromium/content_shell_apk/ContentShellTestBase.java
@@ -198,14 +198,14 @@ * Waits till the ContentViewCore receives the expected page scale factor * from the compositor and asserts that this happens. */ - protected void assertWaitForPageScaleFactorMatch(final float expectedScale) + protected void assertWaitForPageScaleFactorMatch(float expectedScale) throws InterruptedException { - CriteriaHelper.pollForCriteria(new Criteria() { + CriteriaHelper.pollForCriteria(Criteria.equals(expectedScale, new Callable<Float>() { @Override - public boolean isSatisfied() { - return getContentViewCore().getScale() == expectedScale; + public Float call() { + return getContentViewCore().getScale(); } - }); + })); } /**
diff --git a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc index 969b680..adea594 100644 --- a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc +++ b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.cc
@@ -35,7 +35,6 @@ void LayoutTestJavaScriptDialogManager::RunBeforeUnloadDialog( WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { callback.Run(true, base::string16());
diff --git a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h index 04ab714..726bdd2 100644 --- a/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h +++ b/content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h
@@ -29,7 +29,6 @@ bool* did_suppress_message) override; void RunBeforeUnloadDialog(WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override;
diff --git a/content/shell/browser/shell_javascript_dialog_manager.cc b/content/shell/browser/shell_javascript_dialog_manager.cc index a312e8dc..fdd57253 100644 --- a/content/shell/browser/shell_javascript_dialog_manager.cc +++ b/content/shell/browser/shell_javascript_dialog_manager.cc
@@ -66,7 +66,6 @@ void ShellJavaScriptDialogManager::RunBeforeUnloadDialog( WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { if (!dialog_request_callback_.is_null()) { @@ -83,16 +82,15 @@ return; } - base::string16 new_message_text = - message_text + - base::ASCIIToUTF16("\n\nIs it OK to leave/reload this page?"); + base::string16 message_text = + base::ASCIIToUTF16("Is it OK to leave/reload this page?"); gfx::NativeWindow parent_window = web_contents->GetTopLevelNativeWindow(); dialog_.reset(new ShellJavaScriptDialog(this, parent_window, JAVASCRIPT_MESSAGE_TYPE_CONFIRM, - new_message_text, + message_text, base::string16(), // default callback)); #else
diff --git a/content/shell/browser/shell_javascript_dialog_manager.h b/content/shell/browser/shell_javascript_dialog_manager.h index a7c29fb..42311042 100644 --- a/content/shell/browser/shell_javascript_dialog_manager.h +++ b/content/shell/browser/shell_javascript_dialog_manager.h
@@ -32,7 +32,6 @@ bool* did_suppress_message) override; void RunBeforeUnloadDialog(WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override;
diff --git a/content/shell/common/shell_content_client.cc b/content/shell/common/shell_content_client.cc index 842e0c1..82c2f0c5 100644 --- a/content/shell/common/shell_content_client.cc +++ b/content/shell/common/shell_content_client.cc
@@ -20,6 +20,19 @@ namespace content { +namespace { + +// This is the public key which the content shell will use to enable origin +// trial features. +// TODO(iclelland): Update this comment with the location of the public and +// private key files when the command-line tool CL lands +static const uint8_t kOriginTrialPublicKey[] = { + 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, + 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, + 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, +}; +} // namespace + std::string GetShellUserAgent() { std::string product = "Chrome/" CONTENT_SHELL_VERSION; base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); @@ -28,8 +41,12 @@ return BuildUserAgentFromProduct(product); } -ShellContentClient::~ShellContentClient() { -} +ShellContentClient::ShellContentClient() + : origin_trial_public_key_(base::StringPiece( + reinterpret_cast<const char*>(kOriginTrialPublicKey), + arraysize(kOriginTrialPublicKey))) {} + +ShellContentClient::~ShellContentClient() {} std::string ShellContentClient::GetUserAgent() const { return GetShellUserAgent(); @@ -95,4 +112,8 @@ switches::kIsolateSitesForTesting); } +base::StringPiece ShellContentClient::GetOriginTrialPublicKey() { + return origin_trial_public_key_; +} + } // namespace content
diff --git a/content/shell/common/shell_content_client.h b/content/shell/common/shell_content_client.h index ceebc52..2b1e7b65 100644 --- a/content/shell/common/shell_content_client.h +++ b/content/shell/common/shell_content_client.h
@@ -17,6 +17,7 @@ class ShellContentClient : public ContentClient { public: + ShellContentClient(); ~ShellContentClient() override; std::string GetUserAgent() const override; @@ -28,6 +29,10 @@ int resource_id) const override; gfx::Image& GetNativeImageNamed(int resource_id) const override; bool IsSupplementarySiteIsolationModeEnabled() override; + base::StringPiece GetOriginTrialPublicKey() override; + + private: + base::StringPiece origin_trial_public_key_; }; } // namespace content
diff --git a/content/shell/renderer/shell_content_renderer_client.cc b/content/shell/renderer/shell_content_renderer_client.cc index 1d12609..c799904 100644 --- a/content/shell/renderer/shell_content_renderer_client.cc +++ b/content/shell/renderer/shell_content_renderer_client.cc
@@ -17,23 +17,7 @@ namespace content { -namespace { - -// This is the public key which the content shell will use to enable origin -// trial features. -// TODO(iclelland): Update this comment with the location of the public and -// private key files when the command-line tool CL lands -static const uint8_t kOriginTrialPublicKey[] = { - 0x75, 0x10, 0xac, 0xf9, 0x3a, 0x1c, 0xb8, 0xa9, 0x28, 0x70, 0xd2, - 0x9a, 0xd0, 0x0b, 0x59, 0xe1, 0xac, 0x2b, 0xb7, 0xd5, 0xca, 0x1f, - 0x64, 0x90, 0x08, 0x8e, 0xa8, 0xe0, 0x56, 0x3a, 0x04, 0xd0, -}; -} // namespace - -ShellContentRendererClient::ShellContentRendererClient() - : origin_trial_public_key_(base::StringPiece( - reinterpret_cast<const char*>(kOriginTrialPublicKey), - arraysize(kOriginTrialPublicKey))) {} +ShellContentRendererClient::ShellContentRendererClient() {} ShellContentRendererClient::~ShellContentRendererClient() { } @@ -67,8 +51,4 @@ #endif } -base::StringPiece ShellContentRendererClient::GetOriginTrialPublicKey() { - return origin_trial_public_key_; -} - } // namespace content
diff --git a/content/shell/renderer/shell_content_renderer_client.h b/content/shell/renderer/shell_content_renderer_client.h index 23d71a8..6c4e295 100644 --- a/content/shell/renderer/shell_content_renderer_client.h +++ b/content/shell/renderer/shell_content_renderer_client.h
@@ -28,11 +28,9 @@ // need that outside of layout tests? bool IsPluginAllowedToUseCompositorAPI(const GURL& url) override; bool IsPluginAllowedToUseDevChannelAPIs() override; - base::StringPiece GetOriginTrialPublicKey() override; private: scoped_ptr<web_cache::WebCacheRenderProcessObserver> web_cache_observer_; - base::StringPiece origin_trial_public_key_; }; } // namespace content
diff --git a/content/test/gpu/gpu_tests/webgl_conformance.py b/content/test/gpu/gpu_tests/webgl_conformance.py index 277c5375..5fb6884 100644 --- a/content/test/gpu/gpu_tests/webgl_conformance.py +++ b/content/test/gpu/gpu_tests/webgl_conformance.py
@@ -140,7 +140,7 @@ def RunNavigateSteps(self, action_runner): super(WebglConformancePage, self).RunNavigateSteps(action_runner) action_runner.WaitForJavaScriptCondition( - 'webglTestHarness._finished', timeout_in_seconds=180) + 'webglTestHarness._finished', timeout_in_seconds=300) class WebglConformance(gpu_test_base.TestBase): """Conformance with Khronos WebGL Conformance Tests"""
diff --git a/extensions/browser/extension_function_util.cc b/extensions/browser/extension_function_util.cc deleted file mode 100644 index 5e5e763..0000000 --- a/extensions/browser/extension_function_util.cc +++ /dev/null
@@ -1,32 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include <stddef.h> - -#include "extensions/browser/extension_function_util.h" - -namespace extensions { - -bool ReadOneOrMoreIntegers(base::Value* value, std::vector<int>* result) { - if (value->IsType(base::Value::TYPE_INTEGER)) { - int v = -1; - if (!value->GetAsInteger(&v)) - return false; - result->push_back(v); - return true; - - } else if (value->IsType(base::Value::TYPE_LIST)) { - base::ListValue* values = static_cast<base::ListValue*>(value); - for (size_t i = 0; i < values->GetSize(); ++i) { - int v = -1; - if (!values->GetInteger(i, &v)) - return false; - result->push_back(v); - } - return true; - } - return false; -} - -} // namespace extensions
diff --git a/extensions/browser/extension_function_util.h b/extensions/browser/extension_function_util.h deleted file mode 100644 index e9943076d..0000000 --- a/extensions/browser/extension_function_util.h +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef EXTENSIONS_BROWSER_EXTENSION_FUNCTION_UTIL_H__ -#define EXTENSIONS_BROWSER_EXTENSION_FUNCTION_UTIL_H__ - -#include <vector> -#include "base/values.h" - -namespace base { -class Value; -} - -// This file contains various utility functions for extension API -// implementations. -namespace extensions { - -// Reads the |value| as either a single integer value or a list of integers. -bool ReadOneOrMoreIntegers(base::Value* value, std::vector<int>* result); - -} // namespace extensions - -#endif // EXTENSIONS_BROWSER_EXTENSION_FUNCTION_UTIL_H__
diff --git a/extensions/browser/guest_view/web_view/javascript_dialog_helper.cc b/extensions/browser/guest_view/web_view/javascript_dialog_helper.cc index 1ac3c848..83f69d91 100644 --- a/extensions/browser/guest_view/web_view/javascript_dialog_helper.cc +++ b/extensions/browser/guest_view/web_view/javascript_dialog_helper.cc
@@ -72,7 +72,6 @@ void JavaScriptDialogHelper::RunBeforeUnloadDialog( content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { // This is called if the guest has a beforeunload event handler.
diff --git a/extensions/browser/guest_view/web_view/javascript_dialog_helper.h b/extensions/browser/guest_view/web_view/javascript_dialog_helper.h index 804a2065..1d40fb2 100644 --- a/extensions/browser/guest_view/web_view/javascript_dialog_helper.h +++ b/extensions/browser/guest_view/web_view/javascript_dialog_helper.h
@@ -28,7 +28,6 @@ const DialogClosedCallback& callback, bool* did_suppress_message) override; void RunBeforeUnloadDialog(content::WebContents* web_contents, - const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) override; bool HandleJavaScriptDialog(content::WebContents* web_contents,
diff --git a/extensions/extensions.gypi b/extensions/extensions.gypi index 04f3e45..4e3871e 100644 --- a/extensions/extensions.gypi +++ b/extensions/extensions.gypi
@@ -582,8 +582,6 @@ 'browser/extension_function_dispatcher.h', 'browser/extension_function_registry.cc', 'browser/extension_function_registry.h', - 'browser/extension_function_util.cc', - 'browser/extension_function_util.h', 'browser/extension_host.cc', 'browser/extension_host.h', 'browser/extension_host_delegate.h',
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc index 4c1194c..4cda61b 100644 --- a/gpu/command_buffer/client/gles2_implementation.cc +++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -2351,6 +2351,19 @@ CheckGLError(); } +PixelStoreParams GLES2Implementation::GetUnpackParameters(Dimension dimension) { + PixelStoreParams params; + params.alignment = unpack_alignment_; + params.row_length = unpack_row_length_; + params.skip_pixels = unpack_skip_pixels_; + params.skip_rows = unpack_skip_rows_; + if (dimension == k3D) { + params.image_height = unpack_image_height_; + params.skip_images = unpack_skip_images_; + } + return params; +} + void GLES2Implementation::TexImage2D( GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, @@ -2375,15 +2388,44 @@ uint32_t size; uint32_t unpadded_row_size; uint32_t padded_row_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, 1, format, type, unpack_alignment_, &size, - &unpadded_row_size, &padded_row_size)) { + uint32_t skip_size; + PixelStoreParams params = GetUnpackParameters(k2D); + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + params, + &size, + &unpadded_row_size, + &padded_row_size, + &skip_size, + nullptr)) { SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); return; } + if (bound_pixel_unpack_buffer_) { + base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels); + offset += skip_size; + if (!offset.IsValid()) { + SetGLError(GL_INVALID_VALUE, "glTexImage2D", "skip size too large"); + return; + } + helper_->TexImage2D( + target, level, internalformat, width, height, format, type, + 0, offset.ValueOrDefault(0)); + CheckGLError(); + return; + } + // If there's a pixel unpack buffer bound use it when issuing TexImage2D. if (bound_pixel_unpack_transfer_buffer_id_) { + if (unpack_row_length_ > 0 || unpack_image_height_ > 0 || + unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 || + unpack_skip_images_ > 0) { + SetGLError(GL_INVALID_OPERATION, "glTexImage2D", + "No ES3 pack parameters with pixel unpack transfer buffer."); + return; + } + DCHECK_EQ(0u, skip_size); GLuint offset = ToGLuint(pixels); BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid( bound_pixel_unpack_transfer_buffer_id_, "glTexImage2D", offset, size); @@ -2398,36 +2440,38 @@ } // If there's no data just issue TexImage2D - if (!pixels) { + if (!pixels || width == 0 || height == 0) { helper_->TexImage2D( - target, level, internalformat, width, height, format, type, - 0, 0); + target, level, internalformat, width, height, format, type, 0, 0); CheckGLError(); return; } - // compute the advance bytes per row for the src pixels - uint32_t src_padded_row_size; - if (unpack_row_length_ > 0) { - if (!GLES2Util::ComputeImagePaddedRowSize( - unpack_row_length_, format, type, unpack_alignment_, - &src_padded_row_size)) { - SetGLError( - GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large"); + // Compute the advance bytes per row on the service side. + // Note |size| is recomputed here if needed. + uint32_t service_padded_row_size; + if (unpack_row_length_ > 0 && unpack_row_length_ != width) { + // All parameters have been applied to the data that are sent to the + // service side except UNPACK_ALIGNMENT. + PixelStoreParams service_params; + service_params.alignment = unpack_alignment_; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + service_params, + &size, + nullptr, + &service_padded_row_size, + nullptr, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexImage2D", "image size too large"); return; } } else { - src_padded_row_size = padded_row_size; + service_padded_row_size = padded_row_size; } // advance pixels pointer past the skip rows and skip pixels - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_rows_ * src_padded_row_size; - if (unpack_skip_pixels_) { - uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type); - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_pixels_ * group_size; - } + pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size; // Check if we can send it all at once. int32_t shm_id = 0; @@ -2455,8 +2499,8 @@ if (buffer_pointer) { CopyRectToBuffer( - pixels, height, unpadded_row_size, src_padded_row_size, - buffer_pointer, padded_row_size); + pixels, height, unpadded_row_size, padded_row_size, + buffer_pointer, service_padded_row_size); helper_->TexImage2D( target, level, internalformat, width, height, format, type, shm_id, shm_offset); @@ -2470,7 +2514,8 @@ 0, 0); TexSubImage2DImpl( target, level, 0, 0, width, height, format, type, unpadded_row_size, - pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, padded_row_size); + pixels, padded_row_size, GL_TRUE, &transfer_alloc, + service_padded_row_size); CheckGLError(); } @@ -2495,18 +2540,48 @@ SetGLError(GL_INVALID_VALUE, "glTexImage3D", "border != 0"); return; } + uint32_t size; uint32_t unpadded_row_size; uint32_t padded_row_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, depth, format, type, unpack_alignment_, &size, - &unpadded_row_size, &padded_row_size)) { + uint32_t skip_size; + PixelStoreParams params = GetUnpackParameters(k3D); + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + params, + &size, + &unpadded_row_size, + &padded_row_size, + &skip_size, + nullptr)) { SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large"); return; } + if (bound_pixel_unpack_buffer_) { + base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels); + offset += skip_size; + if (!offset.IsValid()) { + SetGLError(GL_INVALID_VALUE, "glTexImage3D", "skip size too large"); + return; + } + helper_->TexImage3D( + target, level, internalformat, width, height, depth, format, type, + 0, offset.ValueOrDefault(0)); + CheckGLError(); + return; + } + // If there's a pixel unpack buffer bound use it when issuing TexImage3D. if (bound_pixel_unpack_transfer_buffer_id_) { + if (unpack_row_length_ > 0 || unpack_image_height_ > 0 || + unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 || + unpack_skip_images_ > 0) { + SetGLError(GL_INVALID_OPERATION, "glTexImage3D", + "No ES3 pack parameters with pixel unpack transfer buffer."); + return; + } + DCHECK_EQ(0u, skip_size); GLuint offset = ToGLuint(pixels); BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid( bound_pixel_unpack_transfer_buffer_id_, "glTexImage3D", offset, size); @@ -2521,7 +2596,7 @@ } // If there's no data just issue TexImage3D - if (!pixels) { + if (!pixels || width == 0 || height == 0 || depth == 0) { helper_->TexImage3D( target, level, internalformat, width, height, depth, format, type, 0, 0); @@ -2529,31 +2604,34 @@ return; } - // compute the advance bytes per row for the src pixels - uint32_t src_padded_row_size; - if (unpack_row_length_ > 0) { - if (!GLES2Util::ComputeImagePaddedRowSize( - unpack_row_length_, format, type, unpack_alignment_, - &src_padded_row_size)) { - SetGLError( - GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); + // Compute the advance bytes per row on the service side. + // Note |size| is recomputed here if needed. + uint32_t service_padded_row_size; + if ((unpack_row_length_ > 0 && unpack_row_length_ != width) || + (unpack_image_height_ > 0 && unpack_image_height_ != height)) { + // All parameters have been applied to the data that are sent to the + // service side except UNPACK_ALIGNMENT. + PixelStoreParams service_params; + service_params.alignment = unpack_alignment_; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + service_params, + &size, + nullptr, + &service_padded_row_size, + nullptr, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexImage3D", "image size too large"); return; } } else { - src_padded_row_size = padded_row_size; + service_padded_row_size = padded_row_size; } uint32_t src_height = unpack_image_height_ > 0 ? unpack_image_height_ : height; // advance pixels pointer past the skip images/rows/pixels - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_images_ * src_padded_row_size * src_height + - unpack_skip_rows_ * src_padded_row_size; - if (unpack_skip_pixels_) { - uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type); - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_pixels_ * group_size; - } + pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size; // Check if we can send it all at once. int32_t shm_id = 0; @@ -2581,16 +2659,13 @@ if (buffer_pointer) { for (GLsizei z = 0; z < depth; ++z) { - // Only the last row of the last image is unpadded. - uint32_t src_unpadded_row_size = - (z == depth - 1) ? unpadded_row_size : src_padded_row_size; CopyRectToBuffer( - pixels, height, src_unpadded_row_size, src_padded_row_size, - buffer_pointer, padded_row_size); + pixels, height, unpadded_row_size, padded_row_size, + buffer_pointer, service_padded_row_size); pixels = reinterpret_cast<const int8_t*>(pixels) + - src_padded_row_size * src_height; - buffer_pointer = - reinterpret_cast<int8_t*>(buffer_pointer) + padded_row_size * height; + padded_row_size * src_height; + buffer_pointer = reinterpret_cast<int8_t*>(buffer_pointer) + + service_padded_row_size * height; } helper_->TexImage3D( target, level, internalformat, width, height, depth, format, type, @@ -2605,8 +2680,8 @@ 0, 0); TexSubImage3DImpl( target, level, 0, 0, 0, width, height, depth, format, type, - unpadded_row_size, pixels, src_padded_row_size, GL_TRUE, &transfer_alloc, - padded_row_size); + unpadded_row_size, pixels, padded_row_size, GL_TRUE, &transfer_alloc, + service_padded_row_size); CheckGLError(); } @@ -2623,30 +2698,55 @@ << GLES2Util::GetStringPixelType(type) << ", " << static_cast<const void*>(pixels) << ")"); - if (level < 0 || height < 0 || width < 0) { + if (level < 0 || height < 0 || width < 0 || xoffset < 0 || yoffset < 0) { SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "dimension < 0"); return; } - if (height == 0 || width == 0) { + + uint32_t size; + uint32_t unpadded_row_size; + uint32_t padded_row_size; + uint32_t skip_size; + PixelStoreParams params = GetUnpackParameters(k2D); + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + params, + &size, + &unpadded_row_size, + &padded_row_size, + &skip_size, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "image size to large"); return; } - uint32_t temp_size; - uint32_t unpadded_row_size; - uint32_t padded_row_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, 1, format, type, unpack_alignment_, &temp_size, - &unpadded_row_size, &padded_row_size)) { - SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "size to large"); + if (bound_pixel_unpack_buffer_) { + base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels); + offset += skip_size; + if (!offset.IsValid()) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "skip size too large"); + return; + } + helper_->TexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, 0, offset.ValueOrDefault(0), false); + CheckGLError(); return; } // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D. if (bound_pixel_unpack_transfer_buffer_id_) { + if (unpack_row_length_ > 0 || unpack_image_height_ > 0 || + unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 || + unpack_skip_images_ > 0) { + SetGLError(GL_INVALID_OPERATION, "glTexSubImage2D", + "No ES3 pack parameters with pixel unpack transfer buffer."); + return; + } + DCHECK_EQ(0u, skip_size); GLuint offset = ToGLuint(pixels); BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid( bound_pixel_unpack_transfer_buffer_id_, - "glTexSubImage2D", offset, temp_size); + "glTexSubImage2D", offset, size); if (buffer && buffer->shm_id() != -1) { helper_->TexSubImage2D( target, level, xoffset, yoffset, width, height, format, type, @@ -2657,34 +2757,45 @@ return; } - // compute the advance bytes per row for the src pixels - uint32_t src_padded_row_size; - if (unpack_row_length_ > 0) { - if (!GLES2Util::ComputeImagePaddedRowSize( - unpack_row_length_, format, type, unpack_alignment_, - &src_padded_row_size)) { - SetGLError( - GL_INVALID_VALUE, "glTexImage2D", "unpack row length too large"); + if (width == 0 || height == 0) { + // No need to worry about pixel data. + helper_->TexSubImage2D(target, level, xoffset, yoffset, width, height, + format, type, 0, 0, false); + CheckGLError(); + return; + } + + // Compute the advance bytes per row on the service side. + // Note |size| is recomputed here if needed. + uint32_t service_padded_row_size; + if (unpack_row_length_ > 0 && unpack_row_length_ != width) { + // All parameters have been applied to the data that are sent to the + // service side except UNPACK_ALIGNMENT. + PixelStoreParams service_params; + service_params.alignment = unpack_alignment_; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + service_params, + &size, + nullptr, + &service_padded_row_size, + nullptr, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage2D", "image size too large"); return; } } else { - src_padded_row_size = padded_row_size; + service_padded_row_size = padded_row_size; } // advance pixels pointer past the skip rows and skip pixels - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_rows_ * src_padded_row_size; - if (unpack_skip_pixels_) { - uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type); - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_pixels_ * group_size; - } + pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size; - ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_); + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); TexSubImage2DImpl( target, level, xoffset, yoffset, width, height, format, type, - unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, &buffer, - padded_row_size); + unpadded_row_size, pixels, padded_row_size, GL_FALSE, &buffer, + service_padded_row_size); CheckGLError(); } @@ -2702,30 +2813,57 @@ << GLES2Util::GetStringPixelType(type) << ", " << static_cast<const void*>(pixels) << ")"); - if (level < 0 || height < 0 || width < 0 || depth < 0) { + if (level < 0 || height < 0 || width < 0 || depth < 0 || + xoffset < 0 || yoffset < 0 || zoffset < 0) { SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "dimension < 0"); return; } - if (height == 0 || width == 0 || depth == 0) { + + uint32_t size; + uint32_t unpadded_row_size; + uint32_t padded_row_size; + uint32_t skip_size; + PixelStoreParams params = GetUnpackParameters(k3D); + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + params, + &size, + &unpadded_row_size, + &padded_row_size, + &skip_size, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "image size to large"); return; } - uint32_t temp_size; - uint32_t unpadded_row_size; - uint32_t padded_row_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, depth, format, type, unpack_alignment_, &temp_size, - &unpadded_row_size, &padded_row_size)) { - SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "size to large"); + if (bound_pixel_unpack_buffer_) { + base::CheckedNumeric<uint32_t> offset = ToGLuint(pixels); + offset += skip_size; + if (!offset.IsValid()) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "skip size too large"); + return; + } + helper_->TexSubImage3D( + target, level, xoffset, yoffset, zoffset, width, height, depth, + format, type, 0, offset.ValueOrDefault(0), false); + CheckGLError(); return; } // If there's a pixel unpack buffer bound use it when issuing TexSubImage2D. if (bound_pixel_unpack_transfer_buffer_id_) { + if (unpack_row_length_ > 0 || unpack_image_height_ > 0 || + unpack_skip_pixels_ > 0 || unpack_skip_rows_ > 0 || + unpack_skip_images_ > 0) { + SetGLError(GL_INVALID_OPERATION, "glTexSubImage2D", + "No ES3 pack parameters with pixel unpack transfer buffer."); + return; + } + DCHECK_EQ(0u, skip_size); GLuint offset = ToGLuint(pixels); BufferTracker::Buffer* buffer = GetBoundPixelTransferBufferIfValid( bound_pixel_unpack_transfer_buffer_id_, - "glTexSubImage3D", offset, temp_size); + "glTexSubImage3D", offset, size); if (buffer && buffer->shm_id() != -1) { helper_->TexSubImage3D( target, level, xoffset, yoffset, zoffset, width, height, depth, @@ -2736,37 +2874,44 @@ return; } - // compute the advance bytes per row for the src pixels - uint32_t src_padded_row_size; - if (unpack_row_length_ > 0) { - if (!GLES2Util::ComputeImagePaddedRowSize( - unpack_row_length_, format, type, unpack_alignment_, - &src_padded_row_size)) { - SetGLError( - GL_INVALID_VALUE, "glTexImage3D", "unpack row length too large"); + if (width == 0 || height == 0 || depth == 0) { + // No need to worry about pixel data. + helper_->TexSubImage3D(target, level, xoffset, yoffset, zoffset, + width, height, depth, format, type, 0, 0, false); + CheckGLError(); + return; + } + + // Compute the advance bytes per row on the service side + // Note |size| is recomputed here if needed. + uint32_t service_padded_row_size; + if ((unpack_row_length_ > 0 && unpack_row_length_ != width) || + (unpack_image_height_ > 0 && unpack_image_height_ != height)) { + PixelStoreParams service_params; + service_params.alignment = unpack_alignment_; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + service_params, + &size, + nullptr, + &service_padded_row_size, + nullptr, + nullptr)) { + SetGLError(GL_INVALID_VALUE, "glTexSubImage3D", "image size too large"); return; } } else { - src_padded_row_size = padded_row_size; + service_padded_row_size = padded_row_size; } - uint32_t src_height = - unpack_image_height_ > 0 ? unpack_image_height_ : height; // advance pixels pointer past the skip images/rows/pixels - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_images_ * src_padded_row_size * src_height + - unpack_skip_rows_ * src_padded_row_size; - if (unpack_skip_pixels_) { - uint32_t group_size = GLES2Util::ComputeImageGroupSize(format, type); - pixels = reinterpret_cast<const int8_t*>(pixels) + - unpack_skip_pixels_ * group_size; - } + pixels = reinterpret_cast<const int8_t*>(pixels) + skip_size; - ScopedTransferBufferPtr buffer(temp_size, helper_, transfer_buffer_); + ScopedTransferBufferPtr buffer(size, helper_, transfer_buffer_); TexSubImage3DImpl( target, level, xoffset, yoffset, zoffset, width, height, depth, - format, type, unpadded_row_size, pixels, src_padded_row_size, GL_FALSE, - &buffer, padded_row_size); + format, type, unpadded_row_size, pixels, padded_row_size, GL_FALSE, + &buffer, service_padded_row_size); CheckGLError(); } @@ -2804,6 +2949,8 @@ DCHECK_GE(level, 0); DCHECK_GT(height, 0); DCHECK_GT(width, 0); + DCHECK_GE(xoffset, 0); + DCHECK_GE(yoffset, 0); const int8_t* source = reinterpret_cast<const int8_t*>(pixels); // Transfer by rows. @@ -2851,9 +2998,12 @@ uint32_t buffer_padded_row_size) { DCHECK(buffer); DCHECK_GE(level, 0); - DCHECK_GT(height, 0); DCHECK_GT(width, 0); + DCHECK_GT(height, 0); DCHECK_GT(depth, 0); + DCHECK_GE(xoffset, 0); + DCHECK_GE(yoffset, 0); + DCHECK_GE(zoffset, 0); const int8_t* source = reinterpret_cast<const int8_t*>(pixels); GLsizei total_rows = height * depth; GLint row_index = 0, depth_index = 0; @@ -2905,24 +3055,14 @@ uint32_t image_size_dst = buffer_padded_row_size * height; uint32_t image_size_src = pixels_padded_row_size * src_height; for (GLint ii = 0; ii < num_images; ++ii) { - uint32_t my_unpadded_row_size; - if (total_rows == num_rows && ii + 1 == num_images) - my_unpadded_row_size = unpadded_row_size; - else - my_unpadded_row_size = pixels_padded_row_size; CopyRectToBuffer( - source + ii * image_size_src, my_height, my_unpadded_row_size, + source + ii * image_size_src, my_height, unpadded_row_size, pixels_padded_row_size, buffer_pointer + ii * image_size_dst, buffer_padded_row_size); } } else { - uint32_t my_unpadded_row_size; - if (total_rows == num_rows) - my_unpadded_row_size = unpadded_row_size; - else - my_unpadded_row_size = pixels_padded_row_size; CopyRectToBuffer( - source, my_height, my_unpadded_row_size, pixels_padded_row_size, + source, my_height, unpadded_row_size, pixels_padded_row_size, buffer->address(), buffer_padded_row_size); } helper_->TexSubImage3D(
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h index 8b8ef63f..02314d0 100644 --- a/gpu/command_buffer/client/gles2_implementation.h +++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -297,6 +297,12 @@ kUnknownExtensionStatus }; + enum Dimension { + k2D, + k3D, + }; + + // Base class for mapped resources. struct MappedResource { MappedResource(GLenum _access, int _shm_id, void* mem, unsigned int offset) @@ -693,6 +699,8 @@ void UpdateCachedExtensionsIfNeeded(); void InvalidateCachedExtensions(); + PixelStoreParams GetUnpackParameters(Dimension dimension); + GLES2Util util_; GLES2CmdHelper* helper_; TransferBufferInterface* transfer_buffer_;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc index 3bacee23..dd3d8259 100644 --- a/gpu/command_buffer/client/gles2_implementation_unittest.cc +++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -427,7 +427,9 @@ bool transfer_buffer_initialize_fail, bool sync_query, bool occlusion_query_boolean, - bool timer_queries) { + bool timer_queries, + int major_version, + int minor_version) { command_buffer_.reset(new StrictMock<MockClientCommandBuffer>()); if (!command_buffer_->Initialize()) return false; @@ -473,6 +475,8 @@ capabilities.sync_query = sync_query; capabilities.occlusion_query_boolean = occlusion_query_boolean; capabilities.timer_queries = timer_queries; + capabilities.major_version = major_version; + capabilities.minor_version = minor_version; EXPECT_CALL(*gpu_control_, GetCapabilities()) .WillOnce(testing::Return(capabilities)); @@ -571,7 +575,9 @@ transfer_buffer_initialize_fail(false), sync_query(true), occlusion_query_boolean(true), - timer_queries(true) {} + timer_queries(true), + major_version(2), + minor_version(0) {} bool bind_generates_resource_client; bool bind_generates_resource_service; @@ -580,6 +586,8 @@ bool sync_query; bool occlusion_query_boolean; bool timer_queries; + int major_version; + int minor_version; }; bool Initialize(const ContextInitOptions& init_options) { @@ -596,7 +604,9 @@ init_options.transfer_buffer_initialize_fail, init_options.sync_query, init_options.occlusion_query_boolean, - init_options.timer_queries)) + init_options.timer_queries, + init_options.major_version, + init_options.minor_version)) success = false; } @@ -799,6 +809,18 @@ ASSERT_TRUE(Initialize(init_options)); } +class GLES3ImplementationTest : public GLES2ImplementationTest { + protected: + void SetUp() override; +}; + +void GLES3ImplementationTest::SetUp() { + ContextInitOptions init_options; + init_options.major_version = 3; + init_options.minor_version = 0; + ASSERT_TRUE(Initialize(init_options)); +} + // GCC requires these declarations, but MSVC requires they not be present #ifndef _MSC_VER const uint8_t GLES2ImplementationTest::kInitialValue; @@ -2637,6 +2659,168 @@ } } +TEST_F(GLES3ImplementationTest, SubImage3DUnpack) { + static const GLint unpack_alignments[] = { 1, 2, 4, 8 }; + + static const GLenum kFormat = GL_RGB; + static const GLenum kType = GL_UNSIGNED_BYTE; + static const GLint kLevel = 0; + static const GLint kBorder = 0; + // We're testing using the unpack params to pull a subimage out of a larger + // source of pixels. Here we specify the subimage by its border rows / + // columns. + static const GLint kSrcWidth = 23; + static const GLint kSrcHeight = 7; + static const GLint kSrcSubImageX0 = 11; + static const GLint kSrcSubImageX1 = 16; + static const GLint kSrcSubImageY0 = 20; + static const GLint kSrcSubImageY1 = 23; + static const GLint kSrcSubImageZ0 = 2; + static const GLint kSrcSubImageZ1 = 5; + static const GLint kSrcSubImageWidth = kSrcSubImageX1 - kSrcSubImageX0; + static const GLint kSrcSubImageHeight = kSrcSubImageY1 - kSrcSubImageY0; + static const GLint kSrcSubImageDepth = kSrcSubImageZ1 - kSrcSubImageZ0; + + // these are only used in the texsubimage tests + static const GLint kTexWidth = 255; + static const GLint kTexHeight = 127; + static const GLint kTexDepth = 11; + static const GLint kTexSubXOffset = 119; + static const GLint kTexSubYOffset = 63; + static const GLint kTexSubZOffset = 1; + + struct { + cmds::PixelStorei pixel_store_i[3]; + cmds::TexImage3D tex_image_3d; + } texImageExpected; + + struct { + cmds::PixelStorei pixel_store_i[3]; + cmds::TexImage3D tex_image_3d; + cmds::TexSubImage3D tex_sub_image_3d; + } texSubImageExpected; + + uint32_t pixel_size; + PixelStoreParams pixel_params; + // Makes sure the pixels size is large enough for all tests. + pixel_params.alignment = 8; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3( + kSrcWidth, kSrcSubImageY1, kSrcSubImageZ1, kFormat, kType, + pixel_params, &pixel_size, nullptr, nullptr, nullptr, nullptr)); + scoped_ptr<uint8_t[]> src_pixels; + src_pixels.reset(new uint8_t[pixel_size]); + for (size_t i = 0; i < pixel_size; ++i) { + src_pixels[i] = static_cast<uint8_t>(i % 255); + } + + for (int sub = 0; sub < 2; ++sub) { + for (size_t a = 0; a < arraysize(unpack_alignments); ++a) { + const void* commands = GetPut(); + + GLint alignment = unpack_alignments[a]; + gl_->PixelStorei(GL_UNPACK_ALIGNMENT, alignment); + gl_->PixelStorei(GL_UNPACK_ROW_LENGTH, kSrcWidth); + gl_->PixelStorei(GL_UNPACK_IMAGE_HEIGHT, kSrcHeight); + gl_->PixelStorei(GL_UNPACK_SKIP_PIXELS, kSrcSubImageX0); + gl_->PixelStorei(GL_UNPACK_SKIP_ROWS, kSrcSubImageY0); + gl_->PixelStorei(GL_UNPACK_SKIP_IMAGES, kSrcSubImageZ0); + + uint32_t client_size; + uint32_t client_unpadded_row_size; + uint32_t client_padded_row_size; + uint32_t client_skip_size; + { + PixelStoreParams params; + params.alignment = alignment; + params.row_length = kSrcWidth; + params.image_height = kSrcHeight; + params.skip_pixels = kSrcSubImageX0; + params.skip_rows = kSrcSubImageY0; + params.skip_images = kSrcSubImageZ0; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3( + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kFormat, kType, params, + &client_size, &client_unpadded_row_size, &client_padded_row_size, + &client_skip_size, nullptr)); + ASSERT_TRUE(client_size + client_skip_size <= pixel_size); + } + + uint32_t service_size; + uint32_t service_unpadded_row_size; + uint32_t service_padded_row_size; + uint32_t service_skip_size; + { + PixelStoreParams params; + // For pixels we send to service side, we already applied all unpack + // parameters except for UNPACK_ALIGNMENT. + params.alignment = alignment; + ASSERT_TRUE(GLES2Util::ComputeImageDataSizesES3( + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kFormat, kType, params, + &service_size, &service_unpadded_row_size, &service_padded_row_size, + &service_skip_size, nullptr)); + ASSERT_TRUE(service_size <= MaxTransferBufferSize()); + ASSERT_TRUE(service_skip_size == 0); + ASSERT_TRUE(client_unpadded_row_size == service_unpadded_row_size); + } + + ExpectedMemoryInfo mem = GetExpectedMemory(service_size); + if (sub) { + gl_->TexImage3D( + GL_TEXTURE_3D, kLevel, kFormat, kTexWidth, kTexHeight, kTexDepth, + kBorder, kFormat, kType, nullptr); + gl_->TexSubImage3D( + GL_TEXTURE_3D, kLevel, + kTexSubXOffset, kTexSubYOffset, kTexSubZOffset, + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kFormat, kType, src_pixels.get()); + texSubImageExpected.pixel_store_i[0].Init( + GL_UNPACK_ALIGNMENT, alignment); + texSubImageExpected.pixel_store_i[1].Init( + GL_UNPACK_ROW_LENGTH, kSrcWidth); + texSubImageExpected.pixel_store_i[2].Init( + GL_UNPACK_IMAGE_HEIGHT, kSrcHeight); + texSubImageExpected.tex_image_3d.Init( + GL_TEXTURE_3D, kLevel, kFormat, kTexWidth, kTexHeight, kTexDepth, + kFormat, kType, 0, 0); + texSubImageExpected.tex_sub_image_3d.Init( + GL_TEXTURE_3D, kLevel, + kTexSubXOffset, kTexSubYOffset, kTexSubZOffset, + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kFormat, kType, mem.id, mem.offset, GL_FALSE); + EXPECT_EQ(0, memcmp(&texSubImageExpected, commands, + sizeof(texSubImageExpected))); + } else { + gl_->TexImage3D( + GL_TEXTURE_3D, kLevel, kFormat, + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kBorder, kFormat, kType, src_pixels.get()); + texImageExpected.pixel_store_i[0].Init(GL_UNPACK_ALIGNMENT, alignment); + texImageExpected.pixel_store_i[1].Init( + GL_UNPACK_ROW_LENGTH, kSrcWidth); + texImageExpected.pixel_store_i[2].Init( + GL_UNPACK_IMAGE_HEIGHT, kSrcHeight); + texImageExpected.tex_image_3d.Init( + GL_TEXTURE_3D, kLevel, kFormat, + kSrcSubImageWidth, kSrcSubImageHeight, kSrcSubImageDepth, + kFormat, kType, mem.id, mem.offset); + EXPECT_EQ(0, memcmp(&texImageExpected, commands, + sizeof(texImageExpected))); + } + for (int z = 0; z < kSrcSubImageDepth; ++z) { + for (int y = 0; y < kSrcSubImageHeight; ++y) { + const uint8_t* src_row = src_pixels.get() + client_skip_size + + (kSrcHeight * z + y) * client_padded_row_size; + const uint8_t* dst_row = mem.ptr + + (kSrcSubImageHeight * z + y) * service_padded_row_size; + EXPECT_EQ(0, memcmp(src_row, dst_row, service_unpadded_row_size)); + } + } + ClearCommands(); + } + } +} + // Test texture related calls with invalid arguments. TEST_F(GLES2ImplementationTest, TextureInvalidArguments) { struct Cmds {
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc index 93a9000..adf0c2d 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.cc +++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -795,6 +795,10 @@ } } +size_t GLES2Util::GetGLTypeSizeForTextures(uint32_t type) { + return static_cast<size_t>(BytesPerElement(type)); +} + size_t GLES2Util::GetGLTypeSizeForBuffers(uint32_t type) { switch (type) { case GL_BYTE:
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h index 99637659..9104fcd 100644 --- a/gpu/command_buffer/common/gles2_cmd_utils.h +++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -155,6 +155,8 @@ // For example, GL_FLOAT_MAT3 returns 9. static uint32_t GetElementCountForUniformType(int type); + static size_t GetGLTypeSizeForTextures(uint32_t type); + static size_t GetGLTypeSizeForBuffers(uint32_t type); static size_t GetGroupSizeForBufferType(uint32_t count, uint32_t type);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index f7bef77..174dcf79 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -11275,19 +11275,49 @@ GLenum type = static_cast<GLenum>(c.type); uint32_t pixels_shm_id = static_cast<uint32_t>(c.pixels_shm_id); uint32_t pixels_shm_offset = static_cast<uint32_t>(c.pixels_shm_offset); + + if (width < 0 || height < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexImage2D", "dimensions < 0"); + return error::kNoError; + } + + PixelStoreParams params; + if (state_.bound_pixel_unpack_buffer.get()) { + if (pixels_shm_id) + return error::kInvalidArguments; + params = state_.GetUnpackParams(ContextState::k2D); + } else { + if (!pixels_shm_id && pixels_shm_offset) + return error::kInvalidArguments; + // When reading from client buffer, the command buffer client side took + // the responsibility to take the pixels from the client buffer and + // unpack them according to the full ES3 pack parameters as source, all + // parameters for 0 (except for alignment) as destination mem for the + // service side. + params.alignment = state_.unpack_alignment; + } uint32_t pixels_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, 1, format, type, state_.unpack_alignment, &pixels_size, - NULL, NULL)) { + uint32_t skip_size; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + params, + &pixels_size, + nullptr, + nullptr, + &skip_size, + nullptr)) { return error::kOutOfBounds; } - const void* pixels = NULL; - if (pixels_shm_id != 0 || pixels_shm_offset != 0) { + DCHECK_EQ(0u, skip_size); + + const void* pixels; + if (pixels_shm_id) { pixels = GetSharedMemoryAs<const void*>( pixels_shm_id, pixels_shm_offset, pixels_size); - if (!pixels) { + if (!pixels) return error::kOutOfBounds; - } + } else { + pixels = reinterpret_cast<const void*>(pixels_shm_offset); } // For testing only. Allows us to stress the ability to respond to OOM errors. @@ -11333,19 +11363,49 @@ GLenum type = static_cast<GLenum>(c.type); uint32_t pixels_shm_id = static_cast<uint32_t>(c.pixels_shm_id); uint32_t pixels_shm_offset = static_cast<uint32_t>(c.pixels_shm_offset); + + if (width < 0 || height < 0 || depth < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexImage3D", "dimensions < 0"); + return error::kNoError; + } + + PixelStoreParams params; + if (state_.bound_pixel_unpack_buffer.get()) { + if (pixels_shm_id) + return error::kInvalidArguments; + params = state_.GetUnpackParams(ContextState::k3D); + } else { + if (!pixels_shm_id && pixels_shm_offset) + return error::kInvalidArguments; + // When reading from client buffer, the command buffer client side took + // the responsibility to take the pixels from the client buffer and + // unpack them according to the full ES3 pack parameters as source, all + // parameters for 0 (except for alignment) as destination mem for the + // service side. + params.alignment = state_.unpack_alignment; + } uint32_t pixels_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, depth, format, type, state_.unpack_alignment, &pixels_size, - NULL, NULL)) { + uint32_t skip_size; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + params, + &pixels_size, + nullptr, + nullptr, + &skip_size, + nullptr)) { return error::kOutOfBounds; } - const void* pixels = NULL; - if (pixels_shm_id != 0 || pixels_shm_offset != 0) { + DCHECK_EQ(0u, skip_size); + + const void* pixels; + if (pixels_shm_id) { pixels = GetSharedMemoryAs<const void*>( pixels_shm_id, pixels_shm_offset, pixels_size); - if (!pixels) { + if (!pixels) return error::kOutOfBounds; - } + } else { + pixels = reinterpret_cast<const void*>(pixels_shm_offset); } // For testing only. Allows us to stress the ability to respond to OOM errors. @@ -11727,21 +11787,54 @@ GLsizei height = static_cast<GLsizei>(c.height); GLenum format = static_cast<GLenum>(c.format); GLenum type = static_cast<GLenum>(c.type); - uint32_t data_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, 1, format, type, state_.unpack_alignment, &data_size, - NULL, NULL)) { - return error::kOutOfBounds; + uint32_t pixels_shm_id = static_cast<uint32_t>(c.pixels_shm_id); + uint32_t pixels_shm_offset = static_cast<uint32_t>(c.pixels_shm_offset); + + if (width < 0 || height < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexSubImage2D", "dimensions < 0"); + return error::kNoError; } - const void* pixels = GetSharedMemoryAs<const void*>( - c.pixels_shm_id, c.pixels_shm_offset, data_size); - if (!pixels) + PixelStoreParams params; + if (state_.bound_pixel_unpack_buffer.get()) { + if (pixels_shm_id) + return error::kInvalidArguments; + params = state_.GetUnpackParams(ContextState::k2D); + } else { + // When reading from client buffer, the command buffer client side took + // the responsibility to take the pixels from the client buffer and + // unpack them according to the full ES3 pack parameters as source, all + // parameters for 0 (except for alignment) as destination mem for the + // service side. + params.alignment = state_.unpack_alignment; + } + uint32_t pixels_size; + uint32_t skip_size; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, 1, + format, type, + params, + &pixels_size, + nullptr, + nullptr, + &skip_size, + nullptr)) { return error::kOutOfBounds; + } + DCHECK_EQ(0u, skip_size); + + const void* pixels; + if (pixels_shm_id) { + pixels = GetSharedMemoryAs<const void*>( + pixels_shm_id, pixels_shm_offset, pixels_size); + if (!pixels) + return error::kOutOfBounds; + } else { + pixels = reinterpret_cast<const void*>(pixels_shm_offset); + } TextureManager::DoTexSubImageArguments args = { target, level, xoffset, yoffset, 0, width, height, 1, - format, type, pixels, data_size, + format, type, pixels, pixels_size, TextureManager::DoTexSubImageArguments::kTexSubImage2D}; texture_manager()->ValidateAndDoTexSubImage(this, &texture_state_, &state_, &framebuffer_state_, @@ -11776,21 +11869,54 @@ GLsizei depth = static_cast<GLsizei>(c.depth); GLenum format = static_cast<GLenum>(c.format); GLenum type = static_cast<GLenum>(c.type); - uint32_t data_size; - if (!GLES2Util::ComputeImageDataSizes( - width, height, depth, format, type, state_.unpack_alignment, &data_size, - NULL, NULL)) { - return error::kOutOfBounds; + uint32_t pixels_shm_id = static_cast<uint32_t>(c.pixels_shm_id); + uint32_t pixels_shm_offset = static_cast<uint32_t>(c.pixels_shm_offset); + + if (width < 0 || height < 0 || depth < 0) { + LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "glTexSubImage3D", "dimensions < 0"); + return error::kNoError; } - const void* pixels = GetSharedMemoryAs<const void*>( - c.pixels_shm_id, c.pixels_shm_offset, data_size); - if (!pixels) + PixelStoreParams params; + if (state_.bound_pixel_unpack_buffer.get()) { + if (pixels_shm_id) + return error::kInvalidArguments; + params = state_.GetUnpackParams(ContextState::k3D); + } else { + // When reading from client buffer, the command buffer client side took + // the responsibility to take the pixels from the client buffer and + // unpack them according to the full ES3 pack parameters as source, all + // parameters for 0 (except for alignment) as destination mem for the + // service side. + params.alignment = state_.unpack_alignment; + } + uint32_t pixels_size; + uint32_t skip_size; + if (!GLES2Util::ComputeImageDataSizesES3(width, height, depth, + format, type, + params, + &pixels_size, + nullptr, + nullptr, + &skip_size, + nullptr)) { return error::kOutOfBounds; + } + DCHECK_EQ(0u, skip_size); + + const void* pixels; + if (pixels_shm_id) { + pixels = GetSharedMemoryAs<const void*>( + pixels_shm_id, pixels_shm_offset, pixels_size); + if (!pixels) + return error::kOutOfBounds; + } else { + pixels = reinterpret_cast<const void*>(pixels_shm_offset); + } TextureManager::DoTexSubImageArguments args = { target, level, xoffset, yoffset, zoffset, width, height, depth, - format, type, pixels, data_size, + format, type, pixels, pixels_size, TextureManager::DoTexSubImageArguments::kTexSubImage3D}; texture_manager()->ValidateAndDoTexSubImage(this, &texture_state_, &state_, &framebuffer_state_,
diff --git a/gpu/command_buffer/service/texture_manager.cc b/gpu/command_buffer/service/texture_manager.cc index 7e8ea5a..d2bc325 100644 --- a/gpu/command_buffer/service/texture_manager.cc +++ b/gpu/command_buffer/service/texture_manager.cc
@@ -302,6 +302,11 @@ } } +// A 32-bit and 64-bit compatible way of converting a pointer to a GLuint. +GLuint ToGLuint(const void* ptr) { + return static_cast<GLuint>(reinterpret_cast<size_t>(ptr)); +} + base::LazyInstance<const FormatTypeValidator>::Leaky g_format_type_validator = LAZY_INSTANCE_INITIALIZER; @@ -2221,6 +2226,40 @@ return false; } + Buffer* buffer = state->bound_pixel_unpack_buffer.get(); + if (buffer) { + if (buffer->GetMappedRange()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer should not be mapped to client memory"); + return error::kNoError; + } + base::CheckedNumeric<uint32_t> size = args.pixels_size; + GLuint offset = ToGLuint(args.pixels); + size += offset; + if (!size.IsValid()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_VALUE, function_name, + "size + offset overflow"); + return error::kNoError; + } + uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); + if (buffer_size < size.ValueOrDefault(0)) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer is not large enough"); + return error::kNoError; + } + size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); + DCHECK_LT(0u, type_size); + if (offset % type_size != 0) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "offset is not evenly divisible by elements"); + return error::kNoError; + } + } + if (!memory_type_tracker_->EnsureGPUMemoryAvailable(args.pixels_size)) { ERRORSTATE_SET_GL_ERROR(error_state, GL_OUT_OF_MEMORY, function_name, "out of memory"); @@ -2285,13 +2324,13 @@ for (GLenum face : undefined_faces) { new_args.target = face; new_args.pixels = zero.get(); - DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, + DoTexImage(texture_state, state, framebuffer_state, function_name, texture_ref, new_args); texture->MarkLevelAsInternalWorkaround(face, args.level); } } - DoTexImage(texture_state, state->GetErrorState(), framebuffer_state, + DoTexImage(texture_state, state, framebuffer_state, function_name, texture_ref, args); } @@ -2310,21 +2349,7 @@ args.target, "target"); return false; } - if (args.width < 0) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, - "width < 0"); - return false; - } - if (args.height < 0) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, - "height < 0"); - return false; - } - if (args.depth < 0) { - ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_VALUE, function_name, - "depth < 0"); - return false; - } + DCHECK(args.width >= 0 && args.height >= 0 && args.depth >= 0); TextureRef* local_texture_ref = GetTextureInfoForTarget(state, args.target); if (!local_texture_ref) { ERRORSTATE_SET_GL_ERROR(error_state, GL_INVALID_OPERATION, function_name, @@ -2366,7 +2391,40 @@ "can not supply data for depth or stencil textures"); return false; } - DCHECK(args.pixels); + + Buffer* buffer = state->bound_pixel_unpack_buffer.get(); + if (buffer) { + if (buffer->GetMappedRange()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer should not be mapped to client memory"); + return error::kNoError; + } + base::CheckedNumeric<uint32_t> size = args.pixels_size; + GLuint offset = ToGLuint(args.pixels); + size += offset; + if (!size.IsValid()) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_VALUE, function_name, + "size + offset overflow"); + return error::kNoError; + } + uint32_t buffer_size = static_cast<uint32_t>(buffer->size()); + if (buffer_size < size.ValueOrDefault(0)) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "pixel unpack buffer is not large enough"); + return error::kNoError; + } + size_t type_size = GLES2Util::GetGLTypeSizeForTextures(args.type); + DCHECK_LT(0u, type_size); + if (offset % type_size != 0) { + ERRORSTATE_SET_GL_ERROR( + error_state, GL_INVALID_OPERATION, function_name, + "offset is not evenly divisible by elements"); + return error::kNoError; + } + } *texture_ref = local_texture_ref; return true; } @@ -2489,11 +2547,12 @@ void TextureManager::DoTexImage( DecoderTextureState* texture_state, - ErrorState* error_state, + ContextState* state, DecoderFramebufferState* framebuffer_state, const char* function_name, TextureRef* texture_ref, const DoTexImageArguments& args) { + ErrorState* error_state = state->GetErrorState(); Texture* texture = texture_ref->texture(); GLsizei tex_width = 0; GLsizei tex_height = 0; @@ -2509,7 +2568,10 @@ args.target, args.level, &tex_type, &tex_internal_format) && args.type == tex_type && args.internal_format == tex_internal_format; - if (level_is_same && !args.pixels) { + bool unpack_buffer_bound = + (state->bound_pixel_unpack_buffer.get() != nullptr); + + if (level_is_same && !args.pixels && !unpack_buffer_bound) { // Just set the level texture but mark the texture as uncleared. SetLevelInfo( texture_ref, args.target, args.level, args.internal_format, args.width, @@ -2524,7 +2586,7 @@ } if (texture_state->texsubimage_faster_than_teximage && - level_is_same && args.pixels) { + level_is_same && args.pixels && !unpack_buffer_bound) { { ScopedTextureUploadTimer timer(texture_state); if (args.command_type == DoTexImageArguments::kTexImage3D) { @@ -2566,7 +2628,7 @@ GetAllGLErrors()); } if (error == GL_NO_ERROR) { - bool set_as_cleared = (args.pixels != nullptr); + bool set_as_cleared = (args.pixels != nullptr || unpack_buffer_bound); SetLevelInfo( texture_ref, args.target, args.level, args.internal_format, args.width, args.height, args.depth, args.border, args.format, args.type,
diff --git a/gpu/command_buffer/service/texture_manager.h b/gpu/command_buffer/service/texture_manager.h index 09ad3df..420b872 100644 --- a/gpu/command_buffer/service/texture_manager.h +++ b/gpu/command_buffer/service/texture_manager.h
@@ -1052,7 +1052,7 @@ void DoTexImage( DecoderTextureState* texture_state, - ErrorState* error_state, + ContextState* state, DecoderFramebufferState* framebuffer_state, const char* function_name, TextureRef* texture_ref,
diff --git a/infra/config/cq.cfg b/infra/config/cq.cfg index dc696e0..ee0f62c 100644 --- a/infra/config/cq.cfg +++ b/infra/config/cq.cfg
@@ -59,7 +59,7 @@ } builders { name: "linux_blink_oilpan_rel" - experiment_percentage: 50 + experiment_percentage: 100 } } buckets {
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn index 9ac855e1..ace65c8a 100644 --- a/ios/web/BUILD.gn +++ b/ios/web/BUILD.gn
@@ -353,7 +353,6 @@ "public/test/test_web_thread_bundle.h", "public/test/test_web_view_content_view.h", "public/test/test_web_view_content_view.mm", - "public/test/web_test_util.h", "test/crw_fake_web_controller_observer.h", "test/crw_fake_web_controller_observer.mm", "test/test_web_thread.cc",
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp index 008c807..49aff7f 100644 --- a/ios/web/ios_web.gyp +++ b/ios/web/ios_web.gyp
@@ -443,7 +443,6 @@ 'public/test/test_web_thread_bundle.h', 'public/test/test_web_view_content_view.h', 'public/test/test_web_view_content_view.mm', - 'public/test/web_test_util.h', 'test/crw_fake_web_controller_observer.h', 'test/crw_fake_web_controller_observer.mm', 'test/test_web_thread.cc',
diff --git a/ios/web/public/test/web_test_util.h b/ios/web/public/test/web_test_util.h deleted file mode 100644 index fe93d073..0000000 --- a/ios/web/public/test/web_test_util.h +++ /dev/null
@@ -1,20 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef IOS_WEB_PUBLIC_TEST_WEB_TEST_UTIL_H_ -#define IOS_WEB_PUBLIC_TEST_WEB_TEST_UTIL_H_ - -#include "ios/web/public/web_view_creation_util.h" - -// A helper macro that allows skipping a unit test on iOS7 and earlier. Example: -// -// TEST_F(WKWebViewTest, WebViewInitializesCorrectly) { -// CR_TEST_REQUIRES_WK_WEB_VIEW(); -// EXPECT_TRUE(NSClassFromString(@"WKWebView") != nil); -// } -#define CR_TEST_REQUIRES_WK_WEB_VIEW() \ - if (!web::IsWKWebViewSupported()) \ - return - -#endif // IOS_WEB_PUBLIC_TEST_WEB_TEST_UTIL_H_
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h index 9fc1050a..51173ab 100644 --- a/ios/web/public/web_state/ui/crw_web_delegate.h +++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -148,9 +148,6 @@ wasInitialNavigation:(BOOL)initialNavigation; // Called from finishHistoryNavigationFromEntry. - (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry; -// Called when a page navigates backwards or forwards. -- (void)webWillGoDelta:(int)delta; -- (void)webDidPrepareForGoBack; // --------------------------------------------------------------------- @optional @@ -202,14 +199,6 @@ - (void)webController:(CRWWebController*)webController didBlockPopup:(const web::BlockedPopupInfo&)blockedPopupInfo; -// TODO(jimblackler): Create a DialogController and move dialog-related delegate -// methods to CRWWebControllerObserver. - -// Called when CRWWebController will present a dialog (only if -// kNotifyBeforeOpeningDialogs policy is set via -// -[CRWWebController setPageDialogsOpenPolicy:] method). -- (void)webControllerWillShowDialog:(CRWWebController*)webController; - // Called when CRWWebController did suppress a dialog (only if kSuppressDialogs // policy is set via -[CRWWebController setPageDialogsOpenPolicy:] method). - (void)webControllerDidSuppressDialog:(CRWWebController*)webController;
diff --git a/ios/web/shell/view_controller.mm b/ios/web/shell/view_controller.mm index f98bc4b..370b1d5 100644 --- a/ios/web/shell/view_controller.mm +++ b/ios/web/shell/view_controller.mm
@@ -336,10 +336,6 @@ } - (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry { } -- (void)webWillGoDelta:(int)delta { -} -- (void)webDidPrepareForGoBack { -} - (int)downloadImageAtUrl:(const GURL&)url maxBitmapSize:(uint32_t)maxBitmapSize callback:
diff --git a/ios/web/web_state/js/resources/dialog_overrides.js b/ios/web/web_state/js/resources/dialog_overrides.js index cd9d984..a127bec 100644 --- a/ios/web/web_state/js/resources/dialog_overrides.js +++ b/ios/web/web_state/js/resources/dialog_overrides.js
@@ -31,9 +31,6 @@ var makeDialogWrapper = function(originalDialogGetter) { return function() { if (!suppressDialogs) { - if (notifyAboutDialogs) { - __gCrWeb.message.invokeOnHost({'command': 'dialog.willShow'}); - } return originalDialogGetter().apply(null, arguments); } else if (notifyAboutDialogs) { __gCrWeb.message.invokeOnHost({'command': 'dialog.suppressed'});
diff --git a/ios/web/web_state/ui/crw_web_controller.h b/ios/web/web_state/ui/crw_web_controller.h index f4eb810..bf01ed4 100644 --- a/ios/web/web_state/ui/crw_web_controller.h +++ b/ios/web/web_state/ui/crw_web_controller.h
@@ -34,9 +34,6 @@ enum PageDialogOpenPolicy { // Default policy. Dialogs are allowed, clients are not notified on display. DIALOG_POLICY_ALLOW = 0, - // Dialogs are allowed, clients are notified when dialog will display with - // -[WebDelegate webControllerWillShowDialog:] delegate method call. - DIALOG_POLICY_NOTIFY_FIRST, // Dialogs are not allowed, client are notified when dialog did block with // -[WebDelegate webControllerDidSuppressDialog:] delegate method call. DIALOG_POLICY_SUPPRESS @@ -298,12 +295,6 @@ // native controller. - (void)loadErrorInNativeView:(NSError*)error; -// Resets the state of a page where a load was rejected. This method must -// be called if an embedder rejected the page load (e.g. by returning NO from -// |-[WebDelegate shouldOpenURL:linkClicked:]|) but wants to continue working -// with CRWWebController. -- (void)restoreStateAfterURLRejection; - // Helper method called at the end of history navigation methods goBack, // goForward, and goDelta. Loads a new URL if the current entry is not from a // pushState() navigation from |fromEntry|. |fromEntry| is the
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 4cd999c..1e111d8 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -436,9 +436,6 @@ // Handles 'dialog.suppressed' message. - (BOOL)handleDialogSuppressedMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; -// Handles 'dialog.willShow' message. -- (BOOL)handleDialogWillShowMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context; // Handles 'document.favicons' message. - (BOOL)handleDocumentFaviconsMessage:(base::DictionaryValue*)message context:(NSDictionary*)context; @@ -1667,10 +1664,6 @@ bool wasShowingInterstitial = _webStateImpl->IsShowingWebInterstitial(); - // Call into the delegate before |recordStateInHistory|. - // TODO(rohitrao): Can this be reordered after |recordStateInHistory|? - [_delegate webDidPrepareForGoBack]; - // Before changing the current session history entry, record the tab state. if (!wasShowingInterstitial) { [self recordStateInHistory]; @@ -1704,8 +1697,6 @@ [self recordStateInHistory]; } - [_delegate webWillGoDelta:delta]; - CRWSessionController* sessionController = _webStateImpl->GetNavigationManagerImpl().GetSessionController(); // fromEntry is retained because it has the potential to be released @@ -2025,8 +2016,6 @@ (*handlers)["console"] = @selector(handleConsoleMessage:context:); (*handlers)["dialog.suppressed"] = @selector(handleDialogSuppressedMessage:context:); - (*handlers)["dialog.willShow"] = - @selector(handleDialogWillShowMessage:context:); (*handlers)["document.favicons"] = @selector(handleDocumentFaviconsMessage:context:); (*handlers)["document.retitled"] = @@ -2144,14 +2133,6 @@ return YES; } -- (BOOL)handleDialogWillShowMessage:(base::DictionaryValue*)message - context:(NSDictionary*)context { - if ([_delegate respondsToSelector:@selector(webControllerWillShowDialog:)]) { - [_delegate webControllerWillShowDialog:self]; - } - return YES; -} - - (BOOL)handleDocumentFaviconsMessage:(base::DictionaryValue*)message context:(NSDictionary*)context { base::ListValue* favicons = nullptr; @@ -2807,18 +2788,6 @@ return YES; } -- (void)restoreStateAfterURLRejection { - [[self sessionController] discardNonCommittedEntries]; - - // Reset |_lastRegisteredRequestURL| so that it reflects the URL from before - // the load was rejected. This value may be out of sync because - // |_lastRegisteredRequestURL| may have already been updated before the load - // was rejected. - _lastRegisteredRequestURL = [self currentURL]; - _loadPhase = web::PAGE_LOADING; - [self didFinishNavigation]; -} - - (void)handleLoadError:(NSError*)error inMainFrame:(BOOL)inMainFrame { if ([error code] == NSURLErrorUnsupportedURL) return; @@ -3230,9 +3199,6 @@ case web::DIALOG_POLICY_ALLOW: [self setSuppressDialogs:NO notify:NO]; return; - case web::DIALOG_POLICY_NOTIFY_FIRST: - [self setSuppressDialogs:NO notify:YES]; - return; case web::DIALOG_POLICY_SUPPRESS: [self setSuppressDialogs:YES notify:YES]; return;
diff --git a/media/BUILD.gn b/media/BUILD.gn index b0750196..c6e496a 100644 --- a/media/BUILD.gn +++ b/media/BUILD.gn
@@ -642,15 +642,19 @@ sources += [ "ffmpeg/ffmpeg_common_unittest.cc", "filters/audio_decoder_unittest.cc", - "filters/audio_file_reader_unittest.cc", "filters/blocking_url_protocol_unittest.cc", - "filters/ffmpeg_demuxer_unittest.cc", "filters/ffmpeg_glue_unittest.cc", "filters/in_memory_url_protocol_unittest.cc", ] if (!is_android) { sources += [ + # These tests are confused by Android always having proprietary + # codecs enabled, but ffmpeg_branding=Chromium. These should be + # fixed, http://crbug.com/570762. + "filters/audio_file_reader_unittest.cc", + "filters/ffmpeg_demuxer_unittest.cc", + # FFmpeg on Android does not include video decoders. "filters/ffmpeg_video_decoder_unittest.cc", ] @@ -858,6 +862,8 @@ ":media", "//base", ] + libfuzzer_options = "filters/vp8_parser_fuzzertest.options" + dict = "test/vp8.dict" } fuzzer_test("media_vp9_parser_fuzzer") { @@ -868,4 +874,5 @@ ":media", "//base", ] + libfuzzer_options = "filters/vp9_parser_fuzzertest.options" }
diff --git a/media/audio/mac/audio_manager_mac.cc b/media/audio/mac/audio_manager_mac.cc index beedf92..6eefcf4e 100644 --- a/media/audio/mac/audio_manager_mac.cc +++ b/media/audio/mac/audio_manager_mac.cc
@@ -610,13 +610,11 @@ AudioOutputStream* AudioManagerMac::MakeLowLatencyOutputStream( const AudioParameters& params, const std::string& device_id) { - AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id); - if (device == kAudioObjectUnknown) { - DLOG(ERROR) << "Failed to open output device: " << device_id; - return NULL; - } - - // Lazily create the audio device listener on the first stream creation. + bool device_listener_first_init = false; + // Lazily create the audio device listener on the first stream creation, + // even if getting an audio device fails. Otherwise, if we have 0 audio + // devices, the listener will never be initialized, and new valid devices + // will never be detected. if (!output_device_listener_) { // NOTE: Use BindToCurrentLoop() to ensure the callback is always PostTask'd // even if OSX calls us on the right thread. Some CoreAudio drivers will @@ -625,6 +623,18 @@ output_device_listener_.reset( new AudioDeviceListenerMac(BindToCurrentLoop(base::Bind( &AudioManagerMac::HandleDeviceChanges, base::Unretained(this))))); + device_listener_first_init = true; + } + + AudioDeviceID device = GetAudioDeviceIdByUId(false, device_id); + if (device == kAudioObjectUnknown) { + DLOG(ERROR) << "Failed to open output device: " << device_id; + return NULL; + } + + // Only set the device and sample rate if we just initialized the device + // listener. + if (device_listener_first_init) { // Only set the current output device for the default device. if (device_id == AudioManagerBase::kDefaultDeviceId || device_id.empty()) current_output_device_ = device;
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn index ef69b2d7..21f54498 100644 --- a/media/base/BUILD.gn +++ b/media/base/BUILD.gn
@@ -113,6 +113,8 @@ "djb2.cc", "djb2.h", "eme_constants.h", + "encryption_scheme.cc", + "encryption_scheme.h", "key_system_info.cc", "key_system_info.h", "key_systems.cc",
diff --git a/media/base/android/BUILD.gn b/media/base/android/BUILD.gn index b9db10a8..7ac7d972 100644 --- a/media/base/android/BUILD.gn +++ b/media/base/android/BUILD.gn
@@ -83,6 +83,7 @@ sources = [ "access_unit_queue_unittest.cc", "media_codec_decoder_unittest.cc", + "media_codec_player_unittest.cc", "media_drm_bridge_unittest.cc", "media_player_bridge_unittest.cc", "media_source_player_unittest.cc", @@ -91,11 +92,6 @@ "test_data_factory.h", "test_statistics.h", ] - - if (proprietary_codecs) { - sources += [ "media_codec_player_unittest.cc" ] - } - deps = [ ":android", "//media/base:test_support",
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc index 3c1b94d..253c82b 100644 --- a/media/base/audio_decoder_config.cc +++ b/media/base/audio_decoder_config.cc
@@ -16,18 +16,17 @@ channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED), samples_per_second_(0), bytes_per_frame_(0), - is_encrypted_(false), - codec_delay_(0) { -} + codec_delay_(0) {} -AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec, - SampleFormat sample_format, - ChannelLayout channel_layout, - int samples_per_second, - const std::vector<uint8_t>& extra_data, - bool is_encrypted) { +AudioDecoderConfig::AudioDecoderConfig( + AudioCodec codec, + SampleFormat sample_format, + ChannelLayout channel_layout, + int samples_per_second, + const std::vector<uint8_t>& extra_data, + const EncryptionScheme& encryption_scheme) { Initialize(codec, sample_format, channel_layout, samples_per_second, - extra_data, is_encrypted, base::TimeDelta(), 0); + extra_data, encryption_scheme, base::TimeDelta(), 0); } AudioDecoderConfig::AudioDecoderConfig(const AudioDecoderConfig& other) = @@ -38,7 +37,7 @@ ChannelLayout channel_layout, int samples_per_second, const std::vector<uint8_t>& extra_data, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, base::TimeDelta seek_preroll, int codec_delay) { codec_ = codec; @@ -47,7 +46,7 @@ sample_format_ = sample_format; bytes_per_channel_ = SampleFormatToBytesPerChannel(sample_format); extra_data_ = extra_data; - is_encrypted_ = is_encrypted; + encryption_scheme_ = encryption_scheme; seek_preroll_ = seek_preroll; codec_delay_ = codec_delay; @@ -75,7 +74,7 @@ (channel_layout() == config.channel_layout()) && (samples_per_second() == config.samples_per_second()) && (extra_data() == config.extra_data()) && - (is_encrypted() == config.is_encrypted()) && + (encryption_scheme().Matches(config.encryption_scheme())) && (sample_format() == config.sample_format()) && (seek_preroll() == config.seek_preroll()) && (codec_delay() == config.codec_delay()));
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h index 71c89302..266de82 100644 --- a/media/base/audio_decoder_config.h +++ b/media/base/audio_decoder_config.h
@@ -14,6 +14,7 @@ #include "base/time/time.h" #include "media/base/audio_codecs.h" #include "media/base/channel_layout.h" +#include "media/base/encryption_scheme.h" #include "media/base/media_export.h" #include "media/base/sample_format.h" @@ -34,7 +35,7 @@ ChannelLayout channel_layout, int samples_per_second, const std::vector<uint8_t>& extra_data, - bool is_encrypted); + const EncryptionScheme& encryption_scheme); AudioDecoderConfig(const AudioDecoderConfig& other); @@ -46,7 +47,7 @@ ChannelLayout channel_layout, int samples_per_second, const std::vector<uint8_t>& extra_data, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, base::TimeDelta seek_preroll, int codec_delay); @@ -79,7 +80,12 @@ // Whether the audio stream is potentially encrypted. // Note that in a potentially encrypted audio stream, individual buffers // can be encrypted or not encrypted. - bool is_encrypted() const { return is_encrypted_; } + bool is_encrypted() const { return encryption_scheme_.is_encrypted(); } + + // Encryption scheme used for encrypted buffers. + const EncryptionScheme& encryption_scheme() const { + return encryption_scheme_; + } private: AudioCodec codec_; @@ -89,7 +95,7 @@ int samples_per_second_; int bytes_per_frame_; std::vector<uint8_t> extra_data_; - bool is_encrypted_; + EncryptionScheme encryption_scheme_; // |seek_preroll_| is the duration of the data that the decoder must decode // before the decoded data is valid.
diff --git a/media/base/encryption_scheme.cc b/media/base/encryption_scheme.cc new file mode 100644 index 0000000..70d133c6 --- /dev/null +++ b/media/base/encryption_scheme.cc
@@ -0,0 +1,37 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/base/encryption_scheme.h" + +namespace media { + +EncryptionScheme::Pattern::Pattern() {} + +EncryptionScheme::Pattern::Pattern(uint32_t encrypt_blocks, + uint32_t skip_blocks) + : encrypt_blocks_(encrypt_blocks), skip_blocks_(skip_blocks) {} + +EncryptionScheme::Pattern::~Pattern() {} + +bool EncryptionScheme::Pattern::Matches(const Pattern& other) const { + return encrypt_blocks_ == other.encrypt_blocks() && + skip_blocks_ == other.skip_blocks(); +} + +bool EncryptionScheme::Pattern::IsInEffect() const { + return encrypt_blocks_ != 0 && skip_blocks_ != 0; +} + +EncryptionScheme::EncryptionScheme() {} + +EncryptionScheme::EncryptionScheme(CipherMode mode, const Pattern& pattern) + : mode_(mode), pattern_(pattern) {} + +EncryptionScheme::~EncryptionScheme() {} + +bool EncryptionScheme::Matches(const EncryptionScheme& other) const { + return mode_ == other.mode_ && pattern_.Matches(other.pattern_); +} + +} // namespace media
diff --git a/media/base/encryption_scheme.h b/media/base/encryption_scheme.h new file mode 100644 index 0000000..37bea67 --- /dev/null +++ b/media/base/encryption_scheme.h
@@ -0,0 +1,79 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BASE_ENCRYPTION_SCHEME_H_ +#define MEDIA_BASE_ENCRYPTION_SCHEME_H_ + +#include <stdint.h> + +#include "media/base/media_export.h" + +namespace media { + +// Specification of whether and how the stream is encrypted (in whole or part). +class MEDIA_EXPORT EncryptionScheme { + public: + // Algorithm and mode used for encryption. CIPHER_MODE_UNENCRYPTED indicates + // no encryption. + enum CipherMode { + CIPHER_MODE_UNENCRYPTED, + CIPHER_MODE_AES_CTR, + CIPHER_MODE_AES_CBC, + CIPHER_MODE_MAX = CIPHER_MODE_AES_CBC + }; + + // CENC 3rd Edition adds pattern encryption, through two new protection + // schemes: 'cens' (with AES-CTR) and 'cbcs' (with AES-CBC). + // The pattern applies independently to each 'encrypted' part of the frame (as + // defined by the relevant subsample entries), and reduces further the + // actual encryption applied through a repeating pattern of (encrypt:skip) + // 16 byte blocks. For example, in a (1:9) pattern, the first block is + // encrypted, and the next nine are skipped. This pattern is applied + // repeatedly until the end of the last 16-byte block in the subsample. + // Any remaining bytes are left clear. + // If either of encrypt_blocks or skip_blocks is 0, pattern encryption is + // disabled. + class MEDIA_EXPORT Pattern { + public: + Pattern(); + Pattern(uint32_t encrypt_blocks, uint32_t skip_blocks); + ~Pattern(); + + bool Matches(const Pattern& other) const; + + uint32_t encrypt_blocks() const { return encrypt_blocks_; } + uint32_t skip_blocks() const { return skip_blocks_; } + + bool IsInEffect() const; + + private: + uint32_t encrypt_blocks_ = 0; + uint32_t skip_blocks_ = 0; + + // Allow copy and assignment. + }; + + // The default constructor makes an instance that indicates no encryption. + EncryptionScheme(); + + // This constructor allows specification of the cipher mode and the pattern. + EncryptionScheme(CipherMode mode, const Pattern& pattern); + ~EncryptionScheme(); + + bool Matches(const EncryptionScheme& other) const; + + bool is_encrypted() const { return mode_ != CIPHER_MODE_UNENCRYPTED; } + CipherMode mode() const { return mode_; } + const Pattern& pattern() const { return pattern_; } + + private: + CipherMode mode_ = CIPHER_MODE_UNENCRYPTED; + Pattern pattern_; + + // Allow copy and assignment. +}; + +} // namespace media + +#endif // MEDIA_BASE_ENCRYPTION_SCHEME_H_
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc index 267b3e5d..7ed5841 100644 --- a/media/base/fake_demuxer_stream.cc +++ b/media/base/fake_demuxer_stream.cc
@@ -147,11 +147,11 @@ void FakeDemuxerStream::UpdateVideoDecoderConfig() { const gfx::Rect kVisibleRect(kStartWidth, kStartHeight); - video_decoder_config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, - PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED, - next_coded_size_, kVisibleRect, - next_coded_size_, EmptyExtraData(), - is_encrypted_); + video_decoder_config_.Initialize( + kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12, + COLOR_SPACE_UNSPECIFIED, next_coded_size_, kVisibleRect, next_coded_size_, + EmptyExtraData(), + is_encrypted_ ? AesCtrEncryptionScheme() : Unencrypted()); next_coded_size_.Enlarge(kWidthDelta, kHeightDelta); }
diff --git a/media/base/media_switches.cc b/media/base/media_switches.cc index a69808aa..e305df6a 100644 --- a/media/base/media_switches.cc +++ b/media/base/media_switches.cc
@@ -67,12 +67,6 @@ // for details. const char kEnableExclusiveAudio[] = "enable-exclusive-audio"; -// Used to troubleshoot problems with different video capture implementations -// on Windows. By default we use the Media Foundation API on Windows 7 and up, -// but specifying this switch will force use of DirectShow always. -// See bug: http://crbug.com/268412 -const char kForceDirectShowVideoCapture[] = "force-directshow"; - // Force the use of MediaFoundation for video capture. This is only supported in // Windows 7 and above. Used, like |kForceDirectShowVideoCapture|, to // troubleshoot problems in Windows platforms.
diff --git a/media/base/media_switches.h b/media/base/media_switches.h index c7677eff..cbc16bd 100644 --- a/media/base/media_switches.h +++ b/media/base/media_switches.h
@@ -40,7 +40,6 @@ #if defined(OS_WIN) MEDIA_EXPORT extern const char kEnableExclusiveAudio[]; -MEDIA_EXPORT extern const char kForceDirectShowVideoCapture[]; MEDIA_EXPORT extern const char kForceMediaFoundationVideoCapture[]; MEDIA_EXPORT extern const char kForceWaveAudio[]; MEDIA_EXPORT extern const char kTrySupportedChannelLayouts[];
diff --git a/media/base/media_util.cc b/media/base/media_util.cc index bd7929f5..a6516cd2 100644 --- a/media/base/media_util.cc +++ b/media/base/media_util.cc
@@ -10,4 +10,13 @@ return std::vector<uint8_t>(); } +EncryptionScheme Unencrypted() { + return EncryptionScheme(); +} + +EncryptionScheme AesCtrEncryptionScheme() { + return EncryptionScheme(EncryptionScheme::CIPHER_MODE_AES_CTR, + EncryptionScheme::Pattern()); +} + } // namespace media
diff --git a/media/base/media_util.h b/media/base/media_util.h index 4e53c9a0..c7ddc8bb 100644 --- a/media/base/media_util.h +++ b/media/base/media_util.h
@@ -8,6 +8,7 @@ #include <stdint.h> #include <vector> +#include "media/base/encryption_scheme.h" #include "media/base/media_export.h" namespace media { @@ -16,6 +17,11 @@ // constructed with empty extra data. MEDIA_EXPORT std::vector<uint8_t> EmptyExtraData(); +// The following helper functions return new instances of EncryptionScheme that +// indicate widely used settings. +MEDIA_EXPORT EncryptionScheme Unencrypted(); +MEDIA_EXPORT EncryptionScheme AesCtrEncryptionScheme(); + } // namespace media #endif // MEDIA_BASE_UTIL_H_
diff --git a/media/base/mime_util_unittest.cc b/media/base/mime_util_unittest.cc index 0690f85..da9877d 100644 --- a/media/base/mime_util_unittest.cc +++ b/media/base/mime_util_unittest.cc
@@ -131,7 +131,7 @@ EXPECT_TRUE(IsSupportedMediaMimeType("video/ogg")); #endif // OS_ANDROID -#if defined(OS_ANDROID) && defined(USE_PROPRIETARY_CODECS) +#if defined(OS_ANDROID) // HLS is supported on Android API level 14 and higher and Chrome supports // API levels 15 and higher, so these are expected to be supported. bool kHlsSupported = true;
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc index b884504..0ab1903 100644 --- a/media/base/test_helpers.cc +++ b/media/base/test_helpers.cc
@@ -129,43 +129,57 @@ gfx::Rect visible_rect(coded_size.width(), coded_size.height()); gfx::Size natural_size = coded_size; - return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN, - PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED, - coded_size, visible_rect, natural_size, - EmptyExtraData(), is_encrypted); + return VideoDecoderConfig( + codec, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12, + COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect, natural_size, + EmptyExtraData(), + is_encrypted ? AesCtrEncryptionScheme() : Unencrypted()); } static const gfx::Size kNormalSize(320, 240); static const gfx::Size kLargeSize(640, 480); +// static VideoDecoderConfig TestVideoConfig::Invalid() { return GetTestConfig(kUnknownVideoCodec, kNormalSize, false); } +// static VideoDecoderConfig TestVideoConfig::Normal() { return GetTestConfig(kCodecVP8, kNormalSize, false); } +// static VideoDecoderConfig TestVideoConfig::NormalEncrypted() { return GetTestConfig(kCodecVP8, kNormalSize, true); } +// static VideoDecoderConfig TestVideoConfig::Large() { return GetTestConfig(kCodecVP8, kLargeSize, false); } +// static VideoDecoderConfig TestVideoConfig::LargeEncrypted() { return GetTestConfig(kCodecVP8, kLargeSize, true); } +// static gfx::Size TestVideoConfig::NormalCodedSize() { return kNormalSize; } +// static gfx::Size TestVideoConfig::LargeCodedSize() { return kLargeSize; } +// static +AudioParameters TestAudioParameters::Normal() { + return AudioParameters(AudioParameters::AUDIO_PCM_LOW_LATENCY, + CHANNEL_LAYOUT_STEREO, 48000, 16, 2048); +} + template <class T> scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, ChannelLayout channel_layout,
diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h index 8576aa8..d14d83c1 100644 --- a/media/base/test_helpers.h +++ b/media/base/test_helpers.h
@@ -9,6 +9,7 @@ #include "base/callback.h" #include "base/macros.h" +#include "media/audio/audio_parameters.h" #include "media/base/channel_layout.h" #include "media/base/media_log.h" #include "media/base/pipeline_status.h" @@ -90,7 +91,16 @@ static gfx::Size LargeCodedSize(); private: - DISALLOW_IMPLICIT_CONSTRUCTORS(TestVideoConfig); + DISALLOW_COPY_AND_ASSIGN(TestVideoConfig); +}; + +// Provides pre-canned AudioParameters objects. +class TestAudioParameters { + public: + static AudioParameters Normal(); + + private: + DISALLOW_COPY_AND_ASSIGN(TestAudioParameters); }; // Create an AudioBuffer containing |frames| frames of data, where each sample
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc index 930ffd9..a0edb401 100644 --- a/media/base/video_decoder_config.cc +++ b/media/base/video_decoder_config.cc
@@ -39,20 +39,20 @@ VideoDecoderConfig::VideoDecoderConfig() : codec_(kUnknownVideoCodec), profile_(VIDEO_CODEC_PROFILE_UNKNOWN), - format_(PIXEL_FORMAT_UNKNOWN), - is_encrypted_(false) {} + format_(PIXEL_FORMAT_UNKNOWN) {} -VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec, - VideoCodecProfile profile, - VideoPixelFormat format, - ColorSpace color_space, - const gfx::Size& coded_size, - const gfx::Rect& visible_rect, - const gfx::Size& natural_size, - const std::vector<uint8_t>& extra_data, - bool is_encrypted) { +VideoDecoderConfig::VideoDecoderConfig( + VideoCodec codec, + VideoCodecProfile profile, + VideoPixelFormat format, + ColorSpace color_space, + const gfx::Size& coded_size, + const gfx::Rect& visible_rect, + const gfx::Size& natural_size, + const std::vector<uint8_t>& extra_data, + const EncryptionScheme& encryption_scheme) { Initialize(codec, profile, format, color_space, coded_size, visible_rect, - natural_size, extra_data, is_encrypted); + natural_size, extra_data, encryption_scheme); } VideoDecoderConfig::VideoDecoderConfig(const VideoDecoderConfig& other) = @@ -68,7 +68,7 @@ const gfx::Rect& visible_rect, const gfx::Size& natural_size, const std::vector<uint8_t>& extra_data, - bool is_encrypted) { + const EncryptionScheme& encryption_scheme) { codec_ = codec; profile_ = profile; format_ = format; @@ -77,7 +77,7 @@ visible_rect_ = visible_rect; natural_size_ = natural_size; extra_data_ = extra_data; - is_encrypted_ = is_encrypted; + encryption_scheme_ = encryption_scheme; } bool VideoDecoderConfig::IsValidConfig() const { @@ -89,14 +89,13 @@ } bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const { - return ((codec() == config.codec()) && - (format() == config.format()) && + return ((codec() == config.codec()) && (format() == config.format()) && (profile() == config.profile()) && (coded_size() == config.coded_size()) && (visible_rect() == config.visible_rect()) && (natural_size() == config.natural_size()) && (extra_data() == config.extra_data()) && - (is_encrypted() == config.is_encrypted())); + (encryption_scheme().Matches(config.encryption_scheme()))); } std::string VideoDecoderConfig::AsHumanReadableString() const {
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h index 4a192d6c..50dee065 100644 --- a/media/base/video_decoder_config.h +++ b/media/base/video_decoder_config.h
@@ -11,6 +11,7 @@ #include <vector> #include "base/macros.h" +#include "media/base/encryption_scheme.h" #include "media/base/media_export.h" #include "media/base/video_codecs.h" #include "media/base/video_types.h" @@ -38,7 +39,7 @@ const gfx::Rect& visible_rect, const gfx::Size& natural_size, const std::vector<uint8_t>& extra_data, - bool is_encrypted); + const EncryptionScheme& encryption_scheme); VideoDecoderConfig(const VideoDecoderConfig& other); @@ -53,7 +54,7 @@ const gfx::Rect& visible_rect, const gfx::Size& natural_size, const std::vector<uint8_t>& extra_data, - bool is_encrypted); + const EncryptionScheme& encryption_scheme); // Returns true if this object has appropriate configuration values, false // otherwise. @@ -100,7 +101,12 @@ // Whether the video stream is potentially encrypted. // Note that in a potentially encrypted video stream, individual buffers // can be encrypted or not encrypted. - bool is_encrypted() const { return is_encrypted_; } + bool is_encrypted() const { return encryption_scheme_.is_encrypted(); } + + // Encryption scheme used for encrypted buffers. + const EncryptionScheme& encryption_scheme() const { + return encryption_scheme_; + } private: VideoCodec codec_; @@ -115,7 +121,7 @@ std::vector<uint8_t> extra_data_; - bool is_encrypted_; + EncryptionScheme encryption_scheme_; // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler // generated copy constructor and assignment operator. Since the extra data is
diff --git a/media/base/video_decoder_config_unittest.cc b/media/base/video_decoder_config_unittest.cc index 7885c8f7..18528330 100644 --- a/media/base/video_decoder_config_unittest.cc +++ b/media/base/video_decoder_config_unittest.cc
@@ -19,7 +19,7 @@ VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_UNKNOWN, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, kNaturalSize, - EmptyExtraData(), false); + EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -27,7 +27,7 @@ gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -35,7 +35,7 @@ gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -43,7 +43,7 @@ gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -51,7 +51,7 @@ gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -61,7 +61,7 @@ gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); } @@ -72,7 +72,7 @@ EXPECT_EQ(0, natural_size.width()); VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); EXPECT_FALSE(config.IsValidConfig()); }
diff --git a/media/base/video_frame_metadata.h b/media/base/video_frame_metadata.h index a4ae4e5..61b33a3 100644 --- a/media/base/video_frame_metadata.h +++ b/media/base/video_frame_metadata.h
@@ -94,6 +94,11 @@ // measurements would be used as feedback. RESOURCE_UTILIZATION, + // Sources of VideoFrames use this marker to indicate that an instance of + // VideoFrameExternalResources produced from the associated video frame + // should use read lock fences. + READ_LOCK_FENCES_ENABLED, + NUM_KEYS };
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn index da6b23c..63c77b28 100644 --- a/media/blink/BUILD.gn +++ b/media/blink/BUILD.gn
@@ -143,6 +143,7 @@ "url_index_unittest.cc", "video_frame_compositor_unittest.cc", "webaudiosourceprovider_impl_unittest.cc", + "webmediaplayer_impl_unittest.cc", ] if (is_android) {
diff --git a/media/blink/buffered_data_source.cc b/media/blink/buffered_data_source.cc index b26f0f13..d1a6c224f 100644 --- a/media/blink/buffered_data_source.cc +++ b/media/blink/buffered_data_source.cc
@@ -23,13 +23,16 @@ // of FFmpeg. const int kInitialReadBufferSize = 32768; -// Number of cache misses or read failures we allow for a single Read() before -// signaling an error. -const int kLoaderRetries = 3; - // The number of milliseconds to wait before retrying a failed load. const int kLoaderFailedRetryDelayMs = 250; +// Each retry, add this many MS to the delay. +// total delay is: +// (kLoaderPartialRetryDelayMs + +// kAdditionalDelayPerRetryMs * (kMaxRetries - 1) / 2) * kLoaderRetries +// = 29250 ms +const int kAdditionalDelayPerRetryMs = 50; + } // namespace namespace media { @@ -491,7 +494,9 @@ FROM_HERE, base::Bind(&BufferedDataSource::ReadCallback, weak_factory_.GetWeakPtr(), BufferedResourceLoader::kCacheMiss, 0), - base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs)); + base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs + + read_op_->retries() * + kAdditionalDelayPerRetryMs)); return; }
diff --git a/media/blink/buffered_data_source.h b/media/blink/buffered_data_source.h index 17b7507b..49b70f9 100644 --- a/media/blink/buffered_data_source.h +++ b/media/blink/buffered_data_source.h
@@ -122,6 +122,9 @@ class MEDIA_BLINK_EXPORT BufferedDataSource : NON_EXPORTED_BASE(public BufferedDataSourceInterface) { public: + // Number of cache misses or read failures we allow for a single Read() before + // signaling an error. + enum { kLoaderRetries = 30 }; typedef base::Callback<void(bool)> DownloadingCB; // |url| and |cors_mode| are passed to the object. Buffered byte range changes
diff --git a/media/blink/buffered_data_source_unittest.cc b/media/blink/buffered_data_source_unittest.cc index eb2114c..cea05b88 100644 --- a/media/blink/buffered_data_source_unittest.cc +++ b/media/blink/buffered_data_source_unittest.cc
@@ -633,18 +633,11 @@ // Make sure there's a pending read -- we'll expect it to error. ReadAt(0); - // It'll try three times. - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->Generate206(0)); - - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->Generate206(0)); - - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->Generate206(0)); + for (int i = 0; i < BufferedDataSource::kLoaderRetries; i++) { + ExpectCreateResourceLoader(); + FinishLoading(); + Respond(response_generator_->Generate206(0)); + } // It'll error after this. EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); @@ -660,18 +653,11 @@ // Make sure there's a pending read -- we'll expect it to error. ReadAt(0); - // It'll try three times. - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->GenerateFileResponse(0)); - - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->GenerateFileResponse(0)); - - ExpectCreateResourceLoader(); - FinishLoading(); - Respond(response_generator_->GenerateFileResponse(0)); + for (int i = 0; i < BufferedDataSource::kLoaderRetries; i++) { + ExpectCreateResourceLoader(); + FinishLoading(); + Respond(response_generator_->GenerateFileResponse(0)); + } // It'll error after this. EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError));
diff --git a/media/blink/media_blink.gyp b/media/blink/media_blink.gyp index 8240d9d..9327041 100644 --- a/media/blink/media_blink.gyp +++ b/media/blink/media_blink.gyp
@@ -148,6 +148,7 @@ 'url_index_unittest.cc', 'video_frame_compositor_unittest.cc', 'webaudiosourceprovider_impl_unittest.cc', + 'webmediaplayer_impl_unittest.cc', ], }, ],
diff --git a/media/blink/multibuffer_data_source_unittest.cc b/media/blink/multibuffer_data_source_unittest.cc index a855001f..a52700c 100644 --- a/media/blink/multibuffer_data_source_unittest.cc +++ b/media/blink/multibuffer_data_source_unittest.cc
@@ -322,6 +322,12 @@ message_loop_.RunUntilIdle(); } + void FailLoading() { + data_provider()->didFail(url_loader(), + response_generator_->GenerateError()); + message_loop_.RunUntilIdle(); + } + void Restart() { EXPECT_TRUE(data_provider()); EXPECT_FALSE(active_loader_allownull()); @@ -793,23 +799,19 @@ // Make sure there's a pending read -- we'll expect it to error. ReadAt(kDataSize); - // It'll try three times. - FinishLoading(); - Restart(); - Respond(response_generator_->Generate206(kDataSize)); + for (int i = 0; i < ResourceMultiBufferDataProvider::kMaxRetries; i++) { + FailLoading(); + data_provider()->Start(); + Respond(response_generator_->Generate206(kDataSize)); + } - FinishLoading(); - Restart(); - Respond(response_generator_->Generate206(kDataSize)); - - FinishLoading(); - Restart(); - Respond(response_generator_->Generate206(kDataSize)); - - // It'll error after this. - EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); - FinishLoading(); - + // Stop() will also cause the readback to be called with kReadError, but + // we want to make sure it was called during FailLoading(). + bool failed_ = false; + EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)) + .WillOnce(Assign(&failed_, true)); + FailLoading(); + EXPECT_TRUE(failed_); EXPECT_FALSE(loading()); Stop(); } @@ -820,23 +822,19 @@ // Make sure there's a pending read -- we'll expect it to error. ReadAt(kDataSize); - // It'll try three times. - FinishLoading(); - Restart(); - Respond(response_generator_->GenerateFileResponse(0)); + for (int i = 0; i < ResourceMultiBufferDataProvider::kMaxRetries; i++) { + FailLoading(); + data_provider()->Start(); + Respond(response_generator_->Generate206(kDataSize)); + } - FinishLoading(); - Restart(); - Respond(response_generator_->GenerateFileResponse(0)); - - FinishLoading(); - Restart(); - Respond(response_generator_->GenerateFileResponse(0)); - - // It'll error after this. - EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)); - FinishLoading(); - + // Stop() will also cause the readback to be called with kReadError, but + // we want to make sure it was called during FailLoading(). + bool failed_ = false; + EXPECT_CALL(*this, ReadCallback(media::DataSource::kReadError)) + .WillOnce(Assign(&failed_, true)); + FailLoading(); + EXPECT_TRUE(failed_); EXPECT_FALSE(loading()); Stop(); }
diff --git a/media/blink/resource_multibuffer_data_provider.cc b/media/blink/resource_multibuffer_data_provider.cc index 0c5c7187..9f31849eb 100644 --- a/media/blink/resource_multibuffer_data_provider.cc +++ b/media/blink/resource_multibuffer_data_provider.cc
@@ -35,6 +35,12 @@ // The number of milliseconds to wait before retrying a failed load. const int kLoaderFailedRetryDelayMs = 250; +// Each retry, add this many MS to the delay. +// total delay is: +// (kLoaderPartialRetryDelayMs + +// kAdditionalDelayPerRetryMs * (kMaxRetries - 1) / 2) * kMaxretries = 29250 ms +const int kAdditionalDelayPerRetryMs = 50; + // The number of milliseconds to wait before retrying when the server // decides to not give us all the data at once. const int kLoaderPartialRetryDelayMs = 25; @@ -42,7 +48,6 @@ const int kHttpOK = 200; const int kHttpPartialContent = 206; const int kHttpRangeNotSatisfiable = 416; -const int kMaxRetries = 3; ResourceMultiBufferDataProvider::ResourceMultiBufferDataProvider( UrlData* url_data, @@ -411,12 +416,11 @@ base::MessageLoop::current()->PostDelayedTask( FROM_HERE, base::Bind(&ResourceMultiBufferDataProvider::Start, weak_factory_.GetWeakPtr()), - base::TimeDelta::FromMilliseconds(kLoaderFailedRetryDelayMs)); + base::TimeDelta::FromMilliseconds( + kLoaderFailedRetryDelayMs + kAdditionalDelayPerRetryMs * retries_)); } else { // We don't need to continue loading after failure. - // - // Keep it alive until we exit this method so that |error| remains valid. - scoped_ptr<ActiveLoader> active_loader = std::move(active_loader_); + // Note that calling Fail() will most likely delete this object. url_data_->Fail(); } }
diff --git a/media/blink/resource_multibuffer_data_provider.h b/media/blink/resource_multibuffer_data_provider.h index ee5a9e8..75df5c55 100644 --- a/media/blink/resource_multibuffer_data_provider.h +++ b/media/blink/resource_multibuffer_data_provider.h
@@ -28,6 +28,9 @@ : NON_EXPORTED_BASE(public MultiBuffer::DataProvider), NON_EXPORTED_BASE(public blink::WebURLLoaderClient) { public: + // NUmber of times we'll retry if the connection fails. + enum { kMaxRetries = 30 }; + ResourceMultiBufferDataProvider(UrlData* url_data, MultiBufferBlockId pos); ~ResourceMultiBufferDataProvider() override;
diff --git a/media/blink/webmediaplayer_delegate.h b/media/blink/webmediaplayer_delegate.h index 7ae31df..30dfc91 100644 --- a/media/blink/webmediaplayer_delegate.h +++ b/media/blink/webmediaplayer_delegate.h
@@ -16,16 +16,26 @@ public: class Observer { public: - // Called when the WebMediaPlayer is no longer in the foreground. Audio may - // continue in the background unless |must_suspend| is true. - virtual void OnHidden(bool must_suspend) = 0; - + // Called when the WebMediaPlayer enters the background or foreground + // respectively. Note: Some implementations will stop playback when hidden, + // and thus subsequently call WebMediaPlayerDelegate::PlayerGone(). + virtual void OnHidden() = 0; virtual void OnShown() = 0; + + // Requests a WebMediaPlayer instance to release all idle resources. If + // |must_suspend| is true, the player must stop playback, release all idle + // resources, and finally call WebMediaPlayerDelegate::PlayerGone(). If + // |must_suspend| is false, the player may ignore the request. Optionally, + // it may do some or all of the same actions as when |must_suspend| is true. + // To be clear, the player is not required to call PlayerGone() when + // |must_suspend| is false. + virtual void OnSuspendRequested(bool must_suspend) = 0; + virtual void OnPlay() = 0; virtual void OnPause() = 0; - // Playout volume should be set to current_volume * multiplier. The range - // is [0, 1] and is typically 1. + // Playout volume should be set to current_volume * multiplier. The range is + // [0, 1] and is typically 1. virtual void OnVolumeMultiplierUpdate(double multiplier) = 0; }; @@ -46,7 +56,8 @@ // The specified player stopped playing media. virtual void DidPause(int delegate_id, bool reached_end_of_stream) = 0; - // The specified player was destroyed or suspended. This may be called + // The specified player was destroyed or suspended and will no longer accept + // Observer::OnPlay() or Observer::OnPause() calls. This may be called // multiple times in row. Note: Clients must still call RemoveObserver() to // unsubscribe from callbacks. virtual void PlayerGone(int delegate_id) = 0;
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index 071e70ea..d5fec260 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -105,6 +105,17 @@ } } +bool IsSuspendUponHiddenEnabled() { +#if !defined(OS_ANDROID) + // Suspend/Resume is only enabled by default on Android. + return base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableMediaSuspend); +#else + return !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableMediaSuspend); +#endif +} + } // namespace class BufferedDataSourceHostImpl; @@ -339,6 +350,7 @@ } #endif + const bool was_paused = paused_; paused_ = false; pipeline_.SetPlaybackRate(playback_rate_); @@ -347,13 +359,13 @@ media_log_->AddEvent(media_log_->CreateEvent(MediaLogEvent::PLAY)); - if (playback_rate_ > 0) { + if (playback_rate_ > 0 && was_paused) { NotifyPlaybackStarted(); - // Resume the player if playback was initiated in the foreground. Resume() - // will do nothing if the pipeline is not suspended state, but will clear - // some internal pending state, so it should always be called. - if (delegate_ && !delegate_->IsHidden()) + // Resume the player if allowed. We always call Resume() in case there is a + // pending suspend that should be aborted. If the pipeline is not suspended, + // Resume() will have no effect. + if (IsAutomaticResumeAllowed()) pipeline_controller_.Resume(); } } @@ -442,10 +454,10 @@ paused_time_ = time; pipeline_controller_.Seek(time, time_updated); - // Resume the pipeline if the seek is initiated in the foreground so that - // the correct frame is displayed. If the pipeline is not suspended, Resume() - // will do nothing but clear some pending state. - if (delegate_ && !delegate_->IsHidden()) + // Resume the pipeline if allowed so that the correct frame is displayed. We + // always call Resume() in case there is a pending suspend that should be + // aborted. If the pipeline is not suspended, Resume() will have no effect. + if (IsAutomaticResumeAllowed()) pipeline_controller_.Resume(); } @@ -858,8 +870,6 @@ } #endif - if (delegate_) - delegate_->PlayerGone(delegate_id_); memory_usage_reporting_timer_.Stop(); ReportMemoryUsage(); @@ -871,8 +881,13 @@ } void WebMediaPlayerImpl::OnPipelineResumed() { - if (playback_rate_ > 0 && !paused_) + if (playback_rate_ > 0 && !paused_) { NotifyPlaybackStarted(); + } else if (!playback_rate_ || paused_ || ended_) { + // Resend our paused notification so the pipeline is considered for idle + // resource reclamation; duplicate pause notifications are ignored. + NotifyPlaybackPaused(); + } } void WebMediaPlayerImpl::OnPipelineEnded() { @@ -936,7 +951,7 @@ // If there is video and the frame is hidden, then it may be time to suspend // playback. if (delegate_ && delegate_->IsHidden()) - OnHidden(false); + OnHidden(); } } @@ -997,49 +1012,35 @@ done_cb.Run(std::move(text_track)); } -void WebMediaPlayerImpl::OnHidden(bool must_suspend) { +void WebMediaPlayerImpl::OnHidden() { DCHECK(main_task_runner_->BelongsToCurrentThread()); - -#if !defined(OS_ANDROID) - // Suspend/Resume is enabled by default on Android. - if (!base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableMediaSuspend)) { + if (!IsSuspendUponHiddenEnabled()) return; - } -#endif // !defined(OS_ANDROID) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableMediaSuspend)) { - return; - } - -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) // WMPI_CAST // If we're remote, the pipeline should already be suspended. if (isRemote()) return; #endif - if (must_suspend || (paused_ && ended_) || hasVideo()) - pipeline_controller_.Suspend(); + // Don't suspend players which only have audio and have not completed + // playback. The user can still control these players via the MediaSession UI. + // If the player has never started playback, OnSuspendRequested() will handle + // release of any idle resources. + if (!hasVideo() && !paused_ && !ended_) + return; + + pipeline_controller_.Suspend(); + if (delegate_) + delegate_->PlayerGone(delegate_id_); } void WebMediaPlayerImpl::OnShown() { DCHECK(main_task_runner_->BelongsToCurrentThread()); - -#if !defined(OS_ANDROID) - // Suspend/Resume is enabled by default on Android. - if (!base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kEnableMediaSuspend)) { + if (!IsSuspendUponHiddenEnabled()) return; - } -#endif // !defined(OS_ANDROID) - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableMediaSuspend)) { - return; - } - -#if defined(OS_ANDROID) +#if defined(OS_ANDROID) // WMPI_CAST // If we're remote, the pipeline should stay suspended. if (isRemote()) return; @@ -1049,6 +1050,27 @@ pipeline_controller_.Resume(); } +void WebMediaPlayerImpl::OnSuspendRequested(bool must_suspend) { + DCHECK(main_task_runner_->BelongsToCurrentThread()); + +#if defined(OS_ANDROID) // WMPI_CAST + // If we're remote, the pipeline should already be suspended. + if (isRemote()) + return; +#endif + + // Suspend should never be requested unless required or we're already in an + // idle state (paused or ended). + DCHECK(must_suspend || paused_ || ended_); + + // Always suspend, but only notify the delegate if we must; this allows any + // exposed UI for player controls to continue to function even though the + // player has now been suspended. + pipeline_controller_.Suspend(); + if (must_suspend && delegate_) + delegate_->PlayerGone(delegate_id_); +} + void WebMediaPlayerImpl::OnPlay() { play(); client_->playbackStateChanged(); @@ -1434,4 +1456,13 @@ adjust_allocated_memory_cb_.Run(delta); } +bool WebMediaPlayerImpl::IsAutomaticResumeAllowed() { +#if defined(OS_ANDROID) + return !hasVideo() || (delegate_ && !delegate_->IsHidden()); +#else + // On non-Android platforms Resume() is always allowed. + return true; +#endif +} + } // namespace media
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index 0dd640de..fac56ed1 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -168,8 +168,9 @@ void exitedFullscreen() override; // WebMediaPlayerDelegate::Observer implementation. - void OnHidden(bool must_suspend) override; + void OnHidden() override; void OnShown() override; + void OnSuspendRequested(bool must_suspend) override; void OnPlay() override; void OnPause() override; void OnVolumeMultiplierUpdate(double multiplier) override; @@ -285,6 +286,9 @@ void ReportMemoryUsage(); void FinishMemoryUsageReport(int64_t demuxer_memory_usage); + // Indicates if automatic resumption of a suspended playback is allowed. + bool IsAutomaticResumeAllowed(); + blink::WebLocalFrame* frame_; // TODO(hclam): get rid of these members and read from the pipeline directly.
diff --git a/media/blink/webmediaplayer_impl_unittest.cc b/media/blink/webmediaplayer_impl_unittest.cc new file mode 100644 index 0000000..5e1dab12 --- /dev/null +++ b/media/blink/webmediaplayer_impl_unittest.cc
@@ -0,0 +1,158 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <stdint.h> + +#include "base/bind.h" +#include "base/callback_helpers.h" +#include "base/memory/ref_counted.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/message_loop/message_loop.h" +#include "base/thread_task_runner_handle.h" +#include "base/threading/thread.h" +#include "media/base/audio_hardware_config.h" +#include "media/base/media_log.h" +#include "media/base/test_helpers.h" +#include "media/blink/webmediaplayer_delegate.h" +#include "media/blink/webmediaplayer_impl.h" +#include "media/blink/webmediaplayer_params.h" +#include "media/renderers/default_renderer_factory.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" +#include "third_party/WebKit/public/platform/WebSecurityOrigin.h" +#include "third_party/WebKit/public/web/WebFrameClient.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/WebKit/public/web/WebView.h" +#include "url/gurl.h" + +namespace media { + +int64_t OnAdjustAllocatedMemory(int64_t delta) { + return 0; +} + +// Dummy superclass necessary since blink::WebFrameClient() has a protected +// destructor. +class DummyWebFrameClient : public blink::WebFrameClient {}; + +class DummyWebMediaPlayerClient : public blink::WebMediaPlayerClient { + public: + DummyWebMediaPlayerClient() {} + + // blink::WebMediaPlayerClient implementation. + void networkStateChanged() override {} + void readyStateChanged() override {} + void timeChanged() override {} + void repaint() override {} + void durationChanged() override {} + void sizeChanged() override {} + void playbackStateChanged() override {} + void setWebLayer(blink::WebLayer*) override {} + blink::WebMediaPlayer::TrackId addAudioTrack( + const blink::WebString& id, + blink::WebMediaPlayerClient::AudioTrackKind, + const blink::WebString& label, + const blink::WebString& language, + bool enabled) override { + return 0; + } + void removeAudioTrack(blink::WebMediaPlayer::TrackId) override {} + blink::WebMediaPlayer::TrackId addVideoTrack( + const blink::WebString& id, + blink::WebMediaPlayerClient::VideoTrackKind, + const blink::WebString& label, + const blink::WebString& language, + bool selected) override { + return 0; + } + void removeVideoTrack(blink::WebMediaPlayer::TrackId) override {} + void addTextTrack(blink::WebInbandTextTrack*) override {} + void removeTextTrack(blink::WebInbandTextTrack*) override {} + void mediaSourceOpened(blink::WebMediaSource*) override {} + void requestSeek(double) override {} + void remoteRouteAvailabilityChanged(bool) override {} + void connectedToRemoteDevice() override {} + void disconnectedFromRemoteDevice() override {} + + private: + DISALLOW_COPY_AND_ASSIGN(DummyWebMediaPlayerClient); +}; + +class WebMediaPlayerImplTest : public testing::Test { + public: + WebMediaPlayerImplTest() + : media_thread_("MediaThreadForTest"), + web_view_(blink::WebView::create(nullptr)), + web_local_frame_( + blink::WebLocalFrame::create(blink::WebTreeScopeType::Document, + &web_frame_client_)), + media_log_(new MediaLog()), + audio_parameters_(TestAudioParameters::Normal()), + audio_hardware_config_(audio_parameters_, audio_parameters_) { + web_view_->setMainFrame(web_local_frame_); + media_thread_.StartAndWaitForTesting(); + + wmpi_.reset(new WebMediaPlayerImpl( + web_local_frame_, &client_, nullptr, + base::WeakPtr<WebMediaPlayerDelegate>(), + make_scoped_ptr(new DefaultRendererFactory(media_log_, nullptr, nullptr, + audio_hardware_config_)), + url_index_, + WebMediaPlayerParams( + WebMediaPlayerParams::DeferLoadCB(), + scoped_refptr<RestartableAudioRendererSink>(), media_log_, + media_thread_.task_runner(), message_loop_.task_runner(), + message_loop_.task_runner(), WebMediaPlayerParams::Context3DCB(), + base::Bind(&OnAdjustAllocatedMemory), nullptr, nullptr, nullptr))); + } + + ~WebMediaPlayerImplTest() override { + // Destruct WebMediaPlayerImpl and pump the message loop to ensure that + // objects passed to the message loop for destruction are released. + // + // NOTE: This should be done before any other member variables are + // destructed since WMPI may reference them during destruction. + wmpi_.reset(); + message_loop_.RunUntilIdle(); + + web_view_->close(); + web_local_frame_->close(); + } + + protected: + // "Renderer" thread. + base::MessageLoop message_loop_; + + // "Media" thread. This is necessary because WMPI destruction waits on a + // WaitableEvent. + base::Thread media_thread_; + + // Blink state. + DummyWebFrameClient web_frame_client_; + blink::WebView* web_view_; + blink::WebLocalFrame* web_local_frame_; + + scoped_refptr<MediaLog> media_log_; + linked_ptr<media::UrlIndex> url_index_; + + // Audio hardware configuration. + AudioParameters audio_parameters_; + AudioHardwareConfig audio_hardware_config_; + + // The client interface used by |wmpi_|. Just a dummy for now, but later we + // may want a mock or intelligent fake. + DummyWebMediaPlayerClient client_; + + // The WebMediaPlayerImpl instance under test. + scoped_ptr<WebMediaPlayerImpl> wmpi_; + + private: + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImplTest); +}; + +TEST_F(WebMediaPlayerImplTest, ConstructAndDestroy) {} + +} // namespace media
diff --git a/media/capture/video/mac/video_capture_device_mac.mm b/media/capture/video/mac/video_capture_device_mac.mm index 432fbfb..ec6fcaf8 100644 --- a/media/capture/video/mac/video_capture_device_mac.mm +++ b/media/capture/video/mac/video_capture_device_mac.mm
@@ -545,8 +545,18 @@ return; } + base::TimeTicks aligned_timestamp; + if (timestamp == media::kNoTimestamp()) { + aligned_timestamp = base::TimeTicks::Now(); + } else { + if (first_timestamp_ == media::kNoTimestamp()) { + first_timestamp_ = timestamp; + first_aligned_timestamp_ = base::TimeTicks::Now(); + } + aligned_timestamp = first_aligned_timestamp_ + timestamp - first_timestamp_; + } client_->OnIncomingCapturedData(video_frame, video_frame_length, frame_format, - 0, base::TimeTicks::Now()); + 0, aligned_timestamp); } void VideoCaptureDeviceMac::ReceiveError(
diff --git a/media/capture/video/win/video_capture_device_factory_win.cc b/media/capture/video/win/video_capture_device_factory_win.cc index 508ba4f..ba0904a2 100644 --- a/media/capture/video/win/video_capture_device_factory_win.cc +++ b/media/capture/video/win/video_capture_device_factory_win.cc
@@ -370,16 +370,11 @@ return g_dlls_available; } -VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() { - // Use Media Foundation for Metro processes (after and including Win8) and - // DirectShow for any other versions, unless forced via flag. Media Foundation - // can also be forced if appropriate flag is set and we are in Windows 7 or - // 8 in non-Metro mode. - const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); - use_media_foundation_ = - base::win::GetVersion() >= base::win::VERSION_WIN7 && - cmd_line->HasSwitch(switches::kForceMediaFoundationVideoCapture); -} +VideoCaptureDeviceFactoryWin::VideoCaptureDeviceFactoryWin() + : use_media_foundation_(base::win::GetVersion() >= + base::win::VERSION_WIN7 && + base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kForceMediaFoundationVideoCapture)) {} scoped_ptr<VideoCaptureDevice> VideoCaptureDeviceFactoryWin::Create( const Name& device_name) {
diff --git a/media/capture/video/win/video_capture_device_factory_win.h b/media/capture/video/win/video_capture_device_factory_win.h index df4be02..7645cb1 100644 --- a/media/capture/video/win/video_capture_device_factory_win.h +++ b/media/capture/video/win/video_capture_device_factory_win.h
@@ -30,7 +30,9 @@ VideoCaptureFormats* supported_formats) override; private: - bool use_media_foundation_; + // Media Foundation is available in Win7 and later, use it if explicitly + // forced via flag, else use DirectShow. + const bool use_media_foundation_; DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceFactoryWin); };
diff --git a/media/capture/video/win/video_capture_device_win.cc b/media/capture/video/win/video_capture_device_win.cc index 21cc4502..53a47dd 100644 --- a/media/capture/video/win/video_capture_device_win.cc +++ b/media/capture/video/win/video_capture_device_win.cc
@@ -453,7 +453,7 @@ int length, base::TimeTicks timestamp) { client_->OnIncomingCapturedData(buffer, length, capture_format_, 0, - base::TimeTicks::Now()); + timestamp); } bool VideoCaptureDeviceWin::CreateCapabilityMap() {
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc index 51e8884..f081255 100644 --- a/media/ffmpeg/ffmpeg_common.cc +++ b/media/ffmpeg/ffmpeg_common.cc
@@ -13,12 +13,24 @@ #include "build/build_config.h" #include "media/base/audio_decoder_config.h" #include "media/base/decoder_buffer.h" +#include "media/base/encryption_scheme.h" +#include "media/base/media_util.h" #include "media/base/video_decoder_config.h" #include "media/base/video_util.h" #include "media/media_features.h" namespace media { +namespace { + +EncryptionScheme GetEncryptionScheme(const AVStream* stream) { + AVDictionaryEntry* key = + av_dict_get(stream->metadata, "enc_key_id", nullptr, 0); + return key ? AesCtrEncryptionScheme() : Unencrypted(); +} + +} // namespace + // Why FF_INPUT_BUFFER_PADDING_SIZE? FFmpeg assumes all input buffers are // padded. Check here to ensure FFmpeg only receives data padded to its // specifications. @@ -303,9 +315,10 @@ return AV_SAMPLE_FMT_NONE; } -bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context, - bool is_encrypted, - AudioDecoderConfig* config) { +bool AVCodecContextToAudioDecoderConfig( + const AVCodecContext* codec_context, + const EncryptionScheme& encryption_scheme, + AudioDecoderConfig* config) { DCHECK_EQ(codec_context->codec_type, AVMEDIA_TYPE_AUDIO); AudioCodec codec = CodecIDToAudioCodec(codec_context->codec_id); @@ -371,13 +384,9 @@ extra_data.assign(codec_context->extradata, codec_context->extradata + codec_context->extradata_size); } - config->Initialize(codec, - sample_format, - channel_layout, - sample_rate, - extra_data, - is_encrypted, - seek_preroll, + + config->Initialize(codec, sample_format, channel_layout, sample_rate, + extra_data, encryption_scheme, seek_preroll, codec_context->delay); // Verify that AudioConfig.bits_per_channel was calculated correctly for @@ -400,13 +409,8 @@ bool AVStreamToAudioDecoderConfig(const AVStream* stream, AudioDecoderConfig* config) { - bool is_encrypted = false; - AVDictionaryEntry* key = - av_dict_get(stream->metadata, "enc_key_id", nullptr, 0); - if (key) - is_encrypted = true; - return AVCodecContextToAudioDecoderConfig(stream->codec, is_encrypted, - config); + return AVCodecContextToAudioDecoderConfig( + stream->codec, GetEncryptionScheme(stream), config); } void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config, @@ -497,12 +501,6 @@ coded_size.set_height((coded_size.height() + 1) / 2 * 2); } - bool is_encrypted = false; - AVDictionaryEntry* key = - av_dict_get(stream->metadata, "enc_key_id", nullptr, 0); - if (key) - is_encrypted = true; - AVDictionaryEntry* webm_alpha = av_dict_get(stream->metadata, "alpha_mode", nullptr, 0); if (webm_alpha && !strcmp(webm_alpha->value, "1")) { @@ -535,7 +533,8 @@ stream->codec->extradata + stream->codec->extradata_size); } config->Initialize(codec, profile, format, color_space, coded_size, - visible_rect, natural_size, extra_data, is_encrypted); + visible_rect, natural_size, extra_data, + GetEncryptionScheme(stream)); return true; }
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h index b66de897..d5ad132 100644 --- a/media/ffmpeg/ffmpeg_common.h +++ b/media/ffmpeg/ffmpeg_common.h
@@ -52,6 +52,7 @@ namespace media { class AudioDecoderConfig; +class EncryptionScheme; class VideoDecoderConfig; // The following implement the deleters declared in ffmpeg_deleters.h (which @@ -113,7 +114,7 @@ // is not modified. MEDIA_EXPORT bool AVCodecContextToAudioDecoderConfig( const AVCodecContext* codec_context, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, AudioDecoderConfig* config); // Converts FFmpeg's channel layout to chrome's ChannelLayout. |channels| can
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc index 1d33405..0650ee65 100644 --- a/media/ffmpeg/ffmpeg_common_unittest.cc +++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -14,6 +14,7 @@ #include "base/memory/scoped_ptr.h" #include "media/base/audio_decoder_config.h" #include "media/base/media.h" +#include "media/base/media_util.h" #include "media/base/test_data_util.h" #include "media/base/video_decoder_config.h" #include "media/ffmpeg/ffmpeg_common.h" @@ -134,7 +135,7 @@ context.sample_rate = 44100; AudioDecoderConfig decoder_config; - ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(&context, false, + ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(&context, Unencrypted(), &decoder_config)); EXPECT_EQ(48000, decoder_config.samples_per_second()); }
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc index 92c4a73..0d87edc 100644 --- a/media/filters/audio_decoder_selector_unittest.cc +++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -77,14 +77,14 @@ void UseClearStream() { AudioDecoderConfig clear_audio_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100, - EmptyExtraData(), false); + EmptyExtraData(), Unencrypted()); demuxer_stream_->set_audio_decoder_config(clear_audio_config); } void UseEncryptedStream() { AudioDecoderConfig encrypted_audio_config( kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100, - EmptyExtraData(), true); + EmptyExtraData(), AesCtrEncryptionScheme()); demuxer_stream_->set_audio_decoder_config(encrypted_audio_config); }
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc index d29a68d..72881b7 100644 --- a/media/filters/audio_decoder_unittest.cc +++ b/media/filters/audio_decoder_unittest.cc
@@ -194,7 +194,7 @@ AudioDecoderConfig config; ASSERT_TRUE(AVCodecContextToAudioDecoderConfig( - reader_->codec_context_for_testing(), false, &config)); + reader_->codec_context_for_testing(), Unencrypted(), &config)); EXPECT_EQ(GetParam().codec, config.codec()); EXPECT_EQ(GetParam().samples_per_second, config.samples_per_second()); @@ -433,14 +433,9 @@ kOpusExtraData, kOpusExtraData + arraysize(kOpusExtraData)); AudioDecoderConfig decoder_config; - decoder_config.Initialize(kCodecOpus, - kSampleFormatF32, - CHANNEL_LAYOUT_STEREO, - 48000, - extra_data, - false, - base::TimeDelta::FromMilliseconds(80), - 0); + decoder_config.Initialize(kCodecOpus, kSampleFormatF32, CHANNEL_LAYOUT_STEREO, + 48000, extra_data, Unencrypted(), + base::TimeDelta::FromMilliseconds(80), 0); InitializeDecoder(decoder_config); } @@ -451,13 +446,8 @@ kOpusExtraData + arraysize(kOpusExtraData)); AudioDecoderConfig decoder_config; decoder_config.Initialize( - kCodecOpus, - kSampleFormatF32, - CHANNEL_LAYOUT_STEREO, - 48000, - extra_data, - false, - base::TimeDelta::FromMilliseconds(80), + kCodecOpus, kSampleFormatF32, CHANNEL_LAYOUT_STEREO, 48000, extra_data, + Unencrypted(), base::TimeDelta::FromMilliseconds(80), // Use a different codec delay than in the extradata. 100); InitializeDecoderWithResult(decoder_config, true); @@ -503,6 +493,7 @@ testing::ValuesIn(kOpusBehavioralTest)); #if defined(OS_ANDROID) + const DecoderTestData kMediaCodecTests[] = { {MEDIA_CODEC, kCodecOpus, "bear-opus.ogg", kBearOpusExpectations, 24, 48000, CHANNEL_LAYOUT_STEREO}, @@ -511,7 +502,10 @@ INSTANTIATE_TEST_CASE_P(MediaCodecAudioDecoderTest, AudioDecoderTest, testing::ValuesIn(kMediaCodecTests)); -#endif // defined(OS_ANDROID) + +#else // !defined(OS_ANDROID) + +// Disable all FFmpeg decoder tests on Android. http://crbug.com/570762. #if defined(USE_PROPRIETARY_CODECS) const DecodedBufferExpectations kSfxMp3Expectations[] = { @@ -594,4 +588,6 @@ FFmpegAudioDecoderBehavioralTest, testing::ValuesIn(kFFmpegBehavioralTest)); +#endif // !defined(OS_ANDROID) + } // namespace media
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc index 2a37b64..6649b68 100644 --- a/media/filters/decrypting_audio_decoder_unittest.cc +++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -120,7 +120,7 @@ config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, kSampleRate, EmptyExtraData(), - true, base::TimeDelta(), 0); + AesCtrEncryptionScheme(), base::TimeDelta(), 0); InitializeAndExpectResult(config_, true); } @@ -286,7 +286,7 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) { AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, kSampleRate, - EmptyExtraData(), false); + EmptyExtraData(), Unencrypted()); InitializeAndExpectResult(config, false); } @@ -294,7 +294,8 @@ // Ensure decoder handles invalid audio configs without crashing. TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) { AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat, - CHANNEL_LAYOUT_STEREO, 0, EmptyExtraData(), true); + CHANNEL_LAYOUT_STEREO, 0, EmptyExtraData(), + AesCtrEncryptionScheme()); InitializeAndExpectResult(config, false); } @@ -307,7 +308,7 @@ AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, kSampleRate, - EmptyExtraData(), true); + EmptyExtraData(), AesCtrEncryptionScheme()); InitializeAndExpectResult(config, false); } @@ -315,7 +316,7 @@ SetCdmType(CDM_WITHOUT_DECRYPTOR); AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, kSampleRate, - EmptyExtraData(), true); + EmptyExtraData(), AesCtrEncryptionScheme()); InitializeAndExpectResult(config, false); } @@ -384,7 +385,7 @@ // channel layout and samples_per_second. AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarS16, CHANNEL_LAYOUT_5_1, 88200, EmptyExtraData(), - true); + AesCtrEncryptionScheme()); EXPECT_NE(new_config.bits_per_channel(), config_.bits_per_channel()); EXPECT_NE(new_config.channel_layout(), config_.channel_layout()); EXPECT_NE(new_config.samples_per_second(), config_.samples_per_second());
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc index 637de2a..a44a036 100644 --- a/media/filters/decrypting_demuxer_stream.cc +++ b/media/filters/decrypting_demuxer_stream.cc
@@ -12,6 +12,7 @@ #include "media/base/bind_to_current_loop.h" #include "media/base/decoder_buffer.h" #include "media/base/media_log.h" +#include "media/base/media_util.h" namespace media { @@ -347,14 +348,12 @@ case AUDIO: { AudioDecoderConfig input_audio_config = demuxer_stream_->audio_decoder_config(); - audio_config_.Initialize(input_audio_config.codec(), - input_audio_config.sample_format(), - input_audio_config.channel_layout(), - input_audio_config.samples_per_second(), - input_audio_config.extra_data(), - false, // Output audio is not encrypted. - input_audio_config.seek_preroll(), - input_audio_config.codec_delay()); + audio_config_.Initialize( + input_audio_config.codec(), input_audio_config.sample_format(), + input_audio_config.channel_layout(), + input_audio_config.samples_per_second(), + input_audio_config.extra_data(), Unencrypted(), + input_audio_config.seek_preroll(), input_audio_config.codec_delay()); break; } @@ -366,7 +365,7 @@ input_video_config.format(), input_video_config.color_space(), input_video_config.coded_size(), input_video_config.visible_rect(), input_video_config.natural_size(), input_video_config.extra_data(), - false); // Output video is not encrypted. + Unencrypted()); break; }
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc index 45cdfe1..f08733b 100644 --- a/media/filters/decrypting_demuxer_stream_unittest.cc +++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -131,7 +131,7 @@ AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100, - EmptyExtraData(), true); + EmptyExtraData(), AesCtrEncryptionScheme()); InitializeAudioAndExpectStatus(input_config, PIPELINE_OK); const AudioDecoderConfig& output_config = @@ -305,7 +305,7 @@ SetCdmType(CDM_WITHOUT_DECRYPTOR); AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100, - EmptyExtraData(), true); + EmptyExtraData(), AesCtrEncryptionScheme()); InitializeAudioAndExpectStatus(input_config, DECODER_ERROR_NOT_SUPPORTED); } @@ -361,7 +361,7 @@ // Test the case where the a key is added when the decryptor is in // kPendingDecrypt state. -TEST_F(DecryptingDemuxerStreamTest, KeyAdded_DruingPendingDecrypt) { +TEST_F(DecryptingDemuxerStreamTest, KeyAdded_DuringPendingDecrypt) { Initialize(); EnterPendingDecryptState(); @@ -457,7 +457,7 @@ AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 88200, EmptyExtraData(), - true); + AesCtrEncryptionScheme()); input_audio_stream_->set_audio_decoder_config(new_config); EXPECT_CALL(*input_audio_stream_, Read(_))
diff --git a/media/filters/ffmpeg_aac_bitstream_converter.cc b/media/filters/ffmpeg_aac_bitstream_converter.cc index ce5e8a20..5b8e6f0 100644 --- a/media/filters/ffmpeg_aac_bitstream_converter.cc +++ b/media/filters/ffmpeg_aac_bitstream_converter.cc
@@ -66,6 +66,7 @@ case FF_PROFILE_AAC_MAIN: break; case FF_PROFILE_AAC_HE: + case FF_PROFILE_AAC_HE_V2: case FF_PROFILE_AAC_LOW: hdr[2] |= (1 << 6); break;
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc index 6eef19f..fa91d50 100644 --- a/media/filters/ffmpeg_video_decoder_unittest.cc +++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -224,7 +224,7 @@ VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN, kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, kNaturalSize, EmptyExtraData(), - false); + Unencrypted()); InitializeWithConfigWithResult(config, false); }
diff --git a/media/filters/frame_processor_unittest.cc b/media/filters/frame_processor_unittest.cc index 289ca8e8..3220ae68 100644 --- a/media/filters/frame_processor_unittest.cc +++ b/media/filters/frame_processor_unittest.cc
@@ -294,7 +294,7 @@ audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO, true)); AudioDecoderConfig decoder_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 1000, - EmptyExtraData(), false); + EmptyExtraData(), Unencrypted()); frame_processor_->OnPossibleAudioConfigUpdate(decoder_config); ASSERT_TRUE(audio_->UpdateAudioConfig(decoder_config, new MediaLog())); break;
diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc index 83dad21..bec37f36 100644 --- a/media/filters/opus_audio_decoder.cc +++ b/media/filters/opus_audio_decoder.cc
@@ -269,7 +269,7 @@ << " vs " << opus_extra_data.skip_samples; config_.Initialize(config_.codec(), config_.sample_format(), config_.channel_layout(), config_.samples_per_second(), - config_.extra_data(), config_.is_encrypted(), + config_.extra_data(), config_.encryption_scheme(), config_.seek_preroll(), opus_extra_data.skip_samples); }
diff --git a/media/filters/source_buffer_stream.cc b/media/filters/source_buffer_stream.cc index e03a8c3..05f23379 100644 --- a/media/filters/source_buffer_stream.cc +++ b/media/filters/source_buffer_stream.cc
@@ -1476,7 +1476,8 @@ return false; } - if (audio_configs_[0].is_encrypted() != config.is_encrypted()) { + if (!audio_configs_[0].encryption_scheme().Matches( + config.encryption_scheme())) { MEDIA_LOG(ERROR, media_log_) << "Audio encryption changes not allowed."; return false; } @@ -1507,7 +1508,8 @@ return false; } - if (video_configs_[0].is_encrypted() != config.is_encrypted()) { + if (!video_configs_[0].encryption_scheme().Matches( + config.encryption_scheme())) { MEDIA_LOG(ERROR, media_log_) << "Video encryption changes not allowed."; return false; }
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc index 53e8066..a9558a2f 100644 --- a/media/filters/source_buffer_stream_unittest.cc +++ b/media/filters/source_buffer_stream_unittest.cc
@@ -95,14 +95,9 @@ void SetAudioStream() { video_config_ = TestVideoConfig::Invalid(); - audio_config_.Initialize(kCodecVorbis, - kSampleFormatPlanarF32, - CHANNEL_LAYOUT_STEREO, - 1000, - EmptyExtraData(), - false, - base::TimeDelta(), - 0); + audio_config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32, + CHANNEL_LAYOUT_STEREO, 1000, EmptyExtraData(), + Unencrypted(), base::TimeDelta(), 0); stream_.reset(new SourceBufferStream(audio_config_, media_log_, true)); // Equivalent to 2ms per frame. @@ -3653,7 +3648,7 @@ // Test all the valid same timestamp cases for audio. TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) { AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO, - 44100, EmptyExtraData(), false); + 44100, EmptyExtraData(), Unencrypted()); stream_.reset(new SourceBufferStream(config, media_log_, true)); Seek(0); NewCodedFrameGroupAppend("0K 0K 30K 30 60 60"); @@ -3664,7 +3659,7 @@ EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog()); AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO, - 44100, EmptyExtraData(), false); + 44100, EmptyExtraData(), Unencrypted()); stream_.reset(new SourceBufferStream(config, media_log_, true)); Seek(0); @@ -4229,7 +4224,7 @@ AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_MONO, 1000, EmptyExtraData(), - false); + Unencrypted()); ASSERT_NE(new_config.channel_layout(), audio_config_.channel_layout()); Seek(0); @@ -4270,8 +4265,8 @@ video_config_ = TestVideoConfig::Invalid(); audio_config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32, - CHANNEL_LAYOUT_STEREO, 4000, EmptyExtraData(), false, - base::TimeDelta(), 0); + CHANNEL_LAYOUT_STEREO, 4000, EmptyExtraData(), + Unencrypted(), base::TimeDelta(), 0); stream_.reset(new SourceBufferStream(audio_config_, media_log_, true)); // Equivalent to 0.5ms per frame. SetStreamInfo(2000, 2000);
diff --git a/media/filters/vp8_parser_fuzzertest.options b/media/filters/vp8_parser_fuzzertest.options new file mode 100644 index 0000000..15c6c27 --- /dev/null +++ b/media/filters/vp8_parser_fuzzertest.options
@@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 400000
diff --git a/media/filters/vp9_parser_fuzzertest.options b/media/filters/vp9_parser_fuzzertest.options new file mode 100644 index 0000000..15c6c27 --- /dev/null +++ b/media/filters/vp9_parser_fuzzertest.options
@@ -0,0 +1,2 @@ +[libfuzzer] +max_len = 400000
diff --git a/media/formats/mp2t/es_adapter_video_unittest.cc b/media/formats/mp2t/es_adapter_video_unittest.cc index a6e16840..5946d21c 100644 --- a/media/formats/mp2t/es_adapter_video_unittest.cc +++ b/media/formats/mp2t/es_adapter_video_unittest.cc
@@ -32,7 +32,7 @@ gfx::Size natural_size(320, 240); return VideoDecoderConfig(kCodecH264, H264PROFILE_MAIN, PIXEL_FORMAT_I420, COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect, - natural_size, EmptyExtraData(), false); + natural_size, EmptyExtraData(), Unencrypted()); } StreamParserBuffer::BufferQueue
diff --git a/media/formats/mp2t/es_parser_adts.cc b/media/formats/mp2t/es_parser_adts.cc index 5a90973..b209d66 100644 --- a/media/formats/mp2t/es_parser_adts.cc +++ b/media/formats/mp2t/es_parser_adts.cc
@@ -13,6 +13,7 @@ #include "media/base/audio_timestamp_helper.h" #include "media/base/bit_reader.h" #include "media/base/channel_layout.h" +#include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" #include "media/base/timestamp_constants.h" #include "media/formats/common/offset_byte_queue.h" @@ -227,12 +228,9 @@ extra_data.push_back(static_cast<uint8_t>(extra_data_int & 0xff)); AudioDecoderConfig audio_decoder_config( - kCodecAAC, - kSampleFormatS16, + kCodecAAC, kSampleFormatS16, kADTSChannelLayoutTable[channel_configuration], - extended_samples_per_second, - extra_data, - false); + extended_samples_per_second, extra_data, Unencrypted()); if (!audio_decoder_config.Matches(last_audio_decoder_config_)) { DVLOG(1) << "Sampling frequency: " << samples_per_second;
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc index dc8315c2..3b47fec0 100644 --- a/media/formats/mp2t/es_parser_h264.cc +++ b/media/formats/mp2t/es_parser_h264.cc
@@ -6,6 +6,8 @@ #include "base/logging.h" #include "base/numerics/safe_conversions.h" +#include "media/base/encryption_scheme.h" +#include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" #include "media/base/timestamp_constants.h" #include "media/base/video_frame.h" @@ -262,7 +264,7 @@ const H264SPS* sps = h264_parser_->GetSPS(pps->seq_parameter_set_id); if (!sps) return false; - RCHECK(UpdateVideoDecoderConfig(sps)); + RCHECK(UpdateVideoDecoderConfig(sps, Unencrypted())); } // Emit a frame. @@ -287,7 +289,8 @@ return es_adapter_.OnNewBuffer(stream_parser_buffer); } -bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) { +bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps, + const EncryptionScheme& scheme) { // Set the SAR to 1 when not specified in the H264 stream. int sar_width = (sps->sar_width == 0) ? 1 : sps->sar_width; int sar_height = (sps->sar_height == 0) ? 1 : sps->sar_height; @@ -314,7 +317,7 @@ VideoDecoderConfig video_decoder_config( kCodecH264, ProfileIDCToVideoCodecProfile(sps->profile_idc), PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709, coded_size, visible_rect, - natural_size, std::vector<uint8_t>(), false); + natural_size, EmptyExtraData(), scheme); if (!video_decoder_config.Matches(last_video_decoder_config_)) { DVLOG(1) << "Profile IDC: " << sps->profile_idc;
diff --git a/media/formats/mp2t/es_parser_h264.h b/media/formats/mp2t/es_parser_h264.h index 9ce8ea0..184ac079 100644 --- a/media/formats/mp2t/es_parser_h264.h +++ b/media/formats/mp2t/es_parser_h264.h
@@ -7,7 +7,6 @@ #include <stdint.h> -#include <list> #include <utility> #include "base/callback.h" @@ -21,6 +20,7 @@ #include "media/formats/mp2t/es_parser.h" namespace media { +class EncryptionScheme; class H264Parser; struct H264SPS; class OffsetByteQueue; @@ -70,7 +70,8 @@ // Update the video decoder config based on an H264 SPS. // Return true if successful. - bool UpdateVideoDecoderConfig(const H264SPS* sps); + bool UpdateVideoDecoderConfig(const H264SPS* sps, + const EncryptionScheme& scheme); EsAdapterVideo es_adapter_;
diff --git a/media/formats/mp2t/es_parser_mpeg1audio.cc b/media/formats/mp2t/es_parser_mpeg1audio.cc index 5032887..96ed8d6 100644 --- a/media/formats/mp2t/es_parser_mpeg1audio.cc +++ b/media/formats/mp2t/es_parser_mpeg1audio.cc
@@ -12,6 +12,7 @@ #include "media/base/audio_timestamp_helper.h" #include "media/base/bit_reader.h" #include "media/base/channel_layout.h" +#include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" #include "media/base/timestamp_constants.h" #include "media/formats/common/offset_byte_queue.h" @@ -170,12 +171,8 @@ // TODO(damienv): Verify whether Android playback requires the extra data // field for Mpeg1 audio. If yes, we should generate this field. AudioDecoderConfig audio_decoder_config( - kCodecMP3, - kSampleFormatS16, - header.channel_layout, - header.sample_rate, - std::vector<uint8_t>(), - false); + kCodecMP3, kSampleFormatS16, header.channel_layout, header.sample_rate, + EmptyExtraData(), Unencrypted()); if (!audio_decoder_config.Matches(last_audio_decoder_config_)) { DVLOG(1) << "Sampling frequency: " << header.sample_rate;
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc index 37b5396..4f72c5e1 100644 --- a/media/formats/mp4/mp4_stream_parser.cc +++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -16,6 +16,7 @@ #include "build/build_config.h" #include "media/base/audio_decoder_config.h" #include "media/base/media_tracks.h" +#include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" #include "media/base/text_track_config.h" #include "media/base/timestamp_constants.h" @@ -304,9 +305,10 @@ is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted; DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_; - audio_config.Initialize(codec, sample_format, channel_layout, - sample_per_second, extra_data, - is_audio_track_encrypted_, base::TimeDelta(), 0); + audio_config.Initialize( + codec, sample_format, channel_layout, sample_per_second, extra_data, + is_audio_track_encrypted_ ? AesCtrEncryptionScheme() : Unencrypted(), + base::TimeDelta(), 0); has_audio_ = true; audio_track_id_ = track->header.track_id; media_tracks->AddAudioTrack( @@ -350,7 +352,8 @@ COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, // No decoder-specific buffer needed for AVC; // SPS/PPS are embedded in the video stream - std::vector<uint8_t>(), is_video_track_encrypted_); + EmptyExtraData(), + is_video_track_encrypted_ ? AesCtrEncryptionScheme() : Unencrypted()); has_video_ = true; video_track_id_ = track->header.track_id; media_tracks->AddVideoTrack(
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc index 202849527..47dd2f6 100644 --- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc +++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -8,6 +8,7 @@ #include "base/callback_helpers.h" #include "base/message_loop/message_loop.h" #include "media/base/media_tracks.h" +#include "media/base/media_util.h" #include "media/base/stream_parser_buffer.h" #include "media/base/text_track_config.h" #include "media/base/timestamp_constants.h" @@ -205,14 +206,9 @@ } if (!config_.IsValidConfig()) { - config_.Initialize(audio_codec_, - kSampleFormatF32, - channel_layout, - sample_rate, - std::vector<uint8_t>(), - false, - base::TimeDelta(), - codec_delay_); + config_.Initialize(audio_codec_, kSampleFormatF32, channel_layout, + sample_rate, std::vector<uint8_t>(), Unencrypted(), + base::TimeDelta(), codec_delay_); base::TimeDelta base_timestamp; if (timestamp_helper_)
diff --git a/media/formats/webm/webm_audio_client.cc b/media/formats/webm/webm_audio_client.cc index fb6a723a..173d81f 100644 --- a/media/formats/webm/webm_audio_client.cc +++ b/media/formats/webm/webm_audio_client.cc
@@ -29,7 +29,7 @@ const std::vector<uint8_t>& codec_private, int64_t seek_preroll, int64_t codec_delay, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, AudioDecoderConfig* config) { DCHECK(config); SampleFormat sample_format = kSampleFormatPlanarF32; @@ -78,16 +78,11 @@ base::Time::kNanosecondsPerSecond); } - config->Initialize( - audio_codec, - sample_format, - channel_layout, - samples_per_second, - codec_private, - is_encrypted, - base::TimeDelta::FromMicroseconds( - (seek_preroll != -1 ? seek_preroll : 0) / 1000), - codec_delay_in_frames); + config->Initialize(audio_codec, sample_format, channel_layout, + samples_per_second, codec_private, encryption_scheme, + base::TimeDelta::FromMicroseconds( + (seek_preroll != -1 ? seek_preroll : 0) / 1000), + codec_delay_in_frames); return config->IsValidConfig(); }
diff --git a/media/formats/webm/webm_audio_client.h b/media/formats/webm/webm_audio_client.h index fefa55f..06d7e0c6 100644 --- a/media/formats/webm/webm_audio_client.h +++ b/media/formats/webm/webm_audio_client.h
@@ -16,6 +16,7 @@ namespace media { class AudioDecoderConfig; +class EncryptionScheme; // Helper class used to parse an Audio element inside a TrackEntry element. class WebMAudioClient : public WebMParserClient { @@ -27,8 +28,8 @@ void Reset(); // Initialize |config| with the data in |codec_id|, |codec_private|, - // |is_encrypted| and the fields parsed from the last audio track element this - // object was used to parse. + // |encryption_scheme| and the fields parsed from the last audio track element + // this object was used to parse. // Returns true if |config| was successfully initialized. // Returns false if there was unexpected values in the provided parameters or // audio track element fields. @@ -36,7 +37,7 @@ const std::vector<uint8_t>& codec_private, const int64_t seek_preroll, const int64_t codec_delay, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, AudioDecoderConfig* config); private:
diff --git a/media/formats/webm/webm_tracks_parser.cc b/media/formats/webm/webm_tracks_parser.cc index 5ffa0aa..112427f 100644 --- a/media/formats/webm/webm_tracks_parser.cc +++ b/media/formats/webm/webm_tracks_parser.cc
@@ -7,6 +7,7 @@ #include "base/logging.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "media/base/media_util.h" #include "media/base/timestamp_constants.h" #include "media/formats/webm/webm_constants.h" #include "media/formats/webm/webm_content_encodings.h" @@ -193,6 +194,9 @@ content_encodings()[0]->encryption_key_id(); } + EncryptionScheme encryption_scheme = + encryption_key_id.empty() ? Unencrypted() : AesCtrEncryptionScheme(); + if (track_type_ == kWebMTrackTypeAudio) { if (audio_track_num_ == -1) { audio_track_num_ = track_num_; @@ -208,7 +212,7 @@ DCHECK(!audio_decoder_config_.IsValidConfig()); if (!audio_client_.InitializeConfig( codec_id_, codec_private_, seek_preroll_, codec_delay_, - !audio_encryption_key_id_.empty(), &audio_decoder_config_)) { + encryption_scheme, &audio_decoder_config_)) { return false; } media_tracks_->AddAudioTrack(audio_decoder_config_, @@ -231,9 +235,9 @@ video_default_duration_ = default_duration_; DCHECK(!video_decoder_config_.IsValidConfig()); - if (!video_client_.InitializeConfig( - codec_id_, codec_private_, !video_encryption_key_id_.empty(), - &video_decoder_config_)) { + if (!video_client_.InitializeConfig(codec_id_, codec_private_, + encryption_scheme, + &video_decoder_config_)) { return false; } media_tracks_->AddVideoTrack(video_decoder_config_,
diff --git a/media/formats/webm/webm_video_client.cc b/media/formats/webm/webm_video_client.cc index 6e57dfbe..9d0435f 100644 --- a/media/formats/webm/webm_video_client.cc +++ b/media/formats/webm/webm_video_client.cc
@@ -33,7 +33,7 @@ bool WebMVideoClient::InitializeConfig( const std::string& codec_id, const std::vector<uint8_t>& codec_private, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, VideoDecoderConfig* config) { DCHECK(config); @@ -93,7 +93,7 @@ config->Initialize(video_codec, profile, format, COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, codec_private, - is_encrypted); + encryption_scheme); return config->IsValidConfig(); }
diff --git a/media/formats/webm/webm_video_client.h b/media/formats/webm/webm_video_client.h index dfdc5f6..d746df9 100644 --- a/media/formats/webm/webm_video_client.h +++ b/media/formats/webm/webm_video_client.h
@@ -15,6 +15,7 @@ #include "media/formats/webm/webm_parser.h" namespace media { +class EncryptionScheme; class VideoDecoderConfig; // Helper class used to parse a Video element inside a TrackEntry element. @@ -27,15 +28,15 @@ void Reset(); // Initialize |config| with the data in |codec_id|, |codec_private|, - // |is_encrypted| and the fields parsed from the last video track element this - // object was used to parse. + // |encryption_scheme| and the fields parsed from the last video track element + // this object was used to parse. // Returns true if |config| was successfully initialized. // Returns false if there was unexpected values in the provided parameters or // video track element fields. The contents of |config| are undefined in this // case and should not be relied upon. bool InitializeConfig(const std::string& codec_id, const std::vector<uint8_t>& codec_private, - bool is_encrypted, + const EncryptionScheme& encryption_scheme, VideoDecoderConfig* config); private:
diff --git a/media/media.gyp b/media/media.gyp index 1616b19..0863c024 100644 --- a/media/media.gyp +++ b/media/media.gyp
@@ -329,6 +329,8 @@ 'base/djb2.cc', 'base/djb2.h', 'base/eme_constants.h', + 'base/encryption_scheme.cc', + 'base/encryption_scheme.h', 'base/key_system_info.cc', 'base/key_system_info.h', 'base/key_systems.cc', @@ -1160,6 +1162,7 @@ '<@(capture_unittests_sources)', 'base/android/access_unit_queue_unittest.cc', 'base/android/media_codec_decoder_unittest.cc', + 'base/android/media_codec_player_unittest.cc', 'base/android/media_drm_bridge_unittest.cc', 'base/android/media_player_bridge_unittest.cc', 'base/android/media_source_player_unittest.cc', @@ -1330,6 +1333,12 @@ 'filters/ffmpeg_video_decoder_unittest.cc', 'test/pipeline_integration_test.cc', 'test/pipeline_integration_test_base.cc', + + # These tests are confused by Android always having proprietary + # codecs enabled, but ffmpeg_branding=Chromium. These should be + # fixed, see http://crbug.com/570762. + 'filters/audio_file_reader_unittest.cc', + 'filters/ffmpeg_demuxer_unittest.cc', ], }], ['OS=="android"', { @@ -1363,7 +1372,6 @@ }], ['proprietary_codecs==1', { 'sources': [ - 'base/android/media_codec_player_unittest.cc', 'cdm/cenc_utils_unittest.cc', 'filters/ffmpeg_aac_bitstream_converter_unittest.cc', 'filters/ffmpeg_h264_to_annex_b_bitstream_converter_unittest.cc',
diff --git a/media/midi/midi_manager_alsa.cc b/media/midi/midi_manager_alsa.cc index 6110e56..d3c4c5e 100644 --- a/media/midi/midi_manager_alsa.cc +++ b/media/midi/midi_manager_alsa.cc
@@ -149,46 +149,55 @@ } // namespace MidiManagerAlsa::MidiManagerAlsa() - : udev_(device::udev_new()), - send_thread_("MidiSendThread"), - event_thread_("MidiEventThread") { - // Initialize decoder. - snd_midi_event_t* decoder; - snd_midi_event_new(0, &decoder); - decoder_.reset(decoder); - snd_midi_event_no_status(decoder_.get(), 1); + : event_thread_("MidiEventThread"), send_thread_("MidiSendThread") {} + +MidiManagerAlsa::~MidiManagerAlsa() { + // Take lock to ensure that the members initialized on the IO thread + // are not destructed here. + base::AutoLock lock(lazy_init_member_lock_); + + // Extra DCHECK to verify all members are already reset. + DCHECK(!initialization_thread_checker_); + DCHECK(!in_client_); + DCHECK(!out_client_); + DCHECK(!decoder_); + DCHECK(!udev_); + DCHECK(!udev_monitor_); } -MidiManagerAlsa::~MidiManagerAlsa() = default; - void MidiManagerAlsa::StartInitialization() { - // Create client handles. - snd_seq_t* in_client; - int err = - snd_seq_open(&in_client, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK); - if (err != 0) { - VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); - return CompleteInitialization(Result::INITIALIZATION_ERROR); - } - in_client_.reset(in_client); - in_client_id_ = snd_seq_client_id(in_client_.get()); + base::AutoLock lock(lazy_init_member_lock_); - snd_seq_t* out_client; - err = snd_seq_open(&out_client, kAlsaHw, SND_SEQ_OPEN_OUTPUT, 0); + initialization_thread_checker_.reset(new base::ThreadChecker()); + + // Create client handles. + snd_seq_t* tmp_seq = nullptr; + int err = + snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_INPUT, SND_SEQ_NONBLOCK); if (err != 0) { VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); return CompleteInitialization(Result::INITIALIZATION_ERROR); } - out_client_.reset(out_client); - out_client_id_ = snd_seq_client_id(out_client_.get()); + ScopedSndSeqPtr in_client(tmp_seq); + tmp_seq = nullptr; + in_client_id_ = snd_seq_client_id(in_client.get()); + + err = snd_seq_open(&tmp_seq, kAlsaHw, SND_SEQ_OPEN_OUTPUT, 0); + if (err != 0) { + VLOG(1) << "snd_seq_open fails: " << snd_strerror(err); + return CompleteInitialization(Result::INITIALIZATION_ERROR); + } + ScopedSndSeqPtr out_client(tmp_seq); + tmp_seq = nullptr; + out_client_id_ = snd_seq_client_id(out_client.get()); // Name the clients. - err = snd_seq_set_client_name(in_client_.get(), "Chrome (input)"); + err = snd_seq_set_client_name(in_client.get(), "Chrome (input)"); if (err != 0) { VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); return CompleteInitialization(Result::INITIALIZATION_ERROR); } - err = snd_seq_set_client_name(out_client_.get(), "Chrome (output)"); + err = snd_seq_set_client_name(out_client.get(), "Chrome (output)"); if (err != 0) { VLOG(1) << "snd_seq_set_client_name fails: " << snd_strerror(err); return CompleteInitialization(Result::INITIALIZATION_ERROR); @@ -196,7 +205,7 @@ // Create input port. in_port_id_ = snd_seq_create_simple_port( - in_client_.get(), NULL, kCreateInputPortCaps, kCreatePortType); + in_client.get(), NULL, kCreateInputPortCaps, kCreatePortType); if (in_port_id_ < 0) { VLOG(1) << "snd_seq_create_simple_port fails: " << snd_strerror(in_port_id_); @@ -214,51 +223,76 @@ announce_dest.port = in_port_id_; snd_seq_port_subscribe_set_sender(subs, &announce_sender); snd_seq_port_subscribe_set_dest(subs, &announce_dest); - err = snd_seq_subscribe_port(in_client_.get(), subs); + err = snd_seq_subscribe_port(in_client.get(), subs); if (err != 0) { VLOG(1) << "snd_seq_subscribe_port on the announce port fails: " << snd_strerror(err); return CompleteInitialization(Result::INITIALIZATION_ERROR); } - // Generate hotplug events for existing ports. - // TODO(agoode): Check the return value for failure. - EnumerateAlsaPorts(); + // Initialize decoder. + snd_midi_event_t* tmp_decoder = nullptr; + snd_midi_event_new(0, &tmp_decoder); + ScopedSndMidiEventPtr decoder(tmp_decoder); + tmp_decoder = nullptr; + snd_midi_event_no_status(decoder.get(), 1); - // Initialize udev monitor. - udev_monitor_.reset( - device::udev_monitor_new_from_netlink(udev_.get(), kUdev)); - if (!udev_monitor_.get()) { + // Initialize udev and monitor. + device::ScopedUdevPtr udev(device::udev_new()); + device::ScopedUdevMonitorPtr udev_monitor( + device::udev_monitor_new_from_netlink(udev.get(), kUdev)); + if (!udev_monitor.get()) { VLOG(1) << "udev_monitor_new_from_netlink fails"; return CompleteInitialization(Result::INITIALIZATION_ERROR); } err = device::udev_monitor_filter_add_match_subsystem_devtype( - udev_monitor_.get(), kUdevSubsystemSound, nullptr); + udev_monitor.get(), kUdevSubsystemSound, nullptr); if (err != 0) { VLOG(1) << "udev_monitor_add_match_subsystem fails: " << base::safe_strerror(-err); return CompleteInitialization(Result::INITIALIZATION_ERROR); } - err = device::udev_monitor_enable_receiving(udev_monitor_.get()); + err = device::udev_monitor_enable_receiving(udev_monitor.get()); if (err != 0) { VLOG(1) << "udev_monitor_enable_receiving fails: " << base::safe_strerror(-err); return CompleteInitialization(Result::INITIALIZATION_ERROR); } - // Generate hotplug events for existing udev devices. + // Success! Now, initialize members from the temporaries. Do not + // initialize these earlier, since they need to be destroyed by the + // thread that calls Finalize(), not the destructor thread (and we + // check this in the destructor). + in_client_.reset(in_client.release()); + out_client_.reset(out_client.release()); + decoder_.reset(decoder.release()); + udev_.reset(udev.release()); + udev_monitor_.reset(udev_monitor_.release()); + + // Generate hotplug events for existing ports. + // TODO(agoode): Check the return value for failure. + EnumerateAlsaPorts(); + + // Generate hotplug events for existing udev devices. This must be done + // after udev_monitor_enable_receiving() is called. See the algorithm + // at http://www.signal11.us/oss/udev/. EnumerateUdevCards(); - // Start processing events. + // Start processing events. Don't do this before enumeration of both + // ALSA and udev. event_thread_.Start(); event_thread_.message_loop()->PostTask( FROM_HERE, base::Bind(&MidiManagerAlsa::ScheduleEventLoop, base::Unretained(this))); + send_thread_.Start(); CompleteInitialization(Result::OK); } void MidiManagerAlsa::Finalize() { + base::AutoLock lock(lazy_init_member_lock_); + DCHECK(initialization_thread_checker_->CalledOnValidThread()); + // Tell the event thread it will soon be time to shut down. This gives // us assurance the thread will stop in case the SND_SEQ_EVENT_CLIENT_EXIT // message is lost. @@ -272,20 +306,23 @@ // Close the out client. This will trigger the event thread to stop, // because of SND_SEQ_EVENT_CLIENT_EXIT. - if (out_client_.get()) - snd_seq_close(out_client_.release()); + out_client_.reset(); // Wait for the event thread to stop. event_thread_.Stop(); + + // Destruct the other stuff we initialized in StartInitialization(). + udev_monitor_.reset(); + udev_.reset(); + decoder_.reset(); + in_client_.reset(); + initialization_thread_checker_.reset(); } void MidiManagerAlsa::DispatchSendMidiData(MidiManagerClient* client, uint32_t port_index, const std::vector<uint8_t>& data, double timestamp) { - if (!send_thread_.IsRunning()) - send_thread_.Start(); - base::TimeDelta delay; if (timestamp != 0.0) { base::TimeTicks time_to_send =
diff --git a/media/midi/midi_manager_alsa.h b/media/midi/midi_manager_alsa.h index efae376..01f84ab 100644 --- a/media/midi/midi_manager_alsa.h +++ b/media/midi/midi_manager_alsa.h
@@ -22,6 +22,10 @@ #include "media/midi/midi_export.h" #include "media/midi/midi_manager.h" +namespace base { +class ThreadChecker; +} + namespace media { namespace midi { @@ -362,8 +366,11 @@ }; }; - typedef base::hash_map<int, uint32_t> SourceMap; - typedef base::hash_map<uint32_t, int> OutPortMap; + using SourceMap = base::hash_map<int, uint32_t>; + using OutPortMap = base::hash_map<uint32_t, int>; + using ScopedSndSeqPtr = scoped_ptr<snd_seq_t, SndSeqDeleter>; + using ScopedSndMidiEventPtr = + scoped_ptr<snd_midi_event_t, SndMidiEventDeleter>; // An internal callback that runs on MidiSendThread. void SendMidiData(uint32_t port_index, const std::vector<uint8_t>& data); @@ -392,19 +399,14 @@ // Returns true if successful. bool Subscribe(uint32_t port_index, int client_id, int port_id); + // Members initialized in the constructor are below. + // Our copies of the internal state of the ports of seq and udev. AlsaSeqState alsa_seq_state_; MidiPortState port_state_; - // ALSA seq handles. - scoped_ptr<snd_seq_t, SndSeqDeleter> in_client_; - int in_client_id_ = -1; - scoped_ptr<snd_seq_t, SndSeqDeleter> out_client_; - int out_client_id_ = -1; - // One input port, many output ports. - int in_port_id_ = -1; - OutPortMap out_ports_; // guarded by out_ports_lock_ base::Lock out_ports_lock_; // guards out_ports_ + OutPortMap out_ports_; // guarded by out_ports_lock_ // Mapping from ALSA client:port to our index. SourceMap source_map_; @@ -418,18 +420,37 @@ // wait for our information from ALSA and udev to get back in sync. int alsa_card_midi_count_ = 0; + base::Lock shutdown_lock_; // guards event_thread_shutdown_ + bool event_thread_shutdown_ = false; // guarded by shutdown_lock_ + + // This lock is needed to ensure that members destroyed in Finalize + // will be visibly destroyed before the destructor is run in the + // other thread. Otherwise, the same objects may have their destructors + // run multiple times in different threads. + base::Lock lazy_init_member_lock_; // guards members below + + // Members initialized in StartInitialization() are below. + // Make sure to destroy these in Finalize()! + scoped_ptr<base::ThreadChecker> initialization_thread_checker_; + + // ALSA seq handles and ids. + ScopedSndSeqPtr in_client_; + int in_client_id_; + ScopedSndSeqPtr out_client_; + int out_client_id_; + int in_port_id_; + // ALSA event -> MIDI coder. - scoped_ptr<snd_midi_event_t, SndMidiEventDeleter> decoder_; + ScopedSndMidiEventPtr decoder_; // udev, for querying hardware devices. device::ScopedUdevPtr udev_; device::ScopedUdevMonitorPtr udev_monitor_; - base::Thread send_thread_; + // Threads for sending and receiving. These are initialized in the + // constructor, but are started at the end of StartInitialization. base::Thread event_thread_; - - bool event_thread_shutdown_ = false; // guarded by shutdown_lock_ - base::Lock shutdown_lock_; // guards event_thread_shutdown_ + base::Thread send_thread_; DISALLOW_COPY_AND_ASSIGN(MidiManagerAlsa); };
diff --git a/media/mojo/common/media_type_converters.cc b/media/mojo/common/media_type_converters.cc index f1bf033c..7725a2ed 100644 --- a/media/mojo/common/media_type_converters.cc +++ b/media/mojo/common/media_type_converters.cc
@@ -17,6 +17,7 @@ #include "media/base/decrypt_config.h" #include "media/base/decryptor.h" #include "media/base/demuxer_stream.h" +#include "media/base/encryption_scheme.h" #include "media/base/media_keys.h" #include "media/base/video_decoder_config.h" #include "media/base/video_frame.h" @@ -221,6 +222,20 @@ ASSERT_ENUM_EQ(VideoCodecProfile, , , VP9PROFILE_MAX); ASSERT_ENUM_EQ(VideoCodecProfile, , , VIDEO_CODEC_PROFILE_MAX); +// CipherMode +ASSERT_ENUM_EQ_RAW(EncryptionScheme::CipherMode, + EncryptionScheme::CipherMode::CIPHER_MODE_UNENCRYPTED, + CipherMode::UNENCRYPTED); +ASSERT_ENUM_EQ_RAW(EncryptionScheme::CipherMode, + EncryptionScheme::CipherMode::CIPHER_MODE_AES_CTR, + CipherMode::AES_CTR); +ASSERT_ENUM_EQ_RAW(EncryptionScheme::CipherMode, + EncryptionScheme::CipherMode::CIPHER_MODE_AES_CBC, + CipherMode::AES_CBC); +ASSERT_ENUM_EQ_RAW(EncryptionScheme::CipherMode, + EncryptionScheme::CipherMode::CIPHER_MODE_MAX, + CipherMode::MAX); + // Decryptor Status ASSERT_ENUM_EQ_RAW(Decryptor::Status, Decryptor::kSuccess, @@ -295,6 +310,59 @@ ASSERT_CDM_MESSAGE_TYPE(LICENSE_RENEWAL); ASSERT_CDM_MESSAGE_TYPE(LICENSE_RELEASE); +template <> +struct TypeConverter<media::interfaces::PatternPtr, + media::EncryptionScheme::Pattern> { + static media::interfaces::PatternPtr Convert( + const media::EncryptionScheme::Pattern& input); +}; +template <> +struct TypeConverter<media::EncryptionScheme::Pattern, + media::interfaces::PatternPtr> { + static media::EncryptionScheme::Pattern Convert( + const media::interfaces::PatternPtr& input); +}; + +// static +media::interfaces::PatternPtr +TypeConverter<media::interfaces::PatternPtr, media::EncryptionScheme::Pattern>:: + Convert(const media::EncryptionScheme::Pattern& input) { + media::interfaces::PatternPtr mojo_pattern(media::interfaces::Pattern::New()); + mojo_pattern->encrypt_blocks = input.encrypt_blocks(); + mojo_pattern->skip_blocks = input.skip_blocks(); + return mojo_pattern; +} + +// static +media::EncryptionScheme::Pattern +TypeConverter<media::EncryptionScheme::Pattern, media::interfaces::PatternPtr>:: + Convert(const media::interfaces::PatternPtr& input) { + return media::EncryptionScheme::Pattern(input->encrypt_blocks, + input->skip_blocks); +} + +// static +media::interfaces::EncryptionSchemePtr TypeConverter< + media::interfaces::EncryptionSchemePtr, + media::EncryptionScheme>::Convert(const media::EncryptionScheme& input) { + media::interfaces::EncryptionSchemePtr mojo_encryption_scheme( + media::interfaces::EncryptionScheme::New()); + mojo_encryption_scheme->mode = + static_cast<media::interfaces::CipherMode>(input.mode()); + mojo_encryption_scheme->pattern = + media::interfaces::Pattern::From(input.pattern()); + return mojo_encryption_scheme; +} + +// static +media::EncryptionScheme +TypeConverter<media::EncryptionScheme, media::interfaces::EncryptionSchemePtr>:: + Convert(const media::interfaces::EncryptionSchemePtr& input) { + return media::EncryptionScheme( + static_cast<media::EncryptionScheme::CipherMode>(input->mode), + input->pattern.To<media::EncryptionScheme::Pattern>()); +} + // static media::interfaces::SubsampleEntryPtr TypeConverter< media::interfaces::SubsampleEntryPtr, @@ -435,7 +503,8 @@ } config->seek_preroll_usec = input.seek_preroll().InMicroseconds(); config->codec_delay = input.codec_delay(); - config->is_encrypted = input.is_encrypted(); + config->encryption_scheme = + media::interfaces::EncryptionScheme::From(input.encryption_scheme()); return config; } @@ -449,7 +518,7 @@ static_cast<media::SampleFormat>(input->sample_format), static_cast<media::ChannelLayout>(input->channel_layout), input->samples_per_second, input->extra_data.storage(), - input->is_encrypted, + input->encryption_scheme.To<media::EncryptionScheme>(), base::TimeDelta::FromMicroseconds(input->seek_preroll_usec), input->codec_delay); return config; @@ -474,7 +543,8 @@ if (!input.extra_data().empty()) { config->extra_data = mojo::Array<uint8_t>::From(input.extra_data()); } - config->is_encrypted = input.is_encrypted(); + config->encryption_scheme = + media::interfaces::EncryptionScheme::From(input.encryption_scheme()); return config; } @@ -484,14 +554,14 @@ media::interfaces::VideoDecoderConfigPtr>:: Convert(const media::interfaces::VideoDecoderConfigPtr& input) { media::VideoDecoderConfig config; - config.Initialize(static_cast<media::VideoCodec>(input->codec), - static_cast<media::VideoCodecProfile>(input->profile), - static_cast<media::VideoPixelFormat>(input->format), - static_cast<media::ColorSpace>(input->color_space), - input->coded_size.To<gfx::Size>(), - input->visible_rect.To<gfx::Rect>(), - input->natural_size.To<gfx::Size>(), - input->extra_data.storage(), input->is_encrypted); + config.Initialize( + static_cast<media::VideoCodec>(input->codec), + static_cast<media::VideoCodecProfile>(input->profile), + static_cast<media::VideoPixelFormat>(input->format), + static_cast<media::ColorSpace>(input->color_space), + input->coded_size.To<gfx::Size>(), input->visible_rect.To<gfx::Rect>(), + input->natural_size.To<gfx::Size>(), input->extra_data.storage(), + input->encryption_scheme.To<media::EncryptionScheme>()); return config; }
diff --git a/media/mojo/common/media_type_converters.h b/media/mojo/common/media_type_converters.h index 50cc30b..6b5664b 100644 --- a/media/mojo/common/media_type_converters.h +++ b/media/mojo/common/media_type_converters.h
@@ -16,6 +16,7 @@ class AudioDecoderConfig; class DecoderBuffer; class DecryptConfig; +class EncryptionScheme; class VideoDecoderConfig; class VideoFrame; struct CdmConfig; @@ -28,6 +29,19 @@ namespace mojo { template <> +struct TypeConverter<media::interfaces::EncryptionSchemePtr, + media::EncryptionScheme> { + static media::interfaces::EncryptionSchemePtr Convert( + const media::EncryptionScheme& input); +}; +template <> +struct TypeConverter<media::EncryptionScheme, + media::interfaces::EncryptionSchemePtr> { + static media::EncryptionScheme Convert( + const media::interfaces::EncryptionSchemePtr& input); +}; + +template <> struct TypeConverter<media::interfaces::SubsampleEntryPtr, media::SubsampleEntry> { static media::interfaces::SubsampleEntryPtr Convert(
diff --git a/media/mojo/common/media_type_converters_unittest.cc b/media/mojo/common/media_type_converters_unittest.cc index 9858cd0..5a2237f 100644 --- a/media/mojo/common/media_type_converters_unittest.cc +++ b/media/mojo/common/media_type_converters_unittest.cc
@@ -13,6 +13,7 @@ #include "media/base/audio_decoder_config.h" #include "media/base/cdm_config.h" #include "media/base/decoder_buffer.h" +#include "media/base/encryption_scheme.h" #include "media/base/media_util.h" #include "media/base/sample_format.h" #include "media/base/test_helpers.h" @@ -287,7 +288,7 @@ AudioDecoderConfig config; config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000, - kExtraDataVector, false, base::TimeDelta(), 0); + kExtraDataVector, Unencrypted(), base::TimeDelta(), 0); interfaces::AudioDecoderConfigPtr ptr( interfaces::AudioDecoderConfig::From(config)); EXPECT_FALSE(ptr->extra_data.is_null()); @@ -298,7 +299,7 @@ TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_EmptyExtraData) { AudioDecoderConfig config; config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000, - EmptyExtraData(), false, base::TimeDelta(), 0); + EmptyExtraData(), Unencrypted(), base::TimeDelta(), 0); interfaces::AudioDecoderConfigPtr ptr( interfaces::AudioDecoderConfig::From(config)); EXPECT_TRUE(ptr->extra_data.is_null()); @@ -309,14 +310,11 @@ TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_Encrypted) { AudioDecoderConfig config; config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000, - EmptyExtraData(), - true, // Is encrypted. + EmptyExtraData(), AesCtrEncryptionScheme(), base::TimeDelta(), 0); interfaces::AudioDecoderConfigPtr ptr( interfaces::AudioDecoderConfig::From(config)); - EXPECT_TRUE(ptr->is_encrypted); AudioDecoderConfig result(ptr.To<AudioDecoderConfig>()); - EXPECT_TRUE(result.is_encrypted()); EXPECT_TRUE(result.Matches(config)); } @@ -327,7 +325,7 @@ VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - kNaturalSize, kExtraDataVector, false); + kNaturalSize, kExtraDataVector, Unencrypted()); interfaces::VideoDecoderConfigPtr ptr( interfaces::VideoDecoderConfig::From(config)); EXPECT_FALSE(ptr->extra_data.is_null()); @@ -338,7 +336,7 @@ TEST(MediaTypeConvertersTest, ConvertVideoDecoderConfig_EmptyExtraData) { VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, - kNaturalSize, EmptyExtraData(), false); + kNaturalSize, EmptyExtraData(), Unencrypted()); interfaces::VideoDecoderConfigPtr ptr( interfaces::VideoDecoderConfig::From(config)); EXPECT_TRUE(ptr->extra_data.is_null()); @@ -350,12 +348,10 @@ VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect, kNaturalSize, EmptyExtraData(), - true /* is_encrypted */); + AesCtrEncryptionScheme()); interfaces::VideoDecoderConfigPtr ptr( interfaces::VideoDecoderConfig::From(config)); - EXPECT_TRUE(ptr->is_encrypted); VideoDecoderConfig result(ptr.To<VideoDecoderConfig>()); - EXPECT_TRUE(result.is_encrypted()); EXPECT_TRUE(result.Matches(config)); } @@ -458,4 +454,21 @@ CompareVideoFrames(frame, result); } +TEST(MediaTypeConvertersTest, ConvertEncryptionSchemeAesCbcWithPattern) { + // Original. + EncryptionScheme scheme(EncryptionScheme::CIPHER_MODE_AES_CBC, + EncryptionScheme::Pattern(1, 9)); + + // Convert to and back. + interfaces::EncryptionSchemePtr ptr( + interfaces::EncryptionScheme::From(scheme)); + EncryptionScheme result(ptr.To<EncryptionScheme>()); + + EXPECT_TRUE(result.Matches(scheme)); + + // Verify a couple of negative cases. + EXPECT_FALSE(result.Matches(Unencrypted())); + EXPECT_FALSE(result.Matches(AesCtrEncryptionScheme())); +} + } // namespace media
diff --git a/media/mojo/interfaces/media_types.mojom b/media/mojo/interfaces/media_types.mojom index 44e6cdf..5f4d942 100644 --- a/media/mojo/interfaces/media_types.mojom +++ b/media/mojo/interfaces/media_types.mojom
@@ -168,6 +168,29 @@ VIDEO_CODEC_PROFILE_MAX = VP9PROFILE_MAX, }; +// See media/base/encryption_scheme.h. +// Kept in sync with media::CipherMode via static_asserts. +enum CipherMode { + UNENCRYPTED = 0, + AES_CTR, + AES_CBC, + MAX = AES_CBC +}; + +// This defines a mojo transport format for media::EncryptionScheme::Pattern +// See media/base/encryption_scheme.h for description. +struct Pattern { + uint32 encrypt_blocks; + uint32 skip_blocks; +}; + +// This defines a mojo transport format for media::EncryptionScheme. +// See media/base/encryption_scheme.h for description. +struct EncryptionScheme { + CipherMode mode; + Pattern pattern; +}; + // This defines a mojo transport format for media::AudioDecoderConfig. // See media/base/audio_decoder_config.h for descriptions. struct AudioDecoderConfig { @@ -178,7 +201,7 @@ array<uint8>? extra_data; int64 seek_preroll_usec; int32 codec_delay; - bool is_encrypted; + EncryptionScheme encryption_scheme; }; // This defines a mojo transport format for media::VideoDecoderConfig. @@ -192,7 +215,7 @@ mojo.Rect visible_rect; mojo.Size natural_size; array<uint8>? extra_data; - bool is_encrypted; + EncryptionScheme encryption_scheme; }; // This defines a mojo transport format for media::SubsampleEntry.
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc index 20c5fdb..0b6a3df 100644 --- a/media/renderers/audio_renderer_impl_unittest.cc +++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -73,12 +73,9 @@ demuxer_stream_(DemuxerStream::AUDIO), decoder_(new MockAudioDecoder()), ended_(false) { - AudioDecoderConfig audio_config(kCodec, - kSampleFormat, - kChannelLayout, - kInputSamplesPerSecond, - EmptyExtraData(), - false); + AudioDecoderConfig audio_config(kCodec, kSampleFormat, kChannelLayout, + kInputSamplesPerSecond, EmptyExtraData(), + Unencrypted()); demuxer_stream_.set_audio_decoder_config(audio_config); // Used to save callbacks and run them at a later time.
diff --git a/media/test/vp8.dict b/media/test/vp8.dict new file mode 100644 index 0000000..4d69827 --- /dev/null +++ b/media/test/vp8.dict
@@ -0,0 +1,10 @@ +"DKIF" +"\x20\x00" +"\x00,\x11" +"\x9d\x01*" +"\x00\x09\x10" +"\x00\x05\x10" +"\x00\x0e\x10" +"\x00\x0b\x10" +"\x00\x04\x10" +
diff --git a/media/video/gpu_memory_buffer_video_frame_pool.cc b/media/video/gpu_memory_buffer_video_frame_pool.cc index e7ffd99..28cb1f6 100644 --- a/media/video/gpu_memory_buffer_video_frame_pool.cc +++ b/media/video/gpu_memory_buffer_video_frame_pool.cc
@@ -637,6 +637,9 @@ render_time); } + frame->metadata()->SetBoolean(VideoFrameMetadata::READ_LOCK_FENCES_ENABLED, + true); + frame_ready_cb.Run(frame); }
diff --git a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc index b107e5d..36f6552 100644 --- a/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc +++ b/media/video/gpu_memory_buffer_video_frame_pool_unittest.cc
@@ -268,6 +268,8 @@ EXPECT_NE(software_frame.get(), frame.get()); EXPECT_EQ(1u, gles2_->gen_textures); + EXPECT_TRUE(frame->metadata()->IsTrue( + media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED)); } TEST_F(GpuMemoryBufferVideoFramePoolTest, CreateOneHardwareNV12Frame) { @@ -281,6 +283,8 @@ EXPECT_NE(software_frame.get(), frame.get()); EXPECT_EQ(1u, gles2_->gen_textures); + EXPECT_TRUE(frame->metadata()->IsTrue( + media::VideoFrameMetadata::READ_LOCK_FENCES_ENABLED)); } // AllocateGpuMemoryBuffer can return null (e.g: when the GPU process is down).
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp index 5474664..a5a65ad1 100644 --- a/mojo/mojo_shell.gyp +++ b/mojo/mojo_shell.gyp
@@ -13,6 +13,8 @@ 'services/catalog/catalog.h', 'services/catalog/entry.cc', 'services/catalog/entry.h', + 'services/catalog/owner.cc', + 'services/catalog/owner.h', 'services/catalog/store.cc', 'services/catalog/store.h', 'shell/loader.h',
diff --git a/mojo/services/catalog/BUILD.gn b/mojo/services/catalog/BUILD.gn index f1eb63d..c958317 100644 --- a/mojo/services/catalog/BUILD.gn +++ b/mojo/services/catalog/BUILD.gn
@@ -21,6 +21,8 @@ "catalog.h", "entry.cc", "entry.h", + "owner.cc", + "owner.h", "store.cc", "store.h", ] @@ -31,7 +33,6 @@ "//mojo/services/catalog/public/interfaces", "//mojo/shell/public/cpp", "//mojo/util:filename_util", - "//net", ] data_deps = [
diff --git a/mojo/services/catalog/DEPS b/mojo/services/catalog/DEPS index fdc591a..4d66b26de 100644 --- a/mojo/services/catalog/DEPS +++ b/mojo/services/catalog/DEPS
@@ -1,9 +1,6 @@ include_rules = [ "+base", "+mojo/common", - "+mojo/message_pump", - "+mojo/shell/loader.h", "+mojo/shell/public", "+mojo/util", - "+net", ]
diff --git a/mojo/services/catalog/catalog.cc b/mojo/services/catalog/catalog.cc index 661ec215..ba6bcfe 100644 --- a/mojo/services/catalog/catalog.cc +++ b/mojo/services/catalog/catalog.cc
@@ -14,7 +14,6 @@ #include "mojo/services/catalog/store.h" #include "mojo/shell/public/cpp/names.h" #include "mojo/util/filename_util.h" -#include "net/base/filename_util.h" #include "url/url_util.h" namespace catalog { @@ -172,8 +171,7 @@ std::string type = mojo::GetNameType(name); CHECK(type == "mojo" || type == "exe"); - base::FilePath manifest_path; - CHECK(net::FileURLToFilePath(manifest_url, &manifest_path)); + base::FilePath manifest_path = mojo::util::UrlToFilePath(manifest_url); base::PostTaskAndReplyWithResult( blocking_pool_, FROM_HERE, base::Bind(&ReadManifest, manifest_path), base::Bind(&Catalog::OnReadManifest, weak_factory_.GetWeakPtr(),
diff --git a/mojo/services/catalog/owner.cc b/mojo/services/catalog/owner.cc new file mode 100644 index 0000000..7d24cfae --- /dev/null +++ b/mojo/services/catalog/owner.cc
@@ -0,0 +1,24 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/services/catalog/owner.h" + +#include "mojo/services/catalog/catalog.h" +#include "mojo/shell/public/cpp/shell_connection.h" + +namespace catalog { + +Owner::Owner(base::TaskRunner* file_task_runner, scoped_ptr<Store> store) + : catalog_shell_client_(new Catalog(file_task_runner, std::move(store))) { + mojo::shell::mojom::ShellClientRequest request = GetProxy(&shell_client_); + catalog_connection_.reset(new mojo::ShellConnection( + catalog_shell_client_.get(), std::move(request))); +} +Owner::~Owner() {} + +mojo::shell::mojom::ShellClientPtr Owner::TakeShellClient() { + return std::move(shell_client_); +} + +} // namespace catalog
diff --git a/mojo/services/catalog/owner.h b/mojo/services/catalog/owner.h new file mode 100644 index 0000000..c399459 --- /dev/null +++ b/mojo/services/catalog/owner.h
@@ -0,0 +1,44 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SERVICES_CATALOG_OWNER_H_ +#define MOJO_SERVICES_CATALOG_OWNER_H_ + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "mojo/shell/public/interfaces/shell_client.mojom.h" + +namespace base { +class TaskRunner; +} + +namespace mojo{ +class ShellClient; +class ShellConnection; +} + +namespace catalog { + +class Store; + +// Creates and owns an instance of the catalog. Exposes a ShellClientPtr that +// can be passed to the Shell, potentially in a different process. +class Owner { + public: + Owner(base::TaskRunner* file_task_runner, scoped_ptr<Store> store); + ~Owner(); + + mojo::shell::mojom::ShellClientPtr TakeShellClient(); + + private: + mojo::shell::mojom::ShellClientPtr shell_client_; + scoped_ptr<mojo::ShellClient> catalog_shell_client_; + scoped_ptr<mojo::ShellConnection> catalog_connection_; + + DISALLOW_COPY_AND_ASSIGN(Owner); +}; + +} // namespace catalog + +#endif // MOJO_SERVICES_CATALOG_OWNER_H_
diff --git a/mojo/shell/DEPS b/mojo/shell/DEPS index 5a272f0..947e7a68 100644 --- a/mojo/shell/DEPS +++ b/mojo/shell/DEPS
@@ -1,14 +1,3 @@ include_rules = [ - "-mojo/runner", + "-mojo/services", ] - -specific_include_rules = { - "application_manager_apptest_driver.cc": [ - "+mojo/runner/child", - "+mojo/runner/init.h", - ], - "application_manager_apptest_target.cc": [ - "+mojo/runner/child", - "+mojo/runner/init.h", - ], -}
diff --git a/mojo/shell/background/DEPS b/mojo/shell/background/DEPS new file mode 100644 index 0000000..175fafb --- /dev/null +++ b/mojo/shell/background/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/services/catalog", +]
diff --git a/mojo/shell/background/background_shell.cc b/mojo/shell/background/background_shell.cc index e336e2c..ed1d5c54a 100644 --- a/mojo/shell/background/background_shell.cc +++ b/mojo/shell/background/background_shell.cc
@@ -12,7 +12,7 @@ #include "base/synchronization/waitable_event.h" #include "base/threading/simple_thread.h" #include "mojo/message_pump/message_pump_mojo.h" -#include "mojo/services/catalog/catalog.h" +#include "mojo/services/catalog/store.h" #include "mojo/shell/connect_params.h" #include "mojo/shell/loader.h" #include "mojo/shell/public/cpp/shell_client.h"
diff --git a/mojo/shell/background/background_shell.h b/mojo/shell/background/background_shell.h index 3aa16b9..7af37140 100644 --- a/mojo/shell/background/background_shell.h +++ b/mojo/shell/background/background_shell.h
@@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "mojo/public/cpp/bindings/interface_request.h" -#include "mojo/services/catalog/catalog.h" +#include "mojo/services/catalog/store.h" #include "mojo/shell/public/interfaces/shell_client.mojom.h" namespace catalog {
diff --git a/mojo/shell/manifest.json b/mojo/shell/manifest.json index 609708d..7d006e6 100644 --- a/mojo/shell/manifest.json +++ b/mojo/shell/manifest.json
@@ -1,5 +1,12 @@ { + "manifest_version": 1, "name": "mojo:shell", "display_name": "Shell", - "capabilities": {} + "capabilities": { + "provided": { + "user_id": [ ], + "client_process": [ ], + "instance_name": [ ] + } + } }
diff --git a/mojo/shell/shell.cc b/mojo/shell/shell.cc index ceb25e6..0d833e1 100644 --- a/mojo/shell/shell.cc +++ b/mojo/shell/shell.cc
@@ -21,7 +21,6 @@ #include "mojo/common/url_type_converters.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/services/catalog/catalog.h" #include "mojo/shell/connect_util.h" #include "mojo/shell/public/cpp/connector.h" #include "mojo/shell/public/cpp/names.h" @@ -30,12 +29,16 @@ #include "mojo/shell/public/interfaces/shell.mojom.h" #include "mojo/shell/public/interfaces/shell_client.mojom.h" #include "mojo/util/filename_util.h" +#include "url/gurl.h" namespace mojo { namespace shell { namespace { const char kCatalogName[] = "mojo:catalog"; const char kShellName[] = "mojo:shell"; +const char kCapabilityClass_UserID[] = "user_id"; +const char kCapabilityClass_ClientProcess[] = "client_process"; +const char kCapabilityClass_InstanceName[] = "instance_name"; void EmptyResolverCallback(const String& resolved_name, const String& resolved_instance, @@ -65,7 +68,7 @@ // Fall back to looking for a wildcard rule. it = source_spec.required.find("*"); - if (source_spec.required.size() == 1 && it != source_spec.required.end()) + if (it != source_spec.required.end()) return it->second; // Finally, nothing is allowed. @@ -105,8 +108,7 @@ id_(GenerateUniqueID()), identity_(identity), capability_spec_(capability_spec), - allow_any_application_(capability_spec.required.size() == 1 && - capability_spec.required.count("*") == 1), + allow_any_application_(capability_spec.required.count("*") == 1), shell_client_(std::move(shell_client)), pid_receiver_binding_(this), weak_factory_(this) { @@ -194,23 +196,18 @@ mojom::ClientProcessConnectionPtr client_process_connection, const ConnectCallback& callback) override { Identity target = target_ptr.To<Identity>(); + if (target.user_id() == mojom::kInheritUserID) + target.set_user_id(identity_.user_id()); + if (!ValidateIdentity(target, callback)) return; if (!ValidateClientProcessConnection(&client_process_connection, target, callback)) { return; } - // TODO(beng): Need to do the following additional policy validation of - // whether this instance is allowed to connect using: - // - a user id other than its own, kInheritUserID or kRootUserID. - // - a non-empty instance name. - // - a non-null client_process_connection. if (!ValidateCapabilities(target, callback)) return; - if (target.user_id() == mojom::kInheritUserID) - target.set_user_id(identity_.user_id()); - scoped_ptr<ConnectParams> params(new ConnectParams); params->set_source(identity_); params->set_target(target); @@ -261,9 +258,19 @@ bool ValidateClientProcessConnection( mojom::ClientProcessConnectionPtr* client_process_connection, - const Identity& identity, + const Identity& target, const ConnectCallback& callback) { if (!client_process_connection->is_null()) { + if (!HasClass(kCapabilityClass_ClientProcess)) { + LOG(ERROR) << "Error: Instance: " << identity_.name() << " attempting " + << "to register an instance for a process it created for " + << "target: " << target.name() << " without the " + << "mojo:shell{client_process} capability class."; + callback.Run(mojom::ConnectResult::ACCESS_DENIED, + mojom::kInheritUserID, mojom::kInvalidInstanceID); + return false; + } + if (!(*client_process_connection)->shell_client_factory.is_valid() || !(*client_process_connection)->pid_receiver_request.is_valid()) { LOG(ERROR) << "Error: must supply both shell_client_factory AND " @@ -273,11 +280,10 @@ mojom::kInheritUserID, mojom::kInvalidInstanceID); return false; } - if (shell_->GetExistingOrRootInstance(identity)) { + if (shell_->GetExistingOrRootInstance(target)) { LOG(ERROR) << "Error: Cannot client process matching existing identity:" - << "Name: " << identity.name() << " User: " - << identity.user_id() << " Instance: " - << identity.instance(); + << "Name: " << target.name() << " User: " << target.user_id() + << " Instance: " << target.instance(); callback.Run(mojom::ConnectResult::INVALID_ARGUMENT, mojom::kInheritUserID, mojom::kInvalidInstanceID); return false; @@ -288,6 +294,33 @@ bool ValidateCapabilities(const Identity& target, const ConnectCallback& callback) { + // TODO(beng): Need to do the following additional policy validation of + // whether this instance is allowed to connect using: + // - a non-null client_process_connection. + if (target.user_id() != identity_.user_id() && + target.user_id() != mojom::kRootUserID && + !HasClass(kCapabilityClass_UserID)) { + LOG(ERROR) << "Instance: " << identity_.name() << " running as: " + << identity_.user_id() << " attempting to connect to: " + << target.name() << " as: " << target.user_id() << " without " + << " the mojo:shell{user_id} capability class."; + callback.Run(mojom::ConnectResult::ACCESS_DENIED, + mojom::kInheritUserID, mojom::kInvalidInstanceID); + return false; + } + if (!target.instance().empty() && + target.instance() != GetNamePath(target.name()) && + !HasClass(kCapabilityClass_InstanceName)) { + LOG(ERROR) << "Instance: " << identity_.name() << " attempting to " + << "connect to " << target.name() << " using Instance name: " + << target.instance() << " without the " + << "mojo:shell{instance_name} capability class."; + callback.Run(mojom::ConnectResult::ACCESS_DENIED, + mojom::kInheritUserID, mojom::kInvalidInstanceID); + return false; + + } + if (allow_any_application_ || capability_spec_.required.find(target.name()) != capability_spec_.required.end()) { @@ -300,6 +333,13 @@ return false; } + bool HasClass(const std::string& class_name) const { + auto it = capability_spec_.required.find(kShellName); + if (it == capability_spec_.required.end()) + return false; + return it->second.classes.find(class_name) != it->second.classes.end(); + } + uint32_t GenerateUniqueID() const { static uint32_t id = mojom::kInvalidInstanceID; ++id; @@ -348,17 +388,18 @@ // Shell, public: Shell::Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, - base::TaskRunner* file_task_runner, - scoped_ptr<catalog::Store> catalog_store) - : file_task_runner_(file_task_runner), - native_runner_factory_(std::move(native_runner_factory)), + mojom::ShellClientPtr catalog) + : native_runner_factory_(std::move(native_runner_factory)), weak_ptr_factory_(this) { - mojom::ShellClientRequest request; - CreateInstance(CreateShellIdentity(), GetPermissiveCapabilities(), &request); + mojom::ShellClientPtr client; + mojom::ShellClientRequest request = GetProxy(&client); + CreateInstance(CreateShellIdentity(), GetPermissiveCapabilities(), + std::move(client)); shell_connection_.reset(new ShellConnection(this, std::move(request))); shell_connection_->WaitForInitialize(); - InitCatalog(std::move(catalog_store)); + if (catalog) + InitCatalog(std::move(catalog)); } Shell::~Shell() { @@ -399,9 +440,10 @@ Identity target(name, mojom::kRootUserID); DCHECK(!GetExistingInstance(target)); - mojom::ShellClientRequest request; + mojom::ShellClientPtr client; + mojom::ShellClientRequest request = GetProxy(&client); embedder_instance_ = - CreateInstance(target, GetPermissiveCapabilities(), &request); + CreateInstance(target, GetPermissiveCapabilities(), std::move(client)); DCHECK(embedder_instance_); return request; @@ -437,25 +479,17 @@ //////////////////////////////////////////////////////////////////////////////// // Shell, private: -void Shell::InitCatalog(scoped_ptr<catalog::Store> store) { - mojom::ShellClientRequest request; +void Shell::InitCatalog(mojom::ShellClientPtr catalog) { Identity identity(kCatalogName, mojom::kRootUserID); - CreateInstance(identity, CapabilitySpec(), &request); - - catalog_shell_client_.reset( - new catalog::Catalog(file_task_runner_, std::move(store))); - catalog_connection_.reset( - new ShellConnection(catalog_shell_client_.get(), std::move(request))); + CreateInstance(identity, CapabilitySpec(), std::move(catalog)); shell_connection_->connector()->ConnectToInterface( kCatalogName, &shell_resolver_); // Seed the catalog with manifest info for the shell & catalog. - if (file_task_runner_) { - shell_resolver_->ResolveMojoName( - kCatalogName, base::Bind(&EmptyResolverCallback)); - shell_resolver_->ResolveMojoName( - kShellName, base::Bind(&EmptyResolverCallback)); - } + shell_resolver_->ResolveMojoName( + kCatalogName, base::Bind(&EmptyResolverCallback)); + shell_resolver_->ResolveMojoName( + kShellName, base::Bind(&EmptyResolverCallback)); } void Shell::TerminateShellConnections() { @@ -506,17 +540,14 @@ return !!instance; } -Shell::Instance* Shell::CreateInstance(const Identity& target_id, - const CapabilitySpec& capabilities, - mojom::ShellClientRequest* request) { - CHECK(target_id.user_id() != mojom::kInheritUserID); - mojom::ShellClientPtr shell_client; - *request = GetProxy(&shell_client); - Instance* instance = - new Instance(std::move(shell_client), this, target_id, capabilities); - DCHECK(identity_to_instance_.find(target_id) == +Shell::Instance* Shell::CreateInstance(const Identity& target, + const CapabilitySpec& spec, + mojom::ShellClientPtr client) { + CHECK(target.user_id() != mojom::kInheritUserID); + Instance* instance = new Instance(std::move(client), this, target, spec); + DCHECK(identity_to_instance_.find(target) == identity_to_instance_.end()); - identity_to_instance_[target_id] = instance; + identity_to_instance_[target] = instance; mojom::InstanceInfoPtr info = instance->CreateInstanceInfo(); instance_listeners_.ForAllPtrs( [this, &info](mojom::InstanceListener* listener) { @@ -600,8 +631,9 @@ mojom::ClientProcessConnectionPtr client_process_connection = params->TakeClientProcessConnection(); - mojom::ShellClientRequest request; - Instance* instance = CreateInstance(target, capabilities, &request); + mojom::ShellClientPtr client; + mojom::ShellClientRequest request = GetProxy(&client); + Instance* instance = CreateInstance(target, capabilities, std::move(client)); instance->ConnectToClient(std::move(params)); if (LoadWithLoader(target, &request))
diff --git a/mojo/shell/shell.h b/mojo/shell/shell.h index e8f18fb7..9a3e2e9a 100644 --- a/mojo/shell/shell.h +++ b/mojo/shell/shell.h
@@ -13,7 +13,6 @@ #include "base/memory/weak_ptr.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/bindings/interface_ptr_set.h" -#include "mojo/services/catalog/catalog.h" #include "mojo/shell/connect_params.h" #include "mojo/shell/loader.h" #include "mojo/shell/native_runner.h" @@ -28,13 +27,7 @@ #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h" #include "mojo/shell/public/interfaces/shell_resolver.mojom.h" -namespace base { -class FilePath; -class SequencedWorkerPool; -} - namespace mojo { -class ShellClient; class ShellConnection; namespace shell { @@ -65,8 +58,7 @@ // operations on. This may be null only in testing environments where // applications are loaded via Loader implementations. Shell(scoped_ptr<NativeRunnerFactory> native_runner_factory, - base::TaskRunner* file_task_runner, - scoped_ptr<catalog::Store> catalog_store); + mojom::ShellClientPtr catalog); ~Shell() override; // Provide a callback to be notified whenever an instance is destroyed. @@ -104,7 +96,7 @@ // ShellClient: bool AcceptConnection(Connection* connection) override; - void InitCatalog(scoped_ptr<catalog::Store> store); + void InitCatalog(mojom::ShellClientPtr catalog); // Destroys all Shell-ends of connections established with Applications. // Applications connected by this Shell will observe pipe errors and have a @@ -127,9 +119,9 @@ // and this function returns true. bool ConnectToExistingInstance(scoped_ptr<ConnectParams>* params); - Instance* CreateInstance(const Identity& target_id, - const CapabilitySpec& capabilities, - mojom::ShellClientRequest* request); + Instance* CreateInstance(const Identity& target, + const CapabilitySpec& spec, + mojom::ShellClientPtr client); // Called from the instance implementing mojom::Shell. void AddInstanceListener(mojom::InstanceListenerPtr listener); @@ -188,12 +180,9 @@ InterfacePtrSet<mojom::InstanceListener> instance_listeners_; base::Callback<void(const Identity&)> instance_quit_callback_; - base::TaskRunner* file_task_runner_; scoped_ptr<NativeRunnerFactory> native_runner_factory_; std::vector<scoped_ptr<NativeRunner>> native_runners_; scoped_ptr<ShellConnection> shell_connection_; - scoped_ptr<ShellConnection> catalog_connection_; - scoped_ptr<ShellClient> catalog_shell_client_; base::WeakPtrFactory<Shell> weak_ptr_factory_; DISALLOW_COPY_AND_ASSIGN(Shell);
diff --git a/mojo/shell/standalone/DEPS b/mojo/shell/standalone/DEPS index 473cdf7a..b404f56 100644 --- a/mojo/shell/standalone/DEPS +++ b/mojo/shell/standalone/DEPS
@@ -1,11 +1,5 @@ include_rules = [ - "+components/mus", - "+components/mus/gles2", - "+components/mus/native_viewport", - "+components/mus/vm/public", "+components/tracing", - "+crypto", - "+jni", - "+sandbox", - "+ui", + "+mojo/services/catalog", + "+mojo/services/tracing", ]
diff --git a/mojo/shell/standalone/context.cc b/mojo/shell/standalone/context.cc index 4e847fb..68d5c3a 100644 --- a/mojo/shell/standalone/context.cc +++ b/mojo/shell/standalone/context.cc
@@ -29,7 +29,8 @@ #include "components/tracing/tracing_switches.h" #include "mojo/edk/embedder/embedder.h" #include "mojo/public/cpp/bindings/strong_binding.h" -#include "mojo/services/catalog/catalog.h" +#include "mojo/services/catalog/owner.h" +#include "mojo/services/catalog/store.h" #include "mojo/services/tracing/public/cpp/switches.h" #include "mojo/services/tracing/public/cpp/trace_provider_impl.h" #include "mojo/services/tracing/public/cpp/tracing_impl.h" @@ -151,11 +152,12 @@ runner_factory.reset(new OutOfProcessNativeRunnerFactory( blocking_pool_.get(), native_runner_delegate)); } - scoped_ptr<catalog::Store> catalog_store; + scoped_ptr<catalog::Store> store; if (init_params) - catalog_store = std::move(init_params->catalog_store); - shell_.reset(new Shell(std::move(runner_factory), blocking_pool_.get(), - std::move(catalog_store))); + store = std::move(init_params->catalog_store); + catalog_.reset(new catalog::Owner(blocking_pool_.get(), std::move(store))); + shell_.reset(new Shell(std::move(runner_factory), + catalog_->TakeShellClient())); shell::mojom::InterfaceProviderPtr tracing_remote_interfaces; shell::mojom::InterfaceProviderPtr tracing_local_interfaces;
diff --git a/mojo/shell/standalone/context.h b/mojo/shell/standalone/context.h index 91ff248..6d10318 100644 --- a/mojo/shell/standalone/context.h +++ b/mojo/shell/standalone/context.h
@@ -20,6 +20,7 @@ } namespace catalog { +class Owner; class Store; } @@ -69,6 +70,7 @@ // Ensure this is destructed before task_runners_ since it owns a message pipe // that needs the IO thread to destruct cleanly. Tracer tracer_; + scoped_ptr<catalog::Owner> catalog_; scoped_ptr<Shell> shell_; base::Time main_entry_time_;
diff --git a/mojo/shell/tests/BUILD.gn b/mojo/shell/tests/BUILD.gn index d044db42..81fb33a 100644 --- a/mojo/shell/tests/BUILD.gn +++ b/mojo/shell/tests/BUILD.gn
@@ -22,7 +22,6 @@ ":interfaces", "//base", "//base/test:test_support", - "//mojo/edk/system", "//mojo/public/cpp/bindings", "//mojo/public/cpp/system", "//mojo/services/catalog:unittests", @@ -46,3 +45,18 @@ "test.mojom", ] } + +source_set("util") { + sources = [ + "util.cc", + "util.h", + ] + deps = [ + "//base", + "//base:base_static", + "//mojo/edk/system", + "//mojo/shell/public/cpp:sources", + "//mojo/shell/public/interfaces", + "//mojo/shell/runner/common", + ] +}
diff --git a/mojo/shell/tests/DEPS b/mojo/shell/tests/DEPS new file mode 100644 index 0000000..175fafb --- /dev/null +++ b/mojo/shell/tests/DEPS
@@ -0,0 +1,3 @@ +include_rules = [ + "+mojo/services/catalog", +]
diff --git a/mojo/shell/tests/connect/BUILD.gn b/mojo/shell/tests/connect/BUILD.gn index f55c225..48c19a15 100644 --- a/mojo/shell/tests/connect/BUILD.gn +++ b/mojo/shell/tests/connect/BUILD.gn
@@ -24,6 +24,8 @@ data_deps = [ ":connect_test_app", ":connect_test_class_app", + ":connect_test_driver", + ":connect_test_exe", ":connect_test_package", ":manifest", ] @@ -33,6 +35,9 @@ sources = [ "connect_test.mojom", ] + deps = [ + "//mojo/shell/public/interfaces", + ] } mojo_application_manifest("manifest") { @@ -117,3 +122,54 @@ application_name = "connect_test_class_app" source = "connect_test_class_app_manifest.json" } + +executable("connect_test_driver") { + testonly = true + + sources = [ + "connect_test_driver.cc", + ] + + deps = [ + ":interfaces", + "//base", + "//mojo/shell/public/cpp", + "//mojo/shell/runner/child:test_native_main", + "//mojo/shell/tests:util", + ] + + data_deps = [ + ":connect_test_driver_manifest", + ] +} + +mojo_application_manifest("connect_test_driver_manifest") { + type = "exe" + application_name = "connect_test_driver" + source = "connect_test_driver_manifest.json" +} + +executable("connect_test_exe") { + testonly = true + + sources = [ + "connect_test_exe.cc", + ] + + deps = [ + ":interfaces", + "//base", + "//mojo/shell/public/cpp", + "//mojo/shell/runner/child:test_native_main", + ] + + data_deps = [ + ":connect_test_exe_manifest", + ] +} + +mojo_application_manifest("connect_test_exe_manifest") { + type = "exe" + application_name = "connect_test_exe" + source = "connect_test_exe_manifest.json" +}
diff --git a/mojo/shell/tests/connect/connect_test.mojom b/mojo/shell/tests/connect/connect_test.mojom index 2598f3e..55d7670 100644 --- a/mojo/shell/tests/connect/connect_test.mojom +++ b/mojo/shell/tests/connect/connect_test.mojom
@@ -4,6 +4,8 @@ module mojo.shell.test.mojom; +import "mojo/shell/public/interfaces/connector.mojom"; + interface ConnectTestService { GetTitle() => (string title); GetInstance() => (string instance); @@ -30,6 +32,23 @@ ConnectToClassInterface() => (string class_interface_response, string title); }; +interface UserIdTest { + // Attempts to connect to mojo:connect_test_class_app as |user_id|. + // The callback takes the connection response result, and the identity + // mojo:connect_test_class_app was run as, which should match |user_id|. + ConnectToClassAppAsDifferentUser(mojo.shell.mojom.Identity target) => + (int32 connection_result, mojo.shell.mojom.Identity target); +}; + +interface ClientProcessTest { + // Attempts to launch a bare exe and connect to it using the + // ClientProcessConnection param to Connector::Connect(). The callback takes + // the result of the connection, and the identity of the app that the caller + // can use to connect to this app as well. + LaunchAndConnectToProcess() => + (int32 connection_result, mojo.shell.mojom.Identity target); +}; + struct ConnectionState { string connection_local_name; string connection_remote_name;
diff --git a/mojo/shell/tests/connect/connect_test_app.cc b/mojo/shell/tests/connect/connect_test_app.cc index abf51dc..342e14d7 100644 --- a/mojo/shell/tests/connect/connect_test_app.cc +++ b/mojo/shell/tests/connect/connect_test_app.cc
@@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/bind.h" +#include "base/guid.h" #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "base/run_loop.h" @@ -18,6 +19,10 @@ namespace mojo { namespace shell { namespace { +void QuitLoop(base::RunLoop* loop) { + loop->Quit(); +} + void ReceiveString(std::string* string, base::RunLoop* loop, const std::string& response) { *string = response; @@ -31,9 +36,11 @@ public InterfaceFactory<test::mojom::ConnectTestService>, public InterfaceFactory<test::mojom::StandaloneApp>, public InterfaceFactory<test::mojom::BlockedInterface>, + public InterfaceFactory<test::mojom::UserIdTest>, public test::mojom::ConnectTestService, public test::mojom::StandaloneApp, - public test::mojom::BlockedInterface { + public test::mojom::BlockedInterface, + public test::mojom::UserIdTest { public: ConnectTestApp() {} ~ConnectTestApp() override {} @@ -56,6 +63,7 @@ connection->AddInterface<test::mojom::ConnectTestService>(this); connection->AddInterface<test::mojom::StandaloneApp>(this); connection->AddInterface<test::mojom::BlockedInterface>(this); + connection->AddInterface<test::mojom::UserIdTest>(this); uint32_t remote_id = connection->GetRemoteInstanceID(); test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New()); @@ -96,6 +104,12 @@ blocked_bindings_.AddBinding(this, std::move(request)); } + // InterfaceFactory<test::mojom::UserIdTest>: + void Create(Connection* connection, + test::mojom::UserIdTestRequest request) override { + user_id_test_bindings_.AddBinding(this, std::move(request)); + } + // test::mojom::ConnectTestService: void GetTitle(const GetTitleCallback& callback) override { callback.Run("APP"); @@ -158,6 +172,23 @@ callback.Run("Called Blocked Interface!"); } + // test::mojom::UserIdTest: + void ConnectToClassAppAsDifferentUser( + mojom::IdentityPtr target, + const ConnectToClassAppAsDifferentUserCallback& callback) override { + Connector::ConnectParams params(target.To<Identity>()); + scoped_ptr<Connection> connection = connector_->Connect(¶ms); + { + base::RunLoop loop; + connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + callback.Run(static_cast<int32_t>(connection->GetResult()), + mojom::Identity::From(connection->GetRemoteIdentity())); + } + void OnConnectionBlocked( const ConnectToAllowedAppInBlockedPackageCallback& callback, base::RunLoop* run_loop) { @@ -184,6 +215,7 @@ BindingSet<test::mojom::ConnectTestService> bindings_; BindingSet<test::mojom::StandaloneApp> standalone_bindings_; BindingSet<test::mojom::BlockedInterface> blocked_bindings_; + BindingSet<test::mojom::UserIdTest> user_id_test_bindings_; test::mojom::ExposedInterfacePtr caller_; DISALLOW_COPY_AND_ASSIGN(ConnectTestApp);
diff --git a/mojo/shell/tests/connect/connect_test_app_a_manifest.json b/mojo/shell/tests/connect/connect_test_app_a_manifest.json index 783a6a1..3ab8927b 100644 --- a/mojo/shell/tests/connect/connect_test_app_a_manifest.json +++ b/mojo/shell/tests/connect/connect_test_app_a_manifest.json
@@ -1,5 +1,6 @@ { + "manifest_version": 1, "name": "mojo:connect_test_a", "display_name": "Connect Test A", - "capabilities": {} + "capabilities": { } }
diff --git a/mojo/shell/tests/connect/connect_test_app_manifest.json b/mojo/shell/tests/connect/connect_test_app_manifest.json index b70cb1b9..7c459227 100644 --- a/mojo/shell/tests/connect/connect_test_app_manifest.json +++ b/mojo/shell/tests/connect/connect_test_app_manifest.json
@@ -6,9 +6,10 @@ "required": { "mojo:connect_test_a": { "interfaces": ["*"] }, "mojo:connect_test_class_app": { - "classes": ["class"], + "classes": [ "class" ], "interfaces": ["mojo::shell::test::mojom::ConnectTestService"] - } + }, + "mojo:shell": { "classes": [ "user_id" ] } } } }
diff --git a/mojo/shell/tests/connect/connect_test_driver.cc b/mojo/shell/tests/connect/connect_test_driver.cc new file mode 100644 index 0000000..9e5a4cc --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_driver.cc
@@ -0,0 +1,83 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/macros.h" +#include "base/process/process.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/shell/public/cpp/connection.h" +#include "mojo/shell/public/cpp/connector.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/runner/child/test_native_main.h" +#include "mojo/shell/runner/init.h" +#include "mojo/shell/tests/connect/connect_test.mojom.h" +#include "mojo/shell/tests/util.h" + +using mojo::shell::test::mojom::ClientProcessTest; +using mojo::shell::test::mojom::ClientProcessTestRequest; + +namespace { + +class Driver : public mojo::ShellClient, + public mojo::InterfaceFactory<ClientProcessTest>, + public ClientProcessTest { + public: + Driver() {} + ~Driver() override {} + + private: + // mojo::ShellClient: + void Initialize(mojo::Connector* connector, const mojo::Identity& identity, + uint32_t id) override { + connector_ = connector; + } + bool AcceptConnection(mojo::Connection* connection) override { + connection->AddInterface<ClientProcessTest>(this); + return true; + } + + // mojo::InterfaceFactory<ConnectTestService>: + void Create(mojo::Connection* connection, + ClientProcessTestRequest request) override { + bindings_.AddBinding(this, std::move(request)); + } + + // test::mojom::ClientProcessTest: + void LaunchAndConnectToProcess( + const LaunchAndConnectToProcessCallback& callback) override { + base::Process process; + scoped_ptr<mojo::Connection> connection = + mojo::shell::test::LaunchAndConnectToProcess( +#if defined(OS_WIN) + "connect_test_exe.exe", +#else + "connect_test_exe", +#endif + mojo::Identity("exe:connect_test_exe", + mojo::shell::mojom::kInheritUserID), + connector_, + &process); + callback.Run(static_cast<int32_t>(connection->GetResult()), + mojo::shell::mojom::Identity::From( + connection->GetRemoteIdentity())); + } + + mojo::Connector* connector_ = nullptr; + mojo::BindingSet<ClientProcessTest> bindings_; + + DISALLOW_COPY_AND_ASSIGN(Driver); +}; + +} // namespace + +int main(int argc, char** argv) { + base::AtExitManager at_exit; + base::CommandLine::Init(argc, argv); + + mojo::shell::InitializeLogging(); + + Driver driver; + return mojo::shell::TestNativeMain(&driver); +}
diff --git a/mojo/shell/tests/connect/connect_test_driver_manifest.json b/mojo/shell/tests/connect/connect_test_driver_manifest.json new file mode 100644 index 0000000..7b9d4f2 --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_driver_manifest.json
@@ -0,0 +1,5 @@ +{ + "name": "exe:connect_test_driver", + "display_name": "Connect Test Driver", + "capabilities": {} +}
diff --git a/mojo/shell/tests/connect/connect_test_exe.cc b/mojo/shell/tests/connect/connect_test_exe.cc new file mode 100644 index 0000000..791b9fb7 --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_exe.cc
@@ -0,0 +1,69 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/at_exit.h" +#include "base/command_line.h" +#include "base/macros.h" +#include "mojo/public/cpp/bindings/binding_set.h" +#include "mojo/shell/public/cpp/connection.h" +#include "mojo/shell/public/cpp/connector.h" +#include "mojo/shell/public/cpp/shell_client.h" +#include "mojo/shell/runner/child/test_native_main.h" +#include "mojo/shell/runner/init.h" +#include "mojo/shell/tests/connect/connect_test.mojom.h" + +using mojo::shell::test::mojom::ConnectTestService; +using mojo::shell::test::mojom::ConnectTestServiceRequest; + +namespace { + +class Target : public mojo::ShellClient, + public mojo::InterfaceFactory<ConnectTestService>, + public ConnectTestService { + public: + Target() {} + ~Target() override {} + + private: + // mojo::ShellClient: + void Initialize(mojo::Connector* connector, const mojo::Identity& identity, + uint32_t id) override { + identity_ = identity; + } + bool AcceptConnection(mojo::Connection* connection) override { + connection->AddInterface<ConnectTestService>(this); + return true; + } + + // mojo::InterfaceFactory<ConnectTestService>: + void Create(mojo::Connection* connection, + ConnectTestServiceRequest request) override { + bindings_.AddBinding(this, std::move(request)); + } + + // ConnectTestService: + void GetTitle(const GetTitleCallback& callback) override { + callback.Run("connect_test_exe"); + } + void GetInstance(const GetInstanceCallback& callback) override { + callback.Run(identity_.instance()); + } + + mojo::Identity identity_; + mojo::BindingSet<ConnectTestService> bindings_; + + DISALLOW_COPY_AND_ASSIGN(Target); +}; + +} // namespace + +int main(int argc, char** argv) { + base::AtExitManager at_exit; + base::CommandLine::Init(argc, argv); + + mojo::shell::InitializeLogging(); + + Target target; + return mojo::shell::TestNativeMain(&target); +}
diff --git a/mojo/shell/tests/connect/connect_test_exe_manifest.json b/mojo/shell/tests/connect/connect_test_exe_manifest.json new file mode 100644 index 0000000..e4b628c --- /dev/null +++ b/mojo/shell/tests/connect/connect_test_exe_manifest.json
@@ -0,0 +1,5 @@ +{ + "name": "exe:connect_test_exe", + "display_name": "Connect Test Exe", + "capabilities": {} +}
diff --git a/mojo/shell/tests/connect/connect_test_package.cc b/mojo/shell/tests/connect/connect_test_package.cc index 6f365e1c..c5a1a07 100644 --- a/mojo/shell/tests/connect/connect_test_package.cc +++ b/mojo/shell/tests/connect/connect_test_package.cc
@@ -15,6 +15,7 @@ #include "mojo/public/c/system/main.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/shell/public/cpp/application_runner.h" +#include "mojo/shell/public/cpp/connector.h" #include "mojo/shell/public/cpp/interface_factory.h" #include "mojo/shell/public/cpp/shell_client.h" #include "mojo/shell/public/interfaces/shell_client_factory.mojom.h" @@ -26,6 +27,11 @@ namespace mojo { namespace shell { +namespace { +void QuitLoop(base::RunLoop* loop) { + loop->Quit(); +} +} using GetTitleCallback = test::mojom::ConnectTestService::GetTitleCallback; @@ -33,8 +39,10 @@ : public ShellClient, public InterfaceFactory<test::mojom::ConnectTestService>, public InterfaceFactory<test::mojom::BlockedInterface>, + public InterfaceFactory<test::mojom::UserIdTest>, public test::mojom::ConnectTestService, public test::mojom::BlockedInterface, + public test::mojom::UserIdTest, public base::SimpleThread { public: ProvidedShellClient(const std::string& title, @@ -52,6 +60,7 @@ // mojo::ShellClient: void Initialize(Connector* connector, const Identity& identity, uint32_t id) override { + connector_ = connector; identity_ = identity; id_ = id; bindings_.set_connection_error_handler( @@ -61,6 +70,7 @@ bool AcceptConnection(Connection* connection) override { connection->AddInterface<test::mojom::ConnectTestService>(this); connection->AddInterface<test::mojom::BlockedInterface>(this); + connection->AddInterface<test::mojom::UserIdTest>(this); uint32_t remote_id = connection->GetRemoteInstanceID(); test::mojom::ConnectionStatePtr state(test::mojom::ConnectionState::New()); @@ -89,6 +99,12 @@ blocked_bindings_.AddBinding(this, std::move(request)); } + // InterfaceFactory<test::mojom::UserIdTest>: + void Create(Connection* connection, + test::mojom::UserIdTestRequest request) override { + user_id_test_bindings_.AddBinding(this, std::move(request)); + } + // test::mojom::ConnectTestService: void GetTitle(const GetTitleCallback& callback) override { callback.Run(title_); @@ -102,6 +118,23 @@ callback.Run("Called Blocked Interface!"); } + // test::mojom::UserIdTest: + void ConnectToClassAppAsDifferentUser( + mojom::IdentityPtr target, + const ConnectToClassAppAsDifferentUserCallback& callback) override { + Connector::ConnectParams params(target.To<Identity>()); + scoped_ptr<Connection> connection = connector_->Connect(¶ms); + { + base::RunLoop loop; + connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + callback.Run(static_cast<int32_t>(connection->GetResult()), + mojom::Identity::From(connection->GetRemoteIdentity())); + } + // base::SimpleThread: void Run() override { ApplicationRunner(this).Run(request_.PassMessagePipe().release().value(), @@ -114,6 +147,7 @@ base::MessageLoop::current()->QuitWhenIdle(); } + Connector* connector_ = nullptr; Identity identity_; uint32_t id_ = shell::mojom::kInvalidInstanceID; const std::string title_; @@ -121,6 +155,7 @@ test::mojom::ExposedInterfacePtr caller_; BindingSet<test::mojom::ConnectTestService> bindings_; BindingSet<test::mojom::BlockedInterface> blocked_bindings_; + BindingSet<test::mojom::UserIdTest> user_id_test_bindings_; DISALLOW_COPY_AND_ASSIGN(ProvidedShellClient); };
diff --git a/mojo/shell/tests/connect/connect_unittest.cc b/mojo/shell/tests/connect/connect_unittest.cc index df6c6fa..8dd65ce 100644 --- a/mojo/shell/tests/connect/connect_unittest.cc +++ b/mojo/shell/tests/connect/connect_unittest.cc
@@ -8,6 +8,7 @@ #include <utility> #include "base/bind.h" +#include "base/guid.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/test/test_suite.h" @@ -28,6 +29,8 @@ const char kTestAppName[] = "mojo:connect_test_app"; const char kTestAppAName[] = "mojo:connect_test_a"; const char kTestAppBName[] = "mojo:connect_test_b"; +const char kTestClassAppName[] = "mojo:connect_test_class_app"; +const char kTestDriverName[] = "exe:connect_test_driver"; void ReceiveOneString(std::string* out_string, base::RunLoop* loop, @@ -44,6 +47,16 @@ loop->Quit(); } +void ReceiveConnectionResult(mojom::ConnectResult* out_result, + Identity* out_target, + base::RunLoop* loop, + int32_t in_result, + mojom::IdentityPtr in_identity) { + *out_result = static_cast<shell::mojom::ConnectResult>(in_result); + *out_target = in_identity.To<Identity>(); + loop->Quit(); +} + void QuitLoop(base::RunLoop* loop) { loop->Quit(); } @@ -286,6 +299,59 @@ EXPECT_EQ("CLASS APP", string2); } +TEST_F(ConnectTest, ConnectAsDifferentUser_Allowed) { + scoped_ptr<Connection> connection = connector()->Connect(kTestAppName); + test::mojom::UserIdTestPtr user_id_test; + connection->GetInterface(&user_id_test); + shell::mojom::ConnectResult result; + Identity target(kTestClassAppName, base::GenerateGUID()); + Identity result_identity; + { + base::RunLoop loop; + user_id_test->ConnectToClassAppAsDifferentUser( + mojom::Identity::From(target), + base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop)); + loop.Run(); + } + EXPECT_EQ(result, shell::mojom::ConnectResult::SUCCEEDED); + EXPECT_EQ(target, result_identity); +} + +TEST_F(ConnectTest, ConnectAsDifferentUser_Blocked) { + scoped_ptr<Connection> connection = connector()->Connect(kTestAppAName); + test::mojom::UserIdTestPtr user_id_test; + connection->GetInterface(&user_id_test); + shell::mojom::ConnectResult result; + Identity target(kTestClassAppName, base::GenerateGUID()); + Identity result_identity; + { + base::RunLoop loop; + user_id_test->ConnectToClassAppAsDifferentUser( + mojom::Identity::From(target), + base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop)); + loop.Run(); + } + EXPECT_EQ(shell::mojom::ConnectResult::ACCESS_DENIED, result); + EXPECT_FALSE(target == result_identity); +} + +// There are various other tests (shell, lifecycle) that test valid client +// process specifications. This is the only one for blocking. +TEST_F(ConnectTest, ConnectToClientProcess_Blocked) { + scoped_ptr<Connection> connection = connector()->Connect(kTestDriverName); + test::mojom::ClientProcessTestPtr client_process_test; + connection->GetInterface(&client_process_test); + shell::mojom::ConnectResult result; + Identity result_identity; + { + base::RunLoop loop; + client_process_test->LaunchAndConnectToProcess( + base::Bind(&ReceiveConnectionResult, &result, &result_identity, &loop)); + loop.Run(); + } + EXPECT_EQ(shell::mojom::ConnectResult::ACCESS_DENIED, result); +} + // Tests that we can expose an interface to targets on outbound connections. TEST_F(ConnectTest, LocalInterface) { // Connect to a standalone application.
diff --git a/mojo/shell/tests/connect/connect_unittests_manifest.json b/mojo/shell/tests/connect/connect_unittests_manifest.json index cb8e865..e0b99ce 100644 --- a/mojo/shell/tests/connect/connect_unittests_manifest.json +++ b/mojo/shell/tests/connect/connect_unittests_manifest.json
@@ -1,11 +1,28 @@ { + "manifest_version": 1, "name": "mojo:connect_unittests", "display_name": "Connect Unittests", "capabilities": { - "mojo:connect_test_package": ["*"], - "mojo:connect_test_app": ["mojo::shell::test::mojom::ConnectTestService", - "mojo::shell::test::mojom::StandaloneApp"], - "mojo:connect_test_a": ["mojo::shell::test::mojom::ConnectTestService", - "mojo::shell::test::mojom::StandaloneApp"] + "required": { + "mojo:connect_test_package": { "interfaces": [ "*" ] }, + "mojo:connect_test_app": { + "interfaces": [ + "mojo::shell::test::mojom::ConnectTestService", + "mojo::shell::test::mojom::StandaloneApp", + "mojo::shell::test::mojom::UserIdTest" + ] + }, + "exe:connect_test_driver": { + "interfaces": [ "mojo::shell::test::mojom::ClientProcessTest" ] + }, + "mojo:connect_test_a": { + "interfaces": [ + "mojo::shell::test::mojom::ConnectTestService", + "mojo::shell::test::mojom::StandaloneApp", + "mojo::shell::test::mojom::UserIdTest" + ] + }, + "mojo:shell": { "classes": [ "instance_name" ] } + } } }
diff --git a/mojo/shell/tests/lifecycle/BUILD.gn b/mojo/shell/tests/lifecycle/BUILD.gn index 75753560..34b0a64 100644 --- a/mojo/shell/tests/lifecycle/BUILD.gn +++ b/mojo/shell/tests/lifecycle/BUILD.gn
@@ -16,11 +16,11 @@ ":interfaces", "//base", "//base/test:test_support", - "//mojo/edk/system", "//mojo/shell/public/cpp:shell_test_support", "//mojo/shell/public/cpp:sources", "//mojo/shell/public/interfaces", "//mojo/shell/runner/common", + "//mojo/shell/tests:util", ] data_deps = [
diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc index 36fec24..fd34f11 100644 --- a/mojo/shell/tests/lifecycle/lifecycle_unittest.cc +++ b/mojo/shell/tests/lifecycle/lifecycle_unittest.cc
@@ -2,22 +2,16 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "base/base_paths.h" -#include "base/base_switches.h" #include "base/bind.h" #include "base/command_line.h" #include "base/macros.h" -#include "base/path_service.h" #include "base/process/process.h" #include "base/run_loop.h" -#include "mojo/edk/embedder/embedder.h" -#include "mojo/edk/embedder/platform_channel_pair.h" -#include "mojo/edk/embedder/scoped_platform_handle.h" #include "mojo/shell/public/cpp/identity.h" #include "mojo/shell/public/cpp/shell_test.h" #include "mojo/shell/public/interfaces/shell.mojom.h" -#include "mojo/shell/runner/common/switches.h" #include "mojo/shell/tests/lifecycle/lifecycle_unittest.mojom.h" +#include "mojo/shell/tests/util.h" namespace mojo { namespace shell { @@ -164,69 +158,16 @@ } base::Process LaunchProcess() { - base::FilePath target_path; - CHECK(base::PathService::Get(base::DIR_EXE, &target_path)); - #if defined(OS_WIN) - target_path = target_path.Append( - FILE_PATH_LITERAL("lifecycle_unittest_exe.exe")); - #else - target_path = target_path.Append( - FILE_PATH_LITERAL("lifecycle_unittest_exe")); - #endif - - base::CommandLine child_command_line(target_path); - // Forward the wait-for-debugger flag but nothing else - we don't want to - // stamp on the platform-channel flag. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kWaitForDebugger)) { - child_command_line.AppendSwitch(switches::kWaitForDebugger); - } - - // Create the channel to be shared with the target process. Pass one end - // on the command line. - mojo::edk::PlatformChannelPair platform_channel_pair; - mojo::edk::HandlePassingInformation handle_passing_info; - platform_channel_pair.PrepareToPassClientHandleToChildProcess( - &child_command_line, &handle_passing_info); - - // Generate a token for the child to find and connect to a primordial pipe - // and pass that as well. - std::string primordial_pipe_token = mojo::edk::GenerateRandomToken(); - child_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken, - primordial_pipe_token); - - // Allocate the pipe locally. - mojo::ScopedMessagePipeHandle pipe = - mojo::edk::CreateParentMessagePipe(primordial_pipe_token); - - mojo::shell::mojom::ShellPtr shell; - connector()->ConnectToInterface("mojo:shell", &shell); - - mojo::shell::mojom::ShellClientFactoryPtr factory; - factory.Bind(mojo::InterfacePtrInfo<mojo::shell::mojom::ShellClientFactory>( - std::move(pipe), 0u)); - mojo::shell::mojom::PIDReceiverPtr receiver; - - mojo::Identity target(kTestExeName, mojo::shell::mojom::kInheritUserID); - mojo::Connector::ConnectParams params(target); - params.set_client_process_connection(std::move(factory), - GetProxy(&receiver)); - scoped_ptr<mojo::Connection> connection = connector()->Connect(¶ms); - base::RunLoop loop; - connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); - loop.Run(); - - base::LaunchOptions options; - #if defined(OS_WIN) - options.handles_to_inherit = &handle_passing_info; - #elif defined(OS_POSIX) - options.fds_to_remap = &handle_passing_info; - #endif - base::Process process = base::LaunchProcess(child_command_line, options); - DCHECK(process.IsValid()); - receiver->SetPID(process.Pid()); - mojo::edk::ChildProcessLaunched(process.Handle(), - platform_channel_pair.PassServerHandle()); + base::Process process; + test::LaunchAndConnectToProcess( +#if defined(OS_WIN) + "lifecycle_unittest_exe.exe", +#else + "lifecycle_unittest_exe", +#endif + Identity(kTestExeName, mojom::kInheritUserID), + connector(), + &process); return process; }
diff --git a/mojo/shell/tests/lifecycle/lifecycle_unittest_manifest.json b/mojo/shell/tests/lifecycle/lifecycle_unittest_manifest.json index 246e5e4..b02dee1e 100644 --- a/mojo/shell/tests/lifecycle/lifecycle_unittest_manifest.json +++ b/mojo/shell/tests/lifecycle/lifecycle_unittest_manifest.json
@@ -1,5 +1,12 @@ { + "manifest_version": 1, "name": "mojo:lifecycle_unittest", "display_name": "Lifecycle Unittest", - "capabilities": { "*": ["*"] } + "capabilities": { + "required": { + "*": { "interfaces": [ "*" ] }, + "mojo:shell": { "classes": [ "instance_name", "client_process" ], + "interfaces": [ "*" ] } + } + } }
diff --git a/mojo/shell/tests/loader_unittest.cc b/mojo/shell/tests/loader_unittest.cc index d7f5b3c..111c0bd 100644 --- a/mojo/shell/tests/loader_unittest.cc +++ b/mojo/shell/tests/loader_unittest.cc
@@ -11,6 +11,8 @@ #include "base/message_loop/message_loop.h" #include "base/run_loop.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "mojo/services/catalog/owner.h" +#include "mojo/services/catalog/store.h" #include "mojo/shell/connect_util.h" #include "mojo/shell/loader.h" #include "mojo/shell/public/cpp/connector.h" @@ -399,7 +401,9 @@ ~LoaderTest() override {} void SetUp() override { - shell_.reset(new Shell(nullptr, nullptr, nullptr)); + blocking_pool_ = new base::SequencedWorkerPool(3, "blocking_pool"); + catalog_.reset(new catalog::Owner(blocking_pool_.get(), nullptr)); + shell_.reset(new Shell(nullptr, catalog_->TakeShellClient())); test_loader_ = new TestLoader(&context_); shell_->set_default_loader(scoped_ptr<Loader>(test_loader_)); @@ -411,6 +415,7 @@ void TearDown() override { test_client_.reset(); shell_.reset(); + blocking_pool_->Shutdown(); } void AddLoaderForName(const std::string& name, @@ -448,6 +453,8 @@ TestContext context_; base::MessageLoop loop_; scoped_ptr<TestClient> test_client_; + scoped_ptr<catalog::Owner> catalog_; + scoped_refptr<base::SequencedWorkerPool> blocking_pool_; scoped_ptr<Shell> shell_; DISALLOW_COPY_AND_ASSIGN(LoaderTest); }; @@ -471,7 +478,8 @@ TEST_F(LoaderTest, Deletes) { { - Shell shell(nullptr, nullptr, nullptr); + catalog::Owner catalog(blocking_pool_.get(), nullptr); + Shell shell(nullptr, catalog.TakeShellClient()); TestLoader* default_loader = new TestLoader(&context_); TestLoader* name_loader1 = new TestLoader(&context_); TestLoader* name_loader2 = new TestLoader(&context_);
diff --git a/mojo/shell/tests/shell/driver_manifest.json b/mojo/shell/tests/shell/driver_manifest.json index 04a394a..8efa0f1 100644 --- a/mojo/shell/tests/shell/driver_manifest.json +++ b/mojo/shell/tests/shell/driver_manifest.json
@@ -1,5 +1,11 @@ { + "manifest_version": 1, "name": "exe:shell_unittest_driver", "display_name": "Shell Unittest: Driver", - "capabilities": { "*": [ "*" ] } + "capabilities": { + "required": { + "*": { "interfaces": [ "*" ] }, + "mojo:shell": { "classes": ["client_process"] } + } + } }
diff --git a/mojo/shell/tests/util.cc b/mojo/shell/tests/util.cc new file mode 100644 index 0000000..d57d311 --- /dev/null +++ b/mojo/shell/tests/util.cc
@@ -0,0 +1,101 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "mojo/shell/tests/util.h" + +#include "base/base_paths.h" +#include "base/base_switches.h" +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/macros.h" +#include "base/message_loop/message_loop.h" +#include "base/path_service.h" +#include "base/process/process.h" +#include "base/run_loop.h" +#include "mojo/edk/embedder/embedder.h" +#include "mojo/edk/embedder/platform_channel_pair.h" +#include "mojo/edk/embedder/scoped_platform_handle.h" +#include "mojo/shell/public/cpp/connection.h" +#include "mojo/shell/public/cpp/connector.h" +#include "mojo/shell/public/interfaces/connector.mojom.h" +#include "mojo/shell/public/interfaces/shell_client_factory.mojom.h" +#include "mojo/shell/runner/common/switches.h" + +namespace mojo { +namespace shell { +namespace test { +namespace { +void QuitLoop(base::RunLoop* loop) { + loop->Quit(); +} +} // namespace + +scoped_ptr<Connection> LaunchAndConnectToProcess( + const std::string& target_exe_name, + const Identity target, + mojo::Connector* connector, + base::Process* process) { + base::FilePath target_path; + CHECK(base::PathService::Get(base::DIR_EXE, &target_path)); + target_path = target_path.AppendASCII(target_exe_name); + + base::CommandLine child_command_line(target_path); + // Forward the wait-for-debugger flag but nothing else - we don't want to + // stamp on the platform-channel flag. + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kWaitForDebugger)) { + child_command_line.AppendSwitch(switches::kWaitForDebugger); + } + + // Create the channel to be shared with the target process. Pass one end + // on the command line. + mojo::edk::PlatformChannelPair platform_channel_pair; + mojo::edk::HandlePassingInformation handle_passing_info; + platform_channel_pair.PrepareToPassClientHandleToChildProcess( + &child_command_line, &handle_passing_info); + + // Generate a token for the child to find and connect to a primordial pipe + // and pass that as well. + std::string primordial_pipe_token = mojo::edk::GenerateRandomToken(); + child_command_line.AppendSwitchASCII(switches::kPrimordialPipeToken, + primordial_pipe_token); + + // Allocate the pipe locally. + mojo::ScopedMessagePipeHandle pipe = + mojo::edk::CreateParentMessagePipe(primordial_pipe_token); + + mojo::shell::mojom::ShellClientFactoryPtr factory; + factory.Bind(mojo::InterfacePtrInfo<mojo::shell::mojom::ShellClientFactory>( + std::move(pipe), 0u)); + mojo::shell::mojom::PIDReceiverPtr receiver; + + mojo::Connector::ConnectParams params(target); + params.set_client_process_connection(std::move(factory), GetProxy(&receiver)); + scoped_ptr<mojo::Connection> connection = connector->Connect(¶ms); + { + base::RunLoop loop; + connection->AddConnectionCompletedClosure(base::Bind(&QuitLoop, &loop)); + base::MessageLoop::ScopedNestableTaskAllower allow( + base::MessageLoop::current()); + loop.Run(); + } + + base::LaunchOptions options; +#if defined(OS_WIN) + options.handles_to_inherit = &handle_passing_info; +#elif defined(OS_POSIX) + options.fds_to_remap = &handle_passing_info; +#endif + *process = base::LaunchProcess(child_command_line, options); + DCHECK(process->IsValid()); + receiver->SetPID(process->Pid()); + mojo::edk::ChildProcessLaunched(process->Handle(), + platform_channel_pair.PassServerHandle()); + return connection; +} + +} // namespace test +} // namespace shell +} // namespace mojo
diff --git a/mojo/shell/tests/util.h b/mojo/shell/tests/util.h new file mode 100644 index 0000000..5520f4e --- /dev/null +++ b/mojo/shell/tests/util.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MOJO_SHELL_TESTS_UTIL_H_ +#define MOJO_SHELL_TESTS_UTIL_H_ + +#include <string> + +#include "base/memory/scoped_ptr.h" + +namespace base { +class Process; +} + +namespace mojo { +class Connection; +class Connector; +class Identity; +namespace shell { +namespace test { + +// Starts the process @ |target_exe_name| and connects to it as |target| using +// |connector|, returning the connection & the process. +// This blocks until the connection is established/rejected by the shell. +scoped_ptr<Connection> LaunchAndConnectToProcess( + const std::string& target_exe_name, + const Identity target, + mojo::Connector* connector, + base::Process* process); + +} // namespace test +} // namespace shell +} // namespace mojo + +#endif // MOJO_SHELL_TESTS_UTIL_H_
diff --git a/net/android/keystore_unittest.cc b/net/android/keystore_unittest.cc index 4faa245..26d49c28 100644 --- a/net/android/keystore_unittest.cc +++ b/net/android/keystore_unittest.cc
@@ -9,7 +9,6 @@ #include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/rsa.h> -#include <openssl/x509.h> #include "base/android/build_info.h" #include "base/android/jni_android.h" @@ -23,6 +22,7 @@ #include "base/files/scoped_file.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" +#include "crypto/auto_cbb.h" #include "crypto/openssl_util.h" #include "net/android/keystore.h" #include "net/android/keystore_openssl.h" @@ -128,18 +128,16 @@ // Returns true on success, false otherwise. bool GetPrivateKeyPkcs8Bytes(const crypto::ScopedEVP_PKEY& pkey, std::string* pkcs8) { - // Convert to PKCS#8 object. - ScopedPKCS8_PRIV_KEY_INFO p8_info(EVP_PKEY2PKCS8(pkey.get())); - if (!p8_info.get()) { - LOG(ERROR) << "Can't get PKCS#8 private key from EVP_PKEY: " - << GetOpenSSLErrorString(); + uint8_t* der; + size_t der_len; + crypto::AutoCBB cbb; + if (!CBB_init(cbb.get(), 0) || + !EVP_marshal_private_key(cbb.get(), pkey.get()) || + !CBB_finish(cbb.get(), &der, &der_len)) { return false; } - - // Then convert it - int len = i2d_PKCS8_PRIV_KEY_INFO(p8_info.get(), NULL); - unsigned char* p = OpenSSLWriteInto(pkcs8, static_cast<size_t>(len)); - i2d_PKCS8_PRIV_KEY_INFO(p8_info.get(), &p); + pkcs8->assign(reinterpret_cast<const char*>(der), der_len); + OPENSSL_free(der); return true; }
diff --git a/net/android/network_library.h b/net/android/network_library.h index ddfb5e9..827548a 100644 --- a/net/android/network_library.h +++ b/net/android/network_library.h
@@ -36,15 +36,10 @@ // Removes all root certificates added by |AddTestRootCertificate| calls. void ClearTestRootCertificates(); -// Helper for the <keygen> handler. Passes the DER-encoded key pair via -// JNI to the Credentials store. Note that the public key must be a DER -// encoded SubjectPublicKeyInfo (X.509), as returned by i2d_PUBKEY() -// (and *not* i2d_PublicKey(), which returns a PKCS#1 key). -// -// Also, the private key must be in PKCS#8 format, as returned by -// i2d_PKCS8_PRIV_KEY_INFO(EVP_PKEY2PKCS8(pkey)), which is a different -// format than what i2d_PrivateKey() returns, so don't use it either. -// +// Helper for the <keygen> handler. Passes the DER-encoded key pair via JNI to +// the Credentials store. The public key should be a DER-encoded +// SubjectPublicKeyInfo (X.509) and the private key a DER-encode PrivateKeyInfo +// (PKCS#8). bool StoreKeyPair(const uint8_t* public_key, size_t public_len, const uint8_t* private_key,
diff --git a/net/base/keygen_handler_mac.cc b/net/base/keygen_handler_mac.cc index 6737363..13814fe 100644 --- a/net/base/keygen_handler_mac.cc +++ b/net/base/keygen_handler_mac.cc
@@ -153,10 +153,15 @@ goto failure; } + // The DER encoding of a NULL. + static const uint8_t kNullDer[] = {0x05, 0x00}; + // Fill in and DER-encode the PublicKeyAndChallenge: SignedPublicKeyAndChallenge spkac; memset(&spkac, 0, sizeof(spkac)); spkac.pkac.spki.algorithm.algorithm = CSSMOID_RSA; + spkac.pkac.spki.algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer); + spkac.pkac.spki.algorithm.parameters.Length = sizeof(kNullDer); spkac.pkac.spki.subjectPublicKey.Length = CFDataGetLength(key_data) * 8; // interpreted as a _bit_ count spkac.pkac.spki.subjectPublicKey.Data = @@ -180,6 +185,8 @@ spkac.signature.Data = signature.Data; spkac.signature.Length = signature.Length * 8; // a _bit_ count spkac.signature_algorithm.algorithm = CSSMOID_MD5WithRSA; + spkac.signature_algorithm.parameters.Data = const_cast<uint8_t*>(kNullDer); + spkac.signature_algorithm.parameters.Length = sizeof(kNullDer); // TODO(snej): MD5 is weak. Can we use SHA1 instead? // See <https://bugzilla.mozilla.org/show_bug.cgi?id=549460>
diff --git a/net/base/keygen_handler_openssl.cc b/net/base/keygen_handler_openssl.cc index bc34012c..f72ca0e 100644 --- a/net/base/keygen_handler_openssl.cc +++ b/net/base/keygen_handler_openssl.cc
@@ -4,11 +4,18 @@ #include "net/base/keygen_handler.h" +#include <openssl/bytestring.h> +#include <openssl/digest.h> +#include <openssl/evp.h> #include <openssl/mem.h> -#include <openssl/ssl.h> +#include <stdint.h> +#include "base/base64.h" +#include "base/location.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/string_piece.h" +#include "crypto/auto_cbb.h" #include "crypto/openssl_util.h" #include "crypto/rsa_private_key.h" #include "crypto/scoped_openssl_types.h" @@ -24,21 +31,94 @@ if (stores_key_) OpenSSLPrivateKeyStore::StoreKeyPair(url_, pkey); - crypto::ScopedOpenSSL<NETSCAPE_SPKI, NETSCAPE_SPKI_free> spki( - NETSCAPE_SPKI_new()); - ASN1_STRING_set(spki.get()->spkac->challenge, - challenge_.data(), challenge_.size()); - NETSCAPE_SPKI_set_pubkey(spki.get(), pkey); - // Using MD5 as this is what is required in HTML5, even though the SPKI - // structure does allow the use of a SHA-1 signature. - NETSCAPE_SPKI_sign(spki.get(), pkey, EVP_md5()); - char* spkistr = NETSCAPE_SPKI_b64_encode(spki.get()); + // Serialize the following structure, from + // https://developer.mozilla.org/en-US/docs/Web/HTML/Element/keygen. + // + // PublicKeyAndChallenge ::= SEQUENCE { + // spki SubjectPublicKeyInfo, + // challenge IA5STRING + // } + // + // SignedPublicKeyAndChallenge ::= SEQUENCE { + // publicKeyAndChallenge PublicKeyAndChallenge, + // signatureAlgorithm AlgorithmIdentifier, + // signature BIT STRING + // } + // + // The signature is over the PublicKeyAndChallenge. - std::string result(spkistr); - OPENSSL_free(spkistr); + // TODO(davidben): If we gain another consumer, factor this code out into + // shared logic, sharing OID definitions with the verifier, to support signing + // other X.509-style structures. + crypto::OpenSSLErrStackTracer tracer(FROM_HERE); + + // Serialize up to the PublicKeyAndChallenge. + crypto::AutoCBB cbb; + CBB spkac, public_key_and_challenge, challenge; + if (!CBB_init(cbb.get(), 0) || + !CBB_add_asn1(cbb.get(), &spkac, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&spkac, &public_key_and_challenge, CBS_ASN1_SEQUENCE) || + !EVP_marshal_public_key(&public_key_and_challenge, pkey) || + !CBB_add_asn1(&public_key_and_challenge, &challenge, + CBS_ASN1_IA5STRING) || + !CBB_add_bytes(&challenge, + reinterpret_cast<const uint8_t*>(challenge_.data()), + challenge_.size()) || + !CBB_flush(&spkac)) { + return std::string(); + } + + // Hash what's been written so far. + crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); + if (!EVP_DigestSignInit(ctx.get(), nullptr, EVP_md5(), nullptr, pkey) || + !EVP_DigestSignUpdate(ctx.get(), CBB_data(&spkac), CBB_len(&spkac))) { + return std::string(); + } + + // The DER encoding of 1.2.840.113549.1.1.4, MD5 with RSA encryption. + static const uint8_t kMd5WithRsaEncryption[] = { + 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, + }; + + // Write the signatureAlgorithm. + CBB algorithm, oid, null; + if (!CBB_add_asn1(&spkac, &algorithm, CBS_ASN1_SEQUENCE) || + !CBB_add_asn1(&algorithm, &oid, CBS_ASN1_OBJECT) || + !CBB_add_bytes(&oid, kMd5WithRsaEncryption, + sizeof(kMd5WithRsaEncryption)) || + !CBB_add_asn1(&algorithm, &null, CBS_ASN1_NULL)) { + return std::string(); + } + + // Compute and write the signature. Note that X.509 signatures, although + // always byte strings for RSA, are encoded as BIT STRINGS with a multiple of + // 8 bits. + CBB sig_bitstring; + uint8_t* sig; + size_t sig_len; + if (!CBB_add_asn1(&spkac, &sig_bitstring, CBS_ASN1_BITSTRING) || + !CBB_add_u8(&sig_bitstring, 0 /* no unused bits */) || + // Determine the maximum length of the signature. + !EVP_DigestSignFinal(ctx.get(), nullptr, &sig_len) || + // Reserve |sig_len| bytes and write the signature to |spkac|. + !CBB_reserve(&sig_bitstring, &sig, sig_len) || + !EVP_DigestSignFinal(ctx.get(), sig, &sig_len) || + !CBB_did_write(&sig_bitstring, sig_len)) { + return std::string(); + } + + // Finally, the structure is base64-encoded. + uint8_t* der; + size_t der_len; + if (!CBB_finish(cbb.get(), &der, &der_len)) { + return std::string(); + } + std::string result; + base::Base64Encode( + base::StringPiece(reinterpret_cast<const char*>(der), der_len), &result); + OPENSSL_free(der); return result; } } // namespace net -
diff --git a/net/base/keygen_handler_unittest.cc b/net/base/keygen_handler_unittest.cc index c1b5fe4..b045abab 100644 --- a/net/base/keygen_handler_unittest.cc +++ b/net/base/keygen_handler_unittest.cc
@@ -4,6 +4,10 @@ #include "net/base/keygen_handler.h" +#include <openssl/bytestring.h> +#include <openssl/evp.h> +#include <stdint.h> + #include <string> #include <utility> @@ -11,10 +15,12 @@ #include "base/bind.h" #include "base/location.h" #include "base/logging.h" +#include "base/strings/string_piece.h" #include "base/synchronization/waitable_event.h" #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" #include "build/build_config.h" +#include "crypto/scoped_openssl_types.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(USE_NSS_CERTS) @@ -48,14 +54,16 @@ }; #endif +const char kChallenge[] = "some challenge"; + class KeygenHandlerTest : public ::testing::Test { public: KeygenHandlerTest() {} ~KeygenHandlerTest() override {} scoped_ptr<KeygenHandler> CreateKeygenHandler() { - scoped_ptr<KeygenHandler> handler(new KeygenHandler( - 768, "some challenge", GURL("http://www.example.com"))); + scoped_ptr<KeygenHandler> handler( + new KeygenHandler(768, kChallenge, GURL("http://www.example.com"))); #if defined(USE_NSS_CERTS) handler->set_crypto_module_delegate( scoped_ptr<crypto::NSSCryptoModuleDelegate>( @@ -71,40 +79,89 @@ #endif }; +base::StringPiece StringPieceFromCBS(const CBS& cbs) { + return base::StringPiece(reinterpret_cast<const char*>(CBS_data(&cbs)), + CBS_len(&cbs)); +} + // Assert that |result| is a valid output for KeygenHandler given challenge // string of |challenge|. void AssertValidSignedPublicKeyAndChallenge(const std::string& result, const std::string& challenge) { - ASSERT_GT(result.length(), 0U); - // Verify it's valid base64: std::string spkac; ASSERT_TRUE(base::Base64Decode(result, &spkac)); - // In lieu of actually parsing and validating the DER data, - // just check that it exists and has a reasonable length. - // (It's almost always 590 bytes, but the DER encoding of the random key - // and signature could sometimes be a few bytes different.) - ASSERT_GE(spkac.length(), 200U); - ASSERT_LE(spkac.length(), 300U); - // NOTE: - // The value of |result| can be validated by prefixing 'SPKAC=' to it - // and piping it through - // openssl spkac -verify - // whose output should look like: - // Netscape SPKI: - // Public Key Algorithm: rsaEncryption - // RSA Public Key: (2048 bit) - // Modulus (2048 bit): - // 00:b6:cc:14:c9:43:b5:2d:51:65:7e:11:8b:80:9e: ..... - // Exponent: 65537 (0x10001) - // Challenge String: some challenge - // Signature Algorithm: md5WithRSAEncryption - // 92:f3:cc:ff:0b:d3:d0:4a:3a:4c:ba:ff:d6:38:7f:a5:4b:b5: ..... - // Signature OK + // Parse the following structure: // - // The value of |spkac| can be ASN.1-parsed with: - // openssl asn1parse -inform DER + // PublicKeyAndChallenge ::= SEQUENCE { + // spki SubjectPublicKeyInfo, + // challenge IA5STRING + // } + // SignedPublicKeyAndChallenge ::= SEQUENCE { + // publicKeyAndChallenge PublicKeyAndChallenge, + // signatureAlgorithm AlgorithmIdentifier, + // signature BIT STRING + // } + + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spkac.data()), spkac.size()); + + // The input should consist of a SEQUENCE. + CBS child; + ASSERT_TRUE(CBS_get_asn1(&cbs, &child, CBS_ASN1_SEQUENCE)); + ASSERT_EQ(0u, CBS_len(&cbs)); + + // Extract the raw PublicKeyAndChallenge. + CBS public_key_and_challenge_raw; + ASSERT_TRUE(CBS_get_asn1_element(&child, &public_key_and_challenge_raw, + CBS_ASN1_SEQUENCE)); + + // Parse out the PublicKeyAndChallenge. + CBS copy = public_key_and_challenge_raw; + CBS public_key_and_challenge; + ASSERT_TRUE( + CBS_get_asn1(©, &public_key_and_challenge, CBS_ASN1_SEQUENCE)); + ASSERT_EQ(0u, CBS_len(©)); + crypto::ScopedEVP_PKEY key(EVP_parse_public_key(&public_key_and_challenge)); + ASSERT_TRUE(key); + CBS challenge_spkac; + ASSERT_TRUE(CBS_get_asn1(&public_key_and_challenge, &challenge_spkac, + CBS_ASN1_IA5STRING)); + ASSERT_EQ(0u, CBS_len(&public_key_and_challenge)); + + // The challenge must match. + ASSERT_EQ(challenge, StringPieceFromCBS(challenge_spkac)); + + // The next element must be the AlgorithmIdentifier for MD5 with RSA. + static const uint8_t kMd5WithRsaEncryption[] = { + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, + }; + CBS algorithm; + ASSERT_TRUE(CBS_get_bytes(&child, &algorithm, sizeof(kMd5WithRsaEncryption))); + ASSERT_EQ( + base::StringPiece(reinterpret_cast<const char*>(kMd5WithRsaEncryption), + sizeof(kMd5WithRsaEncryption)), + StringPieceFromCBS(algorithm)); + + // Finally, parse the signature. + CBS signature; + ASSERT_TRUE(CBS_get_asn1(&child, &signature, CBS_ASN1_BITSTRING)); + ASSERT_EQ(0u, CBS_len(&child)); + uint8_t pad; + ASSERT_TRUE(CBS_get_u8(&signature, &pad)); + ASSERT_EQ(0u, pad); + + // Check the signature. + crypto::ScopedEVP_MD_CTX ctx(EVP_MD_CTX_create()); + ASSERT_TRUE( + EVP_DigestVerifyInit(ctx.get(), nullptr, EVP_md5(), nullptr, key.get())); + ASSERT_TRUE(EVP_DigestVerifyUpdate(ctx.get(), + CBS_data(&public_key_and_challenge_raw), + CBS_len(&public_key_and_challenge_raw))); + ASSERT_TRUE(EVP_DigestVerifyFinal(ctx.get(), CBS_data(&signature), + CBS_len(&signature))); } TEST_F(KeygenHandlerTest, SmokeTest) { @@ -112,7 +169,7 @@ handler->set_stores_key(false); // Don't leave the key-pair behind std::string result = handler->GenKeyAndSignChallenge(); VLOG(1) << "KeygenHandler produced: " << result; - AssertValidSignedPublicKeyAndChallenge(result, "some challenge"); + AssertValidSignedPublicKeyAndChallenge(result, kChallenge); } void ConcurrencyTestCallback(const std::string& challenge,
diff --git a/net/base/openssl_private_key_store_android.cc b/net/base/openssl_private_key_store_android.cc index 538b4746..424f72f 100644 --- a/net/base/openssl_private_key_store_android.cc +++ b/net/base/openssl_private_key_store_android.cc
@@ -4,47 +4,47 @@ #include "net/base/openssl_private_key_store.h" +#include <openssl/bytestring.h> #include <openssl/evp.h> #include <openssl/mem.h> -#include <openssl/x509.h> #include "base/logging.h" #include "base/memory/singleton.h" +#include "crypto/auto_cbb.h" #include "crypto/openssl_util.h" +#include "crypto/scoped_openssl_types.h" #include "net/android/network_library.h" -#include "net/ssl/scoped_openssl_types.h" namespace net { -bool OpenSSLPrivateKeyStore::StoreKeyPair(const GURL& url, - EVP_PKEY* pkey) { +bool OpenSSLPrivateKeyStore::StoreKeyPair(const GURL& url, EVP_PKEY* pkey) { // Always clear openssl errors on exit. crypto::OpenSSLErrStackTracer err_trace(FROM_HERE); - // Important: Do not use i2d_PublicKey() here, which returns data in - // PKCS#1 format, use i2d_PUBKEY() which returns it as DER-encoded - // SubjectPublicKeyInfo (X.509), as expected by the platform. - unsigned char* public_key = NULL; - int public_len = i2d_PUBKEY(pkey, &public_key); - - // Important: Do not use i2d_PrivateKey() here, it returns data - // in a format that is incompatible with what the platform expects. - unsigned char* private_key = NULL; - int private_len = 0; - ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey)); - if (pkcs8) - private_len = i2d_PKCS8_PRIV_KEY_INFO(pkcs8.get(), &private_key); - bool ret = false; - if (public_len > 0 && private_len > 0) { - ret = android::StoreKeyPair( - static_cast<const uint8_t*>(public_key), public_len, - static_cast<const uint8_t*>(private_key), private_len); + uint8_t* public_key; + size_t public_len; + crypto::AutoCBB cbb; + if (!CBB_init(cbb.get(), 0) || !EVP_marshal_public_key(cbb.get(), pkey) || + !CBB_finish(cbb.get(), &public_key, &public_len)) { + return false; } - LOG_IF(ERROR, !ret) << "StoreKeyPair failed. pub len = " << public_len - << " priv len = " << private_len; - OPENSSL_free(public_key); - OPENSSL_free(private_key); - return ret; + crypto::ScopedOpenSSLBytes free_public_key(public_key); + + uint8_t* private_key; + size_t private_len; + cbb.Reset(); + if (!CBB_init(cbb.get(), 0) || !EVP_marshal_private_key(cbb.get(), pkey) || + !CBB_finish(cbb.get(), &private_key, &private_len)) { + return false; + } + crypto::ScopedOpenSSLBytes free_private_key(private_key); + + if (!android::StoreKeyPair(public_key, public_len, private_key, + private_len)) { + LOG(ERROR) << "StoreKeyPair failed. public_len = " << public_len + << " private_len = " << private_len; + } + return true; } } // namespace net
diff --git a/net/cert/ct_log_verifier_openssl.cc b/net/cert/ct_log_verifier_openssl.cc index 5fe41fd..88f9027c 100644 --- a/net/cert/ct_log_verifier_openssl.cc +++ b/net/cert/ct_log_verifier_openssl.cc
@@ -4,8 +4,8 @@ #include "net/cert/ct_log_verifier.h" +#include <openssl/bytestring.h> #include <openssl/evp.h> -#include <openssl/x509.h> #include "base/logging.h" #include "crypto/openssl_util.h" @@ -50,10 +50,11 @@ bool CTLogVerifier::Init(const base::StringPiece& public_key) { crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - const uint8_t* ptr = reinterpret_cast<const uint8_t*>(public_key.data()); - const uint8_t* end = ptr + public_key.size(); - public_key_ = d2i_PUBKEY(nullptr, &ptr, public_key.size()); - if (!public_key_ || ptr != end) + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(public_key.data()), + public_key.size()); + public_key_ = EVP_parse_public_key(&cbs); + if (!public_key_ || CBS_len(&cbs) != 0) return false; key_id_ = crypto::SHA256HashString(public_key);
diff --git a/net/cert/internal/verify_signed_data.cc b/net/cert/internal/verify_signed_data.cc index 9b0ebd4..eb0fd3ff 100644 --- a/net/cert/internal/verify_signed_data.cc +++ b/net/cert/internal/verify_signed_data.cc
@@ -29,12 +29,12 @@ #else +#include <openssl/bytestring.h> #include <openssl/digest.h> #include <openssl/ec.h> #include <openssl/ec_key.h> #include <openssl/evp.h> #include <openssl/rsa.h> -#include <openssl/x509.h> #include "base/compiler_specific.h" #include "crypto/openssl_util.h" @@ -97,9 +97,10 @@ crypto::ScopedEVP_PKEY* pkey) { crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - const uint8_t* ptr = spki.UnsafeData(); - pkey->reset(d2i_PUBKEY(nullptr, &ptr, spki.Length())); - if (!pkey->get() || ptr != spki.UnsafeData() + spki.Length() || + CBS cbs; + CBS_init(&cbs, spki.UnsafeData(), spki.Length()); + pkey->reset(EVP_parse_public_key(&cbs)); + if (!*pkey || CBS_len(&cbs) != 0 || EVP_PKEY_id(pkey->get()) != expected_pkey_id) { pkey->reset(); return false;
diff --git a/net/cert/internal/verify_signed_data_unittest.cc b/net/cert/internal/verify_signed_data_unittest.cc index 239aaae..43a4856b 100644 --- a/net/cert/internal/verify_signed_data_unittest.cc +++ b/net/cert/internal/verify_signed_data_unittest.cc
@@ -101,9 +101,7 @@ } TEST(VerifySignedDataTest, RsaPkcs1Sha256KeyEncodedBer) { - // TODO(eroman): This should fail! (SPKI should be DER-encoded). See - // https://crbug.com/522228 - RunTestCase(SUCCESS, "rsa-pkcs1-sha256-key-encoded-ber.pem"); + RunTestCase(FAILURE, "rsa-pkcs1-sha256-key-encoded-ber.pem"); } TEST(VerifySignedDataTest, EcdsaSecp384r1Sha256) {
diff --git a/net/cert/jwk_serializer_openssl.cc b/net/cert/jwk_serializer_openssl.cc index f5afd4f..12c8e4d 100644 --- a/net/cert/jwk_serializer_openssl.cc +++ b/net/cert/jwk_serializer_openssl.cc
@@ -5,10 +5,10 @@ #include "net/cert/jwk_serializer.h" #include <openssl/bn.h> +#include <openssl/bytestring.h> #include <openssl/ec.h> #include <openssl/ec_key.h> #include <openssl/evp.h> -#include <openssl/x509.h> #include "base/base64url.h" #include "base/logging.h" @@ -96,10 +96,11 @@ crypto::EnsureOpenSSLInit(); crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); - const uint8_t *data = reinterpret_cast<const uint8_t*>(spki_der.data()); - const uint8_t *ptr = data; - crypto::ScopedEVP_PKEY pubkey(d2i_PUBKEY(NULL, &ptr, spki_der.size())); - if (!pubkey || ptr != data + spki_der.size()) + CBS cbs; + CBS_init(&cbs, reinterpret_cast<const uint8_t*>(spki_der.data()), + spki_der.size()); + crypto::ScopedEVP_PKEY pubkey(EVP_parse_public_key(&cbs)); + if (!pubkey || CBS_len(&cbs) != 0) return false; if (pubkey->type == EVP_PKEY_EC) {
diff --git a/net/disk_cache/simple/simple_backend_impl.cc b/net/disk_cache/simple/simple_backend_impl.cc index 9f410ed..00f6d15 100644 --- a/net/disk_cache/simple/simple_backend_impl.cc +++ b/net/disk_cache/simple/simple_backend_impl.cc
@@ -295,8 +295,8 @@ to_run_closures.swap(it->second); entries_pending_doom_.erase(it); - std::for_each(to_run_closures.begin(), to_run_closures.end(), - std::mem_fun_ref(&Closure::Run)); + for (auto& closure : to_run_closures) + closure.Run(); } void SimpleBackendImpl::DoomEntries(std::vector<uint64_t>* entry_hashes,
diff --git a/net/log/net_log_util.cc b/net/log/net_log_util.cc index 4d4dfa6..a0884207 100644 --- a/net/log/net_log_util.cc +++ b/net/log/net_log_util.cc
@@ -274,10 +274,21 @@ // Information about how the "time ticks" values we have given it relate to // actual system times. Time ticks are used throughout since they are stable - // across system clock changes. + // across system clock changes. Note: |timeTickOffset| is only comparable to + // TimeTicks values in milliseconds. + // TODO(csharrison): This is an imprecise way to convert TimeTicks to unix + // time. In fact, there isn't really a good way to do this unless we log Time + // and TimeTicks values side by side for every event. crbug.com/593157 tracks + // a change where the user will be notified if a timing anomaly occured that + // would skew the conversion (i.e. the machine entered suspend mode while + // logging). { + base::TimeDelta time_since_epoch = + base::Time::Now() - base::Time::UnixEpoch(); + base::TimeDelta reference_time_ticks = + base::TimeTicks::Now() - base::TimeTicks(); int64_t tick_to_unix_time_ms = - (base::TimeTicks() - base::TimeTicks::UnixEpoch()).InMilliseconds(); + (time_since_epoch - reference_time_ticks).InMilliseconds(); // Pass it as a string, since it may be too large to fit in an integer. constants_dict->SetString("timeTickOffset",
diff --git a/net/net.gypi b/net/net.gypi index fec3bcc..762355d 100644 --- a/net/net.gypi +++ b/net/net.gypi
@@ -236,10 +236,6 @@ 'quic/congestion_control/rtt_stats.h', 'quic/congestion_control/send_algorithm_interface.cc', 'quic/congestion_control/send_algorithm_interface.h', - 'quic/congestion_control/tcp_cubic_bytes_sender.cc', - 'quic/congestion_control/tcp_cubic_bytes_sender.h', - 'quic/congestion_control/tcp_cubic_sender.cc', - 'quic/congestion_control/tcp_cubic_sender.h', 'quic/congestion_control/tcp_cubic_sender_base.cc', 'quic/congestion_control/tcp_cubic_sender_base.h', 'quic/congestion_control/tcp_cubic_sender_bytes.cc', @@ -1549,8 +1545,6 @@ 'quic/congestion_control/rtt_stats_test.cc', 'quic/congestion_control/send_algorithm_simulator.cc', 'quic/congestion_control/send_algorithm_simulator.h', - 'quic/congestion_control/tcp_cubic_bytes_sender_test.cc', - 'quic/congestion_control/tcp_cubic_sender_test.cc', 'quic/congestion_control/tcp_cubic_sender_bytes_test.cc', 'quic/congestion_control/tcp_cubic_sender_packets_test.cc', 'quic/crypto/aes_128_gcm_12_decrypter_test.cc',
diff --git a/net/quic/congestion_control/pacing_sender_test.cc b/net/quic/congestion_control/pacing_sender_test.cc index 4cd5ac6e9..d5e2fc0 100644 --- a/net/quic/congestion_control/pacing_sender_test.cc +++ b/net/quic/congestion_control/pacing_sender_test.cc
@@ -91,8 +91,9 @@ .WillOnce(Return(zero_time_)); // Verify that the packet is delayed. EXPECT_EQ(delay.ToMicroseconds(), - pacing_sender_->TimeUntilSend(clock_.Now(), kBytesInFlight, - HAS_RETRANSMITTABLE_DATA) + pacing_sender_ + ->TimeUntilSend(clock_.Now(), kBytesInFlight, + HAS_RETRANSMITTABLE_DATA) .ToMicroseconds()); } }
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc index 20821a6..83de14f 100644 --- a/net/quic/congestion_control/send_algorithm_interface.cc +++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -4,8 +4,6 @@ #include "net/quic/congestion_control/send_algorithm_interface.h" -#include "net/quic/congestion_control/tcp_cubic_bytes_sender.h" -#include "net/quic/congestion_control/tcp_cubic_sender.h" #include "net/quic/congestion_control/tcp_cubic_sender_bytes.h" #include "net/quic/congestion_control/tcp_cubic_sender_packets.h" #include "net/quic/quic_flags.h" @@ -27,39 +25,19 @@ kDefaultTCPMSS; switch (congestion_control_type) { case kCubic: - if (FLAGS_quic_use_new_tcp_sender) { - return new TcpCubicSenderPackets( - clock, rtt_stats, false /* don't use Reno */, - initial_congestion_window, max_congestion_window, stats); - } - return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */, - initial_congestion_window, - max_congestion_window, stats); + return new TcpCubicSenderPackets( + clock, rtt_stats, false /* don't use Reno */, + initial_congestion_window, max_congestion_window, stats); case kCubicBytes: - if (FLAGS_quic_use_new_tcp_sender) { - return new TcpCubicSenderBytes( - clock, rtt_stats, false /* don't use Reno */, - initial_congestion_window, max_congestion_window, stats); - } - return new TcpCubicBytesSender( + return new TcpCubicSenderBytes( clock, rtt_stats, false /* don't use Reno */, initial_congestion_window, max_congestion_window, stats); case kReno: - if (FLAGS_quic_use_new_tcp_sender) { - return new TcpCubicSenderPackets(clock, rtt_stats, true /* use Reno */, - initial_congestion_window, - max_congestion_window, stats); - } - return new TcpCubicSender(clock, rtt_stats, true /* use Reno */, - initial_congestion_window, - max_congestion_window, stats); - case kRenoBytes: - if (FLAGS_quic_use_new_tcp_sender) { - return new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */, + return new TcpCubicSenderPackets(clock, rtt_stats, true /* use Reno */, initial_congestion_window, max_congestion_window, stats); - } - return new TcpCubicBytesSender(clock, rtt_stats, true /* use Reno */, + case kRenoBytes: + return new TcpCubicSenderBytes(clock, rtt_stats, true /* use Reno */, initial_congestion_window, max_congestion_window, stats); case kBBR:
diff --git a/net/quic/congestion_control/tcp_cubic_bytes_sender.cc b/net/quic/congestion_control/tcp_cubic_bytes_sender.cc deleted file mode 100644 index 2ceb719..0000000 --- a/net/quic/congestion_control/tcp_cubic_bytes_sender.cc +++ /dev/null
@@ -1,390 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/congestion_control/tcp_cubic_bytes_sender.h" - -#include <algorithm> - -#include "net/quic/congestion_control/prr_sender.h" -#include "net/quic/congestion_control/rtt_stats.h" -#include "net/quic/crypto/crypto_protocol.h" -#include "net/quic/proto/cached_network_parameters.pb.h" -#include "net/quic/quic_bug_tracker.h" -#include "net/quic/quic_flags.h" - -using std::max; -using std::min; - -namespace net { - -namespace { -// Constants based on TCP defaults. -// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a -// fast retransmission. -const QuicByteCount kDefaultMinimumCongestionWindow = 2 * kDefaultTCPMSS; -const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; -const float kRenoBeta = 0.7f; // Reno backoff factor. -const uint32_t kDefaultNumConnections = 2; // N-connection emulation. -} // namespace - -TcpCubicBytesSender::TcpCubicBytesSender( - const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_congestion_window, - QuicConnectionStats* stats) - : cubic_(clock), - rtt_stats_(rtt_stats), - stats_(stats), - reno_(reno), - num_connections_(kDefaultNumConnections), - num_acked_packets_(0), - largest_sent_packet_number_(0), - largest_acked_packet_number_(0), - largest_sent_at_last_cutback_(0), - congestion_window_(initial_tcp_congestion_window * kDefaultTCPMSS), - min_congestion_window_(kDefaultMinimumCongestionWindow), - min4_mode_(false), - max_congestion_window_(max_congestion_window * kDefaultTCPMSS), - slowstart_threshold_(max_congestion_window * kDefaultTCPMSS), - last_cutback_exited_slowstart_(false), - initial_tcp_congestion_window_(initial_tcp_congestion_window * - kDefaultTCPMSS), - initial_max_tcp_congestion_window_(max_congestion_window * - kDefaultTCPMSS), - slow_start_large_reduction_(false) {} - -TcpCubicBytesSender::~TcpCubicBytesSender() {} - -void TcpCubicBytesSender::SetFromConfig(const QuicConfig& config, - Perspective perspective) { - if (perspective == Perspective::IS_SERVER) { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { - // Initial window experiment. - congestion_window_ = 10 * kDefaultTCPMSS; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { - // Min CWND experiment. - min_congestion_window_ = kDefaultTCPMSS; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { - // Min CWND of 4 experiment. - min4_mode_ = true; - min_congestion_window_ = kDefaultTCPMSS; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kSSLR)) { - // Slow Start Fast Exit experiment. - slow_start_large_reduction_ = true; - } - } -} - -void TcpCubicBytesSender::ResumeConnectionState( - const CachedNetworkParameters& cached_network_params, - bool max_bandwidth_resumption) { - QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( - max_bandwidth_resumption - ? cached_network_params.max_bandwidth_estimate_bytes_per_second() - : cached_network_params.bandwidth_estimate_bytes_per_second()); - QuicTime::Delta rtt_ms = - QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); - - // Make sure CWND is in appropriate range (in case of bad data). - QuicByteCount new_congestion_window = bandwidth.ToBytesPerPeriod(rtt_ms); - congestion_window_ = - max(min(new_congestion_window, kMaxCongestionWindow * kDefaultTCPMSS), - kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS); -} - -void TcpCubicBytesSender::SetNumEmulatedConnections(int num_connections) { - num_connections_ = max(1, num_connections); - cubic_.SetNumConnections(num_connections_); -} - -void TcpCubicBytesSender::SetMaxCongestionWindow( - QuicByteCount max_congestion_window) { - max_congestion_window_ = max_congestion_window; -} - -float TcpCubicBytesSender::RenoBeta() const { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (num_connections_ - 1 + kRenoBeta) / num_connections_; -} - -void TcpCubicBytesSender::OnCongestionEvent( - bool rtt_updated, - QuicByteCount bytes_in_flight, - const CongestionVector& acked_packets, - const CongestionVector& lost_packets) { - if (rtt_updated && InSlowStart() && - hybrid_slow_start_.ShouldExitSlowStart( - rtt_stats_->latest_rtt(), rtt_stats_->min_rtt(), - congestion_window_ / kDefaultTCPMSS)) { - slowstart_threshold_ = congestion_window_; - } - for (CongestionVector::const_iterator it = lost_packets.begin(); - it != lost_packets.end(); ++it) { - OnPacketLost(it->first, bytes_in_flight); - } - for (CongestionVector::const_iterator it = acked_packets.begin(); - it != acked_packets.end(); ++it) { - OnPacketAcked(it->first, it->second, bytes_in_flight); - } -} - -void TcpCubicBytesSender::OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight) { - largest_acked_packet_number_ = - max(acked_packet_number, largest_acked_packet_number_); - if (InRecovery()) { - // PRR is used when in recovery. - prr_.OnPacketAcked(acked_bytes); - return; - } - MaybeIncreaseCwnd(acked_packet_number, acked_bytes, bytes_in_flight); - if (InSlowStart()) { - hybrid_slow_start_.OnPacketAcked(acked_packet_number); - } -} - -void TcpCubicBytesSender::OnPacketLost(QuicPacketNumber packet_number, - QuicByteCount bytes_in_flight) { - // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets - // already sent should be treated as a single loss event, since it's expected. - if (packet_number <= largest_sent_at_last_cutback_) { - if (last_cutback_exited_slowstart_) { - ++stats_->slowstart_packets_lost; - if (slow_start_large_reduction_) { - // Reduce congestion window by 1 MSS for every loss. - congestion_window_ = - max(congestion_window_ - kDefaultTCPMSS, min_congestion_window_); - slowstart_threshold_ = congestion_window_; - } - } - DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number - << " because it was sent prior to the last CWND cutback."; - return; - } - ++stats_->tcp_loss_events; - last_cutback_exited_slowstart_ = InSlowStart(); - if (InSlowStart()) { - ++stats_->slowstart_packets_lost; - } - - prr_.OnPacketLost(bytes_in_flight); - - // TODO(jri): Separate out all of slow start into a separate class. - if (slow_start_large_reduction_ && InSlowStart()) { - DCHECK_LT(kDefaultTCPMSS, congestion_window_); - congestion_window_ = congestion_window_ - kDefaultTCPMSS; - } else if (reno_) { - congestion_window_ = congestion_window_ * RenoBeta(); - } else { - congestion_window_ = - cubic_.CongestionWindowAfterPacketLoss(congestion_window_); - } - // Enforce TCP's minimum congestion window of 2*MSS. - if (congestion_window_ < min_congestion_window_) { - congestion_window_ = min_congestion_window_; - } - slowstart_threshold_ = congestion_window_; - largest_sent_at_last_cutback_ = largest_sent_packet_number_; - // Reset packet count from congestion avoidance mode. We start counting again - // when we're out of recovery. - num_acked_packets_ = 0; - DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; -} - -bool TcpCubicBytesSender::OnPacketSent( - QuicTime /*sent_time*/, - QuicByteCount /*bytes_in_flight*/, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) { - if (InSlowStart()) { - ++(stats_->slowstart_packets_sent); - } - - // Only update bytes_in_flight_ for data packets. - if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { - return false; - } - if (InRecovery()) { - // PRR is used when in recovery. - prr_.OnPacketSent(bytes); - } - DCHECK_LT(largest_sent_packet_number_, packet_number); - largest_sent_packet_number_ = packet_number; - hybrid_slow_start_.OnPacketSent(packet_number); - return true; -} - -QuicTime::Delta TcpCubicBytesSender::TimeUntilSend( - QuicTime /* now */, - QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) const { - if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { - DCHECK(!FLAGS_quic_respect_send_alarm2); - // For TCP we can always send an ACK immediately. - return QuicTime::Delta::Zero(); - } - if (InRecovery()) { - // PRR is used when in recovery. - return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, - slowstart_threshold_); - } - if (GetCongestionWindow() > bytes_in_flight) { - return QuicTime::Delta::Zero(); - } - if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { - return QuicTime::Delta::Zero(); - } - return QuicTime::Delta::Infinite(); -} - -QuicBandwidth TcpCubicBytesSender::PacingRate() const { - // We pace at twice the rate of the underlying sender's bandwidth estimate - // during slow start and 1.25x during congestion avoidance to ensure pacing - // doesn't prevent us from filling the window. - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); - } - const QuicBandwidth bandwidth = - QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); - return bandwidth.Scale(InSlowStart() ? 2 : 1.25); -} - -QuicBandwidth TcpCubicBytesSender::BandwidthEstimate() const { - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return QuicBandwidth::Zero(); - } - return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); -} - -QuicTime::Delta TcpCubicBytesSender::RetransmissionDelay() const { - if (rtt_stats_->smoothed_rtt().IsZero()) { - return QuicTime::Delta::Zero(); - } - return rtt_stats_->smoothed_rtt().Add( - rtt_stats_->mean_deviation().Multiply(4)); -} - -QuicByteCount TcpCubicBytesSender::GetCongestionWindow() const { - return congestion_window_; -} - -bool TcpCubicBytesSender::InSlowStart() const { - return congestion_window_ < slowstart_threshold_; -} - -QuicByteCount TcpCubicBytesSender::GetSlowStartThreshold() const { - return slowstart_threshold_; -} - -bool TcpCubicBytesSender::IsCwndLimited(QuicByteCount bytes_in_flight) const { - if (bytes_in_flight >= congestion_window_) { - return true; - } - const QuicByteCount available_bytes = congestion_window_ - bytes_in_flight; - const bool slow_start_limited = - InSlowStart() && bytes_in_flight > congestion_window_ / 2; - return slow_start_limited || available_bytes <= kMaxBurstBytes; -} - -bool TcpCubicBytesSender::InRecovery() const { - return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ && - largest_acked_packet_number_ != 0; -} - -// Called when we receive an ack. Normal TCP tracks how many packets one ack -// represents, but quic has a separate ack for each packet. -void TcpCubicBytesSender::MaybeIncreaseCwnd( - QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight) { - QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery."; - // Do not increase the congestion window unless the sender is close to using - // the current window. - if (!IsCwndLimited(bytes_in_flight)) { - cubic_.OnApplicationLimited(); - return; - } - if (congestion_window_ >= max_congestion_window_) { - return; - } - if (InSlowStart()) { - // TCP slow start, exponential growth, increase by one for each ACK. - congestion_window_ += kDefaultTCPMSS; - DVLOG(1) << "Slow start; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; - return; - } - // Congestion avoidance. - if (reno_) { - // Classic Reno congestion avoidance. - ++num_acked_packets_; - // Divide by num_connections to smoothly increase the CWND at a faster rate - // than conventional Reno. - if (num_acked_packets_ * num_connections_ >= - congestion_window_ / kDefaultTCPMSS) { - congestion_window_ += kDefaultTCPMSS; - num_acked_packets_ = 0; - } - - DVLOG(1) << "Reno; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_ - << " congestion window count: " << num_acked_packets_; - } else { - congestion_window_ = - min(max_congestion_window_, - cubic_.CongestionWindowAfterAck(acked_bytes, congestion_window_, - rtt_stats_->min_rtt())); - DVLOG(1) << "Cubic; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; - } -} - -void TcpCubicBytesSender::OnRetransmissionTimeout(bool packets_retransmitted) { - largest_sent_at_last_cutback_ = 0; - if (!packets_retransmitted) { - return; - } - cubic_.Reset(); - hybrid_slow_start_.Restart(); - slowstart_threshold_ = congestion_window_ / 2; - congestion_window_ = min_congestion_window_; -} - -CongestionControlType TcpCubicBytesSender::GetCongestionControlType() const { - return reno_ ? kRenoBytes : kCubicBytes; -} - -void TcpCubicBytesSender::OnConnectionMigration() { - hybrid_slow_start_.Restart(); - cubic_.Reset(); - prr_ = PrrSender(); - num_acked_packets_ = 0; - largest_sent_packet_number_ = 0; - largest_acked_packet_number_ = 0; - largest_sent_at_last_cutback_ = 0; - congestion_window_ = initial_tcp_congestion_window_; - max_congestion_window_ = initial_max_tcp_congestion_window_; - slowstart_threshold_ = initial_max_tcp_congestion_window_; - last_cutback_exited_slowstart_ = false; -} - -} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_bytes_sender.h b/net/quic/congestion_control/tcp_cubic_bytes_sender.h deleted file mode 100644 index e1b0185..0000000 --- a/net/quic/congestion_control/tcp_cubic_bytes_sender.h +++ /dev/null
@@ -1,151 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic. - -#ifndef NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_BYTES_SENDER_H_ -#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_BYTES_SENDER_H_ - -#include <stdint.h> - -#include "base/macros.h" -#include "net/base/net_export.h" -#include "net/quic/congestion_control/cubic_bytes.h" -#include "net/quic/congestion_control/hybrid_slow_start.h" -#include "net/quic/congestion_control/prr_sender.h" -#include "net/quic/congestion_control/send_algorithm_interface.h" -#include "net/quic/quic_bandwidth.h" -#include "net/quic/quic_connection_stats.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/quic_time.h" - -namespace net { - -class RttStats; - -namespace test { -class TcpCubicBytesSenderPeer; -} // namespace test - -class NET_EXPORT_PRIVATE TcpCubicBytesSender : public SendAlgorithmInterface { - public: - TcpCubicBytesSender(const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_congestion_window, - QuicConnectionStats* stats); - ~TcpCubicBytesSender() override; - - // Start implementation of SendAlgorithmInterface. - void SetFromConfig(const QuicConfig& config, - Perspective perspective) override; - void ResumeConnectionState( - const CachedNetworkParameters& cached_network_params, - bool max_bandwidth_resumption) override; - void SetNumEmulatedConnections(int num_connections) override; - void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override; - void OnCongestionEvent(bool rtt_updated, - QuicByteCount bytes_in_flight, - const CongestionVector& acked_packets, - const CongestionVector& lost_packets) override; - bool OnPacketSent(QuicTime sent_time, - QuicByteCount bytes_in_flight, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) override; - void OnRetransmissionTimeout(bool packets_retransmitted) override; - void OnConnectionMigration() override; - QuicTime::Delta TimeUntilSend( - QuicTime now, - QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) const override; - QuicBandwidth PacingRate() const override; - QuicBandwidth BandwidthEstimate() const override; - QuicTime::Delta RetransmissionDelay() const override; - QuicByteCount GetCongestionWindow() const override; - bool InSlowStart() const override; - bool InRecovery() const override; - QuicByteCount GetSlowStartThreshold() const override; - CongestionControlType GetCongestionControlType() const override; - // End implementation of SendAlgorithmInterface. - - private: - friend class test::TcpCubicBytesSenderPeer; - - // Compute the TCP Reno beta based on the current number of connections. - float RenoBeta() const; - - // TODO(ianswett): Remove these and migrate to OnCongestionEvent. - void OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight); - void OnPacketLost(QuicPacketNumber largest_loss, - QuicByteCount bytes_in_flight); - - void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight); - bool IsCwndLimited(QuicByteCount bytes_in_flight) const; - - HybridSlowStart hybrid_slow_start_; - CubicBytes cubic_; - PrrSender prr_; - const RttStats* rtt_stats_; - QuicConnectionStats* stats_; - - // If true, Reno congestion control is used instead of Cubic. - const bool reno_; - - // Number of connections to simulate. - uint32_t num_connections_; - - // ACK counter for the Reno implementation. - uint64_t num_acked_packets_; - - // Track the largest packet that has been sent. - QuicPacketNumber largest_sent_packet_number_; - - // Track the largest packet that has been acked. - QuicPacketNumber largest_acked_packet_number_; - - // Track the largest packet number outstanding when a CWND cutback occurs. - QuicPacketNumber largest_sent_at_last_cutback_; - - // Congestion window in bytes. - QuicByteCount congestion_window_; - - // Minimum congestion window in bytes. - QuicByteCount min_congestion_window_; - - // Whether to use 4 packets as the actual min, but pace lower. - bool min4_mode_; - - // Maximum congestion window in bytes. - QuicByteCount max_congestion_window_; - - // Slow start congestion window in bytes, aka ssthresh. - QuicByteCount slowstart_threshold_; - - // Whether the last loss event caused us to exit slowstart. Used for stats - // collection of slowstart_packets_lost. - bool last_cutback_exited_slowstart_; - - // Initial TCP congestion window in bytes. This variable can only be set when - // this algorithm is created. - const QuicByteCount initial_tcp_congestion_window_; - - // Initial maximum TCP congestion window in bytes. This variable can only be - // set when this algorithm is created. - const QuicByteCount initial_max_tcp_congestion_window_; - - // When true, exit slow start with large cutback of congestion window. - bool slow_start_large_reduction_; - - DISALLOW_COPY_AND_ASSIGN(TcpCubicBytesSender); -}; - -} // namespace net - -#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_BYTES_SENDER_H_
diff --git a/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc b/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc deleted file mode 100644 index 30894356..0000000 --- a/net/quic/congestion_control/tcp_cubic_bytes_sender_test.cc +++ /dev/null
@@ -1,743 +0,0 @@ -// Copyright (c) 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/congestion_control/tcp_cubic_bytes_sender.h" - -#include <algorithm> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "net/quic/congestion_control/rtt_stats.h" -#include "net/quic/crypto/crypto_protocol.h" -#include "net/quic/proto/cached_network_parameters.pb.h" -#include "net/quic/quic_flags.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/quic_utils.h" -#include "net/quic/test_tools/mock_clock.h" -#include "net/quic/test_tools/quic_config_peer.h" -#include "net/quic/test_tools/quic_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { -namespace test { - -// TODO(ianswett): A number of theses tests were written with the assumption of -// an initial CWND of 10. They have carefully calculated values which should be -// updated to be based on kInitialCongestionWindow. -const uint32_t kInitialCongestionWindowPackets = 10; -const uint32_t kDefaultWindowTCP = - kInitialCongestionWindowPackets * kDefaultTCPMSS; -const float kRenoBeta = 0.7f; // Reno backoff factor. - -class TcpCubicBytesSenderPeer : public TcpCubicBytesSender { - public: - TcpCubicBytesSenderPeer(const QuicClock* clock, bool reno) - : TcpCubicBytesSender(clock, - &rtt_stats_, - reno, - kInitialCongestionWindowPackets, - kMaxCongestionWindow, - &stats_) {} - - const HybridSlowStart& hybrid_slow_start() const { - return hybrid_slow_start_; - } - - float GetRenoBeta() const { return RenoBeta(); } - - RttStats rtt_stats_; - QuicConnectionStats stats_; -}; - -class TcpCubicBytesSenderTest : public ::testing::Test { - protected: - TcpCubicBytesSenderTest() - : one_ms_(QuicTime::Delta::FromMilliseconds(1)), - sender_(new TcpCubicBytesSenderPeer(&clock_, true)), - packet_number_(1), - acked_packet_number_(0), - bytes_in_flight_(0) {} - - int SendAvailableSendWindow() { - // Send as long as TimeUntilSend returns Zero. - int packets_sent = 0; - bool can_send = sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero(); - while (can_send) { - sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++, - kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA); - ++packets_sent; - bytes_in_flight_ += kDefaultTCPMSS; - can_send = sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero(); - } - return packets_sent; - } - - // Normal is that TCP acks every other segment. - void AckNPackets(int n) { - sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60), - QuicTime::Delta::Zero(), clock_.Now()); - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - for (int i = 0; i < n; ++i) { - ++acked_packet_number_; - acked_packets.push_back( - std::make_pair(acked_packet_number_, kDefaultTCPMSS)); - } - sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= n * kDefaultTCPMSS; - clock_.AdvanceTime(one_ms_); - } - - void LoseNPackets(int n) { - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - for (int i = 0; i < n; ++i) { - ++acked_packet_number_; - lost_packets.push_back( - std::make_pair(acked_packet_number_, kDefaultTCPMSS)); - } - sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= n * kDefaultTCPMSS; - } - - // Does not increment acked_packet_number_. - void LosePacket(QuicPacketNumber packet_number) { - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS)); - sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= kDefaultTCPMSS; - } - - const QuicTime::Delta one_ms_; - MockClock clock_; - scoped_ptr<TcpCubicBytesSenderPeer> sender_; - QuicPacketNumber packet_number_; - QuicPacketNumber acked_packet_number_; - QuicByteCount bytes_in_flight_; -}; - -TEST_F(TcpCubicBytesSenderTest, SimpleSender) { - // At startup make sure we are at the default. - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // And that window is un-affected. - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - - // Fill the send window with data, then verify that we can't send. - SendAvailableSendWindow(); - EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), - sender_->GetCongestionWindow(), - HAS_RETRANSMITTABLE_DATA) - .IsZero()); -} - -TEST_F(TcpCubicBytesSenderTest, ApplicationLimitedSlowStart) { - // Send exactly 10 packets and ensure the CWND ends at 14 packets. - const int kNumberOfAcks = 5; - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - - SendAvailableSendWindow(); - for (int i = 0; i < kNumberOfAcks; ++i) { - AckNPackets(2); - } - QuicByteCount bytes_to_send = sender_->GetCongestionWindow(); - // It's expected 2 acks will arrive when the bytes_in_flight are greater than - // half the CWND. - EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send); -} - -TEST_F(TcpCubicBytesSenderTest, ExponentialSlowStart) { - const int kNumberOfAcks = 20; - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - const QuicByteCount cwnd = sender_->GetCongestionWindow(); - EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd); - EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta( - cwnd, sender_->rtt_stats_.smoothed_rtt()), - sender_->BandwidthEstimate()); -} - -TEST_F(TcpCubicBytesSenderTest, SlowStartPacketLoss) { - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose a packet to exit slow start. - LoseNPackets(1); - size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Recovery phase. We need to ack every packet in the recovery window before - // we exit recovery. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - DVLOG(1) << "number_packets: " << number_of_packets_in_window; - AckNPackets(packets_in_recovery_window); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // We need to ack an entire window before we increase CWND by 1. - AckNPackets(number_of_packets_in_window - 2); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase cwnd by 1. - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Now RTO and ensure slow start gets reset. - EXPECT_TRUE(sender_->hybrid_slow_start().started()); - sender_->OnRetransmissionTimeout(true); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -TEST_F(TcpCubicBytesSenderTest, SlowStartPacketLossWithLargeReduction) { - QuicConfig config; - QuicTagVector options; - options.push_back(kSSLR); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose a packet to exit slow start. We should now have fallen out of - // slow start with a window reduced by 1. - LoseNPackets(1); - expected_send_window -= kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose 5 packets in recovery and verify that congestion window is reduced - // further. - LoseNPackets(5); - expected_send_window -= 5 * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; - - // Recovery phase. We need to ack every packet in the recovery window before - // we exit recovery. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - DVLOG(1) << "number_packets: " << number_of_packets_in_window; - AckNPackets(packets_in_recovery_window); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // We need to ack an entire window before we increase CWND by 1. - AckNPackets(number_of_packets_in_window - 1); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase cwnd by 1. - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Now RTO and ensure slow start gets reset. - EXPECT_TRUE(sender_->hybrid_slow_start().started()); - sender_->OnRetransmissionTimeout(true); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -TEST_F(TcpCubicBytesSenderTest, NoPRRWhenLessThanOnePacketInFlight) { - SendAvailableSendWindow(); - LoseNPackets(kInitialCongestionWindowPackets - 1); - AckNPackets(1); - // PRR will allow 2 packets for every ack during recovery. - EXPECT_EQ(2, SendAvailableSendWindow()); - // Simulate abandoning all packets by supplying a bytes_in_flight of 0. - // PRR should now allow a packet to be sent, even though prr's state variables - // believe it has sent enough packets. - EXPECT_EQ(QuicTime::Delta::Zero(), - sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA)); -} - -TEST_F(TcpCubicBytesSenderTest, SlowStartPacketLossPRR) { - sender_->SetNumEmulatedConnections(1); - // Test based on the first example in RFC6937. - // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - size_t send_window_before_loss = expected_send_window; - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Testing TCP proportional rate reduction. - // We should send packets paced over the received acks for the remaining - // outstanding packets. The number of packets before we exit recovery is the - // original CWND minus the packet that has been lost and the one which - // triggered the loss. - size_t remaining_packets_in_recovery = - send_window_before_loss / kDefaultTCPMSS - 2; - - for (size_t i = 0; i < remaining_packets_in_recovery; ++i) { - AckNPackets(1); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - // We need to ack another window before we increase CWND by 1. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - for (size_t i = 0; i < number_of_packets_in_window; ++i) { - AckNPackets(1); - EXPECT_EQ(1, SendAvailableSendWindow()); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, SlowStartBurstPacketLossPRR) { - sender_->SetNumEmulatedConnections(1); - // Test based on the second example in RFC6937, though we also implement - // forward acknowledgements, so the first two incoming acks will trigger - // PRR immediately. - // Ack 20 packets in 10 acks to raise the CWND to 30. - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose one more than the congestion window reduction, so that after loss, - // bytes_in_flight is lesser than the congestion window. - size_t send_window_after_loss = kRenoBeta * expected_send_window; - size_t num_packets_to_lose = - (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1; - LoseNPackets(num_packets_to_lose); - // Immediately after the loss, ensure at least one packet can be sent. - // Losses without subsequent acks can occur with timer based loss detection. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - AckNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Only 2 packets should be allowed to be sent, per PRR-SSRB. - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Ack the next packet, which triggers another loss. - LoseNPackets(1); - AckNPackets(1); - - // Send 2 packets to simulate PRR-SSRB. - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Ack the next packet, which triggers another loss. - LoseNPackets(1); - AckNPackets(1); - - // Send 2 packets to simulate PRR-SSRB. - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Exit recovery and return to sending at the new rate. - for (int i = 0; i < kNumberOfAcks; ++i) { - AckNPackets(1); - EXPECT_EQ(1, SendAvailableSendWindow()); - } -} - -TEST_F(TcpCubicBytesSenderTest, RTOCongestionWindow) { - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - // Expect the window to decrease to the minimum once the RTO fires and slow - // start threshold to be set to 1/2 of the CWND. - sender_->OnRetransmissionTimeout(true); - EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); - EXPECT_EQ(5u * kDefaultTCPMSS, sender_->GetSlowStartThreshold()); -} - -TEST_F(TcpCubicBytesSenderTest, RTOCongestionWindowNoRetransmission) { - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - - // Expect the window to remain unchanged if the RTO fires but no packets are - // retransmitted. - sender_->OnRetransmissionTimeout(false); - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, RetransmissionDelay) { - const int64_t kRttMs = 10; - const int64_t kDeviationMs = 3; - EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay()); - - sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs), - QuicTime::Delta::Zero(), clock_.Now()); - - // Initial value is to set the median deviation to half of the initial rtt, - // the median in then multiplied by a factor of 4 and finally the smoothed rtt - // is added which is the initial rtt. - QuicTime::Delta expected_delay = - QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4); - EXPECT_EQ(expected_delay, sender_->RetransmissionDelay()); - - for (int i = 0; i < 100; ++i) { - // Run to make sure that we converge. - sender_->rtt_stats_.UpdateRtt( - QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs), - QuicTime::Delta::Zero(), clock_.Now()); - sender_->rtt_stats_.UpdateRtt( - QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs), - QuicTime::Delta::Zero(), clock_.Now()); - } - expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4); - - EXPECT_NEAR(kRttMs, sender_->rtt_stats_.smoothed_rtt().ToMilliseconds(), 1); - EXPECT_NEAR(expected_delay.ToMilliseconds(), - sender_->RetransmissionDelay().ToMilliseconds(), 1); - EXPECT_EQ(static_cast<int64_t>( - sender_->GetCongestionWindow() * kNumMicrosPerSecond / - sender_->rtt_stats_.smoothed_rtt().ToMicroseconds()), - sender_->BandwidthEstimate().ToBytesPerSecond()); -} - -TEST_F(TcpCubicBytesSenderTest, TcpCubicResetEpochOnQuiescence) { - const int kMaxCongestionWindow = 50; - const QuicByteCount kMaxCongestionWindowBytes = - kMaxCongestionWindow * kDefaultTCPMSS; - int num_sent = SendAvailableSendWindow(); - - // Make sure we fall out of slow start. - QuicByteCount saved_cwnd = sender_->GetCongestionWindow(); - LoseNPackets(1); - EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow()); - - // Ack the rest of the outstanding packets to get out of recovery. - for (int i = 1; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_EQ(0u, bytes_in_flight_); - - // Send a new window of data and ack all; cubic growth should occur. - saved_cwnd = sender_->GetCongestionWindow(); - num_sent = SendAvailableSendWindow(); - for (int i = 0; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow()); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); - EXPECT_EQ(0u, bytes_in_flight_); - - // Quiescent time of 100 seconds - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000)); - - // Send new window of data and ack one packet. Cubic epoch should have - // been reset; ensure cwnd increase is not dramatic. - saved_cwnd = sender_->GetCongestionWindow(); - SendAvailableSendWindow(); - AckNPackets(1); - EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, MultipleLossesInOneWindow) { - SendAvailableSendWindow(); - const QuicByteCount initial_window = sender_->GetCongestionWindow(); - LosePacket(acked_packet_number_ + 1); - const QuicByteCount post_loss_window = sender_->GetCongestionWindow(); - EXPECT_GT(initial_window, post_loss_window); - LosePacket(acked_packet_number_ + 3); - EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); - LosePacket(packet_number_ - 1); - EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); - - // Lose a later packet and ensure the window decreases. - LosePacket(packet_number_); - EXPECT_GT(post_loss_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, DontTrackAckPackets) { - // Send a packet with no retransmittable data, and ensure it's not tracked. - EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, - packet_number_++, kDefaultTCPMSS, - NO_RETRANSMITTABLE_DATA)); - - // Send a data packet with retransmittable data, and ensure it is tracked. - EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, - packet_number_++, kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA)); -} - -TEST_F(TcpCubicBytesSenderTest, ConfigureMaxInitialWindow) { - QuicConfig config; - - // Verify that kCOPT: kIW10 forces the congestion window to the default of 10. - QuicTagVector options; - options.push_back(kIW10); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - EXPECT_EQ(10u * kDefaultTCPMSS, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) { - sender_->SetNumEmulatedConnections(2); - // Ack 10 packets in 5 acks to raise the CWND to 20. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window = expected_send_window * sender_->GetRenoBeta(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // No congestion window growth should occur in recovery phase, i.e., until the - // currently outstanding 20 packets are acked. - for (int i = 0; i < 10; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - EXPECT_TRUE(sender_->InRecovery()); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - EXPECT_FALSE(sender_->InRecovery()); - - // Out of recovery now. Congestion window should not grow for half an RTT. - size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS; - SendAvailableSendWindow(); - AckNPackets(packets_in_send_window / 2 - 2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase congestion window by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - packets_in_send_window += 1; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Congestion window should remain steady again for half an RTT. - SendAvailableSendWindow(); - AckNPackets(packets_in_send_window / 2 - 1); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should cause congestion window to grow by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) { - sender_->SetNumEmulatedConnections(1); - // Ack 10 packets in 5 acks to raise the CWND to 20. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // No congestion window growth should occur in recovery phase, i.e., until the - // currently outstanding 20 packets are acked. - for (int i = 0; i < 10; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - EXPECT_TRUE(sender_->InRecovery()); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - EXPECT_FALSE(sender_->InRecovery()); - - // Out of recovery now. Congestion window should not grow during RTT. - for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - // Next ack should cause congestion window to grow by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, BandwidthResumption) { - // Test that when provided with CachedNetworkParameters and opted in to the - // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND - // appropriately. - - // Set some common values. - CachedNetworkParameters cached_network_params; - const QuicPacketCount kNumberOfPackets = 123; - const int kBandwidthEstimateBytesPerSecond = - kNumberOfPackets * kDefaultTCPMSS; - cached_network_params.set_bandwidth_estimate_bytes_per_second( - kBandwidthEstimateBytesPerSecond); - cached_network_params.set_min_rtt_ms(1000); - - // Make sure that a bandwidth estimate results in a changed CWND. - cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() - - (kNumSecondsPerHour - 1)); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kNumberOfPackets * kDefaultTCPMSS, sender_->GetCongestionWindow()); - - // Resumed CWND is limited to be in a sensible range. - cached_network_params.set_bandwidth_estimate_bytes_per_second( - (kMaxCongestionWindow + 1) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kMaxCongestionWindow * kDefaultTCPMSS, - sender_->GetCongestionWindow()); - - cached_network_params.set_bandwidth_estimate_bytes_per_second( - (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kMinCongestionWindowForBandwidthResumption * kDefaultTCPMSS, - sender_->GetCongestionWindow()); - - // Resume to the max value. - cached_network_params.set_max_bandwidth_estimate_bytes_per_second( - (kMinCongestionWindowForBandwidthResumption + 10) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, true); - EXPECT_EQ((kMinCongestionWindowForBandwidthResumption + 10) * kDefaultTCPMSS, - sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicBytesSenderTest, PaceBelowCWND) { - QuicConfig config; - - // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up - // to 4 to be sent. - QuicTagVector options; - options.push_back(kMIN4); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - sender_->OnRetransmissionTimeout(true); - EXPECT_EQ(kDefaultTCPMSS, sender_->GetCongestionWindow()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_FALSE(sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); -} - -TEST_F(TcpCubicBytesSenderTest, ResetAfterConnectionMigration) { - // Starts from slow start. - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Loses a packet to exit slow start. - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. Slow - // start threshold is also updated. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - EXPECT_EQ(expected_send_window, sender_->GetSlowStartThreshold()); - - // Resets cwnd and slow start threshold on connection migrations. - sender_->OnConnectionMigration(); - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - EXPECT_EQ(kMaxCongestionWindow * kDefaultTCPMSS, - sender_->GetSlowStartThreshold()); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -} // namespace test -} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc deleted file mode 100644 index f78f587..0000000 --- a/net/quic/congestion_control/tcp_cubic_sender.cc +++ /dev/null
@@ -1,401 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/congestion_control/tcp_cubic_sender.h" - -#include <algorithm> - -#include "base/metrics/histogram_macros.h" -#include "net/quic/congestion_control/prr_sender.h" -#include "net/quic/congestion_control/rtt_stats.h" -#include "net/quic/crypto/crypto_protocol.h" -#include "net/quic/proto/cached_network_parameters.pb.h" -#include "net/quic/quic_bug_tracker.h" -#include "net/quic/quic_flags.h" - -using std::max; -using std::min; - -namespace net { - -namespace { -// Constants based on TCP defaults. -// The minimum cwnd based on RFC 3782 (TCP NewReno) for cwnd reductions on a -// fast retransmission. The cwnd after a timeout is still 1. -const QuicPacketCount kDefaultMinimumCongestionWindow = 2; -const QuicByteCount kMaxBurstBytes = 3 * kDefaultTCPMSS; -const float kRenoBeta = 0.7f; // Reno backoff factor. -const uint32_t kDefaultNumConnections = 2; // N-connection emulation. -} // namespace - -TcpCubicSender::TcpCubicSender(const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_tcp_congestion_window, - QuicConnectionStats* stats) - : cubic_(clock), - rtt_stats_(rtt_stats), - stats_(stats), - reno_(reno), - num_connections_(kDefaultNumConnections), - congestion_window_count_(0), - largest_sent_packet_number_(0), - largest_acked_packet_number_(0), - largest_sent_at_last_cutback_(0), - congestion_window_(initial_tcp_congestion_window), - min_congestion_window_(kDefaultMinimumCongestionWindow), - min4_mode_(false), - slowstart_threshold_(max_tcp_congestion_window), - last_cutback_exited_slowstart_(false), - max_tcp_congestion_window_(max_tcp_congestion_window), - initial_tcp_congestion_window_(initial_tcp_congestion_window), - initial_max_tcp_congestion_window_(max_tcp_congestion_window), - slow_start_large_reduction_(false) {} - -TcpCubicSender::~TcpCubicSender() { - UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_); -} - -void TcpCubicSender::SetFromConfig(const QuicConfig& config, - Perspective perspective) { - if (perspective == Perspective::IS_SERVER) { - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW03)) { - // Initial window experiment. - congestion_window_ = 3; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) { - // Initial window experiment. - congestion_window_ = 10; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW20)) { - // Initial window experiment. - congestion_window_ = 20; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kIW50)) { - // Initial window experiment. - congestion_window_ = 50; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN1)) { - // Min CWND experiment. - min_congestion_window_ = 1; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kMIN4)) { - // Min CWND of 4 experiment. - min4_mode_ = true; - min_congestion_window_ = 1; - } - if (config.HasReceivedConnectionOptions() && - ContainsQuicTag(config.ReceivedConnectionOptions(), kSSLR)) { - // Slow Start Fast Exit experiment. - slow_start_large_reduction_ = true; - } - } -} - -void TcpCubicSender::ResumeConnectionState( - const CachedNetworkParameters& cached_network_params, - bool max_bandwidth_resumption) { - QuicBandwidth bandwidth = QuicBandwidth::FromBytesPerSecond( - max_bandwidth_resumption - ? cached_network_params.max_bandwidth_estimate_bytes_per_second() - : cached_network_params.bandwidth_estimate_bytes_per_second()); - QuicTime::Delta rtt_ms = - QuicTime::Delta::FromMilliseconds(cached_network_params.min_rtt_ms()); - - // Make sure CWND is in appropriate range (in case of bad data). - QuicPacketCount new_congestion_window = - bandwidth.ToBytesPerPeriod(rtt_ms) / kDefaultTCPMSS; - congestion_window_ = max(min(new_congestion_window, kMaxCongestionWindow), - kMinCongestionWindowForBandwidthResumption); -} - -void TcpCubicSender::SetNumEmulatedConnections(int num_connections) { - num_connections_ = max(1, num_connections); - cubic_.SetNumConnections(num_connections_); -} - -void TcpCubicSender::SetMaxCongestionWindow( - QuicByteCount max_congestion_window) { - max_tcp_congestion_window_ = max_congestion_window / kDefaultTCPMSS; -} - -float TcpCubicSender::RenoBeta() const { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (num_connections_ - 1 + kRenoBeta) / num_connections_; -} - -void TcpCubicSender::OnCongestionEvent(bool rtt_updated, - QuicByteCount bytes_in_flight, - const CongestionVector& acked_packets, - const CongestionVector& lost_packets) { - if (rtt_updated && InSlowStart() && - hybrid_slow_start_.ShouldExitSlowStart(rtt_stats_->latest_rtt(), - rtt_stats_->min_rtt(), - congestion_window_)) { - slowstart_threshold_ = congestion_window_; - } - for (CongestionVector::const_iterator it = lost_packets.begin(); - it != lost_packets.end(); ++it) { - OnPacketLost(it->first, bytes_in_flight); - } - for (CongestionVector::const_iterator it = acked_packets.begin(); - it != acked_packets.end(); ++it) { - OnPacketAcked(it->first, it->second, bytes_in_flight); - } -} - -void TcpCubicSender::OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight) { - largest_acked_packet_number_ = - max(acked_packet_number, largest_acked_packet_number_); - if (InRecovery()) { - // PRR is used when in recovery. - prr_.OnPacketAcked(acked_bytes); - return; - } - MaybeIncreaseCwnd(acked_packet_number, bytes_in_flight); - if (InSlowStart()) { - hybrid_slow_start_.OnPacketAcked(acked_packet_number); - } -} - -void TcpCubicSender::OnPacketLost(QuicPacketNumber packet_number, - QuicByteCount bytes_in_flight) { - // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets - // already sent should be treated as a single loss event, since it's expected. - if (packet_number <= largest_sent_at_last_cutback_) { - if (last_cutback_exited_slowstart_) { - ++stats_->slowstart_packets_lost; - if (slow_start_large_reduction_) { - // Reduce congestion window by 1 for every loss. - congestion_window_ = - max(congestion_window_ - 1, min_congestion_window_); - slowstart_threshold_ = congestion_window_; - } - } - DVLOG(1) << "Ignoring loss for largest_missing:" << packet_number - << " because it was sent prior to the last CWND cutback."; - return; - } - ++stats_->tcp_loss_events; - last_cutback_exited_slowstart_ = InSlowStart(); - if (InSlowStart()) { - ++stats_->slowstart_packets_lost; - } - - prr_.OnPacketLost(bytes_in_flight); - - // TODO(jri): Separate out all of slow start into a separate class. - if (slow_start_large_reduction_ && InSlowStart()) { - DCHECK_LT(1u, congestion_window_); - congestion_window_ = congestion_window_ - 1; - } else if (reno_) { - congestion_window_ = congestion_window_ * RenoBeta(); - } else { - congestion_window_ = - cubic_.CongestionWindowAfterPacketLoss(congestion_window_); - } - // Enforce a minimum congestion window. - if (congestion_window_ < min_congestion_window_) { - congestion_window_ = min_congestion_window_; - } - slowstart_threshold_ = congestion_window_; - largest_sent_at_last_cutback_ = largest_sent_packet_number_; - // reset packet count from congestion avoidance mode. We start - // counting again when we're out of recovery. - congestion_window_count_ = 0; - DVLOG(1) << "Incoming loss; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; -} - -bool TcpCubicSender::OnPacketSent(QuicTime /*sent_time*/, - QuicByteCount /*bytes_in_flight*/, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) { - if (InSlowStart()) { - ++(stats_->slowstart_packets_sent); - } - - // Only update bytes_in_flight_ for data packets. - if (is_retransmittable != HAS_RETRANSMITTABLE_DATA) { - return false; - } - if (InRecovery()) { - // PRR is used when in recovery. - prr_.OnPacketSent(bytes); - } - DCHECK_LT(largest_sent_packet_number_, packet_number); - largest_sent_packet_number_ = packet_number; - hybrid_slow_start_.OnPacketSent(packet_number); - return true; -} - -QuicTime::Delta TcpCubicSender::TimeUntilSend( - QuicTime /* now */, - QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) const { - if (has_retransmittable_data == NO_RETRANSMITTABLE_DATA) { - DCHECK(!FLAGS_quic_respect_send_alarm2); - // For TCP we can always send an ACK immediately. - return QuicTime::Delta::Zero(); - } - if (InRecovery()) { - // PRR is used when in recovery. - return prr_.TimeUntilSend(GetCongestionWindow(), bytes_in_flight, - slowstart_threshold_ * kDefaultTCPMSS); - } - if (GetCongestionWindow() > bytes_in_flight) { - return QuicTime::Delta::Zero(); - } - if (min4_mode_ && bytes_in_flight < 4 * kDefaultTCPMSS) { - return QuicTime::Delta::Zero(); - } - return QuicTime::Delta::Infinite(); -} - -QuicBandwidth TcpCubicSender::PacingRate() const { - // We pace at twice the rate of the underlying sender's bandwidth estimate - // during slow start and 1.25x during congestion avoidance to ensure pacing - // doesn't prevent us from filling the window. - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - srtt = QuicTime::Delta::FromMicroseconds(rtt_stats_->initial_rtt_us()); - } - const QuicBandwidth bandwidth = - QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); - return bandwidth.Scale(InSlowStart() ? 2 : 1.25); -} - -QuicBandwidth TcpCubicSender::BandwidthEstimate() const { - QuicTime::Delta srtt = rtt_stats_->smoothed_rtt(); - if (srtt.IsZero()) { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return QuicBandwidth::Zero(); - } - return QuicBandwidth::FromBytesAndTimeDelta(GetCongestionWindow(), srtt); -} - -QuicTime::Delta TcpCubicSender::RetransmissionDelay() const { - if (rtt_stats_->smoothed_rtt().IsZero()) { - return QuicTime::Delta::Zero(); - } - return rtt_stats_->smoothed_rtt().Add( - rtt_stats_->mean_deviation().Multiply(4)); -} - -QuicByteCount TcpCubicSender::GetCongestionWindow() const { - return congestion_window_ * kDefaultTCPMSS; -} - -bool TcpCubicSender::InSlowStart() const { - return congestion_window_ < slowstart_threshold_; -} - -QuicByteCount TcpCubicSender::GetSlowStartThreshold() const { - return slowstart_threshold_ * kDefaultTCPMSS; -} - -bool TcpCubicSender::IsCwndLimited(QuicByteCount bytes_in_flight) const { - const QuicByteCount congestion_window_bytes = GetCongestionWindow(); - if (bytes_in_flight >= congestion_window_bytes) { - return true; - } - const QuicByteCount available_bytes = - congestion_window_bytes - bytes_in_flight; - const bool slow_start_limited = - InSlowStart() && bytes_in_flight > congestion_window_bytes / 2; - return slow_start_limited || available_bytes <= kMaxBurstBytes; -} - -bool TcpCubicSender::InRecovery() const { - return largest_acked_packet_number_ <= largest_sent_at_last_cutback_ && - largest_acked_packet_number_ != 0; -} - -// Called when we receive an ack. Normal TCP tracks how many packets one ack -// represents, but quic has a separate ack for each packet. -void TcpCubicSender::MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, - QuicByteCount bytes_in_flight) { - QUIC_BUG_IF(InRecovery()) << "Never increase the CWND during recovery."; - // Do not increase the congestion window unless the sender is close to using - // the current window. - if (!IsCwndLimited(bytes_in_flight)) { - cubic_.OnApplicationLimited(); - return; - } - if (congestion_window_ >= max_tcp_congestion_window_) { - return; - } - if (InSlowStart()) { - // TCP slow start, exponential growth, increase by one for each ACK. - ++congestion_window_; - DVLOG(1) << "Slow start; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; - return; - } - // Congestion avoidance - if (reno_) { - // Classic Reno congestion avoidance. - ++congestion_window_count_; - // Divide by num_connections to smoothly increase the CWND at a faster - // rate than conventional Reno. - if (congestion_window_count_ * num_connections_ >= congestion_window_) { - ++congestion_window_; - congestion_window_count_ = 0; - } - - DVLOG(1) << "Reno; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_ - << " congestion window count: " << congestion_window_count_; - } else { - congestion_window_ = min(max_tcp_congestion_window_, - cubic_.CongestionWindowAfterAck( - congestion_window_, rtt_stats_->min_rtt())); - DVLOG(1) << "Cubic; congestion window: " << congestion_window_ - << " slowstart threshold: " << slowstart_threshold_; - } -} - -void TcpCubicSender::OnRetransmissionTimeout(bool packets_retransmitted) { - largest_sent_at_last_cutback_ = 0; - if (!packets_retransmitted) { - return; - } - cubic_.Reset(); - hybrid_slow_start_.Restart(); - slowstart_threshold_ = congestion_window_ / 2; - congestion_window_ = min_congestion_window_; -} - -void TcpCubicSender::OnConnectionMigration() { - hybrid_slow_start_.Restart(); - cubic_.Reset(); - prr_ = PrrSender(); - congestion_window_count_ = 0; - largest_sent_packet_number_ = 0; - largest_acked_packet_number_ = 0; - largest_sent_at_last_cutback_ = 0; - congestion_window_ = initial_tcp_congestion_window_; - slowstart_threshold_ = initial_max_tcp_congestion_window_; - last_cutback_exited_slowstart_ = false; - max_tcp_congestion_window_ = initial_max_tcp_congestion_window_; -} - -CongestionControlType TcpCubicSender::GetCongestionControlType() const { - return reno_ ? kReno : kCubic; -} - -} // namespace net
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h deleted file mode 100644 index 9b253a38..0000000 --- a/net/quic/congestion_control/tcp_cubic_sender.h +++ /dev/null
@@ -1,152 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -// -// TCP cubic send side congestion algorithm, emulates the behavior of TCP cubic. - -#ifndef NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_ -#define NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_ - -#include <stdint.h> - -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "net/base/net_export.h" -#include "net/quic/congestion_control/cubic.h" -#include "net/quic/congestion_control/hybrid_slow_start.h" -#include "net/quic/congestion_control/prr_sender.h" -#include "net/quic/congestion_control/send_algorithm_interface.h" -#include "net/quic/quic_bandwidth.h" -#include "net/quic/quic_connection_stats.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/quic_time.h" - -namespace net { - -class RttStats; - -namespace test { -class TcpCubicSenderPeer; -} // namespace test - -class NET_EXPORT_PRIVATE TcpCubicSender : public SendAlgorithmInterface { - public: - // Reno option and max_tcp_congestion_window are provided for testing. - TcpCubicSender(const QuicClock* clock, - const RttStats* rtt_stats, - bool reno, - QuicPacketCount initial_tcp_congestion_window, - QuicPacketCount max_tcp_congestion_window, - QuicConnectionStats* stats); - ~TcpCubicSender() override; - - // Start implementation of SendAlgorithmInterface. - void SetFromConfig(const QuicConfig& config, - Perspective perspective) override; - void ResumeConnectionState( - const CachedNetworkParameters& cached_network_params, - bool max_bandwidth_resumption) override; - void SetNumEmulatedConnections(int num_connections) override; - void SetMaxCongestionWindow(QuicByteCount max_congestion_window) override; - void OnCongestionEvent(bool rtt_updated, - QuicByteCount bytes_in_flight, - const CongestionVector& acked_packets, - const CongestionVector& lost_packets) override; - bool OnPacketSent(QuicTime sent_time, - QuicByteCount bytes_in_flight, - QuicPacketNumber packet_number, - QuicByteCount bytes, - HasRetransmittableData is_retransmittable) override; - void OnRetransmissionTimeout(bool packets_retransmitted) override; - void OnConnectionMigration() override; - QuicTime::Delta TimeUntilSend( - QuicTime now, - QuicByteCount bytes_in_flight, - HasRetransmittableData has_retransmittable_data) const override; - QuicBandwidth PacingRate() const override; - QuicBandwidth BandwidthEstimate() const override; - QuicTime::Delta RetransmissionDelay() const override; - QuicByteCount GetCongestionWindow() const override; - bool InSlowStart() const override; - bool InRecovery() const override; - QuicByteCount GetSlowStartThreshold() const override; - CongestionControlType GetCongestionControlType() const override; - // End implementation of SendAlgorithmInterface. - - private: - friend class test::TcpCubicSenderPeer; - - // Compute the TCP Reno beta based on the current number of connections. - float RenoBeta() const; - - // TODO(ianswett): Remove these and migrate to OnCongestionEvent. - void OnPacketAcked(QuicPacketNumber acked_packet_number, - QuicByteCount acked_bytes, - QuicByteCount bytes_in_flight); - void OnPacketLost(QuicPacketNumber largest_loss, - QuicByteCount bytes_in_flight); - - void MaybeIncreaseCwnd(QuicPacketNumber acked_packet_number, - QuicByteCount bytes_in_flight); - bool IsCwndLimited(QuicByteCount bytes_in_flight) const; - - HybridSlowStart hybrid_slow_start_; - Cubic cubic_; - PrrSender prr_; - const RttStats* rtt_stats_; - QuicConnectionStats* stats_; - - // If true, Reno congestion control is used instead of Cubic. - const bool reno_; - - // Number of connections to simulate. - uint32_t num_connections_; - - // ACK counter for the Reno implementation. - uint64_t congestion_window_count_; - - // Track the largest packet that has been sent. - QuicPacketNumber largest_sent_packet_number_; - - // Track the largest packet that has been acked. - QuicPacketNumber largest_acked_packet_number_; - - // Track the largest packet number outstanding when a CWND cutback occurs. - QuicPacketNumber largest_sent_at_last_cutback_; - - // Congestion window in packets. - QuicPacketCount congestion_window_; - - // Minimum congestion window in packets. - QuicPacketCount min_congestion_window_; - - // Whether to use 4 packets as the actual min, but pace lower. - bool min4_mode_; - - // Slow start congestion window in packets, aka ssthresh. - QuicPacketCount slowstart_threshold_; - - // Whether the last loss event caused us to exit slowstart. - // Used for stats collection of slowstart_packets_lost - bool last_cutback_exited_slowstart_; - - // Maximum number of outstanding packets for tcp. - QuicPacketCount max_tcp_congestion_window_; - - // Initial TCP congestion window. This variable can only be set when this - // algorithm is created. - const QuicPacketCount initial_tcp_congestion_window_; - - // Initial maximum TCP congestion window. This variable can only be set when - // this algorithm is created. - const QuicPacketCount initial_max_tcp_congestion_window_; - - // When true, exit slow start with large cutback of congestion window. - bool slow_start_large_reduction_; - - DISALLOW_COPY_AND_ASSIGN(TcpCubicSender); -}; - -} // namespace net - -#endif // NET_QUIC_CONGESTION_CONTROL_TCP_CUBIC_SENDER_H_
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc deleted file mode 100644 index 13ae6c1..0000000 --- a/net/quic/congestion_control/tcp_cubic_sender_test.cc +++ /dev/null
@@ -1,887 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/quic/congestion_control/tcp_cubic_sender.h" - -#include <algorithm> - -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "net/quic/congestion_control/rtt_stats.h" -#include "net/quic/crypto/crypto_protocol.h" -#include "net/quic/proto/cached_network_parameters.pb.h" -#include "net/quic/quic_flags.h" -#include "net/quic/quic_protocol.h" -#include "net/quic/quic_utils.h" -#include "net/quic/test_tools/mock_clock.h" -#include "net/quic/test_tools/quic_config_peer.h" -#include "net/quic/test_tools/quic_test_utils.h" -#include "testing/gtest/include/gtest/gtest.h" - -using std::min; - -namespace net { -namespace test { - -// TODO(ianswett): A number of theses tests were written with the assumption of -// an initial CWND of 10. They have carefully calculated values which should be -// updated to be based on kInitialCongestionWindow. -const uint32_t kInitialCongestionWindowPackets = 10; -const uint32_t kDefaultWindowTCP = - kInitialCongestionWindowPackets * kDefaultTCPMSS; -const float kRenoBeta = 0.7f; // Reno backoff factor. - -class TcpCubicSenderPeer : public TcpCubicSender { - public: - TcpCubicSenderPeer(const QuicClock* clock, - bool reno, - QuicPacketCount max_tcp_congestion_window) - : TcpCubicSender(clock, - &rtt_stats_, - reno, - kInitialCongestionWindowPackets, - max_tcp_congestion_window, - &stats_) {} - - QuicPacketCount congestion_window() { return congestion_window_; } - - QuicPacketCount slowstart_threshold() { return slowstart_threshold_; } - - const HybridSlowStart& hybrid_slow_start() const { - return hybrid_slow_start_; - } - - float GetRenoBeta() const { return RenoBeta(); } - - RttStats rtt_stats_; - QuicConnectionStats stats_; -}; - -class TcpCubicSenderTest : public ::testing::Test { - protected: - TcpCubicSenderTest() - : one_ms_(QuicTime::Delta::FromMilliseconds(1)), - sender_(new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindow)), - packet_number_(1), - acked_packet_number_(0), - bytes_in_flight_(0) {} - - int SendAvailableSendWindow() { - // Send as long as TimeUntilSend returns Zero. - int packets_sent = 0; - bool can_send = sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero(); - while (can_send) { - sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, packet_number_++, - kDefaultTCPMSS, HAS_RETRANSMITTABLE_DATA); - ++packets_sent; - bytes_in_flight_ += kDefaultTCPMSS; - can_send = sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero(); - } - return packets_sent; - } - - // Normal is that TCP acks every other segment. - void AckNPackets(int n) { - sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(60), - QuicTime::Delta::Zero(), clock_.Now()); - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - for (int i = 0; i < n; ++i) { - ++acked_packet_number_; - acked_packets.push_back( - std::make_pair(acked_packet_number_, kDefaultTCPMSS)); - } - sender_->OnCongestionEvent(true, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= n * kDefaultTCPMSS; - clock_.AdvanceTime(one_ms_); - } - - void LoseNPackets(int n) { - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - for (int i = 0; i < n; ++i) { - ++acked_packet_number_; - lost_packets.push_back( - std::make_pair(acked_packet_number_, kDefaultTCPMSS)); - } - sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= n * kDefaultTCPMSS; - } - - // Does not increment acked_packet_number_. - void LosePacket(QuicPacketNumber packet_number) { - SendAlgorithmInterface::CongestionVector acked_packets; - SendAlgorithmInterface::CongestionVector lost_packets; - lost_packets.push_back(std::make_pair(packet_number, kDefaultTCPMSS)); - sender_->OnCongestionEvent(false, bytes_in_flight_, acked_packets, - lost_packets); - bytes_in_flight_ -= kDefaultTCPMSS; - } - - const QuicTime::Delta one_ms_; - MockClock clock_; - scoped_ptr<TcpCubicSenderPeer> sender_; - QuicPacketNumber packet_number_; - QuicPacketNumber acked_packet_number_; - QuicByteCount bytes_in_flight_; -}; - -TEST_F(TcpCubicSenderTest, SimpleSender) { - // At startup make sure we are at the default. - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // And that window is un-affected. - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - - // Fill the send window with data, then verify that we can't send. - SendAvailableSendWindow(); - EXPECT_FALSE(sender_->TimeUntilSend(clock_.Now(), - sender_->GetCongestionWindow(), - HAS_RETRANSMITTABLE_DATA) - .IsZero()); -} - -TEST_F(TcpCubicSenderTest, ApplicationLimitedSlowStart) { - // Send exactly 10 packets and ensure the CWND ends at 14 packets. - const int kNumberOfAcks = 5; - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - - SendAvailableSendWindow(); - for (int i = 0; i < kNumberOfAcks; ++i) { - AckNPackets(2); - } - QuicByteCount bytes_to_send = sender_->GetCongestionWindow(); - // It's expected 2 acks will arrive when the bytes_in_flight are greater than - // half the CWND. - EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * 2, bytes_to_send); -} - -TEST_F(TcpCubicSenderTest, ExponentialSlowStart) { - const int kNumberOfAcks = 20; - // At startup make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_EQ(QuicBandwidth::Zero(), sender_->BandwidthEstimate()); - // Make sure we can send. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA) - .IsZero()); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - const QuicByteCount cwnd = sender_->GetCongestionWindow(); - EXPECT_EQ(kDefaultWindowTCP + kDefaultTCPMSS * 2 * kNumberOfAcks, cwnd); - EXPECT_EQ(QuicBandwidth::FromBytesAndTimeDelta( - cwnd, sender_->rtt_stats_.smoothed_rtt()), - sender_->BandwidthEstimate()); -} - -TEST_F(TcpCubicSenderTest, SlowStartPacketLoss) { - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose a packet to exit slow start. - LoseNPackets(1); - size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Recovery phase. We need to ack every packet in the recovery window before - // we exit recovery. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - DVLOG(1) << "number_packets: " << number_of_packets_in_window; - AckNPackets(packets_in_recovery_window); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // We need to ack an entire window before we increase CWND by 1. - AckNPackets(number_of_packets_in_window - 2); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase cwnd by 1. - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Now RTO and ensure slow start gets reset. - EXPECT_TRUE(sender_->hybrid_slow_start().started()); - sender_->OnRetransmissionTimeout(true); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -TEST_F(TcpCubicSenderTest, SlowStartPacketLossWithLargeReduction) { - QuicConfig config; - QuicTagVector options; - options.push_back(kSSLR); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose a packet to exit slow start. We should now have fallen out of - // slow start with a window reduced by 1. - LoseNPackets(1); - expected_send_window -= kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose 5 packets in recovery and verify that congestion window is reduced - // further. - LoseNPackets(5); - expected_send_window -= 5 * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - size_t packets_in_recovery_window = expected_send_window / kDefaultTCPMSS; - - // Recovery phase. We need to ack every packet in the recovery window before - // we exit recovery. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - DVLOG(1) << "number_packets: " << number_of_packets_in_window; - AckNPackets(packets_in_recovery_window); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // We need to ack the rest of the window before cwnd increases by 1. - AckNPackets(number_of_packets_in_window - 1); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase cwnd by 1. - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Now RTO and ensure slow start gets reset. - EXPECT_TRUE(sender_->hybrid_slow_start().started()); - sender_->OnRetransmissionTimeout(true); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -TEST_F(TcpCubicSenderTest, NoPRRWhenLessThanOnePacketInFlight) { - SendAvailableSendWindow(); - LoseNPackets(kInitialCongestionWindowPackets - 1); - AckNPackets(1); - // PRR will allow 2 packets for every ack during recovery. - EXPECT_EQ(2, SendAvailableSendWindow()); - // Simulate abandoning all packets by supplying a bytes_in_flight of 0. - // PRR should now allow a packet to be sent, even though prr's state - // variables believe it has sent enough packets. - EXPECT_EQ(QuicTime::Delta::Zero(), - sender_->TimeUntilSend(clock_.Now(), 0, HAS_RETRANSMITTABLE_DATA)); -} - -TEST_F(TcpCubicSenderTest, SlowStartPacketLossPRR) { - sender_->SetNumEmulatedConnections(1); - // Test based on the first example in RFC6937. - // Ack 10 packets in 5 acks to raise the CWND to 20, as in the example. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - size_t send_window_before_loss = expected_send_window; - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Testing TCP proportional rate reduction. - // We should send packets paced over the received acks for the remaining - // outstanding packets. The number of packets before we exit recovery is the - // original CWND minus the packet that has been lost and the one which - // triggered the loss. - size_t remaining_packets_in_recovery = - send_window_before_loss / kDefaultTCPMSS - 2; - - for (size_t i = 0; i < remaining_packets_in_recovery; ++i) { - AckNPackets(1); - SendAvailableSendWindow(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - // We need to ack another window before we increase CWND by 1. - size_t number_of_packets_in_window = expected_send_window / kDefaultTCPMSS; - for (size_t i = 0; i < number_of_packets_in_window; ++i) { - AckNPackets(1); - EXPECT_EQ(1, SendAvailableSendWindow()); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - AckNPackets(1); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, SlowStartBurstPacketLossPRR) { - sender_->SetNumEmulatedConnections(1); - // Test based on the second example in RFC6937, though we also implement - // forward acknowledgements, so the first two incoming acks will trigger - // PRR immediately. - // Ack 20 packets in 10 acks to raise the CWND to 30. - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Lose one more than the congestion window reduction, so that after loss, - // bytes_in_flight is lesser than the congestion window. - size_t send_window_after_loss = kRenoBeta * expected_send_window; - size_t num_packets_to_lose = - (expected_send_window - send_window_after_loss) / kDefaultTCPMSS + 1; - LoseNPackets(num_packets_to_lose); - // Immediately after the loss, ensure at least one packet can be sent. - // Losses without subsequent acks can occur with timer based loss detection. - EXPECT_TRUE(sender_->TimeUntilSend(clock_.Now(), bytes_in_flight_, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - AckNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Only 2 packets should be allowed to be sent, per PRR-SSRB - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Ack the next packet, which triggers another loss. - LoseNPackets(1); - AckNPackets(1); - - // Send 2 packets to simulate PRR-SSRB. - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Ack the next packet, which triggers another loss. - LoseNPackets(1); - AckNPackets(1); - - // Send 2 packets to simulate PRR-SSRB. - EXPECT_EQ(2, SendAvailableSendWindow()); - - // Exit recovery and return to sending at the new rate. - for (int i = 0; i < kNumberOfAcks; ++i) { - AckNPackets(1); - EXPECT_EQ(1, SendAvailableSendWindow()); - } -} - -TEST_F(TcpCubicSenderTest, RTOCongestionWindow) { - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - EXPECT_EQ(kMaxCongestionWindow, sender_->slowstart_threshold()); - - // Expect the window to decrease to the minimum once the RTO fires - // and slow start threshold to be set to 1/2 of the CWND. - sender_->OnRetransmissionTimeout(true); - EXPECT_EQ(2 * kDefaultTCPMSS, sender_->GetCongestionWindow()); - EXPECT_EQ(5u, sender_->slowstart_threshold()); -} - -TEST_F(TcpCubicSenderTest, RTOCongestionWindowNoRetransmission) { - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - - // Expect the window to remain unchanged if the RTO fires but no - // packets are retransmitted. - sender_->OnRetransmissionTimeout(false); - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, RetransmissionDelay) { - const int64_t kRttMs = 10; - const int64_t kDeviationMs = 3; - EXPECT_EQ(QuicTime::Delta::Zero(), sender_->RetransmissionDelay()); - - sender_->rtt_stats_.UpdateRtt(QuicTime::Delta::FromMilliseconds(kRttMs), - QuicTime::Delta::Zero(), clock_.Now()); - - // Initial value is to set the median deviation to half of the initial - // rtt, the median in then multiplied by a factor of 4 and finally the - // smoothed rtt is added which is the initial rtt. - QuicTime::Delta expected_delay = - QuicTime::Delta::FromMilliseconds(kRttMs + kRttMs / 2 * 4); - EXPECT_EQ(expected_delay, sender_->RetransmissionDelay()); - - for (int i = 0; i < 100; ++i) { - // Run to make sure that we converge. - sender_->rtt_stats_.UpdateRtt( - QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs), - QuicTime::Delta::Zero(), clock_.Now()); - sender_->rtt_stats_.UpdateRtt( - QuicTime::Delta::FromMilliseconds(kRttMs - kDeviationMs), - QuicTime::Delta::Zero(), clock_.Now()); - } - expected_delay = QuicTime::Delta::FromMilliseconds(kRttMs + kDeviationMs * 4); - - EXPECT_NEAR(kRttMs, sender_->rtt_stats_.smoothed_rtt().ToMilliseconds(), 1); - EXPECT_NEAR(expected_delay.ToMilliseconds(), - sender_->RetransmissionDelay().ToMilliseconds(), 1); - EXPECT_EQ(static_cast<int64_t>( - sender_->GetCongestionWindow() * kNumMicrosPerSecond / - sender_->rtt_stats_.smoothed_rtt().ToMicroseconds()), - sender_->BandwidthEstimate().ToBytesPerSecond()); -} - -TEST_F(TcpCubicSenderTest, SlowStartMaxSendWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - const int kNumberOfAcks = 100; - sender_.reset( - new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP)); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpRenoMaxCongestionWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - const int kNumberOfAcks = 1000; - sender_.reset(new TcpCubicSenderPeer(&clock_, true, kMaxCongestionWindowTCP)); - - SendAvailableSendWindow(); - AckNPackets(2); - // Make sure we fall out of slow start. - LoseNPackets(1); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - - QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpCubicMaxCongestionWindow) { - const QuicPacketCount kMaxCongestionWindowTCP = 50; - // Set to 10000 to compensate for small cubic alpha. - const int kNumberOfAcks = 10000; - - sender_.reset( - new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindowTCP)); - - SendAvailableSendWindow(); - AckNPackets(2); - // Make sure we fall out of slow start. - LoseNPackets(1); - - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - - QuicByteCount expected_send_window = kMaxCongestionWindowTCP * kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpCubicResetEpochOnQuiescence) { - const int kMaxCongestionWindow = 50; - const QuicByteCount kMaxCongestionWindowBytes = - kMaxCongestionWindow * kDefaultTCPMSS; - sender_.reset(new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindow)); - - int num_sent = SendAvailableSendWindow(); - - // Make sure we fall out of slow start. - QuicByteCount saved_cwnd = sender_->GetCongestionWindow(); - LoseNPackets(1); - EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow()); - - // Ack the rest of the outstanding packets to get out of recovery. - for (int i = 1; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_EQ(0u, bytes_in_flight_); - - // Send a new window of data and ack all; cubic growth should occur. - saved_cwnd = sender_->GetCongestionWindow(); - num_sent = SendAvailableSendWindow(); - for (int i = 0; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow()); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); - EXPECT_EQ(0u, bytes_in_flight_); - - // Quiescent time of 100 seconds - clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(100000)); - - // Send new window of data and ack one packet. Cubic epoch should have - // been reset; ensure cwnd increase is not dramatic. - saved_cwnd = sender_->GetCongestionWindow(); - SendAvailableSendWindow(); - AckNPackets(1); - EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, TcpCubicShiftedEpochOnQuiescence) { - ValueRestore<bool> old_flag(&FLAGS_shift_quic_cubic_epoch_when_app_limited, - true); - const int kMaxCongestionWindow = 50; - const QuicByteCount kMaxCongestionWindowBytes = - kMaxCongestionWindow * kDefaultTCPMSS; - sender_.reset(new TcpCubicSenderPeer(&clock_, false, kMaxCongestionWindow)); - - int num_sent = SendAvailableSendWindow(); - - // Make sure we fall out of slow start. - QuicByteCount saved_cwnd = sender_->GetCongestionWindow(); - LoseNPackets(1); - EXPECT_GT(saved_cwnd, sender_->GetCongestionWindow()); - - // Ack the rest of the outstanding packets to get out of recovery. - for (int i = 1; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_EQ(0u, bytes_in_flight_); - - // Send a new window of data and ack all; cubic growth should occur. - saved_cwnd = sender_->GetCongestionWindow(); - num_sent = SendAvailableSendWindow(); - for (int i = 0; i < num_sent; ++i) { - AckNPackets(1); - } - EXPECT_LT(saved_cwnd, sender_->GetCongestionWindow()); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); - EXPECT_EQ(0u, bytes_in_flight_); - - // Quiescent time of 100 seconds - clock_.AdvanceTime(QuicTime::Delta::FromSeconds(100)); - - // Send new window of data and ack one packet. Cubic epoch should have - // been reset; ensure cwnd increase is not dramatic. - saved_cwnd = sender_->GetCongestionWindow(); - SendAvailableSendWindow(); - AckNPackets(1); - EXPECT_NEAR(saved_cwnd, sender_->GetCongestionWindow(), kDefaultTCPMSS); - EXPECT_GT(kMaxCongestionWindowBytes, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, MultipleLossesInOneWindow) { - SendAvailableSendWindow(); - const QuicByteCount initial_window = sender_->GetCongestionWindow(); - LosePacket(acked_packet_number_ + 1); - const QuicByteCount post_loss_window = sender_->GetCongestionWindow(); - EXPECT_GT(initial_window, post_loss_window); - LosePacket(acked_packet_number_ + 3); - EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); - LosePacket(packet_number_ - 1); - EXPECT_EQ(post_loss_window, sender_->GetCongestionWindow()); - - // Lose a later packet and ensure the window decreases. - LosePacket(packet_number_); - EXPECT_GT(post_loss_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, DontTrackAckPackets) { - // Send a packet with no retransmittable data, and ensure it's not tracked. - EXPECT_FALSE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, - packet_number_++, kDefaultTCPMSS, - NO_RETRANSMITTABLE_DATA)); - - // Send a data packet with retransmittable data, and ensure it is tracked. - EXPECT_TRUE(sender_->OnPacketSent(clock_.Now(), bytes_in_flight_, - packet_number_++, kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA)); -} - -TEST_F(TcpCubicSenderTest, ConfigureInitialWindow) { - QuicConfig config; - - QuicTagVector options; - options.push_back(kIW03); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - EXPECT_EQ(3u, sender_->congestion_window()); - - options.clear(); - options.push_back(kIW10); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - EXPECT_EQ(10u, sender_->congestion_window()); - - options.clear(); - options.push_back(kIW20); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - EXPECT_EQ(20u, sender_->congestion_window()); - - options.clear(); - options.push_back(kIW50); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - EXPECT_EQ(50u, sender_->congestion_window()); -} - -TEST_F(TcpCubicSenderTest, ConfigureMinimumWindow) { - QuicConfig config; - - // Verify that kCOPT: kMIN1 forces the min CWND to 1 packet. - QuicTagVector options; - options.push_back(kMIN1); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - sender_->OnRetransmissionTimeout(true); - EXPECT_EQ(1u, sender_->congestion_window()); -} - -TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) { - sender_->SetNumEmulatedConnections(2); - // Ack 10 packets in 5 acks to raise the CWND to 20. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window = expected_send_window * sender_->GetRenoBeta(); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // No congestion window growth should occur in recovery phase, i.e., until the - // currently outstanding 20 packets are acked. - for (int i = 0; i < 10; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - EXPECT_TRUE(sender_->InRecovery()); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - EXPECT_FALSE(sender_->InRecovery()); - - // Out of recovery now. Congestion window should not grow for half an RTT. - size_t packets_in_send_window = expected_send_window / kDefaultTCPMSS; - SendAvailableSendWindow(); - AckNPackets(packets_in_send_window / 2 - 2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should increase congestion window by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - packets_in_send_window += 1; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Congestion window should remain steady again for half an RTT. - SendAvailableSendWindow(); - AckNPackets(packets_in_send_window / 2 - 1); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Next ack should cause congestion window to grow by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, 1ConnectionCongestionAvoidanceAtEndOfRecovery) { - sender_->SetNumEmulatedConnections(1); - // Ack 10 packets in 5 acks to raise the CWND to 20. - const int kNumberOfAcks = 5; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // No congestion window growth should occur in recovery phase, i.e., until the - // currently outstanding 20 packets are acked. - for (int i = 0; i < 10; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - EXPECT_TRUE(sender_->InRecovery()); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - EXPECT_FALSE(sender_->InRecovery()); - - // Out of recovery now. Congestion window should not grow during RTT. - for (uint64_t i = 0; i < expected_send_window / kDefaultTCPMSS - 2; i += 2) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - } - - // Next ack should cause congestion window to grow by 1MSS. - SendAvailableSendWindow(); - AckNPackets(2); - expected_send_window += kDefaultTCPMSS; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, BandwidthResumption) { - // Test that when provided with CachedNetworkParameters and opted in to the - // bandwidth resumption experiment, that the TcpCubicSender sets initial CWND - // appropriately. - - // Set some common values. - CachedNetworkParameters cached_network_params; - const QuicPacketCount kNumberOfPackets = 123; - const int kBandwidthEstimateBytesPerSecond = - kNumberOfPackets * kDefaultTCPMSS; - cached_network_params.set_bandwidth_estimate_bytes_per_second( - kBandwidthEstimateBytesPerSecond); - cached_network_params.set_min_rtt_ms(1000); - - // Make sure that a bandwidth estimate results in a changed CWND. - cached_network_params.set_timestamp(clock_.WallNow().ToUNIXSeconds() - - (kNumSecondsPerHour - 1)); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kNumberOfPackets, sender_->congestion_window()); - - // Resumed CWND is limited to be in a sensible range. - cached_network_params.set_bandwidth_estimate_bytes_per_second( - (kMaxCongestionWindow + 1) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kMaxCongestionWindow, sender_->congestion_window()); - - cached_network_params.set_bandwidth_estimate_bytes_per_second( - (kMinCongestionWindowForBandwidthResumption - 1) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, false); - EXPECT_EQ(kMinCongestionWindowForBandwidthResumption, - sender_->congestion_window()); - - // Resume to the max value. - cached_network_params.set_max_bandwidth_estimate_bytes_per_second( - (kMinCongestionWindowForBandwidthResumption + 10) * kDefaultTCPMSS); - sender_->ResumeConnectionState(cached_network_params, true); - EXPECT_EQ((kMinCongestionWindowForBandwidthResumption + 10) * kDefaultTCPMSS, - sender_->GetCongestionWindow()); -} - -TEST_F(TcpCubicSenderTest, PaceBelowCWND) { - QuicConfig config; - - // Verify that kCOPT: kMIN4 forces the min CWND to 1 packet, but allows up - // to 4 to be sent. - QuicTagVector options; - options.push_back(kMIN4); - QuicConfigPeer::SetReceivedConnectionOptions(&config, options); - sender_->SetFromConfig(config, Perspective::IS_SERVER); - sender_->OnRetransmissionTimeout(true); - EXPECT_EQ(1u, sender_->congestion_window()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), 2 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_TRUE(sender_->TimeUntilSend(QuicTime::Zero(), 3 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); - EXPECT_FALSE(sender_->TimeUntilSend(QuicTime::Zero(), 4 * kDefaultTCPMSS, - HAS_RETRANSMITTABLE_DATA) - .IsZero()); -} - -TEST_F(TcpCubicSenderTest, ResetAfterConnectionMigration) { - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - EXPECT_EQ(kMaxCongestionWindow, sender_->slowstart_threshold()); - - // Starts with slow start. - sender_->SetNumEmulatedConnections(1); - const int kNumberOfAcks = 10; - for (int i = 0; i < kNumberOfAcks; ++i) { - // Send our full send window. - SendAvailableSendWindow(); - AckNPackets(2); - } - SendAvailableSendWindow(); - QuicByteCount expected_send_window = - kDefaultWindowTCP + (kDefaultTCPMSS * 2 * kNumberOfAcks); - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - - // Loses a packet to exit slow start. - LoseNPackets(1); - - // We should now have fallen out of slow start with a reduced window. Slow - // start threshold is also updated. - expected_send_window *= kRenoBeta; - EXPECT_EQ(expected_send_window, sender_->GetCongestionWindow()); - EXPECT_EQ(expected_send_window / kDefaultTCPMSS, - sender_->slowstart_threshold()); - - // Resets cwnd and slow start threshold on connection migrations. - sender_->OnConnectionMigration(); - EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow()); - EXPECT_EQ(kMaxCongestionWindow, sender_->slowstart_threshold()); - EXPECT_FALSE(sender_->hybrid_slow_start().started()); -} - -} // namespace test -} // namespace net
diff --git a/net/quic/crypto/aead_base_decrypter.h b/net/quic/crypto/aead_base_decrypter.h index edd110b..c76f11f 100644 --- a/net/quic/crypto/aead_base_decrypter.h +++ b/net/quic/crypto/aead_base_decrypter.h
@@ -40,8 +40,8 @@ bool SetNoncePrefix(base::StringPiece nonce_prefix) override; bool DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const base::StringPiece& associated_data, - const base::StringPiece& ciphertext, + base::StringPiece associated_data, + base::StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) override; @@ -65,7 +65,7 @@ }; virtual void FillAeadParams(base::StringPiece nonce, - const base::StringPiece& associated_data, + base::StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const = 0; #endif // !defined(USE_OPENSSL)
diff --git a/net/quic/crypto/aead_base_decrypter_nss.cc b/net/quic/crypto/aead_base_decrypter_nss.cc index 26e72ee..46228cc 100644 --- a/net/quic/crypto/aead_base_decrypter_nss.cc +++ b/net/quic/crypto/aead_base_decrypter_nss.cc
@@ -49,8 +49,8 @@ bool AeadBaseDecrypter::DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const StringPiece& associated_data, - const StringPiece& ciphertext, + StringPiece associated_data, + StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) {
diff --git a/net/quic/crypto/aead_base_decrypter_openssl.cc b/net/quic/crypto/aead_base_decrypter_openssl.cc index 512b8047..097cb4f 100644 --- a/net/quic/crypto/aead_base_decrypter_openssl.cc +++ b/net/quic/crypto/aead_base_decrypter_openssl.cc
@@ -81,8 +81,8 @@ bool AeadBaseDecrypter::DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const StringPiece& associated_data, - const StringPiece& ciphertext, + StringPiece associated_data, + StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) {
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter.h b/net/quic/crypto/aes_128_gcm_12_decrypter.h index d0d305a..f8b1196 100644 --- a/net/quic/crypto/aes_128_gcm_12_decrypter.h +++ b/net/quic/crypto/aes_128_gcm_12_decrypter.h
@@ -33,7 +33,7 @@ protected: // AeadBaseDecrypter methods: void FillAeadParams(base::StringPiece nonce, - const base::StringPiece& associated_data, + base::StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const override; #endif
diff --git a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc index abbc565..d4480f4 100644 --- a/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc +++ b/net/quic/crypto/aes_128_gcm_12_decrypter_nss.cc
@@ -28,7 +28,7 @@ Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {} void Aes128Gcm12Decrypter::FillAeadParams(StringPiece nonce, - const StringPiece& associated_data, + StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const { aead_params->len = sizeof(aead_params->data.gcm_params);
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter.h b/net/quic/crypto/chacha20_poly1305_decrypter.h index fad9bbb..1e0fd05f 100644 --- a/net/quic/crypto/chacha20_poly1305_decrypter.h +++ b/net/quic/crypto/chacha20_poly1305_decrypter.h
@@ -34,7 +34,7 @@ protected: // AeadBaseDecrypter methods: void FillAeadParams(base::StringPiece nonce, - const base::StringPiece& associated_data, + base::StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const override; #endif
diff --git a/net/quic/crypto/chacha20_poly1305_decrypter_nss.cc b/net/quic/crypto/chacha20_poly1305_decrypter_nss.cc index 893f8a7..aeff43a 100644 --- a/net/quic/crypto/chacha20_poly1305_decrypter_nss.cc +++ b/net/quic/crypto/chacha20_poly1305_decrypter_nss.cc
@@ -29,11 +29,10 @@ ChaCha20Poly1305Decrypter::~ChaCha20Poly1305Decrypter() {} -void ChaCha20Poly1305Decrypter::FillAeadParams( - StringPiece nonce, - const StringPiece& associated_data, - size_t auth_tag_size, - AeadParams* aead_params) const { +void ChaCha20Poly1305Decrypter::FillAeadParams(StringPiece nonce, + StringPiece associated_data, + size_t auth_tag_size, + AeadParams* aead_params) const { aead_params->len = sizeof(aead_params->data.nss_aead_params); CK_NSS_AEAD_PARAMS* nss_aead_params = &aead_params->data.nss_aead_params; nss_aead_params->pIv =
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h index 3889216..57609d0 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter.h
@@ -42,7 +42,7 @@ protected: // AeadBaseDecrypter methods: void FillAeadParams(base::StringPiece nonce, - const base::StringPiece& associated_data, + base::StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const override; #endif
diff --git a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc index 8c830e9..799a2c5a 100644 --- a/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc +++ b/net/quic/crypto/chacha20_poly1305_rfc7539_decrypter_nss.cc
@@ -43,7 +43,7 @@ void ChaCha20Poly1305Rfc7539Decrypter::FillAeadParams( base::StringPiece nonce, - const base::StringPiece& associated_data, + base::StringPiece associated_data, size_t auth_tag_size, AeadParams* aead_params) const {}
diff --git a/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h index 5d2f71f5..14d3fab 100644 --- a/net/quic/crypto/crypto_protocol.h +++ b/net/quic/crypto/crypto_protocol.h
@@ -89,6 +89,8 @@ const QuicTag kTLPR = TAG('T', 'L', 'P', 'R'); // Tail loss probe delay of // 0.5RTT. const QuicTag kACKD = TAG('A', 'C', 'K', 'D'); // Ack decimation style acking. +const QuicTag kAKD2 = TAG('A', 'K', 'D', '2'); // Ack decimation tolerating + // out of order packets. const QuicTag kSSLR = TAG('S', 'S', 'L', 'R'); // Slow Start Large Reduction. // Optional support of truncated Connection IDs. If sent by a peer, the value @@ -99,15 +101,6 @@ // Multipath option. const QuicTag kMPTH = TAG('M', 'P', 'T', 'H'); // Enable multipath. -// FEC options -const QuicTag kFHDR = TAG('F', 'H', 'D', 'R'); // FEC protect headers -const QuicTag kFSTR = TAG('F', 'S', 'T', 'R'); // FEC protect all streams -// Set FecSendPolicy for sending FEC packet only when FEC alarm goes off. -const QuicTag kFSPA = TAG('F', 'S', 'P', 'A'); -// Run an experiment that sets FecTimeOut alarm to 0.25RTT. -// TODO(rtenneti): Delete it after the experiment. -const QuicTag kFRTT = TAG('F', 'R', 'T', 'T'); - // Enable bandwidth resumption experiment. const QuicTag kBWRE = TAG('B', 'W', 'R', 'E'); // Bandwidth resumption. const QuicTag kBWMX = TAG('B', 'W', 'M', 'X'); // Max bandwidth resumption.
diff --git a/net/quic/crypto/crypto_server_test.cc b/net/quic/crypto/crypto_server_test.cc index 8c0e3ee..85cf2aa 100644 --- a/net/quic/crypto/crypto_server_test.cc +++ b/net/quic/crypto/crypto_server_test.cc
@@ -507,7 +507,6 @@ } TEST_P(CryptoServerTest, RejectTooLargeButValidSTK) { - ValueRestore<bool> old_flag(&FLAGS_quic_validate_stk_without_scid, true); // Check that the server replies with no certificate when a CHLO is // constructed with a PDMD but no SKT when the REJ would be too large. // clang-format off @@ -540,37 +539,6 @@ CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); } -TEST_P(CryptoServerTest, RejectTooLargeButValidSTKWithoutFlag) { - ValueRestore<bool> old_flag(&FLAGS_quic_validate_stk_without_scid, false); - // Check that the server replies with no certificate when a CHLO is - // constructed with a PDMD but no SKT when the REJ would be too large. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PDMD", "X509", - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on - - // The REJ will be larger than the CHLO so no PROF or CRT will be sent. - config_.set_chlo_multiplier(1); - - ShouldSucceed(msg); - StringPiece cert, proof, cert_sct; - EXPECT_FALSE(out_.GetStringPiece(kCertificateTag, &cert)); - EXPECT_FALSE(out_.GetStringPiece(kPROF, &proof)); - EXPECT_FALSE(out_.GetStringPiece(kCertificateSCTTag, &cert_sct)); - const HandshakeFailureReason kRejectReasons[] = { - SERVER_CONFIG_INCHOATE_HELLO_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); -} - TEST_P(CryptoServerTest, TooSmall) { // clang-format off ShouldFailMentioning("too small", CryptoTestUtils::Message( @@ -758,50 +726,7 @@ }; } -TEST_P(CryptoServerTest, ReplayProtection) { - if (client_version_ > QUIC_VERSION_30) { - return; - } - FLAGS_require_strike_register_or_server_nonce = false; - // This tests that disabling replay protection works. - // clang-format off - CryptoHandshakeMessage msg = CryptoTestUtils::Message( - "CHLO", - "AEAD", "AESG", - "KEXS", "C255", - "SCID", scid_hex_.c_str(), - "#004b5453", srct_hex_.c_str(), - "PUBS", pub_hex_.c_str(), - "NONC", nonce_hex_.c_str(), - "XLCT", XlctHexString().c_str(), - "VER\0", client_version_string_.c_str(), - "$padding", static_cast<int>(kClientHelloMinimumSize), - nullptr); - // clang-format on - ShouldSucceed(msg); - // The message should be rejected because the strike-register is still - // quiescent. - CheckRejectTag(); - - const HandshakeFailureReason kRejectReasons[] = { - CLIENT_NONCE_INVALID_TIME_FAILURE}; - CheckRejectReasons(kRejectReasons, arraysize(kRejectReasons)); - - config_.set_replay_protection(false); - - ShouldSucceed(msg); - // The message should be accepted now. - ASSERT_EQ(kSHLO, out_.tag()); - CheckServerHello(out_); - - ShouldSucceed(msg); - // The message should accepted twice when replay protection is off. - ASSERT_EQ(kSHLO, out_.tag()); - CheckServerHello(out_); -} - TEST_P(CryptoServerTest, NoServerNonce) { - FLAGS_require_strike_register_or_server_nonce = true; // When no server nonce is present and no strike register is configured, // the CHLO should be rejected. // clang-format off
diff --git a/net/quic/crypto/curve25519_key_exchange.cc b/net/quic/crypto/curve25519_key_exchange.cc index cf97add..6545d21 100644 --- a/net/quic/crypto/curve25519_key_exchange.cc +++ b/net/quic/crypto/curve25519_key_exchange.cc
@@ -18,8 +18,7 @@ Curve25519KeyExchange::~Curve25519KeyExchange() {} // static -Curve25519KeyExchange* Curve25519KeyExchange::New( - const StringPiece& private_key) { +Curve25519KeyExchange* Curve25519KeyExchange::New(StringPiece private_key) { Curve25519KeyExchange* ka; // We don't want to #include the NaCl headers in the public header file, so // we use literals for the sizes of private_key_ and public_key_. Here we @@ -58,9 +57,8 @@ return Curve25519KeyExchange::New(private_value); } -bool Curve25519KeyExchange::CalculateSharedKey( - const StringPiece& peer_public_value, - string* out_result) const { +bool Curve25519KeyExchange::CalculateSharedKey(StringPiece peer_public_value, + string* out_result) const { if (peer_public_value.size() != crypto::curve25519::kBytes) { return false; }
diff --git a/net/quic/crypto/curve25519_key_exchange.h b/net/quic/crypto/curve25519_key_exchange.h index 1637bbb..a95cf7f 100644 --- a/net/quic/crypto/curve25519_key_exchange.h +++ b/net/quic/crypto/curve25519_key_exchange.h
@@ -26,7 +26,7 @@ // New creates a new object from a private key. If the private key is // invalid, nullptr is returned. - static Curve25519KeyExchange* New(const base::StringPiece& private_key); + static Curve25519KeyExchange* New(base::StringPiece private_key); // NewPrivateKey returns a private key, generated from |rand|, suitable for // passing to |New|. @@ -34,7 +34,7 @@ // KeyExchange interface. KeyExchange* NewKeyPair(QuicRandom* rand) const override; - bool CalculateSharedKey(const base::StringPiece& peer_public_value, + bool CalculateSharedKey(base::StringPiece peer_public_value, std::string* shared_key) const override; base::StringPiece public_value() const override; QuicTag tag() const override;
diff --git a/net/quic/crypto/key_exchange.h b/net/quic/crypto/key_exchange.h index 8690f0e..a6de1c39 100644 --- a/net/quic/crypto/key_exchange.h +++ b/net/quic/crypto/key_exchange.h
@@ -29,7 +29,7 @@ // CalculateSharedKey computes the shared key between the local private key // (which is implicitly known by a KeyExchange object) and a public value // from the peer. - virtual bool CalculateSharedKey(const base::StringPiece& peer_public_value, + virtual bool CalculateSharedKey(base::StringPiece peer_public_value, std::string* shared_key) const = 0; // public_value returns the local public key which can be sent to a peer in
diff --git a/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc index 52217b5..43adb6795 100644 --- a/net/quic/crypto/null_decrypter.cc +++ b/net/quic/crypto/null_decrypter.cc
@@ -27,8 +27,8 @@ bool NullDecrypter::DecryptPacket(QuicPathId /*path_id*/, QuicPacketNumber /*packet_number*/, - const StringPiece& associated_data, - const StringPiece& ciphertext, + StringPiece associated_data, + StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) {
diff --git a/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h index 91b5856..e5e15b2 100644 --- a/net/quic/crypto/null_decrypter.h +++ b/net/quic/crypto/null_decrypter.h
@@ -30,8 +30,8 @@ bool SetNoncePrefix(base::StringPiece nonce_prefix) override; bool DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const base::StringPiece& associated_data, - const base::StringPiece& ciphertext, + base::StringPiece associated_data, + base::StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) override; @@ -43,8 +43,7 @@ private: bool ReadHash(QuicDataReader* reader, uint128* hash); - uint128 ComputeHash(const base::StringPiece data1, - const base::StringPiece data2) const; + uint128 ComputeHash(base::StringPiece data1, base::StringPiece data2) const; DISALLOW_COPY_AND_ASSIGN(NullDecrypter); };
diff --git a/net/quic/crypto/p256_key_exchange.h b/net/quic/crypto/p256_key_exchange.h index e6855aa..197adfe5 100644 --- a/net/quic/crypto/p256_key_exchange.h +++ b/net/quic/crypto/p256_key_exchange.h
@@ -42,7 +42,7 @@ // KeyExchange interface. KeyExchange* NewKeyPair(QuicRandom* rand) const override; - bool CalculateSharedKey(const base::StringPiece& peer_public_value, + bool CalculateSharedKey(base::StringPiece peer_public_value, std::string* shared_key) const override; base::StringPiece public_value() const override; QuicTag tag() const override;
diff --git a/net/quic/crypto/p256_key_exchange_nss.cc b/net/quic/crypto/p256_key_exchange_nss.cc index 576825f9..c5529ab 100644 --- a/net/quic/crypto/p256_key_exchange_nss.cc +++ b/net/quic/crypto/p256_key_exchange_nss.cc
@@ -153,7 +153,7 @@ return P256KeyExchange::New(private_value); } -bool P256KeyExchange::CalculateSharedKey(const StringPiece& peer_public_value, +bool P256KeyExchange::CalculateSharedKey(StringPiece peer_public_value, string* out_result) const { if (peer_public_value.size() != kUncompressedP256PointBytes || peer_public_value[0] != kUncompressedECPointForm) {
diff --git a/net/quic/crypto/p256_key_exchange_openssl.cc b/net/quic/crypto/p256_key_exchange_openssl.cc index 7a9707e..9703a2e9 100644 --- a/net/quic/crypto/p256_key_exchange_openssl.cc +++ b/net/quic/crypto/p256_key_exchange_openssl.cc
@@ -77,7 +77,7 @@ return P256KeyExchange::New(private_value); } -bool P256KeyExchange::CalculateSharedKey(const StringPiece& peer_public_value, +bool P256KeyExchange::CalculateSharedKey(StringPiece peer_public_value, string* out_result) const { if (peer_public_value.size() != kUncompressedP256PointBytes) { DVLOG(1) << "Peer public value is invalid";
diff --git a/net/quic/crypto/quic_crypto_server_config.cc b/net/quic/crypto/quic_crypto_server_config.cc index cd14bc1e1..25d344b7 100644 --- a/net/quic/crypto/quic_crypto_server_config.cc +++ b/net/quic/crypto/quic_crypto_server_config.cc
@@ -997,23 +997,21 @@ HandshakeFailureReason source_address_token_error = MAX_FAILURE_REASON; StringPiece srct; - if (FLAGS_quic_validate_stk_without_scid) { - if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { - Config& config = - requested_config != nullptr ? *requested_config : *primary_config; - source_address_token_error = - ParseSourceAddressToken(config, srct, &info->source_address_tokens); + if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { + Config& config = + requested_config != nullptr ? *requested_config : *primary_config; + source_address_token_error = + ParseSourceAddressToken(config, srct, &info->source_address_tokens); - if (source_address_token_error == HANDSHAKE_OK) { - source_address_token_error = ValidateSourceAddressTokens( - info->source_address_tokens, info->client_ip, info->now, - &client_hello_state->cached_network_params); - } - info->valid_source_address_token = - (source_address_token_error == HANDSHAKE_OK); - } else { - source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; + if (source_address_token_error == HANDSHAKE_OK) { + source_address_token_error = ValidateSourceAddressTokens( + info->source_address_tokens, info->client_ip, info->now, + &client_hello_state->cached_network_params); } + info->valid_source_address_token = + (source_address_token_error == HANDSHAKE_OK); + } else { + source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; } if (!requested_config.get()) { @@ -1028,23 +1026,6 @@ return; } - if (!FLAGS_quic_validate_stk_without_scid) { - if (client_hello.GetStringPiece(kSourceAddressTokenTag, &srct)) { - source_address_token_error = ParseSourceAddressToken( - *requested_config, srct, &info->source_address_tokens); - - if (source_address_token_error == HANDSHAKE_OK) { - source_address_token_error = ValidateSourceAddressTokens( - info->source_address_tokens, info->client_ip, info->now, - &client_hello_state->cached_network_params); - } - info->valid_source_address_token = - (source_address_token_error == HANDSHAKE_OK); - } else { - source_address_token_error = SOURCE_ADDRESS_TOKEN_INVALID_FAILURE; - } - } - bool found_error = false; if (source_address_token_error != HANDSHAKE_OK) { info->reject_reasons.push_back(source_address_token_error); @@ -1140,18 +1121,6 @@ StrikeRegisterClient* strike_register_client; { base::AutoLock locked(strike_register_client_lock_); - - if (strike_register_client_.get() == nullptr) { - if (!FLAGS_require_strike_register_or_server_nonce) { - strike_register_client_.reset(new LocalStrikeRegisterClient( - strike_register_max_entries_, - static_cast<uint32_t>(info->now.ToUNIXSeconds()), - strike_register_window_secs_, primary_orbit, - strike_register_no_startup_period_ - ? StrikeRegister::NO_STARTUP_PERIOD_NEEDED - : StrikeRegister::DENY_REQUESTS_AT_STARTUP)); - } - } strike_register_client = strike_register_client_.get(); }
diff --git a/net/quic/crypto/quic_crypto_server_config_test.cc b/net/quic/crypto/quic_crypto_server_config_test.cc index f3f9de7..0585a19 100644 --- a/net/quic/crypto/quic_crypto_server_config_test.cc +++ b/net/quic/crypto/quic_crypto_server_config_test.cc
@@ -145,7 +145,8 @@ } ASSERT_TRUE(found) << "Failed to find match for " << i.first - << " in configs:\n" << ConfigsDebug(); + << " in configs:\n" + << ConfigsDebug(); } }
diff --git a/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h index 3e55170..4f2be96 100644 --- a/net/quic/crypto/quic_decrypter.h +++ b/net/quic/crypto/quic_decrypter.h
@@ -52,8 +52,8 @@ // to non-authentic inputs, as opposed to other reasons for failure. virtual bool DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const base::StringPiece& associated_data, - const base::StringPiece& ciphertext, + base::StringPiece associated_data, + base::StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) = 0;
diff --git a/net/quic/quic_alarm.cc b/net/quic/quic_alarm.cc index b978a14..ca407b52 100644 --- a/net/quic/quic_alarm.cc +++ b/net/quic/quic_alarm.cc
@@ -5,6 +5,7 @@ #include "net/quic/quic_alarm.h" #include "base/logging.h" +#include "net/quic/quic_flags.h" namespace net { @@ -13,29 +14,33 @@ QuicAlarm::~QuicAlarm() {} -void QuicAlarm::Set(QuicTime deadline) { +void QuicAlarm::Set(QuicTime new_deadline) { DCHECK(!IsSet()); - DCHECK(deadline.IsInitialized()); - deadline_ = deadline; + DCHECK(new_deadline.IsInitialized()); + deadline_ = new_deadline; SetImpl(); } void QuicAlarm::Cancel() { + if (FLAGS_quic_only_cancel_set_alarms && !IsSet()) { + // Don't try to cancel an alarm that hasn't been set. + return; + } deadline_ = QuicTime::Zero(); CancelImpl(); } -void QuicAlarm::Update(QuicTime deadline, QuicTime::Delta granularity) { - if (!deadline.IsInitialized()) { +void QuicAlarm::Update(QuicTime new_deadline, QuicTime::Delta granularity) { + if (!new_deadline.IsInitialized()) { Cancel(); return; } - if (std::abs(deadline.Subtract(deadline_).ToMicroseconds()) < + if (std::abs(new_deadline.Subtract(deadline_).ToMicroseconds()) < granularity.ToMicroseconds()) { return; } Cancel(); - Set(deadline); + Set(new_deadline); } bool QuicAlarm::IsSet() const { @@ -43,19 +48,12 @@ } void QuicAlarm::Fire() { - if (!deadline_.IsInitialized()) { + if (!IsSet()) { return; } deadline_ = QuicTime::Zero(); - QuicTime deadline = delegate_->OnAlarm(); - // delegate_->OnAlarm() might call Set(), in which case deadline_ - // will already contain the new value, so don't overwrite it. Also, - // OnAlarm() might delete |this| so check |deadline| before - // |deadline_|. - if (deadline.IsInitialized() && !deadline_.IsInitialized()) { - Set(deadline); - } + delegate_->OnAlarm(); } } // namespace net
diff --git a/net/quic/quic_alarm.h b/net/quic/quic_alarm.h index a775cfb5..53a823f 100644 --- a/net/quic/quic_alarm.h +++ b/net/quic/quic_alarm.h
@@ -24,10 +24,8 @@ public: virtual ~Delegate() {} - // Invoked when the alarm fires. If the return value is not - // infinite, then the alarm will be rescheduled at the - // specified time. - virtual QuicTime OnAlarm() = 0; + // Invoked when the alarm fires. + virtual void OnAlarm() = 0; }; explicit QuicAlarm(QuicArenaScopedPtr<Delegate> delegate); @@ -36,7 +34,7 @@ // Sets the alarm to fire at |deadline|. Must not be called while // the alarm is set. To reschedule an alarm, call Cancel() first, // then Set(). - void Set(QuicTime deadline); + void Set(QuicTime new_deadline); // Cancels the alarm. May be called repeatedly. Does not // guarantee that the underlying scheduling system will remove @@ -47,8 +45,9 @@ // Cancels and sets the alarm if the |deadline| is farther from the current // deadline than |granularity|, and otherwise does nothing. If |deadline| is // not initialized, the alarm is cancelled. - void Update(QuicTime deadline, QuicTime::Delta granularity); + void Update(QuicTime new_deadline, QuicTime::Delta granularity); + // Returns true if |deadline_| has been set to a non-zero time. bool IsSet() const; QuicTime deadline() const { return deadline_; }
diff --git a/net/quic/quic_alarm_test.cc b/net/quic/quic_alarm_test.cc index 0ae64597..0509090 100644 --- a/net/quic/quic_alarm_test.cc +++ b/net/quic/quic_alarm_test.cc
@@ -17,7 +17,7 @@ class MockDelegate : public QuicAlarm::Delegate { public: - MOCK_METHOD0(OnAlarm, QuicTime()); + MOCK_METHOD0(OnAlarm, void()); }; class DestructiveDelegate : public QuicAlarm::Delegate { @@ -26,10 +26,9 @@ void set_alarm(QuicAlarm* alarm) { alarm_ = alarm; } - QuicTime OnAlarm() override { + void OnAlarm() override { DCHECK(alarm_); delete alarm_; - return QuicTime::Zero(); } private: @@ -137,28 +136,17 @@ TEST_F(QuicAlarmTest, Fire) { QuicTime deadline = QuicTime::Zero().Add(QuicTime::Delta::FromSeconds(7)); alarm_.Set(deadline); - EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Return(QuicTime::Zero())); alarm_.FireAlarm(); EXPECT_FALSE(alarm_.IsSet()); EXPECT_FALSE(alarm_.scheduled()); EXPECT_EQ(QuicTime::Zero(), alarm_.deadline()); } -TEST_F(QuicAlarmTest, FireAndResetViaReturn) { - alarm_.Set(deadline_); - EXPECT_CALL(*delegate_, OnAlarm()).WillOnce(Return(deadline2_)); - alarm_.FireAlarm(); - EXPECT_TRUE(alarm_.IsSet()); - EXPECT_TRUE(alarm_.scheduled()); - EXPECT_EQ(deadline2_, alarm_.deadline()); -} - TEST_F(QuicAlarmTest, FireAndResetViaSet) { alarm_.Set(deadline_); new_deadline_ = deadline2_; EXPECT_CALL(*delegate_, OnAlarm()) - .WillOnce(DoAll(Invoke(this, &QuicAlarmTest::ResetAlarm), - Return(QuicTime::Zero()))); + .WillOnce(Invoke(this, &QuicAlarmTest::ResetAlarm)); alarm_.FireAlarm(); EXPECT_TRUE(alarm_.IsSet()); EXPECT_TRUE(alarm_.scheduled());
diff --git a/net/quic/quic_chromium_client_session_test.cc b/net/quic/quic_chromium_client_session_test.cc index bb1a57a..2de5d3c 100644 --- a/net/quic/quic_chromium_client_session_test.cc +++ b/net/quic/quic_chromium_client_session_test.cc
@@ -368,7 +368,7 @@ iov[0].iov_base = data; iov[0].iov_len = 4; session_->WritevData(5, QuicIOVector(iov, arraysize(iov), 4), 0, false, - MAY_FEC_PROTECT, nullptr); + nullptr); EXPECT_TRUE(socket_data.AllReadDataConsumed()); EXPECT_TRUE(socket_data.AllWriteDataConsumed());
diff --git a/net/quic/quic_chromium_client_stream.cc b/net/quic/quic_chromium_client_stream.cc index b68fa82e..529f0a7 100644 --- a/net/quic/quic_chromium_client_stream.cc +++ b/net/quic/quic_chromium_client_stream.cc
@@ -36,35 +36,27 @@ void QuicChromiumClientStream::OnStreamHeadersComplete(bool fin, size_t frame_len) { QuicSpdyStream::OnStreamHeadersComplete(fin, frame_len); - SpdyHeaderBlock headers; - SpdyFramer framer(HTTP2); - - size_t headers_len; - const char* header_data; if (decompressed_headers().empty() && !decompressed_trailers().empty()) { DCHECK(trailers_decompressed()); - headers_len = decompressed_trailers().length(); - header_data = decompressed_trailers().data(); + // The delegate will read the trailers via a posted task. + NotifyDelegateOfHeadersCompleteLater(response_trailers(), frame_len); } else { DCHECK(!headers_delivered_); - headers_len = decompressed_headers().length(); - header_data = decompressed_headers().data(); - } - if (!framer.ParseHeaderBlockInBuffer(header_data, headers_len, &headers)) { - DLOG(WARNING) << "Invalid headers"; - Reset(QUIC_BAD_APPLICATION_PAYLOAD); - return; - } - - if (!headers_delivered_) { + SpdyHeaderBlock headers; + SpdyFramer framer(HTTP2); + size_t headers_len = decompressed_headers().length(); + const char* header_data = decompressed_headers().data(); + if (!framer.ParseHeaderBlockInBuffer(header_data, headers_len, &headers)) { + DLOG(WARNING) << "Invalid headers"; + Reset(QUIC_BAD_APPLICATION_PAYLOAD); + return; + } MarkHeadersConsumed(headers_len); session_->OnInitialHeadersComplete(id(), headers); - } else { - MarkTrailersConsumed(headers_len); - } - // The delegate will read the headers via a posted task. - NotifyDelegateOfHeadersCompleteLater(headers, frame_len); + // The delegate will read the headers via a posted task. + NotifyDelegateOfHeadersCompleteLater(headers, frame_len); + } } void QuicChromiumClientStream::OnPromiseHeadersComplete( @@ -194,6 +186,9 @@ size_t frame_len) { if (!delegate_) return; + // Only mark trailers consumed when we are about to notify delegate. + if (headers_delivered_) + MarkTrailersConsumed(decompressed_trailers().length()); headers_delivered_ = true; delegate_->OnHeadersAvailable(headers, frame_len);
diff --git a/net/quic/quic_chromium_client_stream_test.cc b/net/quic/quic_chromium_client_stream_test.cc index f384304..4e9e2bc 100644 --- a/net/quic/quic_chromium_client_stream_test.cc +++ b/net/quic/quic_chromium_client_stream_test.cc
@@ -5,6 +5,8 @@ #include "net/quic/quic_chromium_client_stream.h" #include "base/macros.h" +#include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "net/base/net_errors.h" #include "net/base/test_completion_callback.h" #include "net/quic/quic_chromium_client_session.h" @@ -35,7 +37,8 @@ MOCK_METHOD0(OnSendData, int()); MOCK_METHOD2(OnSendDataComplete, int(int, bool*)); - MOCK_METHOD2(OnHeadersAvailable, void(const SpdyHeaderBlock&, size_t)); + MOCK_METHOD2(OnHeadersAvailable, + void(const SpdyHeaderBlock& headers, size_t frame_len)); MOCK_METHOD2(OnDataReceived, int(const char*, int)); MOCK_METHOD0(OnDataAvailable, void()); MOCK_METHOD1(OnClose, void(QuicErrorCode)); @@ -60,12 +63,11 @@ MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicChromiumClientStream*(SpdyPriority priority)); - MOCK_METHOD6(WritevData, + MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id, QuicIOVector data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface*)); MOCK_METHOD3(SendRstStream, void(QuicStreamId stream_id, @@ -102,7 +104,6 @@ const QuicIOVector& data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* ack_notifier_delegate); void OnProofValid( @@ -125,7 +126,7 @@ DefaultQuicConfig()) { crypto_stream_.reset(new QuicCryptoStream(this)); Initialize(); - ON_CALL(*this, WritevData(_, _, _, _, _, _)) + ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } @@ -315,14 +316,103 @@ SpdyHeaderBlock trailers; trailers["bar"] = "foo"; + trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data)); std::string uncompressed_trailers = SpdyUtils::SerializeUncompressedHeaders(trailers); stream_->OnStreamHeaders(uncompressed_trailers); stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length()); + SpdyHeaderBlock actual_trailers; + + base::RunLoop run_loop; + EXPECT_CALL(delegate_, OnHeadersAvailable(_, uncompressed_trailers.length())) + .WillOnce(testing::DoAll( + testing::SaveArg<0>(&actual_trailers), + testing::InvokeWithoutArgs([&run_loop]() { run_loop.Quit(); }))); + + run_loop.Run(); + // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers. + trailers.erase(kFinalOffsetHeaderKey); + EXPECT_EQ(trailers, actual_trailers); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); +} + +// Tests that trailers are marked as consumed only before delegate is to be +// immediately notified about trailers. +TEST_P(QuicChromiumClientStreamTest, MarkTrailersConsumedWhenNotifyDelegate) { + InitializeHeaders(); + std::string uncompressed_headers = + SpdyUtils::SerializeUncompressedHeaders(headers_); + stream_->OnStreamHeaders(uncompressed_headers); + stream_->OnStreamHeadersComplete(false, uncompressed_headers.length()); + EXPECT_CALL(delegate_, - OnHeadersAvailable(trailers, uncompressed_trailers.length())); + OnHeadersAvailable(headers_, uncompressed_headers.length())); + base::MessageLoop::current()->RunUntilIdle(); + EXPECT_TRUE(stream_->decompressed_headers().empty()); + + const char data[] = "hello world!"; + stream_->OnStreamFrame(QuicStreamFrame(kTestStreamId, /*fin=*/false, + /*offset=*/0, data)); + + base::RunLoop run_loop; + EXPECT_CALL(delegate_, OnDataAvailable()) + .Times(1) + .WillOnce(testing::DoAll( + testing::Invoke(CreateFunctor( + &QuicChromiumClientStreamTest::ReadData, base::Unretained(this), + StringPiece(data, arraysize(data) - 1))), + testing::Invoke([&run_loop]() { run_loop.Quit(); }))); + + // Wait for the read to complete. + run_loop.Run(); + + // Read again, and it will be pending. + scoped_refptr<IOBuffer> buffer(new IOBuffer(1)); + EXPECT_EQ(ERR_IO_PENDING, stream_->Read(buffer.get(), 1)); + + SpdyHeaderBlock trailers; + trailers["bar"] = "foo"; + trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(data)); + std::string uncompressed_trailers = + SpdyUtils::SerializeUncompressedHeaders(trailers); + + stream_->OnStreamHeaders(uncompressed_trailers); + stream_->OnStreamHeadersComplete(true, uncompressed_trailers.length()); + EXPECT_FALSE(stream_->IsDoneReading()); + + // Now the pending should complete. Make sure that IsDoneReading() is false + // even though ReadData returns 0 byte, because OnHeadersAvailable callback + // comes after this OnDataAvailable callback. + base::RunLoop run_loop2; + EXPECT_CALL(delegate_, OnDataAvailable()) + .Times(1) + .WillOnce(testing::DoAll( + testing::Invoke(CreateFunctor(&QuicChromiumClientStreamTest::ReadData, + base::Unretained(this), StringPiece())), + testing::InvokeWithoutArgs([&run_loop2]() { run_loop2.Quit(); }))); + run_loop2.Run(); + // Make sure that the stream is not closed, even though ReadData returns 0. + EXPECT_FALSE(stream_->IsDoneReading()); + + // The OnHeadersAvailable call should follow. + base::RunLoop run_loop3; + SpdyHeaderBlock actual_trailers; + EXPECT_CALL(delegate_, + OnHeadersAvailable(trailers, uncompressed_trailers.length())) + .WillOnce(testing::DoAll( + testing::SaveArg<0>(&actual_trailers), + testing::InvokeWithoutArgs([&run_loop3]() { run_loop3.Quit(); }))); + + run_loop3.Run(); + // Make sure the stream is properly closed since trailers and data are all + // consumed. + EXPECT_TRUE(stream_->IsDoneReading()); + // Make sure kFinalOffsetHeaderKey is gone from the delivered actual trailers. + trailers.erase(kFinalOffsetHeaderKey); + EXPECT_EQ(trailers, actual_trailers); base::MessageLoop::current()->RunUntilIdle(); EXPECT_CALL(delegate_, OnClose(QUIC_NO_ERROR)); @@ -335,7 +425,7 @@ const size_t kDataLen = arraysize(kData1); // All data written. - EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)) .WillOnce(Return(QuicConsumedData(kDataLen, true))); TestCompletionCallback callback; EXPECT_EQ(OK, stream_->WriteStreamData(base::StringPiece(kData1, kDataLen), @@ -350,7 +440,7 @@ const size_t kDataLen = arraysize(kData1); // No data written. - EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)) .WillOnce(Return(QuicConsumedData(0, false))); TestCompletionCallback callback; EXPECT_EQ(ERR_IO_PENDING, @@ -359,7 +449,7 @@ ASSERT_FALSE(callback.have_result()); // All data written. - EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(stream_->id(), _, _, _, _)) .WillOnce(Return(QuicConsumedData(kDataLen, true))); stream_->OnCanWrite(); ASSERT_TRUE(callback.have_result());
diff --git a/net/quic/quic_chromium_connection_helper_test.cc b/net/quic/quic_chromium_connection_helper_test.cc index aefa22a..9fab8fb5 100644 --- a/net/quic/quic_chromium_connection_helper_test.cc +++ b/net/quic/quic_chromium_connection_helper_test.cc
@@ -17,10 +17,7 @@ public: TestDelegate() : fired_(false) {} - QuicTime OnAlarm() override { - fired_ = true; - return QuicTime::Zero(); - } + void OnAlarm() override { fired_ = true; } bool fired() const { return fired_; } void Clear() { fired_ = false; }
diff --git a/net/quic/quic_client_promised_info.cc b/net/quic/quic_client_promised_info.cc index 3b8740c4..d3816bf 100644 --- a/net/quic/quic_client_promised_info.cc +++ b/net/quic/quic_client_promised_info.cc
@@ -23,10 +23,9 @@ QuicClientPromisedInfo::~QuicClientPromisedInfo() {} -QuicTime QuicClientPromisedInfo::CleanupAlarm::OnAlarm() { +void QuicClientPromisedInfo::CleanupAlarm::OnAlarm() { DVLOG(1) << "self GC alarm for stream " << promised_->id_; promised_->Reset(QUIC_STREAM_CANCELLED); - return QuicTime::Zero(); } void QuicClientPromisedInfo::Init() {
diff --git a/net/quic/quic_client_promised_info.h b/net/quic/quic_client_promised_info.h index 300c41f..f4bb50f2 100644 --- a/net/quic/quic_client_promised_info.h +++ b/net/quic/quic_client_promised_info.h
@@ -83,7 +83,7 @@ explicit CleanupAlarm(QuicClientPromisedInfo* promised) : promised_(promised) {} - QuicTime OnAlarm() override; + void OnAlarm() override; QuicClientPromisedInfo* promised_; };
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc index ec1c6aa..b18673e 100644 --- a/net/quic/quic_config_test.cc +++ b/net/quic/quic_config_test.cc
@@ -77,7 +77,6 @@ client_config.SetSocketReceiveBufferToSend(kDefaultSocketReceiveBuffer); QuicTagVector copt; copt.push_back(kTBBR); - copt.push_back(kFHDR); client_config.SetConnectionOptionsToSend(copt); CryptoHandshakeMessage msg; client_config.ToHandshakeMessage(&msg); @@ -102,10 +101,9 @@ EXPECT_EQ(kDefaultMaxStreamsPerConnection, config_.MaxStreamsPerConnection()); EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs()); EXPECT_TRUE(config_.HasReceivedConnectionOptions()); - EXPECT_EQ(3u, config_.ReceivedConnectionOptions().size()); + EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kIW50); EXPECT_EQ(config_.ReceivedConnectionOptions()[1], kTBBR); - EXPECT_EQ(config_.ReceivedConnectionOptions()[2], kFHDR); EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(), 2 * kInitialStreamFlowControlWindowForTest); EXPECT_EQ(config_.ReceivedInitialSessionFlowControlWindowBytes(), @@ -228,12 +226,9 @@ QuicConfig client_config; QuicTagVector copt; copt.push_back(kTBBR); - copt.push_back(kFHDR); client_config.SetConnectionOptionsToSend(copt); EXPECT_TRUE(client_config.HasClientSentConnectionOption( kTBBR, Perspective::IS_CLIENT)); - EXPECT_TRUE(client_config.HasClientSentConnectionOption( - kFHDR, Perspective::IS_CLIENT)); CryptoHandshakeMessage msg; client_config.ToHandshakeMessage(&msg); @@ -245,11 +240,9 @@ EXPECT_TRUE(config_.negotiated()); EXPECT_TRUE(config_.HasReceivedConnectionOptions()); - EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size()); + EXPECT_EQ(1u, config_.ReceivedConnectionOptions().size()); EXPECT_TRUE( config_.HasClientSentConnectionOption(kTBBR, Perspective::IS_SERVER)); - EXPECT_TRUE( - config_.HasClientSentConnectionOption(kFHDR, Perspective::IS_SERVER)); } } // namespace
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc index a210022b0..74bc9e3 100644 --- a/net/quic/quic_connection.cc +++ b/net/quic/quic_connection.cc
@@ -31,7 +31,6 @@ #include "net/quic/quic_bandwidth.h" #include "net/quic/quic_bug_tracker.h" #include "net/quic/quic_config.h" -#include "net/quic/quic_fec_group.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_packet_generator.h" #include "net/quic/quic_utils.h" @@ -60,10 +59,6 @@ // This will likely have to be tuned. const QuicPacketNumber kMaxPacketGap = 5000; -// Limit the number of FEC groups to two. If we get enough out of order packets -// that this becomes limiting, we can revisit. -const size_t kMaxFecGroups = 2; - // Maximum number of acks received before sending an ack in response. const QuicPacketCount kMaxPacketsReceivedBeforeAckSend = 20; @@ -91,10 +86,10 @@ public: explicit AckAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { + void OnAlarm() override { DCHECK(connection_->ack_frame_updated()); - connection_->SendAck(); - return QuicTime::Zero(); + QuicConnection::ScopedPacketBundler bundler(connection_, + QuicConnection::SEND_ACK); } private: @@ -111,10 +106,7 @@ explicit RetransmissionAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { - connection_->OnRetransmissionTimeout(); - return QuicTime::Zero(); - } + void OnAlarm() override { connection_->OnRetransmissionTimeout(); } private: QuicConnection* connection_; @@ -128,11 +120,7 @@ public: explicit SendAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { - connection_->WriteIfNotBlocked(); - // Never reschedule the alarm, since CanWrite does that. - return QuicTime::Zero(); - } + void OnAlarm() override { connection_->WriteAndBundleAcksIfNotBlocked(); } private: QuicConnection* connection_; @@ -144,11 +132,7 @@ public: explicit TimeoutAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { - connection_->CheckForTimeout(); - // Never reschedule the alarm, since CheckForTimeout does that. - return QuicTime::Zero(); - } + void OnAlarm() override { connection_->CheckForTimeout(); } private: QuicConnection* connection_; @@ -160,10 +144,7 @@ public: explicit PingAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { - connection_->OnPingTimeout(); - return QuicTime::Zero(); - } + void OnAlarm() override { connection_->OnPingTimeout(); } private: QuicConnection* connection_; @@ -176,11 +157,7 @@ explicit MtuDiscoveryAlarm(QuicConnection* connection) : connection_(connection) {} - QuicTime OnAlarm() override { - connection_->DiscoverMtu(); - // DiscoverMtu() handles rescheduling the alarm by itself. - return QuicTime::Zero(); - } + void OnAlarm() override { connection_->DiscoverMtu(); } private: QuicConnection* connection_; @@ -188,23 +165,6 @@ DISALLOW_COPY_AND_ASSIGN(MtuDiscoveryAlarm); }; -// This alarm may be scheduled when an FEC protected packet is sent out. -class FecAlarm : public QuicAlarm::Delegate { - public: - explicit FecAlarm(QuicPacketGenerator* packet_generator) - : packet_generator_(packet_generator) {} - - QuicTime OnAlarm() override { - packet_generator_->OnFecTimeout(); - return QuicTime::Zero(); - } - - private: - QuicPacketGenerator* packet_generator_; - - DISALLOW_COPY_AND_ASSIGN(FecAlarm); -}; - // Listens for acks of MTU discovery packets and raises the maximum packet size // of the connection if the probe succeeds. class MtuDiscoveryAckListener : public QuicAckListenerInterface { @@ -265,8 +225,8 @@ peer_address_(address), migrating_peer_port_(0), last_packet_decrypted_(false), - last_packet_revived_(false), last_size_(0), + current_packet_data_(nullptr), last_decrypted_packet_level_(ENCRYPTION_NONE), should_last_packet_instigate_acks_(false), largest_seen_packet_with_ack_(0), @@ -278,11 +238,13 @@ received_packet_manager_(&stats_), ack_queued_(false), num_retransmittable_packets_received_since_last_ack_sent_(0), + last_ack_had_missing_packets_(false), num_packets_received_since_last_ack_sent_(0), stop_waiting_count_(0), - ack_decimation_enabled_(false), + ack_mode_(TCP_ACKING), delay_setting_retransmission_alarm_(false), pending_retransmission_alarm_(false), + defer_send_in_response_to_packets_(false), arena_(), ack_alarm_(helper->CreateAlarm(arena_.New<AckAlarm>(this), &arena_)), retransmission_alarm_( @@ -302,8 +264,6 @@ random_generator_, helper->GetBufferAllocator(), this), - fec_alarm_(helper->CreateAlarm(arena_.New<FecAlarm>(&packet_generator_), - &arena_)), idle_network_timeout_(QuicTime::Delta::Infinite()), handshake_timeout_(QuicTime::Delta::Infinite()), time_of_last_received_packet_(clock_->ApproximateNow()), @@ -356,7 +316,6 @@ if (termination_packets_.get() != nullptr) { STLDeleteElements(termination_packets_.get()); } - STLDeleteValues(&group_map_); ClearQueuedPackets(); } @@ -395,16 +354,6 @@ } max_undecryptable_packets_ = config.max_undecryptable_packets(); - if (config.HasClientSentConnectionOption(kFSPA, perspective_)) { - packet_generator_.set_fec_send_policy(FecSendPolicy::FEC_ALARM_TRIGGER); - } - if (config.HasClientSentConnectionOption(kFRTT, perspective_)) { - // TODO(rtenneti): Delete this code after the 0.25 RTT FEC experiment. - const float kFecTimeoutRttMultiplier = 0.25; - packet_generator_.set_rtt_multiplier_for_fec_timeout( - kFecTimeoutRttMultiplier); - } - if (config.HasClientSentConnectionOption(kMTUH, perspective_)) { SetMtuDiscoveryTarget(kMtuDiscoveryTargetPacketSizeHigh); } @@ -415,7 +364,11 @@ debug_visitor_->OnSetFromConfig(config); } if (config.HasClientSentConnectionOption(kACKD, perspective_)) { - ack_decimation_enabled_ = true; + ack_mode_ = ACK_DECIMATION; + } + if (FLAGS_quic_ack_decimation2 && + config.HasClientSentConnectionOption(kAKD2, perspective_)) { + ack_mode_ = ACK_DECIMATION_WITH_REORDERING; } } @@ -470,20 +423,8 @@ SendConnectionCloseWithDetails(framer->error(), framer->detailed_error()); } -void QuicConnection::MaybeSetFecAlarm(QuicPacketNumber packet_number) { - if (fec_alarm_->IsSet()) { - return; - } - QuicTime::Delta timeout = packet_generator_.GetFecTimeout(packet_number); - if (!timeout.IsInfinite()) { - fec_alarm_->Update(clock_->ApproximateNow().Add(timeout), - QuicTime::Delta::FromMilliseconds(1)); - } -} - void QuicConnection::OnPacket() { last_packet_decrypted_ = false; - last_packet_revived_ = false; } void QuicConnection::OnPublicResetPacket(const QuicPublicResetPacket& packet) { @@ -601,8 +542,6 @@ RetransmitUnackedPackets(ALL_UNACKED_RETRANSMISSION); } -void QuicConnection::OnRevivedPacket() {} - bool QuicConnection::OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header) { if (header.connection_id == connection_id_) { @@ -689,15 +628,6 @@ return true; } -void QuicConnection::OnFecProtectedPayload(StringPiece payload) { - DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group); - DCHECK_NE(0u, last_header_.fec_group); - QuicFecGroup* group = GetFecGroup(); - if (group != nullptr) { - group->Update(last_decrypted_packet_level_, last_header_, payload); - } -} - bool QuicConnection::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK(connected_); if (debug_visitor_ != nullptr) { @@ -708,6 +638,7 @@ QUIC_BUG << ENDPOINT << "Received an unencrypted data frame: closing connection" << " packet_number:" << last_header_.packet_number + << " stream_id:" << frame.stream_id << " received_packets:" << received_packet_manager_.ack_frame(); SendConnectionCloseWithDetails(QUIC_UNENCRYPTED_STREAM_DATA, "Unencrypted stream data seen"); @@ -773,8 +704,6 @@ const QuicStopWaitingFrame& stop_waiting) { largest_seen_packet_with_stop_waiting_ = last_header_.packet_number; received_packet_manager_.UpdatePacketInformationSentByPeer(stop_waiting); - // Possibly close any FecGroups which are now irrelevant. - CloseFecGroupsBefore(stop_waiting.least_unacked + 1); } bool QuicConnection::OnStopWaitingFrame(const QuicStopWaitingFrame& frame) { @@ -820,7 +749,10 @@ if (incoming_ack.largest_observed < sent_packet_manager_.largest_observed()) { LOG(WARNING) << ENDPOINT << "Peer's largest_observed packet decreased:" << incoming_ack.largest_observed << " vs " - << sent_packet_manager_.largest_observed(); + << sent_packet_manager_.largest_observed() + << " packet_number:" << last_header_.packet_number + << " largest seen with ack:" << largest_seen_packet_with_ack_ + << " connection_id: " << connection_id_; // A new ack has a diminished largest_observed value. Error out. // If this was an old packet, we wouldn't even have checked. return "Largest observed too low"; @@ -854,14 +786,6 @@ return "Invalid entropy"; } - if (incoming_ack.latest_revived_packet != 0 && - !incoming_ack.missing_packets.Contains( - incoming_ack.latest_revived_packet)) { - LOG(WARNING) << ENDPOINT - << "Peer specified revived packet which was not missing." - << " revived_packet:" << incoming_ack.latest_revived_packet; - return "Invalid revived packet"; - } return nullptr; } @@ -887,15 +811,6 @@ return nullptr; } -void QuicConnection::OnFecData(StringPiece redundancy) { - DCHECK_EQ(IN_FEC_GROUP, last_header_.is_in_fec_group); - DCHECK_NE(0u, last_header_.fec_group); - QuicFecGroup* group = GetFecGroup(); - if (group != nullptr) { - group->UpdateFec(last_decrypted_packet_level_, last_header_, redundancy); - } -} - bool QuicConnection::OnRstStreamFrame(const QuicRstStreamFrame& frame) { DCHECK(connected_); if (debug_visitor_ != nullptr) { @@ -987,8 +902,7 @@ return; } - DVLOG(1) << ENDPOINT << (last_packet_revived_ ? "Revived" : "Got") - << " packet " << last_header_.packet_number << " for " + DVLOG(1) << ENDPOINT << "Got packet " << last_header_.packet_number << " for " << last_header_.public_header.connection_id; // An ack will be sent if a missing retransmittable packet was received; @@ -996,15 +910,11 @@ should_last_packet_instigate_acks_ && received_packet_manager_.IsMissing(last_header_.packet_number); - // Record received or revived packet to populate ack info correctly before - // processing stream frames, since the processing may result in a response - // packet with a bundled ack. - if (last_packet_revived_) { - received_packet_manager_.RecordPacketRevived(last_header_.packet_number); - } else { - received_packet_manager_.RecordPacketReceived( - last_size_, last_header_, time_of_last_received_packet_); - } + // Record received to populate ack info correctly before processing stream + // frames, since the processing may result in a response packet with a bundled + // ack. + received_packet_manager_.RecordPacketReceived(last_size_, last_header_, + time_of_last_received_packet_); // Process stop waiting frames here, instead of inline, because the packet // needs to be considered 'received' before the entropy can be updated. @@ -1019,7 +929,6 @@ ClearLastFrames(); MaybeCloseIfTooManyOutstandingPackets(); - MaybeProcessRevivedPacket(); } void QuicConnection::MaybeQueueAck(bool was_missing) { @@ -1033,13 +942,16 @@ // Determine whether the newly received packet was missing before recording // the received packet. - if (was_missing) { + // Ack decimation with reordering relies on the timer to send an ack, but if + // missing packets we reported in the previous ack, send an ack immediately. + if (was_missing && (ack_mode_ != ACK_DECIMATION_WITH_REORDERING || + last_ack_had_missing_packets_)) { ack_queued_ = true; } if (should_last_packet_instigate_acks_ && !ack_queued_) { ++num_retransmittable_packets_received_since_last_ack_sent_; - if (ack_decimation_enabled_ && + if (ack_mode_ != TCP_ACKING && last_header_.packet_number > kMinReceivedBeforeAckDecimation) { // Ack up to 10 packets at once. if (num_retransmittable_packets_received_since_last_ack_sent_ >= @@ -1064,10 +976,18 @@ } // If there are new missing packets to report, send an ack immediately. - // TODO(ianswett): Consider allowing 1ms of reordering for the - // ack decimation experiment. if (received_packet_manager_.HasNewMissingPackets()) { - ack_queued_ = true; + if (ack_mode_ == ACK_DECIMATION_WITH_REORDERING) { + // Wait the minimum of an eighth min_rtt and the existing ack time. + QuicTime ack_time = clock_->ApproximateNow().Add( + sent_packet_manager_.GetRttStats()->min_rtt().Multiply(0.125)); + if (!ack_alarm_->IsSet() || ack_alarm_->deadline() > ack_time) { + ack_alarm_->Cancel(); + ack_alarm_->Set(ack_time); + } + } else { + ack_queued_ = true; + } } } @@ -1119,11 +1039,14 @@ if (!connected_) { return; } - ScopedPacketBundler bundler(this, ack_queued_ ? SEND_ACK : NO_ACK); - // Now that we have received an ack, we might be able to send packets which // are queued locally, or drain streams which are blocked. - WriteIfNotBlocked(); + if (defer_send_in_response_to_packets_) { + send_alarm_->Cancel(); + send_alarm_->Set(clock_->ApproximateNow()); + } else { + WriteAndBundleAcksIfNotBlocked(); + } } void QuicConnection::SendVersionNegotiationPacket() { @@ -1162,7 +1085,6 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* listener) { if (!fin && iov.total_length == 0) { QUIC_BUG << "Attempt to send empty stream frame"; @@ -1184,8 +1106,7 @@ // processing left that may cause received_info_ to change. ScopedRetransmissionScheduler alarm_delayer(this); ScopedPacketBundler ack_bundler(this, BUNDLE_PENDING_ACK); - return packet_generator_.ConsumeData(id, iov, offset, fin, fec_protection, - listener); + return packet_generator_.ConsumeData(id, iov, offset, fin, listener); } void QuicConnection::SendRstStream(QuicStreamId id, @@ -1263,7 +1184,7 @@ stats_.srtt_us = srtt.ToMicroseconds(); stats_.estimated_bandwidth = sent_packet_manager_.BandwidthEstimate(); - stats_.max_packet_size = packet_generator_.GetMaxPacketLength(); + stats_.max_packet_size = packet_generator_.GetCurrentMaxPacketLength(); stats_.max_received_packet_size = largest_received_packet_size_; return stats_; } @@ -1278,6 +1199,7 @@ debug_visitor_->OnPacketReceived(self_address, peer_address, packet); } last_size_ = packet.length(); + current_packet_data_ = packet.data(); if (FLAGS_check_peer_address_change_after_decryption) { last_packet_destination_address_ = self_address; @@ -1309,6 +1231,7 @@ } DVLOG(1) << ENDPOINT << "Unable to process packet. Last packet processed: " << last_header_.packet_number; + current_packet_data_ = nullptr; return; } @@ -1316,6 +1239,7 @@ MaybeProcessUndecryptablePackets(); MaybeSendInResponseToPacket(); SetPingAlarm(); + current_packet_data_ = nullptr; } void QuicConnection::CheckForAddressMigration(const IPEndPoint& self_address, @@ -1384,7 +1308,19 @@ } } +void QuicConnection::WriteAndBundleAcksIfNotBlocked() { + if (!writer_->IsWriteBlocked()) { + ScopedPacketBundler bundler(this, ack_queued_ ? SEND_ACK : NO_ACK); + OnCanWrite(); + } +} + bool QuicConnection::ProcessValidatedPacket(const QuicPacketHeader& header) { + if (header.fec_flag) { + // Drop any FEC packet. + return false; + } + if (FLAGS_check_peer_address_change_after_decryption) { if (perspective_ == Perspective::IS_SERVER && IsInitializedIPEndPoint(self_address_) && @@ -1459,7 +1395,7 @@ if (perspective_ == Perspective::IS_SERVER && encryption_level_ == ENCRYPTION_NONE && - last_size_ > packet_generator_.GetMaxPacketLength()) { + last_size_ > packet_generator_.GetCurrentMaxPacketLength()) { SetMaxPacketLength(last_size_); } return true; @@ -1492,7 +1428,6 @@ } // Re-packetize the frames with a new packet number for retransmission. - // Retransmitted data packets do not use FEC, even when it's enabled. // Retransmitted packets use the same packet number length as the // original. // Flush the packet generator before making a new packet. @@ -1615,13 +1550,11 @@ } DCHECK_LE(encrypted_length, kMaxPacketSize); - DCHECK_LE(encrypted_length, packet_generator_.GetMaxPacketLength()); + DCHECK_LE(encrypted_length, packet_generator_.GetCurrentMaxPacketLength()); DVLOG(1) << ENDPOINT << "Sending packet " << packet_number << " : " - << (packet->is_fec_packet - ? "FEC " - : (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA - ? "data bearing " - : " ack only ")) + << (IsRetransmittable(*packet) == HAS_RETRANSMITTABLE_DATA + ? "data bearing " + : " ack only ") << ", encryption level: " << QuicUtils::EncryptionLevelToString(packet->encryption_level) << ", encrypted length:" << encrypted_length; @@ -1663,7 +1596,6 @@ } } SetPingAlarm(); - MaybeSetFecAlarm(packet_number); MaybeSetMtuAlarm(); DVLOG(1) << ENDPOINT << "time we began writing last sent packet: " << packet_send_time.ToDebuggingValue(); @@ -1751,10 +1683,6 @@ CloseConnection(QUIC_ENCRYPTION_FAILURE, ConnectionCloseSource::FROM_SELF); return; } - if (serialized_packet->is_fec_packet && fec_alarm_->IsSet()) { - // If an FEC packet is serialized with the FEC alarm set, cancel the alarm. - fec_alarm_->Cancel(); - } SendOrQueuePacket(serialized_packet); } @@ -1765,17 +1693,7 @@ CloseConnection(error, source); } -void QuicConnection::OnResetFecGroup() { - if (!fec_alarm_->IsSet()) { - return; - } - // If an FEC Group is closed with the FEC alarm set, cancel the alarm. - fec_alarm_->Cancel(); -} - void QuicConnection::OnCongestionWindowChange() { - packet_generator_.OnCongestionWindowChange( - sent_packet_manager_.EstimateMaxPacketsInFlight(max_packet_length())); visitor_->OnCongestionWindowChange(clock_->ApproximateNow()); } @@ -1786,9 +1704,9 @@ rtt = QuicTime::Delta::FromMicroseconds( sent_packet_manager_.GetRttStats()->initial_rtt_us()); } + if (debug_visitor_) debug_visitor_->OnRttChanged(rtt); - packet_generator_.OnRttChange(rtt); } void QuicConnection::OnPathDegrading() { @@ -1853,6 +1771,7 @@ ack_queued_ = false; stop_waiting_count_ = 0; num_retransmittable_packets_received_since_last_ack_sent_ = 0; + last_ack_had_missing_packets_ = received_packet_manager_.HasMissingPackets(); num_packets_received_since_last_ack_sent_ = 0; packet_generator_.SetShouldSendAck(true); @@ -1969,75 +1888,6 @@ } } -void QuicConnection::MaybeProcessRevivedPacket() { - QuicFecGroup* group = GetFecGroup(); - if (!connected_ || group == nullptr || !group->CanRevive()) { - return; - } - QuicPacketHeader revived_header; - char revived_payload[kMaxPacketSize]; - size_t len = group->Revive(&revived_header, revived_payload, kMaxPacketSize); - if (!received_packet_manager_.IsAwaitingPacket( - revived_header.packet_number)) { - // Close this FEC group because all packets in the group has been received. - group_map_.erase(last_header_.fec_group); - delete group; - return; - } - revived_header.public_header.connection_id = connection_id_; - revived_header.public_header.connection_id_length = - last_header_.public_header.connection_id_length; - revived_header.public_header.version_flag = false; - revived_header.public_header.reset_flag = false; - revived_header.public_header.packet_number_length = - last_header_.public_header.packet_number_length; - revived_header.fec_flag = false; - revived_header.is_in_fec_group = NOT_IN_FEC_GROUP; - revived_header.fec_group = 0; - group_map_.erase(last_header_.fec_group); - last_decrypted_packet_level_ = group->EffectiveEncryptionLevel(); - DCHECK_LT(last_decrypted_packet_level_, NUM_ENCRYPTION_LEVELS); - delete group; - - last_packet_revived_ = true; - if (debug_visitor_ != nullptr) { - debug_visitor_->OnRevivedPacket(revived_header, - StringPiece(revived_payload, len)); - } - - ++stats_.packets_revived; - framer_.ProcessRevivedPacket(&revived_header, - StringPiece(revived_payload, len)); -} - -QuicFecGroup* QuicConnection::GetFecGroup() { - QuicFecGroupNumber fec_group_num = last_header_.fec_group; - if (fec_group_num == 0 || - (fec_group_num < - received_packet_manager_.peer_least_packet_awaiting_ack() && - !ContainsKey(group_map_, fec_group_num))) { - // If the group number is below peer_least_packet_awaiting_ack and this - // group does not exist, which means this group has missing packets below - // |peer_least_packet_awaiting_ack| which we would never receive, so return - // nullptr. - return nullptr; - } - if (!ContainsKey(group_map_, fec_group_num)) { - if (group_map_.size() >= kMaxFecGroups) { // Too many groups - if (fec_group_num < group_map_.begin()->first) { - // The group being requested is a group we've seen before and deleted. - // Don't recreate it. - return nullptr; - } - // Clear the lowest group number. - delete group_map_.begin()->second; - group_map_.erase(group_map_.begin()); - } - group_map_[fec_group_num] = new QuicFecGroup(fec_group_num); - } - return group_map_[fec_group_num]; -} - void QuicConnection::SendConnectionCloseWithDetails(QuicErrorCode error, const string& details) { if (!connected_) { @@ -2087,7 +1937,6 @@ // connection is closed. ack_alarm_->Cancel(); ping_alarm_->Cancel(); - fec_alarm_->Cancel(); resume_writes_alarm_->Cancel(); retransmission_alarm_->Cancel(); send_alarm_->Cancel(); @@ -2112,31 +1961,12 @@ QuicFrame(new QuicGoAwayFrame(error, last_good_stream_id, reason))); } -void QuicConnection::CloseFecGroupsBefore(QuicPacketNumber packet_number) { - FecGroupMap::iterator it = group_map_.begin(); - while (it != group_map_.end()) { - // If the group doesn't protect this packet we can ignore it. - if (!it->second->IsWaitingForPacketBefore(packet_number)) { - ++it; - continue; - } - QuicFecGroup* fec_group = it->second; - DCHECK(!fec_group->CanRevive()); - FecGroupMap::iterator next = it; - ++next; - group_map_.erase(it); - delete fec_group; - it = next; - } -} - QuicByteCount QuicConnection::max_packet_length() const { - return packet_generator_.GetMaxPacketLength(); + return packet_generator_.GetCurrentMaxPacketLength(); } void QuicConnection::SetMaxPacketLength(QuicByteCount length) { - return packet_generator_.SetMaxPacketLength(LimitMaxPacketSize(length), - /*force=*/false); + return packet_generator_.SetMaxPacketLength(LimitMaxPacketSize(length)); } bool QuicConnection::HasQueuedData() const { @@ -2184,14 +2014,8 @@ void QuicConnection::CheckForTimeout() { QuicTime now = clock_->ApproximateNow(); - QuicTime time_of_last_packet = QuicTime::Zero(); - if (!FLAGS_quic_use_new_idle_timeout) { - time_of_last_packet = - max(time_of_last_received_packet_, time_of_last_sent_new_packet_); - } else { - time_of_last_packet = - max(time_of_last_received_packet_, last_send_for_timeout_); - } + QuicTime time_of_last_packet = + max(time_of_last_received_packet_, last_send_for_timeout_); // |delta| can be < 0 as |now| is approximate time but |time_of_last_packet| // is accurate time. However, this should not change the behavior of @@ -2502,4 +2326,11 @@ return received_packet_manager_.ack_frame_updated(); } +StringPiece QuicConnection::GetCurrentPacket() { + if (current_packet_data_ == nullptr) { + return StringPiece(); + } + return StringPiece(current_packet_data_, last_size_); +} + } // namespace net
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h index b9e9ef7..bf4e85cb 100644 --- a/net/quic/quic_connection.h +++ b/net/quic/quic_connection.h
@@ -54,7 +54,6 @@ class QuicConfig; class QuicConnection; class QuicEncrypter; -class QuicFecGroup; class QuicRandom; namespace test { @@ -234,11 +233,6 @@ virtual void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) {} - // Called after a packet has been successfully parsed which results - // in the revival of a packet via FEC. - virtual void OnRevivedPacket(const QuicPacketHeader& revived_header, - base::StringPiece payload) {} - // Called when the connection is closed. virtual void OnConnectionClosed(QuicErrorCode error, ConnectionCloseSource source) {} @@ -307,6 +301,8 @@ BUNDLE_PENDING_ACK = 2, }; + enum AckMode { TCP_ACKING, ACK_DECIMATION, ACK_DECIMATION_WITH_REORDERING }; + // Constructs a new QuicConnection for |connection_id| and |address| using // |writer| to write packets. |owns_writer| specifies whether the connection // takes ownership of |writer|. |helper| must outlive this connection. @@ -342,10 +338,7 @@ // Returns a pair with the number of bytes consumed from data, and a boolean // indicating if the fin bit was consumed. This does not indicate the data // has been sent on the wire: it may have been turned into a packet and queued - // if the socket was unexpectedly blocked. |fec_protection| indicates if - // data is to be FEC protected. Note that data that is sent immediately - // following MUST_FEC_PROTECT data may get protected by falling within the - // same FEC group. + // if the socket was unexpectedly blocked. // If |listener| is provided, then it will be informed once ACKs have been // received for all the packets written in this call. // The |listener| is not owned by the QuicConnection and must outlive it. @@ -353,7 +346,6 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* listener); // Send a RST_STREAM frame to the peer. @@ -392,8 +384,7 @@ const QuicConnectionStats& GetStats(); // Processes an incoming UDP packet (consisting of a QuicEncryptedPacket) from - // the peer. If processing this packet permits a packet to be revived from - // its FEC group that packet will be revived and processed. + // the peer. // In a client, the packet may be "stray" and have a different connection ID // than that of this connection. virtual void ProcessUdpPacket(const IPEndPoint& self_address, @@ -412,6 +403,10 @@ // If the socket is not blocked, writes queued packets. void WriteIfNotBlocked(); + // If the socket is not blocked, writes queued packets and bundles any pending + // ACKs. + void WriteAndBundleAcksIfNotBlocked(); + // Set the packet writer. void SetQuicPacketWriter(QuicPacketWriter* writer, bool owns_writer) { DCHECK(writer != nullptr); @@ -440,13 +435,11 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; - void OnRevivedPacket() override; bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; - void OnFecProtectedPayload(base::StringPiece payload) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnAckFrame(const QuicAckFrame& frame) override; bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override; @@ -457,7 +450,6 @@ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override; - void OnFecData(base::StringPiece redundnancy) override; void OnPacketComplete() override; // QuicPacketGenerator::DelegateInterface @@ -470,7 +462,6 @@ void OnSerializedPacket(SerializedPacket* packet) override; void OnUnrecoverableError(QuicErrorCode error, ConnectionCloseSource source) override; - void OnResetFecGroup() override; // QuicSentPacketManager::NetworkChangeVisitor void OnCongestionWindowChange() override; @@ -516,8 +507,6 @@ return server_supported_versions_; } - size_t NumFecGroups() const { return group_map_.size(); } - // Testing only. size_t NumQueuedPackets() const { return queued_packets_.size(); } @@ -555,10 +544,6 @@ // remaining unacked packets. void OnRetransmissionTimeout(); - // Called when a data packet is sent. Starts an alarm if the data sent in - // |packet_number| was FEC protected. - void MaybeSetFecAlarm(QuicPacketNumber packet_number); - // Retransmits all unacked packets with retransmittable frames if // |retransmission_type| is ALL_UNACKED_PACKETS, otherwise retransmits only // initially encrypted packets. Used when the negotiated protocol version is @@ -676,6 +661,8 @@ QuicConnectionHelperInterface* helper() { return helper_; } + base::StringPiece GetCurrentPacket(); + protected: // Send a packet to the peer, and takes ownership of the packet if the packet // cannot be written immediately. @@ -711,12 +698,18 @@ per_packet_options_ = options; } + // If |defer| is true, configures the connection to defer sending packets in + // response to an ACK to the SendAlarm. If |defer| is false, packets may be + // sent immediately after receiving an ACK. + void set_defer_send_in_response_to_packets(bool defer) { + defer_send_in_response_to_packets_ = defer; + } + private: friend class test::QuicConnectionPeer; friend class test::PacketSavingConnection; typedef std::list<SerializedPacket> QueuedPacketList; - typedef std::map<QuicFecGroupNumber, QuicFecGroup*> FecGroupMap; // Writes the given packet to socket, encrypted with packet's // encryption_level. Returns true on successful write, and false if the writer @@ -767,10 +760,6 @@ // Attempts to process any queued undecryptable packets. void MaybeProcessUndecryptablePackets(); - // If a packet can be revived from the current FEC group, then - // revive and process the packet. - void MaybeProcessRevivedPacket(); - void ProcessAckFrame(const QuicAckFrame& incoming_ack); void ProcessStopWaitingFrame(const QuicStopWaitingFrame& stop_waiting); @@ -787,13 +776,6 @@ // to be sent if there are no outstanding packets. QuicPacketNumber GetLeastUnacked() const; - // Get the FEC group associate with the last processed packet or nullptr, if - // the group has already been deleted. - QuicFecGroup* GetFecGroup(); - - // Closes any FEC groups protecting packets before |packet_number|. - void CloseFecGroupsBefore(QuicPacketNumber packet_number); - // Sets the timeout alarm to the appropriate value, if any. void SetTimeoutAlarm(); @@ -865,8 +847,10 @@ // True if the last packet has gotten far enough in the framer to be // decrypted. bool last_packet_decrypted_; - bool last_packet_revived_; // True if the last packet was revived from FEC. QuicByteCount last_size_; // Size of the last received packet. + // TODO(rch): remove this when b/27221014 is fixed. + const char* current_packet_data_; // UDP payload of packet currently being + // parsed or nullptr. EncryptionLevel last_decrypted_packet_level_; QuicPacketHeader last_header_; QuicStopWaitingFrame last_stop_waiting_frame_; @@ -910,8 +894,6 @@ // This is particularly important on mobile, where connections are short. bool silent_close_enabled_; - FecGroupMap group_map_; - QuicReceivedPacketManager received_packet_manager_; QuicSentEntropyManager sent_entropy_manager_; @@ -919,13 +901,15 @@ bool ack_queued_; // How many retransmittable packets have arrived without sending an ack. QuicPacketCount num_retransmittable_packets_received_since_last_ack_sent_; + // Whether there were missing packets in the last sent ack. + bool last_ack_had_missing_packets_; // How many consecutive packets have arrived without sending an ack. QuicPacketCount num_packets_received_since_last_ack_sent_; // Indicates how many consecutive times an ack has arrived which indicates // the peer needs to stop waiting for some packets. int stop_waiting_count_; - // When true, ack only every 10 packets as long as they arrive close together. - bool ack_decimation_enabled_; + // Indicates the current ack mode, defaults to acking every 2 packets. + AckMode ack_mode_; // Indicates the retransmit alarm is going to be set by the // ScopedRetransmitAlarmDelayer @@ -933,6 +917,10 @@ // Indicates the retransmission alarm needs to be set. bool pending_retransmission_alarm_; + // If true, defer sending data in response to received packets to the + // SendAlarm. + bool defer_send_in_response_to_packets_; + // Arena to store class implementations within the QuicConnection. QuicConnectionArena arena_; @@ -959,9 +947,6 @@ QuicPacketGenerator packet_generator_; - // An alarm that fires when an FEC packet should be sent. - QuicArenaScopedPtr<QuicAlarm> fec_alarm_; - // Network idle time before this connection is closed. QuicTime::Delta idle_network_timeout_; // The connection will wait this long for the handshake to complete.
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc index 6b82396..ad4775d 100644 --- a/net/quic/quic_connection_logger.cc +++ b/net/quic/quic_connection_logger.cc
@@ -124,9 +124,6 @@ for (QuicPacketNumber packet : frame->missing_packets) missing->AppendString(base::Uint64ToString(packet)); - dict->SetString("latest_revived_packet", - base::Int64ToString(frame->latest_revived_packet)); - base::ListValue* received = new base::ListValue(); dict->Set("received_packet_times", received); const PacketTimeVector& received_times = frame->received_packet_times; @@ -640,14 +637,6 @@ base::Bind(&NetLogQuicVersionNegotiationPacketCallback, &packet)); } -void QuicConnectionLogger::OnRevivedPacket( - const QuicPacketHeader& revived_header, - base::StringPiece payload) { - net_log_.AddEvent( - NetLog::TYPE_QUIC_SESSION_PACKET_HEADER_REVIVED, - base::Bind(&NetLogQuicPacketHeaderCallback, &revived_header)); -} - void QuicConnectionLogger::OnCryptoHandshakeMessageReceived( const CryptoHandshakeMessage& message) { net_log_.AddEvent(
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h index f059ef94..4aba233 100644 --- a/net/quic/quic_connection_logger.h +++ b/net/quic/quic_connection_logger.h
@@ -69,8 +69,6 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override; void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override; - void OnRevivedPacket(const QuicPacketHeader& revived_header, - base::StringPiece payload) override; void OnConnectionClosed(QuicErrorCode error, ConnectionCloseSource source) override; void OnSuccessfulVersionNegotiation(const QuicVersion& version) override;
diff --git a/net/quic/quic_connection_stats.cc b/net/quic/quic_connection_stats.cc index f314452..bb3130f5 100644 --- a/net/quic/quic_connection_stats.cc +++ b/net/quic/quic_connection_stats.cc
@@ -24,7 +24,6 @@ packets_lost(0), slowstart_packets_sent(0), slowstart_packets_lost(0), - packets_revived(0), packets_dropped(0), crypto_retransmit_count(0), loss_timeout_count(0),
diff --git a/net/quic/quic_connection_stats.h b/net/quic/quic_connection_stats.h index 2787612..b955b661 100644 --- a/net/quic/quic_connection_stats.h +++ b/net/quic/quic_connection_stats.h
@@ -26,7 +26,7 @@ std::ostream& os, const QuicConnectionStats& s); - QuicByteCount bytes_sent; // Includes retransmissions, fec. + QuicByteCount bytes_sent; // Includes retransmissions. QuicPacketCount packets_sent; // Non-retransmitted bytes sent in a stream frame. QuicByteCount stream_bytes_sent; @@ -35,7 +35,7 @@ // These include version negotiation and public reset packets, which do not // have packet numbers or frame data. - QuicByteCount bytes_received; // Includes duplicate data for a stream, fec. + QuicByteCount bytes_received; // Includes duplicate data for a stream. // Includes packets which were not processable. QuicPacketCount packets_received; // Excludes packets which were not processable. @@ -55,7 +55,6 @@ // Number of packets lost exiting slow start. QuicPacketCount slowstart_packets_lost; - QuicPacketCount packets_revived; QuicPacketCount packets_dropped; // Duplicate or less than least unacked. size_t crypto_retransmit_count; // Count of times the loss detection alarm fired. At least one packet should
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc index c30ac0a6..969fcf2f 100644 --- a/net/quic/quic_connection_test.cc +++ b/net/quic/quic_connection_test.cc
@@ -141,8 +141,8 @@ bool DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const StringPiece& associated_data, - const StringPiece& ciphertext, + StringPiece associated_data, + StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) override { @@ -482,31 +482,9 @@ QuicStreamOffset offset, bool fin, QuicAckListenerInterface* listener) { - return SendStreamDataWithStringHelper(id, data, offset, fin, - MAY_FEC_PROTECT, listener); - } - - QuicConsumedData SendStreamDataWithStringWithFec( - QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin, - QuicAckListenerInterface* listener) { - return SendStreamDataWithStringHelper(id, data, offset, fin, - MUST_FEC_PROTECT, listener); - } - - QuicConsumedData SendStreamDataWithStringHelper( - QuicStreamId id, - StringPiece data, - QuicStreamOffset offset, - bool fin, - FecProtection fec_protection, - QuicAckListenerInterface* listener) { struct iovec iov; QuicIOVector data_iov(MakeIOVector(data, &iov)); - return QuicConnection::SendStreamData(id, data_iov, offset, fin, - fec_protection, listener); + return QuicConnection::SendStreamData(id, data_iov, offset, fin, listener); } QuicConsumedData SendStreamData3() { @@ -514,20 +492,11 @@ nullptr); } - QuicConsumedData SendStreamData3WithFec() { - return SendStreamDataWithStringWithFec(kClientDataStreamId1, "food", 0, - !kFin, nullptr); - } - QuicConsumedData SendStreamData5() { return SendStreamDataWithString(kClientDataStreamId2, "food2", 0, !kFin, nullptr); } - QuicConsumedData SendStreamData5WithFec() { - return SendStreamDataWithStringWithFec(kClientDataStreamId2, "food2", 0, - !kFin, nullptr); - } // Ensures the connection can write stream data before writing. QuicConsumedData EnsureWritableAndSendStreamData5() { EXPECT_TRUE(CanWriteStreamData()); @@ -586,11 +555,6 @@ QuicConnectionPeer::GetPingAlarm(this)); } - TestConnectionHelper::TestAlarm* GetFecAlarm() { - return reinterpret_cast<TestConnectionHelper::TestAlarm*>( - QuicConnectionPeer::GetFecAlarm(this)); - } - TestConnectionHelper::TestAlarm* GetResumeWritesAlarm() { return reinterpret_cast<TestConnectionHelper::TestAlarm*>( QuicConnectionPeer::GetResumeWritesAlarm(this)); @@ -617,6 +581,7 @@ } using QuicConnection::SelectMutualVersion; + using QuicConnection::set_defer_send_in_response_to_packets; private: TestPacketWriter* writer() { @@ -626,34 +591,23 @@ DISALLOW_COPY_AND_ASSIGN(TestConnection); }; -// Used for testing packets revived from FEC packets. -class FecQuicConnectionDebugVisitor : public QuicConnectionDebugVisitor { - public: - void OnRevivedPacket(const QuicPacketHeader& header, - StringPiece data) override { - revived_header_ = header; - } +enum class AckResponse { kDefer, kImmediate }; - // Public accessor method. - QuicPacketHeader revived_header() const { return revived_header_; } - - private: - QuicPacketHeader revived_header_; -}; - -// Run tests with combinations of {QuicVersion, fec_send_policy}. +// Run tests with combinations of {QuicVersion, AckResponse}. struct TestParams { - TestParams(QuicVersion version, FecSendPolicy fec_send_policy) - : version(version), fec_send_policy(fec_send_policy) {} + TestParams(QuicVersion version, AckResponse ack_response) + : version(version), ack_response(ack_response) {} friend ostream& operator<<(ostream& os, const TestParams& p) { os << "{ client_version: " << QuicVersionToString(p.version) - << " fec_send_policy: " << p.fec_send_policy << " }"; + << " ack_response: " + << (p.ack_response == AckResponse::kDefer ? "defer" : "immediate") + << " }"; return os; } QuicVersion version; - FecSendPolicy fec_send_policy; + AckResponse ack_response; }; // Constructs various test permutations. @@ -661,8 +615,10 @@ vector<TestParams> params; QuicVersionVector all_supported_versions = QuicSupportedVersions(); for (size_t i = 0; i < all_supported_versions.size(); ++i) { - params.push_back(TestParams(all_supported_versions[i], FEC_ANY_TRIGGER)); - params.push_back(TestParams(all_supported_versions[i], FEC_ALARM_TRIGGER)); + for (AckResponse ack_response : + {AckResponse::kDefer, AckResponse::kImmediate}) { + params.push_back(TestParams(all_supported_versions[i], ack_response)); + } } return params; } @@ -696,12 +652,13 @@ frame2_(1, false, 3, StringPiece(data2)), packet_number_length_(PACKET_6BYTE_PACKET_NUMBER), connection_id_length_(PACKET_8BYTE_CONNECTION_ID) { + connection_.set_defer_send_in_response_to_packets(GetParam().ack_response == + AckResponse::kDefer); FLAGS_quic_always_log_bugs_for_tests = true; connection_.set_visitor(&visitor_); connection_.SetSendAlgorithm(send_algorithm_); connection_.SetLossAlgorithm(loss_algorithm_); framer_.set_received_entropy_calculator(&entropy_calculator_); - generator_->set_fec_send_policy(GetParam().fec_send_policy); EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)) .WillRepeatedly(Return(QuicTime::Delta::Zero())); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)) @@ -735,7 +692,6 @@ // TODO(ianswett): Fix QuicConnectionTests so they don't attempt to write // non-crypto stream data at ENCRYPTION_NONE. FLAGS_quic_never_write_unencrypted_data = false; - FLAGS_quic_no_unencrypted_fec = false; } QuicVersion version() { return GetParam().version; } @@ -761,7 +717,10 @@ void ProcessPacket(QuicPathId path_id, QuicPacketNumber number) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacket(path_id, number, 0, !kEntropyFlag); + ProcessDataPacket(path_id, number, !kEntropyFlag); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } } QuicPacketEntropyHash ProcessFramePacket(QuicFrame frame) { @@ -785,6 +744,9 @@ self_address, peer_address, QuicEncryptedPacket(serialized_packet.encrypted_buffer, serialized_packet.encrypted_length)); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } return serialized_packet.entropy_hash; } @@ -814,33 +776,32 @@ size_t ProcessDataPacket(QuicPathId path_id, QuicPacketNumber number, - QuicFecGroupNumber fec_group, bool entropy_flag) { - return ProcessDataPacketAtLevel(path_id, number, fec_group, entropy_flag, - false, ENCRYPTION_NONE); + return ProcessDataPacketAtLevel(path_id, number, entropy_flag, false, + ENCRYPTION_NONE); } size_t ProcessDataPacketAtLevel(QuicPathId path_id, QuicPacketNumber number, - QuicFecGroupNumber fec_group, bool entropy_flag, bool has_stop_waiting, EncryptionLevel level) { - scoped_ptr<QuicPacket> packet(ConstructDataPacket( - path_id, number, fec_group, entropy_flag, has_stop_waiting)); + scoped_ptr<QuicPacket> packet( + ConstructDataPacket(path_id, number, entropy_flag, has_stop_waiting)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( level, path_id, number, *packet, buffer, kMaxPacketSize); connection_.ProcessUdpPacket( kSelfAddress, kPeerAddress, QuicEncryptedPacket(buffer, encrypted_length, false)); + if (connection_.GetSendAlarm()->IsSet()) { + connection_.GetSendAlarm()->Fire(); + } return encrypted_length; } - void ProcessClosePacket(QuicPathId path_id, - QuicPacketNumber number, - QuicFecGroupNumber fec_group) { - scoped_ptr<QuicPacket> packet(ConstructClosePacket(number, fec_group)); + void ProcessClosePacket(QuicPathId path_id, QuicPacketNumber number) { + scoped_ptr<QuicPacket> packet(ConstructClosePacket(number)); char buffer[kMaxPacketSize]; size_t encrypted_length = framer_.EncryptPayload( ENCRYPTION_NONE, path_id, number, *packet, buffer, kMaxPacketSize); @@ -849,106 +810,6 @@ QuicEncryptedPacket(buffer, encrypted_length, false)); } - size_t ProcessFecProtectedPacket(QuicPathId path_id, - QuicPacketNumber number, - bool expect_revival, - bool entropy_flag, - bool has_stop_waiting) { - return ProcessFecProtectedPacketAtLevel(path_id, number, 1, expect_revival, - entropy_flag, has_stop_waiting, - ENCRYPTION_NONE); - } - - size_t ProcessFecProtectedPacketAtLevel(QuicPathId path_id, - QuicPacketNumber number, - QuicFecGroupNumber fec_group, - bool expect_revival, - bool entropy_flag, - bool has_stop_waiting, - EncryptionLevel level) { - if (expect_revival) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - } - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1).RetiresOnSaturation(); - return ProcessDataPacketAtLevel(path_id, number, fec_group, entropy_flag, - has_stop_waiting, level); - } - - // Processes an FEC packet that covers the packets that would have been - // received. - size_t ProcessFecPacket(QuicPathId path_id, - QuicPacketNumber number, - QuicPacketNumber min_protected_packet, - bool expect_revival, - bool entropy_flag, - QuicPacket* packet) { - return ProcessFecPacketAtLevel(path_id, number, min_protected_packet, - expect_revival, entropy_flag, packet, - ENCRYPTION_NONE); - } - - // Processes an FEC packet that covers the packets that would have been - // received. - size_t ProcessFecPacketAtLevel(QuicPathId path_id, - QuicPacketNumber number, - QuicPacketNumber min_protected_packet, - bool expect_revival, - bool entropy_flag, - QuicPacket* packet, - EncryptionLevel level) { - if (expect_revival) { - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - } - - // Construct the decrypted data packet so we can compute the correct - // redundancy. If |packet| has been provided then use that, otherwise - // construct a default data packet. - scoped_ptr<QuicPacket> data_packet; - if (packet) { - data_packet.reset(packet); - } else { - data_packet.reset(ConstructDataPacket(path_id, number, 1, !kEntropyFlag, - !kHasStopWaiting)); - } - - QuicPacketHeader header; - header.public_header.connection_id = connection_id_; - header.public_header.packet_number_length = packet_number_length_; - header.public_header.connection_id_length = connection_id_length_; - header.public_header.multipath_flag = path_id != kDefaultPathId; - header.path_id = path_id; - header.packet_number = number; - header.entropy_flag = entropy_flag; - header.fec_flag = true; - header.is_in_fec_group = IN_FEC_GROUP; - header.fec_group = min_protected_packet; - - // Since all data packets in this test have the same payload, the - // redundancy is either equal to that payload or the xor of that payload - // with itself, depending on the number of packets. - if (((number - min_protected_packet) % 2) == 0) { - for (size_t i = GetStartOfFecProtectedData( - header.public_header.connection_id_length, - header.public_header.version_flag, - header.public_header.multipath_flag, - header.public_header.packet_number_length); - i < data_packet->length(); ++i) { - data_packet->mutable_data()[i] ^= data_packet->data()[i]; - } - } - - scoped_ptr<QuicPacket> fec_packet( - framer_.BuildFecPacket(header, data_packet->FecProtectedData())); - char buffer[kMaxPacketSize]; - size_t encrypted_length = framer_.EncryptPayload( - level, path_id, number, *fec_packet, buffer, kMaxPacketSize); - - connection_.ProcessUdpPacket( - kSelfAddress, kPeerAddress, - QuicEncryptedPacket(buffer, encrypted_length, false)); - return encrypted_length; - } - QuicByteCount SendStreamDataToPeer(QuicStreamId id, StringPiece data, QuicStreamOffset offset, @@ -1015,7 +876,6 @@ QuicPacket* ConstructDataPacket(QuicPathId path_id, QuicPacketNumber number, - QuicFecGroupNumber fec_group, bool entropy_flag, bool has_stop_waiting) { QuicPacketHeader header; @@ -1026,8 +886,8 @@ header.entropy_flag = entropy_flag; header.path_id = path_id; header.packet_number = number; - header.is_in_fec_group = fec_group == 0u ? NOT_IN_FEC_GROUP : IN_FEC_GROUP; - header.fec_group = fec_group; + header.is_in_fec_group = NOT_IN_FEC_GROUP; + header.fec_group = 0; QuicFrames frames; frames.push_back(QuicFrame(&frame1_)); @@ -1037,13 +897,12 @@ return ConstructPacket(header, frames); } - QuicPacket* ConstructClosePacket(QuicPacketNumber number, - QuicFecGroupNumber fec_group) { + QuicPacket* ConstructClosePacket(QuicPacketNumber number) { QuicPacketHeader header; header.public_header.connection_id = connection_id_; header.packet_number = number; - header.is_in_fec_group = fec_group == 0u ? NOT_IN_FEC_GROUP : IN_FEC_GROUP; - header.fec_group = fec_group; + header.is_in_fec_group = NOT_IN_FEC_GROUP; + header.fec_group = 0; QuicConnectionCloseFrame qccf; qccf.error_code = QUIC_PEER_GOING_AWAY; @@ -1099,7 +958,7 @@ ConnectionCloseSource::FROM_SELF)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - ProcessDataPacket(kDefaultPathId, 6000, 0, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); } @@ -1346,7 +1205,7 @@ // Send packet 3 again, but do not set the expectation that // the visitor OnStreamFrame() will be called. - ProcessDataPacket(kDefaultPathId, 3, 0, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag); EXPECT_EQ(3u, outgoing_ack()->largest_observed); EXPECT_TRUE(IsMissing(2)); EXPECT_TRUE(IsMissing(1)); @@ -1387,7 +1246,7 @@ ConnectionCloseSource::FROM_SELF)); // Call ProcessDataPacket rather than ProcessPacket, as we should not get a // packet call to the visitor. - ProcessDataPacket(kDefaultPathId, 6000, 0, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 6000, !kEntropyFlag); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); } @@ -1398,7 +1257,7 @@ EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_UNENCRYPTED_STREAM_DATA, ConnectionCloseSource::FROM_SELF)); - EXPECT_DFATAL(ProcessDataPacket(kDefaultPathId, 1, 0, !kEntropyFlag), ""); + EXPECT_DFATAL(ProcessDataPacket(kDefaultPathId, 1, !kEntropyFlag), ""); EXPECT_FALSE(QuicConnectionPeer::GetConnectionClosePacket(&connection_) == nullptr); const vector<QuicConnectionCloseFrame>& connection_close_frames = @@ -1867,412 +1726,6 @@ << ". Actual time = " << actual_recorded_send_time.ToDebuggingValue(); } -TEST_P(QuicConnectionTest, FECSending) { - // All packets carry version info till version is negotiated. - size_t payload_length; - // GetPacketLengthForOneStream() assumes a stream offset of 0 in determining - // packet length. The size of the offset field in a stream frame is 0 for - // offset 0, and 2 for non-zero offsets up through 64K. Increase - // max_packet_length by 2 so that subsequent packets containing subsequent - // stream frames with non-zero offets will fit within the packet length. - size_t length = - 2 + GetPacketLengthForOneStream( - connection_.version(), kIncludeVersion, !kIncludePathId, - PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, - IN_FEC_GROUP, &payload_length); - connection_.SetMaxPacketLength(length); - - if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) { - // Send 4 protected data packets. FEC packet is not sent. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(4); - } else { - // Send 4 protected data packets, which should also trigger 1 FEC packet. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(5); - } - // The first stream frame will have 2 fewer overhead bytes than the other 3. - const string payload(payload_length * 4 + 2, 'a'); - connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr); - // Expect the FEC group to be closed after SendStreamDataWithString. - EXPECT_FALSE(creator_->IsFecGroupOpen()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicConnectionTest, FECQueueing) { - // All packets carry version info till version is negotiated. - size_t payload_length; - size_t length = GetPacketLengthForOneStream( - connection_.version(), kIncludeVersion, !kIncludePathId, - PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, IN_FEC_GROUP, - &payload_length); - connection_.SetMaxPacketLength(length); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - - EXPECT_EQ(0u, connection_.NumQueuedPackets()); - BlockOnNextWrite(); - const string payload(payload_length, 'a'); - connection_.SendStreamDataWithStringWithFec(1, payload, 0, !kFin, nullptr); - EXPECT_FALSE(creator_->IsFecGroupOpen()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) { - // Expect the first data packet to be queued and not the FEC packet. - EXPECT_EQ(1u, connection_.NumQueuedPackets()); - } else { - // Expect the first data packet and the fec packet to be queued. - EXPECT_EQ(2u, connection_.NumQueuedPackets()); - } -} - -TEST_P(QuicConnectionTest, FECAlarmStoppedWhenFECPacketSent) { - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - creator_->set_max_packets_per_fec_group(2); - - // 1 Data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 1u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, true, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - - if (generator_->fec_send_policy() == FEC_ALARM_TRIGGER) { - // If FEC send policy is FEC_ALARM_TRIGGER, FEC packet is not sent. - // FEC alarm should not be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - } else { - // Second data packet triggers FEC packet out. FEC alarm should not be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(2); - } - connection_.SendStreamDataWithStringWithFec(5, "foo", 0, true, nullptr); - if (generator_->fec_send_policy() == FEC_ANY_TRIGGER) { - EXPECT_TRUE(writer_->header().fec_flag); - } - EXPECT_FALSE(creator_->IsFecGroupOpen()); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); -} - -TEST_P(QuicConnectionTest, FECAlarmStoppedOnConnectionClose) { - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - creator_->set_max_packets_per_fec_group(100); - - // 1 Data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 1u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NO_ERROR, - ConnectionCloseSource::FROM_SELF)); - // Closing connection should stop the FEC alarm. - connection_.CloseConnection(QUIC_NO_ERROR, ConnectionCloseSource::FROM_SELF); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); -} - -TEST_P(QuicConnectionTest, RemoveFECFromInflightOnRetransmissionTimeout) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // 1 Data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 1u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - size_t protected_packet = - QuicSentPacketManagerPeer::GetBytesInFlight(manager_); - - // Force FEC timeout to send FEC packet out. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 2u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetFecAlarm()->Fire(); - EXPECT_TRUE(writer_->header().fec_flag); - - size_t fec_packet = protected_packet; - EXPECT_EQ(protected_packet + fec_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - clock_.AdvanceTime(DefaultRetransmissionTime()); - - // On RTO, both data and FEC packets are removed from inflight, only the data - // packet is retransmitted, and this retransmission (but not FEC) gets added - // back into the inflight. - EXPECT_CALL(*send_algorithm_, OnRetransmissionTimeout(true)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - connection_.GetRetransmissionAlarm()->Fire(); - - // The retransmission of packet 1 will be 3 bytes smaller than packet 1, since - // the first transmission will have 1 byte for FEC group number and 2 bytes of - // stream frame size, which are absent in the retransmission. - size_t retransmitted_packet = protected_packet - 3; - EXPECT_EQ(protected_packet + retransmitted_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // Receive ack for the retransmission. No data should be outstanding. - QuicAckFrame ack = InitAckFrame(3); - NackPacket(1, &ack); - NackPacket(2, &ack); - SendAlgorithmInterface::CongestionVector lost_packets; - lost_packets.push_back(std::make_pair(1, kMaxPacketSize)); - EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _)) - .WillOnce(SetArgPointee<3>(lost_packets)); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - ProcessAckPacket(&ack); - - // Ensure the alarm is not set since all packets have been acked or abandoned. - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); -} - -TEST_P(QuicConnectionTest, RemoveFECFromInflightOnLossRetransmission) { - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // 1 FEC-protected data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - size_t protected_packet = - QuicSentPacketManagerPeer::GetBytesInFlight(manager_); - - // Force FEC timeout to send FEC packet out. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetFecAlarm()->Fire(); - EXPECT_TRUE(writer_->header().fec_flag); - size_t fec_packet = protected_packet; - EXPECT_EQ(protected_packet + fec_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // Send more data to trigger NACKs. Note that all data starts at stream offset - // 0 to ensure the same packet size, for ease of testing. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(4); - connection_.SendStreamDataWithString(5, "foo", 0, kFin, nullptr); - connection_.SendStreamDataWithString(7, "foo", 0, kFin, nullptr); - connection_.SendStreamDataWithString(9, "foo", 0, kFin, nullptr); - connection_.SendStreamDataWithString(11, "foo", 0, kFin, nullptr); - - // An unprotected packet will be 3 bytes smaller than an FEC-protected packet, - // since the protected packet will have 1 byte for FEC group number and - // 2 bytes of stream frame size, which are absent in the unprotected packet. - size_t unprotected_packet = protected_packet - 3; - EXPECT_EQ(protected_packet + fec_packet + 4 * unprotected_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // Ack data packets, and NACK FEC packet and one data packet. Triggers - // NACK-based loss detection of both packets, but only data packet is - // retransmitted and considered outstanding. - QuicAckFrame ack = InitAckFrame(6); - NackPacket(2, &ack); - NackPacket(3, &ack); - SendAlgorithmInterface::CongestionVector lost_packets; - lost_packets.push_back(std::make_pair(2, kMaxPacketSize)); - lost_packets.push_back(std::make_pair(3, kMaxPacketSize)); - EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _)) - .WillOnce(SetArgPointee<3>(lost_packets)); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessAckPacket(&ack); - // On receiving this ack from the server, the client will no longer send - // version number in subsequent packets, including in this retransmission. - size_t unprotected_packet_no_version = unprotected_packet - 4; - EXPECT_EQ(unprotected_packet_no_version, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // Receive ack for the retransmission. No data should be outstanding. - QuicAckFrame ack2 = InitAckFrame(7); - NackPacket(2, &ack2); - NackPacket(3, &ack2); - EXPECT_CALL(*loss_algorithm_, DetectLosses(_, _, _, _)); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - ProcessAckPacket(&ack2); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); -} - -TEST_P(QuicConnectionTest, FECRemainsInflightOnTLPOfEarlierData) { - // This test checks if TLP is sent correctly when a data and an FEC packet - // are outstanding. TLP should be sent for the data packet when the - // retransmission alarm fires. - // Turn on TLP for this test. - QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 1); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // 1 Data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 1u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - size_t protected_packet = - QuicSentPacketManagerPeer::GetBytesInFlight(manager_); - EXPECT_LT(0u, protected_packet); - - // Force FEC timeout to send FEC packet out. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 2u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetFecAlarm()->Fire(); - EXPECT_TRUE(writer_->header().fec_flag); - size_t fec_packet = protected_packet; - EXPECT_EQ(protected_packet + fec_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // TLP alarm should be set. - QuicTime retransmission_time = - connection_.GetRetransmissionAlarm()->deadline(); - EXPECT_NE(QuicTime::Zero(), retransmission_time); - // Simulate the retransmission alarm firing and sending a TLP, so send - // algorithm's OnRetransmissionTimeout is not called. - clock_.AdvanceTime(retransmission_time.Subtract(clock_.Now())); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 3u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetRetransmissionAlarm()->Fire(); - // The TLP retransmission of packet 1 will be 3 bytes smaller than packet 1, - // since packet 1 will have 1 byte for FEC group number and 2 bytes of stream - // frame size, which are absent in the the TLP retransmission. - size_t tlp_packet = protected_packet - 3; - EXPECT_EQ(protected_packet + fec_packet + tlp_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); -} - -TEST_P(QuicConnectionTest, FECRemainsInflightOnTLPOfLaterData) { - // Tests if TLP is sent correctly when data packet 1 and an FEC packet are - // sent followed by data packet 2, and data packet 1 is acked. TLP should be - // sent for data packet 2 when the retransmission alarm fires. Turn on TLP for - // this test. - QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 1); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - - // 1 Data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 1u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - size_t protected_packet = - QuicSentPacketManagerPeer::GetBytesInFlight(manager_); - EXPECT_LT(0u, protected_packet); - - // Force FEC timeout to send FEC packet out. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 2u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetFecAlarm()->Fire(); - EXPECT_TRUE(writer_->header().fec_flag); - // Protected data packet and FEC packet oustanding. - size_t fec_packet = protected_packet; - EXPECT_EQ(protected_packet + fec_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // Send 1 unprotected data packet. No FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 3u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithString(5, "foo", 0, kFin, nullptr); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); - // Protected data packet, FEC packet, and unprotected data packet oustanding. - // An unprotected packet will be 3 bytes smaller than an FEC-protected packet, - // since the protected packet will have 1 byte for FEC group number and - // 2 bytes of stream frame size, which are absent in the unprotected packet. - size_t unprotected_packet = protected_packet - 3; - EXPECT_EQ(protected_packet + fec_packet + unprotected_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // Receive ack for first data packet. FEC and second data packet are still - // outstanding. - QuicAckFrame ack = InitAckFrame(1); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessAckPacket(&ack); - // FEC packet and unprotected data packet oustanding. - EXPECT_EQ(fec_packet + unprotected_packet, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - - // TLP alarm should be set. - QuicTime retransmission_time = - connection_.GetRetransmissionAlarm()->deadline(); - EXPECT_NE(QuicTime::Zero(), retransmission_time); - // Simulate the retransmission alarm firing and sending a TLP, so send - // algorithm's OnRetransmissionTimeout is not called. - clock_.AdvanceTime(retransmission_time.Subtract(clock_.Now())); - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, 4u, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetRetransmissionAlarm()->Fire(); - - // Having received an ack from the server, the client will no longer send - // version number in subsequent packets, including in this retransmission. - size_t tlp_packet_no_version = unprotected_packet - 4; - EXPECT_EQ(fec_packet + unprotected_packet + tlp_packet_no_version, - QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); -} - -TEST_P(QuicConnectionTest, NoTLPForFECPacket) { - // Turn on TLP for this test. - QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 1); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Send 1 FEC-protected data packet. FEC alarm should be set. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.SendStreamDataWithStringWithFec(3, "foo", 0, !kFin, nullptr); - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); - // Force FEC timeout to send FEC packet out. - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, _, _, _, HAS_RETRANSMITTABLE_DATA)) - .Times(1); - connection_.GetFecAlarm()->Fire(); - EXPECT_TRUE(writer_->header().fec_flag); - - // Ack data packet, but not FEC packet. - QuicAckFrame ack = InitAckFrame(1); - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - ProcessAckPacket(&ack); - - // No TLP alarm for FEC, but retransmission alarm should be set for an RTO. - EXPECT_LT(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); - EXPECT_TRUE(connection_.GetRetransmissionAlarm()->IsSet()); - QuicTime rto_time = connection_.GetRetransmissionAlarm()->deadline(); - EXPECT_NE(QuicTime::Zero(), rto_time); - - // Simulate the retransmission alarm firing. FEC packet is no longer - // outstanding. - clock_.AdvanceTime(rto_time.Subtract(clock_.Now())); - connection_.GetRetransmissionAlarm()->Fire(); - - EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); - EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetBytesInFlight(manager_)); -} - TEST_P(QuicConnectionTest, FramePacking) { // Send an ack and two stream frames in 1 packet by queueing them. { @@ -2333,34 +1786,11 @@ EXPECT_EQ(kClientDataStreamId1, writer_->stream_frames()[0]->stream_id); } -TEST_P(QuicConnectionTest, FramePackingFEC) { - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(creator_)); - - // Queue an ack and two stream frames. Ack gets flushed when FEC is turned on - // for sending protected data; two stream frames are packed in 1 packet. - { - QuicConnection::ScopedPacketBundler bundler(&connection_, - QuicConnection::SEND_ACK); - connection_.SendStreamData3WithFec(); - connection_.SendStreamData5WithFec(); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1); - } - EXPECT_EQ(0u, connection_.NumQueuedPackets()); - EXPECT_FALSE(connection_.HasQueuedData()); - - // Parse the last packet and ensure it's in an fec group. - EXPECT_EQ(2u, writer_->header().fec_group); - EXPECT_EQ(2u, writer_->frame_count()); - - // FEC alarm should be set. - EXPECT_TRUE(connection_.GetFecAlarm()->IsSet()); -} - TEST_P(QuicConnectionTest, FramePackingAckResponse) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); // Process a data packet to queue up a pending ack. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacket(kDefaultPathId, 1, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag); EXPECT_CALL(visitor_, OnCanWrite()) .WillOnce(DoAll(IgnoreResult(InvokeWithoutArgs( @@ -2398,8 +1828,7 @@ iov[0].iov_len = 2; iov[1].iov_base = data + 2; iov[1].iov_len = 2; - connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, - MAY_FEC_PROTECT, nullptr); + connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -2424,8 +1853,7 @@ iov[0].iov_len = 2; iov[1].iov_base = data + 2; iov[1].iov_len = 2; - connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, - MAY_FEC_PROTECT, nullptr); + connection_.SendStreamData(1, QuicIOVector(iov, 2, 4), 0, !kFin, nullptr); EXPECT_EQ(1u, connection_.NumQueuedPackets()); EXPECT_TRUE(connection_.HasQueuedData()); @@ -2445,7 +1873,7 @@ // Send a zero byte write with a fin using writev. EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); QuicIOVector empty_iov(nullptr, 0, 0); - connection_.SendStreamData(1, empty_iov, 0, kFin, MAY_FEC_PROTECT, nullptr); + connection_.SendStreamData(1, empty_iov, 0, kFin, nullptr); EXPECT_EQ(0u, connection_.NumQueuedPackets()); EXPECT_FALSE(connection_.HasQueuedData()); @@ -2985,128 +2413,6 @@ EXPECT_EQ(6u, stop_waiting()->least_unacked); } -TEST_P(QuicConnectionTest, ReviveMissingPacketAfterFecPacket) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Don't send missing packet 1. - ProcessFecPacket(kDefaultPathId, 2, 1, true, !kEntropyFlag, nullptr); - // Entropy flag should be false, so entropy should be 0. - EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2)); -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketWithVaryingSeqNumLengths) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Set up a debug visitor to the connection. - scoped_ptr<FecQuicConnectionDebugVisitor> fec_visitor( - new FecQuicConnectionDebugVisitor()); - connection_.set_debug_visitor(fec_visitor.get()); - - QuicPacketNumber fec_packet = 0; - // clang-format off - QuicPacketNumberLength lengths[] = { - PACKET_6BYTE_PACKET_NUMBER, PACKET_4BYTE_PACKET_NUMBER, - PACKET_2BYTE_PACKET_NUMBER, PACKET_1BYTE_PACKET_NUMBER}; - // clang-format on - // For each packet number length size, revive a packet and check sequence - // number length in the revived packet. - for (size_t i = 0; i < arraysize(lengths); ++i) { - // Set packet_number_length_ (for data and FEC packets). - packet_number_length_ = lengths[i]; - fec_packet += 2; - // Don't send missing packet, but send fec packet right after it. - ProcessFecPacket(kDefaultPathId, fec_packet, fec_packet - 1, true, - !kEntropyFlag, nullptr); - // packet number length in the revived header should be the same as - // in the original data/fec packet headers. - EXPECT_EQ(packet_number_length_, - fec_visitor->revived_header().public_header.packet_number_length); - } -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketWithVaryingConnectionIdLengths) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Set up a debug visitor to the connection. - scoped_ptr<FecQuicConnectionDebugVisitor> fec_visitor( - new FecQuicConnectionDebugVisitor()); - connection_.set_debug_visitor(fec_visitor.get()); - - QuicPacketNumber fec_packet = 0; - QuicConnectionIdLength lengths[] = { - PACKET_8BYTE_CONNECTION_ID, PACKET_4BYTE_CONNECTION_ID, - PACKET_1BYTE_CONNECTION_ID, PACKET_0BYTE_CONNECTION_ID}; - // For each connection id length size, revive a packet and check connection - // id length in the revived packet. - for (size_t i = 0; i < arraysize(lengths); ++i) { - // Set connection id length (for data and FEC packets). - connection_id_length_ = lengths[i]; - fec_packet += 2; - // Don't send missing packet, but send fec packet right after it. - ProcessFecPacket(kDefaultPathId, fec_packet, fec_packet - 1, true, - !kEntropyFlag, nullptr); - // Connection id length in the revived header should be the same as - // in the original data/fec packet headers. - EXPECT_EQ(connection_id_length_, - fec_visitor->revived_header().public_header.connection_id_length); - } -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketThenFecPacket) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - ProcessFecProtectedPacket(kDefaultPathId, 1, false, kEntropyFlag, - !kHasStopWaiting); - // Don't send missing packet 2. - ProcessFecPacket(kDefaultPathId, 3, 1, true, !kEntropyFlag, nullptr); - // Entropy flag should be true, so entropy should not be 0. - EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2)); -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacketsThenFecPacket) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - ProcessFecProtectedPacket(kDefaultPathId, 1, false, !kEntropyFlag, - !kHasStopWaiting); - // Don't send missing packet 2. - ProcessFecProtectedPacket(kDefaultPathId, 3, false, !kEntropyFlag, - !kHasStopWaiting); - ProcessFecPacket(kDefaultPathId, 4, 1, true, kEntropyFlag, nullptr); - // Ensure QUIC no longer revives entropy for lost packets. - EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2)); - EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 4)); -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPacket) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Don't send missing packet 1. - ProcessFecPacket(kDefaultPathId, 3, 1, false, !kEntropyFlag, nullptr); - // Out of order. - ProcessFecProtectedPacket(kDefaultPathId, 2, true, !kEntropyFlag, - !kHasStopWaiting); - // Entropy flag should be false, so entropy should be 0. - EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2)); -} - -TEST_P(QuicConnectionTest, ReviveMissingPacketAfterDataPackets) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - ProcessFecProtectedPacket(kDefaultPathId, 1, false, !kEntropyFlag, - !kHasStopWaiting); - // Don't send missing packet 2. - ProcessFecPacket(kDefaultPathId, 6, 1, false, kEntropyFlag, nullptr); - ProcessFecProtectedPacket(kDefaultPathId, 3, false, kEntropyFlag, - !kHasStopWaiting); - ProcessFecProtectedPacket(kDefaultPathId, 4, false, kEntropyFlag, - !kHasStopWaiting); - ProcessFecProtectedPacket(kDefaultPathId, 5, true, !kEntropyFlag, - !kHasStopWaiting); - // Ensure entropy is not revived for the missing packet. - EXPECT_EQ(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 2)); - EXPECT_NE(0u, QuicConnectionPeer::ReceivedEntropyHash(&connection_, 3)); -} - TEST_P(QuicConnectionTest, TLP) { QuicSentPacketManagerPeer::SetMaxTailLossProbes(manager_, 1); @@ -3315,7 +2621,7 @@ // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. - ProcessDataPacketAtLevel(kDefaultPathId, 1, 0, kEntropyFlag, !kHasStopWaiting, + ProcessDataPacketAtLevel(kDefaultPathId, 1, kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); // Transition to the new encryption state and process another encrypted packet @@ -3324,55 +2630,16 @@ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2); - ProcessDataPacketAtLevel(kDefaultPathId, 2, 0, kEntropyFlag, !kHasStopWaiting, + ProcessDataPacketAtLevel(kDefaultPathId, 2, kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 3, 0, kEntropyFlag, !kHasStopWaiting, + ProcessDataPacketAtLevel(kDefaultPathId, 3, kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); } -TEST_P(QuicConnectionTest, ProcessBufferedFECGroup) { - // SetFromConfig is always called after construction from InitializeSession. - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - config.set_max_undecryptable_packets(100); - connection_.SetFromConfig(config); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - use_tagging_decrypter(); - - const uint8_t tag = 0x07; - framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); - - // Don't send packet 1 and buffer initially encrypted packets. - ProcessFecProtectedPacketAtLevel(kDefaultPathId, 2, 1, false, !kEntropyFlag, - !kHasStopWaiting, ENCRYPTION_INITIAL); - ProcessFecPacketAtLevel(kDefaultPathId, 3, 1, false, kEntropyFlag, nullptr, - ENCRYPTION_INITIAL); - // Since the packets were buffered, no FEC group should be open. - ASSERT_EQ(0u, connection_.NumFecGroups()); - - // Now send non-fec protected ack packet and close the group. - QuicStopWaitingFrame frame = InitStopWaitingFrame(4); - ProcessStopWaitingPacketAtLevel(kDefaultPathId, 4, &frame, - ENCRYPTION_INITIAL); - - // Transition to the new encryption state and process another encrypted packet - // which should result in the original packets being processed. The missing - // packet should be revived before the STOP_WAITING packet is processed. - connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); - connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); - connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); - - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(2).RetiresOnSaturation(); - ProcessDataPacketAtLevel(kDefaultPathId, 5, 0, kEntropyFlag, !kHasStopWaiting, - ENCRYPTION_INITIAL); - const QuicConnectionStats& stats = connection_.GetStats(); - EXPECT_EQ(1u, stats.packets_revived); -} - TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) { // SetFromConfig is always called after construction from InitializeSession. EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -3388,8 +2655,8 @@ // Process an encrypted packet which can not yet be decrypted which should // result in the packet being buffered. for (QuicPacketNumber i = 1; i <= 100; ++i) { - ProcessDataPacketAtLevel(kDefaultPathId, i, 0, kEntropyFlag, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kDefaultPathId, i, kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); } // Transition to the new encryption state and process another encrypted packet @@ -3398,14 +2665,14 @@ connection_.SetDefaultEncryptionLevel(ENCRYPTION_INITIAL); connection_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(101); - ProcessDataPacketAtLevel(kDefaultPathId, 101, 0, kEntropyFlag, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kDefaultPathId, 101, kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Finally, process a third packet and note that we do not reprocess the // buffered packet. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 102, 0, kEntropyFlag, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kDefaultPathId, 102, kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); } TEST_P(QuicConnectionTest, TestRetransmitOrder) { @@ -3501,53 +2768,6 @@ EXPECT_EQ(0u, connection_.NumQueuedPackets()); } -TEST_P(QuicConnectionTest, CloseFecGroup) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - // Don't send missing packet 1. - // Don't send missing packet 2. - ProcessFecProtectedPacket(kDefaultPathId, 3, false, !kEntropyFlag, - !kHasStopWaiting); - // Don't send missing FEC packet 3. - ASSERT_EQ(1u, connection_.NumFecGroups()); - - // Now send non-fec protected ack packet and close the group. - QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 4); - QuicStopWaitingFrame frame = InitStopWaitingFrame(5); - ProcessStopWaitingPacket(&frame); - ASSERT_EQ(0u, connection_.NumFecGroups()); -} - -TEST_P(QuicConnectionTest, - CloseFecGroupUnderStopWaitingAndWaitingForPacketsBelowStopWaiting) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - // Don't send missing packet 1. - ProcessFecProtectedPacket(kDefaultPathId, 2, false, !kEntropyFlag, - !kHasStopWaiting); - EXPECT_EQ(1u, connection_.NumFecGroups()); - stop_waiting_ = InitStopWaitingFrame(2); - ProcessFecProtectedPacket(kDefaultPathId, 3, false, !kEntropyFlag, - kHasStopWaiting); - // This Fec group would be closed. - EXPECT_EQ(0u, connection_.NumFecGroups()); -} - -TEST_P(QuicConnectionTest, - DoNotCloseFecGroupUnderStopWaitingButNotWaitingForPacketsBelow) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessFecProtectedPacket(kDefaultPathId, 1, false, !kEntropyFlag, - !kHasStopWaiting); - ProcessFecProtectedPacket(kDefaultPathId, 2, false, !kEntropyFlag, - !kHasStopWaiting); - // Don't send missing packet 3. - EXPECT_EQ(1u, connection_.NumFecGroups()); - stop_waiting_ = InitStopWaitingFrame(2); - ProcessFecProtectedPacket(kDefaultPathId, 3, false, !kEntropyFlag, - kHasStopWaiting); - // This group will not be closed because this group is not waiting for packets - // below stop waiting. - EXPECT_EQ(1u, connection_.NumFecGroups()); -} - TEST_P(QuicConnectionTest, InitialTimeout) { EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber()); @@ -3573,7 +2793,6 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -3617,7 +2836,6 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); EXPECT_FALSE(connection_.GetPingAlarm()->IsSet()); - EXPECT_FALSE(connection_.GetFecAlarm()->IsSet()); EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet()); EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet()); EXPECT_FALSE(connection_.GetSendAlarm()->IsSet()); @@ -3898,110 +3116,7 @@ EXPECT_FALSE(connection_.GetMtuDiscoveryAlarm()->IsSet()); } -TEST_P(QuicConnectionTest, OldTimeoutAfterSend) { - ValueRestore<bool> old_flags(&FLAGS_quic_use_new_idle_timeout, false); - EXPECT_TRUE(connection_.connected()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - connection_.SetFromConfig(config); - EXPECT_FALSE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); - - const QuicTime::Delta initial_idle_timeout = - QuicTime::Delta::FromSeconds(kInitialIdleTimeoutSecs - 1); - const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); - QuicTime default_timeout = clock_.ApproximateNow().Add(initial_idle_timeout); - - // When we send a packet, the timeout will change to 5ms + - // kInitialIdleTimeoutSecs. - clock_.AdvanceTime(five_ms); - - // Send an ack so we don't set the retransmission alarm. - SendAckPacketToPeer(); - EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline()); - - // The original alarm will fire. We should not time out because we had a - // network event at t=5ms. The alarm will reregister. - clock_.AdvanceTime(initial_idle_timeout.Subtract(five_ms)); - EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - connection_.GetTimeoutAlarm()->Fire(); - EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_TRUE(connection_.connected()); - EXPECT_EQ(default_timeout.Add(five_ms), - connection_.GetTimeoutAlarm()->deadline()); - - // This time, we should time out. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, - ConnectionCloseSource::FROM_SELF)); - EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); - clock_.AdvanceTime(five_ms); - EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow()); - connection_.GetTimeoutAlarm()->Fire(); - EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_FALSE(connection_.connected()); -} - -TEST_P(QuicConnectionTest, OldTimeoutAfterSendSilentClose) { - ValueRestore<bool> old_flags(&FLAGS_quic_use_new_idle_timeout, false); - // Same test as above, but complete a handshake which enables silent close, - // causing no connection close packet to be sent. - EXPECT_TRUE(connection_.connected()); - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - - // Create a handshake message that also enables silent close. - CryptoHandshakeMessage msg; - string error_details; - QuicConfig client_config; - client_config.SetInitialStreamFlowControlWindowToSend( - kInitialStreamFlowControlWindowForTest); - client_config.SetInitialSessionFlowControlWindowToSend( - kInitialSessionFlowControlWindowForTest); - client_config.SetIdleConnectionStateLifetime( - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs), - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)); - client_config.ToHandshakeMessage(&msg); - const QuicErrorCode error = - config.ProcessPeerHello(msg, CLIENT, &error_details); - EXPECT_EQ(QUIC_NO_ERROR, error); - - connection_.SetFromConfig(config); - EXPECT_TRUE(QuicConnectionPeer::IsSilentCloseEnabled(&connection_)); - - const QuicTime::Delta default_idle_timeout = - QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs - 1); - const QuicTime::Delta five_ms = QuicTime::Delta::FromMilliseconds(5); - QuicTime default_timeout = clock_.ApproximateNow().Add(default_idle_timeout); - - // When we send a packet, the timeout will change to 5ms + - // kInitialIdleTimeoutSecs. - clock_.AdvanceTime(five_ms); - - // Send an ack so we don't set the retransmission alarm. - SendAckPacketToPeer(); - EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline()); - - // The original alarm will fire. We should not time out because we had a - // network event at t=5ms. The alarm will reregister. - clock_.AdvanceTime(default_idle_timeout.Subtract(five_ms)); - EXPECT_EQ(default_timeout, clock_.ApproximateNow()); - connection_.GetTimeoutAlarm()->Fire(); - EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_TRUE(connection_.connected()); - EXPECT_EQ(default_timeout.Add(five_ms), - connection_.GetTimeoutAlarm()->deadline()); - - // This time, we should time out. - EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_NETWORK_IDLE_TIMEOUT, - ConnectionCloseSource::FROM_SELF)); - clock_.AdvanceTime(five_ms); - EXPECT_EQ(default_timeout.Add(five_ms), clock_.ApproximateNow()); - connection_.GetTimeoutAlarm()->Fire(); - EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet()); - EXPECT_FALSE(connection_.connected()); -} - TEST_P(QuicConnectionTest, TimeoutAfterSend) { - ValueRestore<bool> old_flags(&FLAGS_quic_use_new_idle_timeout, true); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); QuicConfig config; @@ -4047,7 +3162,6 @@ } TEST_P(QuicConnectionTest, NewTimeoutAfterSendSilentClose) { - ValueRestore<bool> old_flags(&FLAGS_quic_use_new_idle_timeout, true); // Same test as above, but complete a handshake which enables silent close, // causing no connection close packet to be sent. EXPECT_TRUE(connection_.connected()); @@ -4159,7 +3273,6 @@ } TEST_P(QuicConnectionTest, TimeoutAfterReceiveNotSendWhenUnacked) { - ValueRestore<bool> old_flags(&FLAGS_quic_use_new_idle_timeout, true); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); EXPECT_TRUE(connection_.connected()); EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); @@ -4220,8 +3333,8 @@ TEST_P(QuicConnectionTest, SendScheduler) { // Test that if we send a packet without delay, it is not queued. - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, 0, !kEntropyFlag, - !kHasStopWaiting); + QuicPacket* packet = + ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)); connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false, @@ -4233,8 +3346,8 @@ // Test that the connection does not crash when it fails to send the first // packet at which point self_address_ might be uninitialized. EXPECT_CALL(visitor_, OnConnectionClosed(_, _)).Times(1); - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, 0, !kEntropyFlag, - !kHasStopWaiting); + QuicPacket* packet = + ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting); writer_->SetShouldWriteFail(); connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false, @@ -4242,8 +3355,8 @@ } TEST_P(QuicConnectionTest, SendSchedulerEAGAIN) { - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, 0, !kEntropyFlag, - !kHasStopWaiting); + QuicPacket* packet = + ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting); BlockOnNextWrite(); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, @@ -4257,8 +3370,7 @@ size_t payload_length; size_t length = GetPacketLengthForOneStream( connection_.version(), kIncludeVersion, !kIncludePathId, - PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP, - &payload_length); + PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, &payload_length); connection_.SetMaxPacketLength(length); // Queue the first packet. @@ -4279,11 +3391,10 @@ // offset 0, and 2 for non-zero offsets up through 16K. Increase // max_packet_length by 2 so that subsequent packets containing subsequent // stream frames with non-zero offets will fit within the packet length. - size_t length = - 2 + GetPacketLengthForOneStream( - connection_.version(), kIncludeVersion, !kIncludePathId, - PACKET_8BYTE_CONNECTION_ID, PACKET_1BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP, &payload_length); + size_t length = 2 + GetPacketLengthForOneStream( + connection_.version(), kIncludeVersion, + !kIncludePathId, PACKET_8BYTE_CONNECTION_ID, + PACKET_1BYTE_PACKET_NUMBER, &payload_length); connection_.SetMaxPacketLength(length); // Queue the first packet. @@ -4356,8 +3467,8 @@ // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1, 0, !kEntropyFlag, - !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -4372,7 +3483,7 @@ } TEST_P(QuicConnectionTest, SendDelayedAckDecimation) { - QuicConnectionPeer::EnableAckDecimation(&connection_); + QuicConnectionPeer::SetAckMode(&connection_, QuicConnection::ACK_DECIMATION); const size_t kMinRttMs = 40; RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager_); @@ -4394,15 +3505,15 @@ QuicPacketNumber kFirstDecimatedPacket = 101; for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, 0, !kEntropyFlag, + ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); } EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used // instead of ENCRYPTION_NONE. EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, 0, - !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag, + !kHasStopWaiting, ENCRYPTION_INITIAL); // Check if delayed ack timer is running for the expected interval. EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); @@ -4412,7 +3523,7 @@ for (int i = 0; i < 9; ++i) { EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); - ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, 0, + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); } @@ -4423,6 +3534,142 @@ EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); } +TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithReordering) { + FLAGS_quic_ack_decimation2 = true; + QuicConnectionPeer::SetAckMode( + &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + + const size_t kMinRttMs = 40; + RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager_); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow().Add( + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + const uint8_t tag = 0x07; + connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); + framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + // Process a packet from the non-crypto stream. + frame1_.stream_id = 3; + + // Process all the initial packets in order so there aren't missing packets. + QuicPacketNumber kFirstDecimatedPacket = 101; + for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag, + !kHasStopWaiting, ENCRYPTION_INITIAL); + } + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // instead of ENCRYPTION_NONE. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag, + !kHasStopWaiting, ENCRYPTION_INITIAL); + + // Check if delayed ack timer is running for the expected interval. + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); + + // Process packet 10 first and ensure the alarm is one eighth min_rtt. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 9, + !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); + ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); + + // The 10th received packet causes an ack to be sent. + for (int i = 0; i < 8; ++i) { + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, + !kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); + } + // Check that ack is sent and that delayed ack alarm is reset. + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); +} + +TEST_P(QuicConnectionTest, SendDelayedAckDecimationWithLargeReordering) { + FLAGS_quic_ack_decimation2 = true; + QuicConnectionPeer::SetAckMode( + &connection_, QuicConnection::ACK_DECIMATION_WITH_REORDERING); + + const size_t kMinRttMs = 40; + RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager_); + rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(kMinRttMs), + QuicTime::Delta::Zero(), QuicTime::Zero()); + // The ack time should be based on min_rtt/4, since it's less than the + // default delayed ack time. + QuicTime ack_time = clock_.ApproximateNow().Add( + QuicTime::Delta::FromMilliseconds(kMinRttMs / 4)); + EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + const uint8_t tag = 0x07; + connection_.SetDecrypter(ENCRYPTION_INITIAL, new StrictTaggingDecrypter(tag)); + framer_.SetEncrypter(ENCRYPTION_INITIAL, new TaggingEncrypter(tag)); + // Process a packet from the non-crypto stream. + frame1_.stream_id = 3; + + // Process all the initial packets in order so there aren't missing packets. + QuicPacketNumber kFirstDecimatedPacket = 101; + for (unsigned int i = 0; i < kFirstDecimatedPacket - 1; ++i) { + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, 1 + i, !kEntropyFlag, + !kHasStopWaiting, ENCRYPTION_INITIAL); + } + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + // The same as ProcessPacket(1) except that ENCRYPTION_INITIAL is used + // instead of ENCRYPTION_NONE. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket, !kEntropyFlag, + !kHasStopWaiting, ENCRYPTION_INITIAL); + + // Check if delayed ack timer is running for the expected interval. + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); + + // Process packet 10 first and ensure the alarm is one eighth min_rtt. + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 19, + !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); + ack_time = clock_.ApproximateNow().Add(QuicTime::Delta::FromMilliseconds(5)); + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_EQ(ack_time, connection_.GetAckAlarm()->deadline()); + + // The 10th received packet causes an ack to be sent. + for (int i = 0; i < 8; ++i) { + EXPECT_TRUE(connection_.GetAckAlarm()->IsSet()); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 1 + i, + !kEntropyFlag, !kHasStopWaiting, + ENCRYPTION_INITIAL); + } + // Check that ack is sent and that delayed ack alarm is reset. + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + + // The next packet received in order will cause an immediate ack, + // because it fills a hole. + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); + EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(1); + ProcessDataPacketAtLevel(kDefaultPathId, kFirstDecimatedPacket + 10, + !kEntropyFlag, !kHasStopWaiting, ENCRYPTION_INITIAL); + // Check that ack is sent and that delayed ack alarm is reset. + EXPECT_EQ(2u, writer_->frame_count()); + EXPECT_FALSE(writer_->stop_waiting_frames().empty()); + EXPECT_FALSE(writer_->ack_frames().empty()); + EXPECT_FALSE(connection_.GetAckAlarm()->IsSet()); +} + TEST_P(QuicConnectionTest, SendDelayedAckOnHandshakeConfirmed) { EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); ProcessPacket(kDefaultPathId, 1); @@ -4594,7 +3841,7 @@ EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_PEER_GOING_AWAY, ConnectionCloseSource::FROM_PEER)); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(0); - ProcessClosePacket(kDefaultPathId, 2, 0); + ProcessClosePacket(kDefaultPathId, 2); } TEST_P(QuicConnectionTest, SendWhenDisconnected) { @@ -4605,8 +3852,8 @@ ConnectionCloseSource::FROM_SELF); EXPECT_FALSE(connection_.connected()); EXPECT_FALSE(connection_.CanWriteStreamData()); - QuicPacket* packet = ConstructDataPacket(kDefaultPathId, 1, 0, !kEntropyFlag, - !kHasStopWaiting); + QuicPacket* packet = + ConstructDataPacket(kDefaultPathId, 1, !kEntropyFlag, !kHasStopWaiting); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, 1, _, _)).Times(0); connection_.SendPacket(ENCRYPTION_NONE, kDefaultPathId, 1, packet, kTestEntropyHash, HAS_RETRANSMITTABLE_DATA, false, @@ -4684,30 +3931,19 @@ TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculation) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessDataPacket(kDefaultPathId, 1, 1, kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 4, 1, kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 3, 1, !kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 7, 1, kEntropyFlag); - EXPECT_EQ(146u, outgoing_ack()->entropy_hash); -} - -TEST_P(QuicConnectionTest, ReceivedEntropyHashCalculationHalfFEC) { - // FEC packets should not change the entropy hash calculation. - EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1)); - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessDataPacket(kDefaultPathId, 1, 1, kEntropyFlag); - ProcessFecPacket(kDefaultPathId, 4, 1, false, kEntropyFlag, nullptr); - ProcessDataPacket(kDefaultPathId, 3, 3, !kEntropyFlag); - ProcessFecPacket(kDefaultPathId, 7, 3, false, kEntropyFlag, nullptr); + ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 4, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 3, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 7, kEntropyFlag); EXPECT_EQ(146u, outgoing_ack()->entropy_hash); } TEST_P(QuicConnectionTest, UpdateEntropyForReceivedPackets) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessDataPacket(kDefaultPathId, 1, 1, kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 5, 1, kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 4, 1, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 5, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 4, !kEntropyFlag); EXPECT_EQ(34u, outgoing_ack()->entropy_hash); // Make 4th packet my least unacked, and update entropy for 2, 3 packets. QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 5); @@ -4726,9 +3962,9 @@ TEST_P(QuicConnectionTest, UpdateEntropyHashUptoCurrentPacket) { EXPECT_CALL(visitor_, OnStreamFrame(_)).Times(AtLeast(1)); EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - ProcessDataPacket(kDefaultPathId, 1, 1, kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 5, 1, !kEntropyFlag); - ProcessDataPacket(kDefaultPathId, 22, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 5, !kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 22, kEntropyFlag); EXPECT_EQ(66u, outgoing_ack()->entropy_hash); QuicPacketCreatorPeer::SetPacketNumber(&peer_creator_, 22); QuicPacketEntropyHash random_entropy_hash = 85u; @@ -4739,7 +3975,7 @@ ack_entropy_hash = ProcessStopWaitingPacket(&frame); EXPECT_EQ((random_entropy_hash + ack_entropy_hash), outgoing_ack()->entropy_hash); - ProcessDataPacket(kDefaultPathId, 25, 1, kEntropyFlag); + ProcessDataPacket(kDefaultPathId, 25, kEntropyFlag); EXPECT_EQ((random_entropy_hash + ack_entropy_hash + (1 << (25 % 8))), outgoing_ack()->entropy_hash); } @@ -4761,7 +3997,7 @@ } else { entropy[i] = entropy[i - 1]; } - ProcessDataPacket(kDefaultPathId, i, 1, entropy_flag); + ProcessDataPacket(kDefaultPathId, i, entropy_flag); } for (int i = 1; i < 50; ++i) { EXPECT_EQ(entropy[i], @@ -4965,52 +4201,6 @@ EXPECT_EQ(kDefaultMaxPacketSize, stats.max_packet_size); } -TEST_P(QuicConnectionTest, CheckReceiveStats) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - size_t received_bytes = 0; - received_bytes += ProcessFecProtectedPacket(kDefaultPathId, 1, false, - !kEntropyFlag, !kHasStopWaiting); - received_bytes += ProcessFecProtectedPacket(kDefaultPathId, 3, false, - !kEntropyFlag, !kHasStopWaiting); - // Should be counted against dropped packets. - received_bytes += ProcessDataPacket(kDefaultPathId, 3, 1, !kEntropyFlag); - received_bytes += - ProcessFecPacket(kDefaultPathId, 4, 1, true, !kEntropyFlag, nullptr); - - EXPECT_CALL(*send_algorithm_, BandwidthEstimate()) - .WillOnce(Return(QuicBandwidth::Zero())); - - const QuicConnectionStats& stats = connection_.GetStats(); - EXPECT_EQ(received_bytes, stats.bytes_received); - EXPECT_EQ(4u, stats.packets_received); - - EXPECT_EQ(1u, stats.packets_revived); - EXPECT_EQ(1u, stats.packets_dropped); -} - -TEST_P(QuicConnectionTest, TestFecGroupLimits) { - // Create and return a group for 1. - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 1) != nullptr); - - // Create and return a group for 2. - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) != nullptr); - - // Create and return a group for 4. This should remove 1 but not 2. - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 4) != nullptr); - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 1) == nullptr); - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) != nullptr); - - // Create and return a group for 3. This will kill off 2. - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 3) != nullptr); - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 2) == nullptr); - - // Verify that adding 5 kills off 3, despite 4 being created before 3. - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 5) != nullptr); - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 4) != nullptr); - ASSERT_TRUE(QuicConnectionPeer::GetFecGroup(&connection_, 3) == nullptr); -} - TEST_P(QuicConnectionTest, ProcessFramesIfPacketClosedConnection) { // Construct a packet with stream frame and connection close frame. QuicPacketHeader header; @@ -5252,116 +4442,6 @@ ProcessAckPacket(&third_ack_frame); } -TEST_P(QuicConnectionTest, AckNotifierFECTriggerCallback) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - - // Create a listener which we expect to be called. - scoped_refptr<MockAckListener> listener(new MockAckListener); - EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(1); - // Send some data, which will register the listener to be notified. - connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get()); - connection_.SendStreamDataWithString(2, "bar", 0, !kFin, nullptr); - - // Process an ACK from the server with a revived packet, which should trigger - // the callback. - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - QuicAckFrame frame = InitAckFrame(2); - NackPacket(1, &frame); - frame.latest_revived_packet = 1; - ProcessAckPacket(&frame); - // If the ack is processed again, the notifier should not be called again. - ProcessAckPacket(&frame); -} - -TEST_P(QuicConnectionTest, AckNotifierCallbackAfterFECRecovery) { - EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_)); - EXPECT_CALL(visitor_, OnCanWrite()); - - // Create a listener which we expect to be called. - scoped_refptr<MockAckListener> listener(new MockAckListener); - EXPECT_CALL(*listener, OnPacketAcked(_, _)).Times(1); - - // Expect ACKs for 1 packet. - EXPECT_CALL(*send_algorithm_, OnCongestionEvent(true, _, _, _)); - - // Send one packet, and register to be notified on ACK. - connection_.SendStreamDataWithString(1, "foo", 0, !kFin, listener.get()); - - // Ack packet gets dropped, but we receive an FEC packet that covers it. - // Should recover the Ack packet and trigger the notification callback. - QuicFrames frames; - - QuicAckFrame ack_frame = InitAckFrame(1); - frames.push_back(QuicFrame(&ack_frame)); - - // Dummy stream frame to satisfy expectations set elsewhere. - frames.push_back(QuicFrame(&frame1_)); - - QuicPacketHeader ack_header; - ack_header.public_header.connection_id = connection_id_; - ack_header.public_header.reset_flag = false; - ack_header.public_header.version_flag = false; - ack_header.entropy_flag = !kEntropyFlag; - ack_header.fec_flag = true; - ack_header.packet_number = 1; - ack_header.is_in_fec_group = IN_FEC_GROUP; - ack_header.fec_group = 1; - - QuicPacket* packet = BuildUnsizedDataPacket(&framer_, ack_header, frames); - - // Take the packet which contains the ACK frame, and construct and deliver an - // FEC packet which allows the ACK packet to be recovered. - ProcessFecPacket(kDefaultPathId, 2, 1, true, !kEntropyFlag, packet); -} - -TEST_P(QuicConnectionTest, NetworkChangeVisitorCwndCallbackChangesFecState) { - size_t max_packets_per_fec_group = creator_->max_packets_per_fec_group(); - - QuicSentPacketManager::NetworkChangeVisitor* visitor = - QuicSentPacketManagerPeer::GetNetworkChangeVisitor(manager_); - EXPECT_TRUE(visitor); - - // Increase FEC group size by increasing congestion window to a large number. - EXPECT_CALL(*send_algorithm_, GetCongestionWindow()) - .WillRepeatedly(Return(1000 * kDefaultTCPMSS)); - visitor->OnCongestionWindowChange(); - EXPECT_LT(max_packets_per_fec_group, creator_->max_packets_per_fec_group()); -} - -TEST_P(QuicConnectionTest, NetworkChangeVisitorConfigCallbackChangesFecState) { - QuicSentPacketManager::NetworkChangeVisitor* visitor = - QuicSentPacketManagerPeer::GetNetworkChangeVisitor(manager_); - EXPECT_TRUE(visitor); - EXPECT_EQ(QuicTime::Delta::Zero(), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); - - // Verify that sending a config with a new initial rtt changes fec timeout. - // Create and process a config with a non-zero initial RTT. - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - config.SetInitialRoundTripTimeUsToSend(300000); - connection_.SetFromConfig(config); - EXPECT_LT(QuicTime::Delta::Zero(), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); -} - -TEST_P(QuicConnectionTest, NetworkChangeVisitorRttCallbackChangesFecState) { - // Verify that sending a config with a new initial rtt changes fec timeout. - QuicSentPacketManager::NetworkChangeVisitor* visitor = - QuicSentPacketManagerPeer::GetNetworkChangeVisitor(manager_); - EXPECT_TRUE(visitor); - EXPECT_EQ(QuicTime::Delta::Zero(), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); - - // Increase FEC timeout by increasing RTT. - RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(manager_); - rtt_stats->UpdateRtt(QuicTime::Delta::FromMilliseconds(300), - QuicTime::Delta::Zero(), QuicTime::Zero()); - visitor->OnRttChange(); - EXPECT_LT(QuicTime::Delta::Zero(), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); -} - TEST_P(QuicConnectionTest, OnPacketHeaderDebugVisitor) { QuicPacketHeader header; @@ -5422,43 +4502,6 @@ "Attempt to send empty stream frame"); } -TEST_P(QuicConnectionTest, FecSendPolicyReceivedConnectionOption) { - // Test sending SetReceivedConnectionOptions when FEC send policy is - // FEC_ANY_TRIGGER. - if (GetParam().fec_send_policy == FEC_ALARM_TRIGGER) { - return; - } - connection_.set_perspective(Perspective::IS_SERVER); - - // Test ReceivedConnectionOptions. - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - QuicTagVector copt; - copt.push_back(kFSPA); - QuicConfigPeer::SetReceivedConnectionOptions(&config, copt); - EXPECT_EQ(FEC_ANY_TRIGGER, generator_->fec_send_policy()); - connection_.SetFromConfig(config); - EXPECT_EQ(FEC_ALARM_TRIGGER, generator_->fec_send_policy()); -} - -// TODO(rtenneti): Delete this code after the 0.25 RTT FEC experiment. -TEST_P(QuicConnectionTest, FecRTTMultiplierReceivedConnectionOption) { - connection_.set_perspective(Perspective::IS_SERVER); - - // Test ReceivedConnectionOptions. - EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)); - QuicConfig config; - QuicTagVector copt; - copt.push_back(kFRTT); - QuicConfigPeer::SetReceivedConnectionOptions(&config, copt); - float rtt_multiplier_for_fec_timeout = - QuicPacketCreatorPeer::GetRttMultiplierForFecTimeout(creator_); - connection_.SetFromConfig(config); - // New RTT multiplier is half of the old RTT multiplier. - EXPECT_EQ(rtt_multiplier_for_fec_timeout, - QuicPacketCreatorPeer::GetRttMultiplierForFecTimeout(creator_) * 2); -} - TEST_P(QuicConnectionTest, DoNotSendGoAwayTwice) { EXPECT_FALSE(connection_.goaway_sent()); EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(1);
diff --git a/net/quic/quic_crypto_client_stream_test.cc b/net/quic/quic_crypto_client_stream_test.cc index e95582c9..01ea2d4a 100644 --- a/net/quic/quic_crypto_client_stream_test.cc +++ b/net/quic/quic_crypto_client_stream_test.cc
@@ -263,6 +263,8 @@ server_crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), CryptoTestUtils::ProofSourceForTesting()), + server_compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED) { TestQuicSpdyClientSession* client_session = nullptr; CreateClientSessionForTest( @@ -288,10 +290,10 @@ // Initializes the server_stream_ for stateless rejects. void InitializeFakeStatelessRejectServer() { TestQuicSpdyServerSession* server_session = nullptr; - CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000), - QuicSupportedVersions(), &helper_, - &server_crypto_config_, &server_connection_, - &server_session); + CreateServerSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), + QuicSupportedVersions(), &helper_, &server_crypto_config_, + &server_compressed_certs_cache_, &server_connection_, &server_session); CHECK(server_session); server_session_.reset(server_session); CryptoTestUtils::FakeServerOptions options; @@ -312,6 +314,7 @@ PacketSavingConnection* server_connection_; scoped_ptr<TestQuicSpdyServerSession> server_session_; QuicCryptoServerConfig server_crypto_config_; + QuicCompressedCertsCache server_compressed_certs_cache_; QuicServerId server_id_; };
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc index f53602e..41a701e4 100644 --- a/net/quic/quic_crypto_server_stream.cc +++ b/net/quic/quic_crypto_server_stream.cc
@@ -48,15 +48,18 @@ QuicCryptoServerStream::QuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + bool use_stateless_rejects_if_peer_supported, QuicSession* session) : QuicCryptoServerStreamBase(session), crypto_config_(crypto_config), + compressed_certs_cache_(compressed_certs_cache), validate_client_hello_cb_(nullptr), num_handshake_messages_(0), num_handshake_messages_with_server_nonces_(0), num_server_config_update_messages_sent_(0), use_stateless_rejects_if_peer_supported_( - FLAGS_enable_quic_stateless_reject_support), + use_stateless_rejects_if_peer_supported), peer_supports_stateless_rejects_(false) { DCHECK_EQ(Perspective::IS_SERVER, session->connection()->perspective()); }
diff --git a/net/quic/quic_crypto_server_stream.h b/net/quic/quic_crypto_server_stream.h index fc9a7f3..b78e888 100644 --- a/net/quic/quic_crypto_server_stream.h +++ b/net/quic/quic_crypto_server_stream.h
@@ -11,6 +11,7 @@ #include "base/macros.h" #include "net/quic/crypto/crypto_handshake.h" +#include "net/quic/crypto/quic_compressed_certs_cache.h" #include "net/quic/crypto/quic_crypto_server_config.h" #include "net/quic/proto/source_address_token.pb.h" #include "net/quic/quic_config.h" @@ -52,7 +53,6 @@ // various code and test refactoring. class NET_EXPORT_PRIVATE QuicCryptoServerStreamBase : public QuicCryptoStream { public: - // |crypto_config| must outlive the stream. explicit QuicCryptoServerStreamBase(QuicSession* session) : QuicCryptoStream(session) {} ~QuicCryptoServerStreamBase() override {} @@ -93,6 +93,8 @@ public: // |crypto_config| must outlive the stream. QuicCryptoServerStream(const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + bool use_stateless_rejects_if_peer_supported, QuicSession* session); ~QuicCryptoServerStream() override; @@ -165,6 +167,10 @@ // crypto_config_ contains crypto parameters for the handshake. const QuicCryptoServerConfig* crypto_config_; + // compressed_certs_cache_ contains a set of most recently compressed certs. + // Owned by QuicDispatcher. + QuicCompressedCertsCache* compressed_certs_cache_; + // Server's certificate chain and signature of the server config, as provided // by ProofSource::GetProof. QuicCryptoProof crypto_proof_;
diff --git a/net/quic/quic_crypto_server_stream_test.cc b/net/quic/quic_crypto_server_stream_test.cc index 4b32c18..d4eea18 100644 --- a/net/quic/quic_crypto_server_stream_test.cc +++ b/net/quic/quic_crypto_server_stream_test.cc
@@ -70,6 +70,8 @@ : server_crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), CryptoTestUtils::ProofSourceForTesting()), + server_compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), server_id_(kServerHostname, kServerPort, PRIVACY_MODE_DISABLED), client_crypto_config_(CryptoTestUtils::ProofVerifierForTesting()) { FLAGS_enable_quic_stateless_reject_support = false; @@ -107,11 +109,10 @@ void InitializeServer() { TestQuicSpdyServerSession* server_session = nullptr; helpers_.push_back(new MockConnectionHelper); - - CreateServerSessionForTest(server_id_, QuicTime::Delta::FromSeconds(100000), - supported_versions_, helpers_.back(), - &server_crypto_config_, &server_connection_, - &server_session); + CreateServerSessionForTest( + server_id_, QuicTime::Delta::FromSeconds(100000), supported_versions_, + helpers_.back(), &server_crypto_config_, + &server_compressed_certs_cache_, &server_connection_, &server_session); CHECK(server_session); server_session_.reset(server_session); CryptoTestUtils::FakeServerOptions options; @@ -186,6 +187,7 @@ PacketSavingConnection* server_connection_; scoped_ptr<TestQuicSpdyServerSession> server_session_; QuicCryptoServerConfig server_crypto_config_; + QuicCompressedCertsCache server_compressed_certs_cache_; QuicServerId server_id_; // Client state @@ -375,11 +377,10 @@ server_stream()); } - if (FLAGS_require_strike_register_or_server_nonce && - !AsyncStrikeRegisterVerification()) { - EXPECT_EQ(2, client_stream()->num_sent_client_hellos()); - } else { + if (AsyncStrikeRegisterVerification()) { EXPECT_EQ(1, client_stream()->num_sent_client_hellos()); + } else { + EXPECT_EQ(2, client_stream()->num_sent_client_hellos()); } }
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc index 9878561..7dea7ec 100644 --- a/net/quic/quic_flags.cc +++ b/net/quic/quic_flags.cc
@@ -62,46 +62,21 @@ // Disable QUIC's userspace pacing. bool FLAGS_quic_disable_pacing = false; -// If true, QUIC connections will timeout when packets are not being recieved, -// even if they are being sent. -bool FLAGS_quic_use_new_idle_timeout = true; - // If true, don't send QUIC packets if the send alarm is set. bool FLAGS_quic_respect_send_alarm2 = true; -// If true, allow each quic stream to write 16k blocks rather than doing a round -// robin of one packet per session when ack clocked or paced. -bool FLAGS_quic_batch_writes = true; - -// If true, QUIC sessions will write block streams that attempt to write -// unencrypted data. -bool FLAGS_quic_block_unencrypted_writes = true; - // If true, Close the connection instead of writing unencrypted stream data. bool FLAGS_quic_never_write_unencrypted_data = true; -// If true, clear the FEC group instead of sending it with ENCRYPTION_NONE. -// Close the connection if we ever try to serialized unencrypted FEC. -bool FLAGS_quic_no_unencrypted_fec = true; - // If true, reject any incoming QUIC which does not have the FIXD tag. bool FLAGS_quic_require_fix = true; // If true, headers stream will support receiving PUSH_PROMISE frames. bool FLAGS_quic_supports_push_promise = false; -// If true, QUIC servers will attempt to validate a client's source -// address token using the primary config, even if no server config id -// is present in the client hello. -bool FLAGS_quic_validate_stk_without_scid = true; - // If true, QUIC will support RFC 7539 variants of ChaCha20 Poly1305. bool FLAGS_quic_use_rfc7539 = true; -// If true, require QUIC connections to use a valid server nonce or a non-local -// strike register. -bool FLAGS_require_strike_register_or_server_nonce = true; - // When turn on, log packet loss into transport connection stats LossEvent. bool FLAGS_quic_log_loss_event = true; @@ -141,3 +116,20 @@ // If true, the QUIC dispatcher will directly send version negotiation packets // without needing to create a QUIC session first. bool FLAGS_quic_stateless_version_negotiation = false; + +// QUIC Ack Decimation with tolerance for packet reordering. +bool FLAGS_quic_ack_decimation2 = true; + +// If true, QUIC connections will defer responding to ACKs to their send alarms. +bool FLAGS_quic_connection_defer_ack_response = true; + +// If true, calls to QuicAlarm::Cancel don't do anything if the alarm is not +// set. +bool FLAGS_quic_only_cancel_set_alarms = true; + +// Simplify QUIC's write path for inplace encryption now that FEC is gone. +bool FLAGS_quic_inplace_encryption2 = true; + +// If true, SpdyFramer will call OnStreamEnd from SpdyFramerVisitorInterface +// instead of empty-data sentinel calls when the stream is to be ended. +bool FLAGS_spdy_on_stream_end = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h index a110e578..c50d527 100644 --- a/net/quic/quic_flags.h +++ b/net/quic/quic_flags.h
@@ -23,19 +23,13 @@ NET_EXPORT_PRIVATE extern bool FLAGS_shift_quic_cubic_epoch_when_app_limited; NET_EXPORT_PRIVATE extern bool FLAGS_quic_measure_headers_hol_blocking_time; NET_EXPORT_PRIVATE extern bool FLAGS_quic_disable_pacing; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_new_idle_timeout; NET_EXPORT_PRIVATE extern bool FLAGS_quic_respect_send_alarm2; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_batch_writes; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_block_unencrypted_writes; NET_EXPORT_PRIVATE extern bool FLAGS_quic_never_write_unencrypted_data; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_no_unencrypted_fec; NET_EXPORT_PRIVATE extern bool FLAGS_quic_require_fix; NET_EXPORT_PRIVATE extern bool FLAGS_quic_stateless_version_negotiation; NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise; NET_EXPORT_PRIVATE extern bool FLAGS_quic_supports_push_promise; -NET_EXPORT_PRIVATE extern bool FLAGS_quic_validate_stk_without_scid; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_rfc7539; -NET_EXPORT_PRIVATE extern bool FLAGS_require_strike_register_or_server_nonce; NET_EXPORT_PRIVATE extern bool FLAGS_quic_log_loss_event; NET_EXPORT_PRIVATE extern bool FLAGS_quic_include_path_id_in_iv; NET_EXPORT_PRIVATE extern bool FLAGS_quic_cede_correctly; @@ -46,5 +40,10 @@ NET_EXPORT_PRIVATE extern bool FLAGS_quic_log_received_parameters; NET_EXPORT_PRIVATE extern bool FLAGS_quic_use_new_tcp_sender; NET_EXPORT_PRIVATE extern bool FLAGS_quic_save_initial_subkey_secret; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_ack_decimation2; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_connection_defer_ack_response; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_only_cancel_set_alarms; +NET_EXPORT_PRIVATE extern bool FLAGS_quic_inplace_encryption2; +NET_EXPORT_PRIVATE extern bool FLAGS_spdy_on_stream_end; #endif // NET_QUIC_QUIC_FLAGS_H_
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc index ac58d57a..fa667f24 100644 --- a/net/quic/quic_framer.cc +++ b/net/quic/quic_framer.cc
@@ -159,13 +159,10 @@ // static size_t QuicFramer::GetMinStreamFrameSize(QuicStreamId stream_id, QuicStreamOffset offset, - bool last_frame_in_packet, - InFecGroup is_in_fec_group) { - bool no_stream_frame_length = - last_frame_in_packet && is_in_fec_group == NOT_IN_FEC_GROUP; + bool last_frame_in_packet) { return kQuicFrameTypeSize + GetStreamIdSize(stream_id) + GetStreamOffsetSize(offset) + - (no_stream_frame_length ? 0 : kQuicStreamPayloadLengthSize); + (last_frame_in_packet ? 0 : kQuicStreamPayloadLengthSize); } // static @@ -270,7 +267,6 @@ size_t free_bytes, bool first_frame, bool last_frame, - InFecGroup is_in_fec_group, QuicPacketNumberLength packet_number_length) { // Prevent a rare crash reported in b/19458523. if ((frame.type == STREAM_FRAME || frame.type == ACK_FRAME) && @@ -278,7 +274,6 @@ QUIC_BUG << "Cannot compute the length of a null frame. " << "type:" << frame.type << "free_bytes:" << free_bytes << " first_frame:" << first_frame << " last_frame:" << last_frame - << " is_in_fec:" << is_in_fec_group << " seq num length:" << packet_number_length; set_error(QUIC_INTERNAL_ERROR); visitor_->OnError(this); @@ -288,8 +283,8 @@ // PADDING implies end of packet. return free_bytes; } - size_t frame_len = ComputeFrameLength(frame, last_frame, is_in_fec_group, - packet_number_length); + size_t frame_len = + ComputeFrameLength(frame, last_frame, packet_number_length); if (frame_len <= free_bytes) { // Frame fits within packet. Note that acks may be truncated. return frame_len; @@ -336,9 +331,7 @@ size_t i = 0; for (const QuicFrame& frame : frames) { // Determine if we should write stream frame length in header. - const bool no_stream_frame_length = - (header.is_in_fec_group == NOT_IN_FEC_GROUP) && - (i == frames.size() - 1); + const bool no_stream_frame_length = i == frames.size() - 1; if (!AppendTypeByte(frame, no_stream_frame_length, &writer)) { QUIC_BUG << "AppendTypeByte failed"; return 0; @@ -421,31 +414,6 @@ return writer.length(); } -QuicPacket* QuicFramer::BuildFecPacket(const QuicPacketHeader& header, - StringPiece redundancy) { - DCHECK_EQ(IN_FEC_GROUP, header.is_in_fec_group); - DCHECK_NE(0u, header.fec_group); - size_t len = GetPacketHeaderSize(header); - len += redundancy.length(); - - scoped_ptr<char[]> buffer(new char[len]); - QuicDataWriter writer(len, buffer.get()); - if (!AppendPacketHeader(header, &writer)) { - QUIC_BUG << "AppendPacketHeader failed"; - return nullptr; - } - - if (!writer.WriteBytes(redundancy.data(), redundancy.length())) { - QUIC_BUG << "Failed to add FEC"; - return nullptr; - } - - return new QuicPacket( - buffer.release(), len, true, header.public_header.connection_id_length, - header.public_header.version_flag, header.public_header.multipath_flag, - header.public_header.packet_number_length); -} - // static QuicEncryptedPacket* QuicFramer::BuildPublicResetPacket( const QuicPublicResetPacket& packet) { @@ -619,19 +587,12 @@ return RaiseError(QUIC_PACKET_TOO_LARGE); } + DCHECK(!header.fec_flag); // Handle the payload. - if (!header.fec_flag) { - if (header.is_in_fec_group == IN_FEC_GROUP) { - StringPiece payload = reader.PeekRemainingPayload(); - visitor_->OnFecProtectedPayload(payload); - } - if (!ProcessFrameData(&reader, header)) { - DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error. - DLOG(WARNING) << "Unable to process frame data."; - return false; - } - } else { - visitor_->OnFecData(reader.ReadRemainingPayload()); + if (!ProcessFrameData(&reader, header)) { + DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error. + DLOG(WARNING) << "Unable to process frame data."; + return false; } visitor_->OnPacketComplete(); @@ -679,36 +640,9 @@ return true; } -bool QuicFramer::ProcessRevivedPacket(QuicPacketHeader* header, - StringPiece payload) { - visitor_->OnRevivedPacket(); - - header->entropy_hash = GetPacketEntropyHash(*header); - - if (!visitor_->OnPacketHeader(*header)) { - return true; - } - - if (payload.length() > kMaxPacketSize) { - set_detailed_error("Revived packet too large."); - return RaiseError(QUIC_PACKET_TOO_LARGE); - } - - QuicDataReader reader(payload.data(), payload.length()); - if (!ProcessFrameData(&reader, *header)) { - DCHECK_NE(QUIC_NO_ERROR, error_); // ProcessFrameData sets the error. - DLOG(WARNING) << "Unable to process frame data."; - return false; - } - - visitor_->OnPacketComplete(); - return true; -} - bool QuicFramer::AppendPacketHeader(const QuicPacketHeader& header, QuicDataWriter* writer) { DVLOG(1) << "Appending header: " << header; - DCHECK(header.fec_group > 0 || header.is_in_fec_group == NOT_IN_FEC_GROUP); uint8_t public_flags = 0; if (header.public_header.reset_flag) { public_flags |= PACKET_PUBLIC_FLAGS_RST; @@ -785,30 +719,10 @@ if (header.entropy_flag) { private_flags |= PACKET_PRIVATE_FLAGS_ENTROPY; } - if (header.is_in_fec_group == IN_FEC_GROUP) { - private_flags |= PACKET_PRIVATE_FLAGS_FEC_GROUP; - } - if (header.fec_flag) { - private_flags |= PACKET_PRIVATE_FLAGS_FEC; - } if (!writer->WriteUInt8(private_flags)) { return false; } - // The FEC group number is the packet number of the first fec - // protected packet, or 0 if this packet is not protected. - if (header.is_in_fec_group == IN_FEC_GROUP) { - DCHECK_LE(header.fec_group, header.packet_number); - DCHECK_LT(header.packet_number - header.fec_group, 255u); - // Offset from the current packet number to the first fec - // protected packet. - uint8_t first_fec_protected_packet_offset = - static_cast<uint8_t>(header.packet_number - header.fec_group); - if (!writer->WriteBytes(&first_fec_protected_packet_offset, 1)) { - return false; - } - } - return true; } @@ -1470,7 +1384,6 @@ set_detailed_error("Unable to read revived packet."); return false; } - ack_frame->latest_revived_packet = revived_packet; } return true; @@ -1718,6 +1631,27 @@ encrypter_[level].reset(encrypter); } +size_t QuicFramer::EncryptInPlace(EncryptionLevel level, + QuicPathId path_id, + QuicPacketNumber packet_number, + size_t ad_len, + size_t total_len, + size_t buffer_len, + char* buffer) { + size_t output_length = 0; + if (!encrypter_[level]->EncryptPacket( + path_id, packet_number, + StringPiece(buffer, ad_len), // Associated data + StringPiece(buffer + ad_len, total_len - ad_len), // Plaintext + buffer + ad_len, // Destination buffer + &output_length, buffer_len - ad_len)) { + RaiseError(QUIC_ENCRYPTION_FAILURE); + return 0; + } + + return ad_len + output_length; +} + size_t QuicFramer::EncryptPayload(EncryptionLevel level, QuicPathId path_id, QuicPacketNumber packet_number, @@ -1768,7 +1702,7 @@ size_t* decrypted_length) { StringPiece encrypted = encrypted_reader->ReadRemainingPayload(); DCHECK(decrypter_.get() != nullptr); - const StringPiece& associated_data = GetAssociatedDataFromEncryptedPacket( + StringPiece associated_data = GetAssociatedDataFromEncryptedPacket( packet, header.public_header.connection_id_length, header.public_header.version_flag, header.public_header.multipath_flag, header.public_header.packet_number_length); @@ -1822,9 +1756,6 @@ ack_size += kNumberOfNackRangesSize + kNumberOfRevivedPacketsSize; ack_size += min(ack_info.nack_ranges.size(), kMaxNackRanges) * (missing_packet_number_length + PACKET_1BYTE_PACKET_NUMBER); - if (ack.latest_revived_packet != 0) { - ack_size += largest_observed_length; - } } // In version 23, if the ack will be truncated due to too many nack ranges, @@ -1849,13 +1780,12 @@ size_t QuicFramer::ComputeFrameLength( const QuicFrame& frame, bool last_frame_in_packet, - InFecGroup is_in_fec_group, QuicPacketNumberLength packet_number_length) { switch (frame.type) { case STREAM_FRAME: return GetMinStreamFrameSize(frame.stream_frame->stream_id, frame.stream_frame->offset, - last_frame_in_packet, is_in_fec_group) + + last_frame_in_packet) + frame.stream_frame->frame_length; case ACK_FRAME: { return GetAckFrameSize(*frame.ack_frame, packet_number_length); @@ -2114,24 +2044,12 @@ DCHECK_EQ(num_missing_ranges, num_ranges_written); // Append revived packets. - // If not all the revived packets fit, only mention the ones that do. - uint8_t num_revived_packets = frame.latest_revived_packet == 0 ? 0 : 1; - if (((writer->capacity() - writer->length()) / largest_observed_length) == - 0) { - num_revived_packets = 0; - } + // FEC is not supported. + uint8_t num_revived_packets = 0; if (!writer->WriteBytes(&num_revived_packets, 1)) { return false; } - if (num_revived_packets > 0) { - QUIC_BUG_IF(!frame.missing_packets.Contains(frame.latest_revived_packet)); - if (!AppendPacketSequenceNumber(largest_observed_length, - frame.latest_revived_packet, writer)) { - return false; - } - } - return true; }
diff --git a/net/quic/quic_framer.h b/net/quic/quic_framer.h index 3cc24267..a0a0db1 100644 --- a/net/quic/quic_framer.h +++ b/net/quic/quic_framer.h
@@ -91,10 +91,6 @@ virtual void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) = 0; - // Called when a lost packet has been recovered via FEC, - // before it has been processed. - virtual void OnRevivedPacket() = 0; - // Called when the public header has been parsed, but has not been // authenticated. If it returns false, framing for this packet will cease. virtual bool OnUnauthenticatedPublicHeader( @@ -113,10 +109,6 @@ // If OnPacketHeader returns false, framing for this packet will cease. virtual bool OnPacketHeader(const QuicPacketHeader& header) = 0; - // Called when a data packet is parsed that is part of an FEC group. - // |payload| is the non-encrypted FEC protected payload of the packet. - virtual void OnFecProtectedPayload(base::StringPiece payload) = 0; - // Called when a StreamFrame has been parsed. virtual bool OnStreamFrame(const QuicStreamFrame& frame) = 0; @@ -149,9 +141,6 @@ // Called when a PathCloseFrame has been parsed. virtual bool OnPathCloseFrame(const QuicPathCloseFrame& frame) = 0; - // Called when FEC data has been parsed. - virtual void OnFecData(base::StringPiece redundancy) = 0; - // Called when a packet has been completely processed. virtual void OnPacketComplete() = 0; }; @@ -173,8 +162,6 @@ // Class for parsing and constructing QUIC packets. It has a // QuicFramerVisitorInterface that is called when packets are parsed. -// It also has a QuicFecBuilder that is called when packets are constructed -// in order to generate FEC data for subsequently building FEC packets. class NET_EXPORT_PRIVATE QuicFramer { public: // Constructs a new framer that installs a kNULL QuicEncrypter and @@ -228,18 +215,10 @@ // ignored. bool ProcessPacket(const QuicEncryptedPacket& packet); - // Pass a data packet that was revived from FEC data into the framer - // for parsing. - // Return true if the packet was processed succesfully. |payload| must be - // the complete DECRYPTED payload of the revived packet. - bool ProcessRevivedPacket(QuicPacketHeader* header, - base::StringPiece payload); - // Largest size in bytes of all stream frame fields without the payload. static size_t GetMinStreamFrameSize(QuicStreamId stream_id, QuicStreamOffset offset, - bool last_frame_in_packet, - InFecGroup is_in_fec_group); + bool last_frame_in_packet); // Size in bytes of all ack frame fields without the missing packets. static size_t GetMinAckFrameSize( QuicPacketNumberLength largest_observed_length); @@ -276,7 +255,6 @@ size_t free_bytes, bool first_frame_in_packet, bool last_frame_in_packet, - InFecGroup is_in_fec_group, QuicPacketNumberLength packet_number_length); // Returns the associated data from the encrypted packet |encrypted| as a @@ -296,12 +274,6 @@ char* buffer, size_t packet_length); - // Returns a QuicPacket* that is owned by the caller, and is populated with - // the fields in |header| and |fec|. Returns nullptr if the packet could - // not be created. - QuicPacket* BuildFecPacket(const QuicPacketHeader& header, - base::StringPiece redundancy); - // Returns a new public reset packet, owned by the caller. static QuicEncryptedPacket* BuildPublicResetPacket( const QuicPublicResetPacket& packet); @@ -335,6 +307,17 @@ // takes ownership of |encrypter|. void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); + // Encrypts a payload in |buffer|. |ad_len| is the length of the associated + // data. |total_len| is the length of the associated data plus plaintext. + // |buffer_len| is the full length of the allocated buffer. + size_t EncryptInPlace(EncryptionLevel level, + QuicPathId path_id, + QuicPacketNumber packet_number, + size_t ad_len, + size_t total_len, + size_t buffer_len, + char* buffer); + // Returns the length of the data encrypted into |buffer| if |buffer_len| is // long enough, and otherwise 0. size_t EncryptPayload(EncryptionLevel level, @@ -467,7 +450,6 @@ // Computes the wire size in bytes of the payload of |frame|. size_t ComputeFrameLength(const QuicFrame& frame, bool last_frame_in_packet, - InFecGroup is_in_fec_group, QuicPacketNumberLength packet_number_length); static bool AppendPacketSequenceNumber( @@ -529,12 +511,12 @@ // TODO(fayang): this set is never cleaned up. A possible improvement is to // use intervals. std::unordered_set<QuicPathId> closed_paths_; - // Map mapping path id to packet number of last successfully decrypted/revived + // Map mapping path id to packet number of last successfully decrypted // received packet. std::unordered_map<QuicPathId, QuicPacketNumber> last_packet_numbers_; // Updated by ProcessPacketHeader when it succeeds. QuicPacketNumber last_packet_number_; - // The path on which last successfully decrypted/revived packet was received. + // The path on which last successfully decrypted packet was received. QuicPathId last_path_id_; // Updated by WritePacketHeader. QuicConnectionId last_serialized_connection_id_;
diff --git a/net/quic/quic_framer_test.cc b/net/quic/quic_framer_test.cc index 025fb831..d770db9d 100644 --- a/net/quic/quic_framer_test.cc +++ b/net/quic/quic_framer_test.cc
@@ -106,29 +106,6 @@ packet_number_length; } -// Index into the fec group offset in the header. -size_t GetFecGroupOffset(QuicConnectionIdLength connection_id_length, - bool include_version, - bool include_path_id) { - return GetPrivateFlagsOffset(connection_id_length, include_version, - include_path_id) + - kPrivateFlagsSize; -} - -size_t GetFecGroupOffset(bool include_version, bool include_path_id) { - return GetPrivateFlagsOffset(PACKET_8BYTE_CONNECTION_ID, include_version, - include_path_id) + - kPrivateFlagsSize; -} - -size_t GetFecGroupOffset(bool include_version, - bool include_path_id, - QuicPacketNumberLength packet_number_length) { - return GetPrivateFlagsOffset(include_version, include_path_id, - packet_number_length) + - kPrivateFlagsSize; -} - // Index into the message tag of the public reset packet. // Public resets always have full connection_ids. const size_t kPublicResetPacketMessageTagOffset = @@ -177,8 +154,8 @@ bool SetNoncePrefix(StringPiece nonce_prefix) override { return true; } bool DecryptPacket(QuicPathId path_id, QuicPacketNumber packet_number, - const StringPiece& associated_data, - const StringPiece& ciphertext, + StringPiece associated_data, + StringPiece ciphertext, char* output, size_t* output_length, size_t max_output_length) override { @@ -208,9 +185,7 @@ version_mismatch_(0), packet_count_(0), frame_count_(0), - fec_count_(0), complete_packets_(0), - revived_packets_(0), accept_packet_(true), accept_public_header_(true) {} @@ -239,8 +214,6 @@ version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet)); } - void OnRevivedPacket() override { ++revived_packets_; } - bool OnProtocolVersionMismatch(QuicVersion version) override { DVLOG(1) << "QuicFramer Version Mismatch, version: " << version; ++version_mismatch_; @@ -260,6 +233,10 @@ void OnDecryptedPacket(EncryptionLevel level) override {} bool OnPacketHeader(const QuicPacketHeader& header) override { + if (header.fec_flag) { + // Drop any FEC packet. + return false; + } ++packet_count_; header_.reset(new QuicPacketHeader(header)); return accept_packet_; @@ -277,10 +254,6 @@ return true; } - void OnFecProtectedPayload(StringPiece payload) override { - fec_protected_payload_ = payload.as_string(); - } - bool OnAckFrame(const QuicAckFrame& frame) override { ++frame_count_; ack_frames_.push_back(new QuicAckFrame(frame)); @@ -299,11 +272,6 @@ return true; } - void OnFecData(StringPiece redundancy) override { - ++fec_count_; - fec_data_redundancy_.push_back(redundancy.as_string()); - } - void OnPacketComplete() override { ++complete_packets_; } bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { @@ -341,9 +309,7 @@ int version_mismatch_; int packet_count_; int frame_count_; - int fec_count_; int complete_packets_; - int revived_packets_; bool accept_packet_; bool accept_public_header_; @@ -355,7 +321,6 @@ vector<QuicAckFrame*> ack_frames_; vector<QuicStopWaitingFrame*> stop_waiting_frames_; vector<QuicPingFrame*> ping_frames_; - string fec_protected_payload_; QuicRstStreamFrame rst_stream_frame_; QuicConnectionCloseFrame connection_close_frame_; QuicGoAwayFrame goaway_frame_; @@ -363,7 +328,6 @@ QuicBlockedFrame blocked_frame_; QuicPathCloseFrame path_close_frame_; vector<string*> stream_data_; - vector<string> fec_data_redundancy_; }; class QuicFramerTest : public ::testing::TestWithParam<QuicVersion> { @@ -481,8 +445,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, include_version, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_STREAM_DATA); } } @@ -648,10 +611,10 @@ memset(packet + GetPacketHeaderSize( PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP), 0, + PACKET_6BYTE_PACKET_NUMBER), 0, kMaxPacketSize - GetPacketHeaderSize( PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP) + 1); + PACKET_6BYTE_PACKET_NUMBER) + 1); // clang-format on QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); @@ -696,8 +659,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -706,10 +668,8 @@ expected_error = "Unable to read ConnectionId."; } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(!kIncludeVersion, !kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -749,8 +709,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -761,11 +720,8 @@ } else if (i < GetPrivateFlagsOffset(PACKET_4BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(PACKET_4BYTE_CONNECTION_ID, - !kIncludeVersion, !kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -805,8 +761,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -817,11 +772,8 @@ } else if (i < GetPrivateFlagsOffset(PACKET_1BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(PACKET_1BYTE_CONNECTION_ID, - !kIncludeVersion, !kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -861,8 +813,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -873,11 +824,8 @@ } else if (i < GetPrivateFlagsOffset(PACKET_0BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(PACKET_0BYTE_CONNECTION_ID, - !kIncludeVersion, !kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -918,8 +866,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -930,10 +877,8 @@ expected_error = "Unable to read protocol version."; } else if (i < GetPrivateFlagsOffset(kIncludeVersion, !kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(kIncludeVersion, !kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -975,8 +920,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -988,10 +932,8 @@ expected_error = "Unable to read path id."; } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(!kIncludeVersion, kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -1036,8 +978,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -1051,10 +992,8 @@ expected_error = "Unable to read path id."; } else if (i < GetPrivateFlagsOffset(kIncludeVersion, kIncludePathId)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(kIncludeVersion, kIncludePathId)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -1201,8 +1140,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_4BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_4BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -1212,11 +1150,8 @@ } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId, PACKET_4BYTE_PACKET_NUMBER)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(!kIncludeVersion, !kIncludePathId, - PACKET_4BYTE_PACKET_NUMBER)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -1256,8 +1191,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_2BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_2BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -1267,11 +1201,8 @@ } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId, PACKET_2BYTE_PACKET_NUMBER)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(!kIncludeVersion, !kIncludePathId, - PACKET_2BYTE_PACKET_NUMBER)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -1311,8 +1242,7 @@ // Now test framing boundaries. for (size_t i = 0; i < GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_1BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP); + !kIncludePathId, PACKET_1BYTE_PACKET_NUMBER); ++i) { string expected_error; if (i < kConnectionIdOffset) { @@ -1322,11 +1252,8 @@ } else if (i < GetPrivateFlagsOffset(!kIncludeVersion, !kIncludePathId, PACKET_1BYTE_PACKET_NUMBER)) { expected_error = "Unable to read packet number."; - } else if (i < GetFecGroupOffset(!kIncludeVersion, !kIncludePathId, - PACKET_1BYTE_PACKET_NUMBER)) { - expected_error = "Unable to read private flags."; } else { - expected_error = "Unable to read first fec protected packet offset."; + expected_error = "Unable to read private flags."; } CheckProcessingFails(packet, i, expected_error, QUIC_INVALID_PACKET_HEADER); } @@ -1504,8 +1431,7 @@ // A packet with no frames is not acceptable. CheckProcessingFails( packet, GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), "Packet has no frames.", QUIC_MISSING_PAYLOAD); } @@ -1823,114 +1749,6 @@ ASSERT_FALSE(visitor_.header_.get()); } -TEST_P(QuicFramerTest, RevivedStreamFrame) { - // clang-format off - unsigned char payload[] = { - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0xBA, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - // clang-format on - - QuicPacketHeader header; - header.public_header.connection_id = kConnectionId; - header.public_header.reset_flag = false; - header.public_header.version_flag = false; - header.fec_flag = true; - header.entropy_flag = true; - header.packet_number = kPacketNumber; - header.fec_group = 0; - - // Do not encrypt the payload because the revived payload is post-encryption. - EXPECT_TRUE(framer_.ProcessRevivedPacket( - &header, StringPiece(AsChars(payload), arraysize(payload)))); - - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); - ASSERT_EQ(1, visitor_.revived_packets_); - ASSERT_TRUE(visitor_.header_.get()); - EXPECT_EQ(kConnectionId, visitor_.header_->public_header.connection_id); - EXPECT_FALSE(visitor_.header_->public_header.reset_flag); - EXPECT_FALSE(visitor_.header_->public_header.version_flag); - EXPECT_TRUE(visitor_.header_->fec_flag); - EXPECT_TRUE(visitor_.header_->entropy_flag); - EXPECT_EQ(1 << (header.packet_number % 8), visitor_.header_->entropy_hash); - EXPECT_EQ(kPacketNumber, visitor_.header_->packet_number); - EXPECT_EQ(NOT_IN_FEC_GROUP, visitor_.header_->is_in_fec_group); - EXPECT_EQ(0u, visitor_.header_->fec_group); - - ASSERT_EQ(1u, visitor_.stream_frames_.size()); - EXPECT_EQ(0u, visitor_.ack_frames_.size()); - EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); - EXPECT_TRUE(visitor_.stream_frames_[0]->fin); - EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); - CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); -} - -TEST_P(QuicFramerTest, StreamFrameInFecGroup) { - // clang-format off - unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x3C, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, - // private flags (fec group) - 0x02, - // first fec protected packet offset - 0x02, - - // frame type (stream frame with fin) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0xBA, - // data length - 0x0c, 0x00, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - // clang-format on - - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); - ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId)); - EXPECT_EQ(IN_FEC_GROUP, visitor_.header_->is_in_fec_group); - EXPECT_EQ(kPacketNumber - 2, visitor_.header_->fec_group); - const size_t fec_offset = - GetStartOfFecProtectedData(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); - EXPECT_EQ( - string(AsChars(packet) + fec_offset, arraysize(packet) - fec_offset), - visitor_.fec_protected_payload_); - - ASSERT_EQ(1u, visitor_.stream_frames_.size()); - EXPECT_EQ(0u, visitor_.ack_frames_.size()); - EXPECT_EQ(kStreamId, visitor_.stream_frames_[0]->stream_id); - EXPECT_TRUE(visitor_.stream_frames_[0]->fin); - EXPECT_EQ(kStreamOffset, visitor_.stream_frames_[0]->offset); - CheckStreamFrameData("hello world!", visitor_.stream_frames_[0]); -} - TEST_P(QuicFramerTest, AckFrameTwoTimestamp) { // clang-format off unsigned char packet[] = { @@ -2046,8 +1864,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_ACK_DATA); } } @@ -2153,8 +1970,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_ACK_DATA); } } @@ -2248,8 +2064,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_ACK_DATA); } } @@ -2353,8 +2168,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_ACK_DATA); } } @@ -2462,7 +2276,6 @@ QuicAckFrame* frame = visitor_.ack_frames_[0]; EXPECT_EQ(0xBA, frame->entropy_hash); EXPECT_EQ(kLargestObserved, frame->largest_observed); - EXPECT_EQ(0u, frame->latest_revived_packet); ASSERT_EQ(500u, frame->missing_packets.NumPacketsSlow()); EXPECT_EQ(kMissingPacket - 499, frame->missing_packets.Min()); EXPECT_EQ(kMissingPacket, frame->missing_packets.Max()); @@ -2529,8 +2342,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_STOP_WAITING_DATA); } } @@ -2590,8 +2402,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_RST_STREAM_DATA); } } @@ -2651,8 +2462,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_CONNECTION_CLOSE_DATA); } } @@ -2714,8 +2524,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_GOAWAY_DATA); } } @@ -2767,8 +2576,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_WINDOW_UPDATE_DATA); } } @@ -2811,8 +2619,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_BLOCKED_DATA); } } @@ -2887,8 +2694,7 @@ CheckProcessingFails( packet, i + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, - kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + kIncludePathId, PACKET_6BYTE_PACKET_NUMBER), expected_error, QUIC_INVALID_PATH_CLOSE_DATA); } } @@ -3102,7 +2908,7 @@ } } -TEST_P(QuicFramerTest, FecPacket) { +TEST_P(QuicFramerTest, DropFecPacket) { // clang-format off unsigned char packet[] = { // public flags (8 byte connection_id) @@ -3130,13 +2936,7 @@ EXPECT_TRUE(framer_.ProcessPacket(encrypted)); EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); - ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(CheckDecryption(encrypted, !kIncludeVersion, !kIncludePathId)); - - EXPECT_EQ(0u, visitor_.stream_frames_.size()); - EXPECT_EQ(0u, visitor_.ack_frames_.size()); - ASSERT_EQ(1, visitor_.fec_count_); - EXPECT_EQ("abcdefghijklmnop", visitor_.fec_data_redundancy_[0]); + EXPECT_FALSE(visitor_.header_.get()); } TEST_P(QuicFramerTest, BuildPaddingFramePacket) { @@ -3173,9 +2973,9 @@ }; // clang-format on - uint64_t header_size = GetPacketHeaderSize( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP); + uint64_t header_size = + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER); memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -3220,9 +3020,9 @@ }; // clang-format on - uint64_t header_size = GetPacketHeaderSize( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_4BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP); + uint64_t header_size = + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_4BYTE_PACKET_NUMBER); memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -3267,9 +3067,9 @@ }; // clang-format on - uint64_t header_size = GetPacketHeaderSize( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_2BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP); + uint64_t header_size = + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_2BYTE_PACKET_NUMBER); memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -3314,9 +3114,9 @@ }; // clang-format on - uint64_t header_size = GetPacketHeaderSize( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_1BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP); + uint64_t header_size = + GetPacketHeaderSize(PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_1BYTE_PACKET_NUMBER); memset(packet + header_size + 1, 0x00, kMaxPacketSize - header_size - 1); scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); @@ -3378,55 +3178,6 @@ arraysize(packet)); } -TEST_P(QuicFramerTest, BuildStreamFramePacketInFecGroup) { - QuicPacketHeader header; - header.public_header.connection_id = kConnectionId; - header.public_header.reset_flag = false; - header.public_header.version_flag = false; - header.fec_flag = false; - header.entropy_flag = true; - header.packet_number = kPacketNumber; - header.is_in_fec_group = IN_FEC_GROUP; - header.fec_group = kPacketNumber; - - QuicStreamFrame stream_frame(kStreamId, true, kStreamOffset, - StringPiece("hello world!")); - - QuicFrames frames; - frames.push_back(QuicFrame(&stream_frame)); - // clang-format off - unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x3C, - // connection_id - 0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE, - // packet number - 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags (entropy, is_in_fec_group) - 0x03, - // FEC group - 0x00, - // frame type (stream frame with fin and data length field) - 0xFF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, 0xDC, 0xFE, 0x98, 0xBA, - // data length (since packet is in an FEC group) - 0x0C, 0x00, - // data - 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!', - }; - // clang-format on - - scoped_ptr<QuicPacket> data(BuildDataPacket(header, frames)); - ASSERT_TRUE(data != nullptr); - - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet), - arraysize(packet)); -} - TEST_P(QuicFramerTest, BuildStreamFramePacketWithVersionFlag) { QuicPacketHeader header; header.public_header.connection_id = kConnectionId; @@ -4372,50 +4123,6 @@ arraysize(packet)); } -TEST_P(QuicFramerTest, BuildFecPacket) { - QuicPacketHeader header; - header.public_header.connection_id = kConnectionId; - header.public_header.reset_flag = false; - header.public_header.version_flag = false; - header.fec_flag = true; - header.entropy_flag = true; - header.packet_number = kPacketNumber; - header.is_in_fec_group = IN_FEC_GROUP; - header.fec_group = kPacketNumber - 1; - - string redundancy = "abcdefghijklmnop"; - - // clang-format off - unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x3C, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, - // private flags (entropy & fec group & fec packet) - 0x07, - // first fec protected packet offset - 0x01, - - // redundancy - 'a', 'b', 'c', 'd', - 'e', 'f', 'g', 'h', - 'i', 'j', 'k', 'l', - 'm', 'n', 'o', 'p', - }; - // clang-format on - - scoped_ptr<QuicPacket> data(framer_.BuildFecPacket(header, redundancy)); - ASSERT_TRUE(data != nullptr); - - test::CompareCharArraysWithHexError("constructed packet", data->data(), - data->length(), AsChars(packet), - arraysize(packet)); -} - TEST_P(QuicFramerTest, EncryptPacket) { QuicPacketNumber packet_number = kPacketNumber; // clang-format off @@ -4428,10 +4135,8 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags (fec group & fec packet) - 0x06, - // first fec protected packet offset - 0x01, + // private flags + 0x00, // redundancy 'a', 'b', 'c', 'd', @@ -4467,10 +4172,8 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags (fec group & fec flags) - 0x06, - // first fec protected packet offset - 0x01, + // private flags + 0x00, // redundancy 'a', 'b', 'c', 'd', @@ -4506,10 +4209,8 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags (fec group & fec flags) - 0x06, - // first fec protected packet offset - 0x01, + // private flags + 0x00, // redundancy 'a', 'b', 'c', 'd', @@ -4546,10 +4247,8 @@ // packet number 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12, - // private flags (fec group & fec flags) - 0x06, - // first fec protected packet offset - 0x01, + // private flags + 0x00, // redundancy 'a', 'b', 'c', 'd', @@ -4731,45 +4430,6 @@ EXPECT_FALSE(visitor_.header_->fec_flag); }; -TEST_P(QuicFramerTest, FecEntropyTest) { - // clang-format off - unsigned char packet[] = { - // public flags (8 byte connection_id) - 0x3C, - // connection_id - 0x10, 0x32, 0x54, 0x76, - 0x98, 0xBA, 0xDC, 0xFE, - // packet number - 0xBC, 0x9A, 0x78, 0x56, - 0x34, 0x12, - // private flags (Entropy & fec group & FEC) - 0x07, - // first fec protected packet offset - 0xFF, - - // frame type (stream frame with fin and no length) - 0xDF, - // stream id - 0x04, 0x03, 0x02, 0x01, - // offset - 0x54, 0x76, 0x10, 0x32, - 0xDC, 0xFE, 0x98, 0xBA, - // data - 'h', 'e', 'l', 'l', - 'o', ' ', 'w', 'o', - 'r', 'l', 'd', '!', - }; - // clang-format on - - QuicEncryptedPacket encrypted(AsChars(packet), arraysize(packet), false); - EXPECT_TRUE(framer_.ProcessPacket(encrypted)); - EXPECT_EQ(QUIC_NO_ERROR, framer_.error()); - ASSERT_TRUE(visitor_.header_.get()); - EXPECT_TRUE(visitor_.header_->fec_flag); - EXPECT_TRUE(visitor_.header_->entropy_flag); - EXPECT_EQ(1 << 4, visitor_.header_->entropy_hash); -}; - TEST_P(QuicFramerTest, StopPacketProcessing) { // clang-format off unsigned char packet[] = {
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc index b62717c2..88a6186c 100644 --- a/net/quic/quic_headers_stream.cc +++ b/net/quic/quic_headers_stream.cc
@@ -66,7 +66,8 @@ } void OnStreamEnd(SpdyStreamId stream_id) override { - LOG(DFATAL) << "Unimplemented."; + // The framer invokes OnStreamEnd after processing a SYN_STREAM + // or SYN_REPLY frame that had the fin bit set. } void OnStreamPadding(SpdyStreamId stream_id, size_t len) override {
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc index a821fb2..2f51bab6 100644 --- a/net/quic/quic_headers_stream_test.cc +++ b/net/quic/quic_headers_stream_test.cc
@@ -93,19 +93,26 @@ MOCK_METHOD2(OnUnknownFrame, bool(SpdyStreamId stream_id, int frame_type)); }; -// Run all tests with each version, and client or server +// Run all tests with each version, perspective (client or server), +// and relevant flag options (false or true) struct TestParams { - TestParams(QuicVersion version, Perspective perspective) - : version(version), perspective(perspective) {} + TestParams(QuicVersion version, + Perspective perspective, + bool spdy_on_stream_end) + : version(version), + perspective(perspective), + spdy_on_stream_end(spdy_on_stream_end) {} friend ostream& operator<<(ostream& os, const TestParams& p) { os << "{ version: " << QuicVersionToString(p.version); - os << ", perspective: " << p.perspective << " }"; + os << ", perspective: " << p.perspective; + os << ", spdy_on_stream_end: " << p.spdy_on_stream_end << " }"; return os; } QuicVersion version; Perspective perspective; + bool spdy_on_stream_end; }; // Constructs various test permutations. @@ -113,8 +120,10 @@ vector<TestParams> params; QuicVersionVector all_supported_versions = QuicSupportedVersions(); for (const QuicVersion version : all_supported_versions) { - params.push_back(TestParams(version, Perspective::IS_CLIENT)); - params.push_back(TestParams(version, Perspective::IS_SERVER)); + params.push_back(TestParams(version, Perspective::IS_CLIENT, true)); + params.push_back(TestParams(version, Perspective::IS_SERVER, true)); + params.push_back(TestParams(version, Perspective::IS_CLIENT, false)); + params.push_back(TestParams(version, Perspective::IS_SERVER, false)); } FLAGS_quic_supports_push_promise = true; return params; @@ -129,14 +138,15 @@ session_(connection_), headers_stream_(QuicSpdySessionPeer::GetHeadersStream(&session_)), body_("hello world"), - framer_(HTTP2), stream_frame_(kHeadersStreamId, /*fin=*/false, /*offset=*/0, ""), next_promised_stream_id_(2) { FLAGS_quic_always_log_bugs_for_tests = true; headers_[":version"] = "HTTP/1.1"; headers_[":status"] = "200 Ok"; headers_["content-length"] = "11"; - framer_.set_visitor(&visitor_); + FLAGS_spdy_on_stream_end = GetParam().spdy_on_stream_end; + framer_ = std::unique_ptr<SpdyFramer>(new SpdyFramer(HTTP2)); + framer_->set_visitor(&visitor_); EXPECT_EQ(version(), session_.connection()->version()); EXPECT_TRUE(headers_stream_ != nullptr); VLOG(1) << GetParam(); @@ -176,7 +186,7 @@ SpdyPriority priority, SpdyFrameType type) { // Write the headers and capture the outgoing data - EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, _, nullptr)) + EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, nullptr)) .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); headers_stream_->WriteHeaders(stream_id, headers_, fin, priority, nullptr); @@ -197,11 +207,15 @@ .WillRepeatedly(WithArgs<1, 2>( Invoke(this, &QuicHeadersStreamTest::SaveHeaderData))); if (fin) { - EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, nullptr, 0, true)); + if (FLAGS_spdy_on_stream_end) { + EXPECT_CALL(visitor_, OnStreamEnd(stream_id)); + } else { + EXPECT_CALL(visitor_, OnStreamFrameData(stream_id, nullptr, 0, true)); + } } - framer_.ProcessInput(saved_data_.data(), saved_data_.length()); - EXPECT_FALSE(framer_.HasError()) - << SpdyFramer::ErrorCodeToString(framer_.error_code()); + framer_->ProcessInput(saved_data_.data(), saved_data_.length()); + EXPECT_FALSE(framer_->HasError()) + << SpdyFramer::ErrorCodeToString(framer_->error_code()); CheckHeaders(); saved_data_.clear(); @@ -209,7 +223,7 @@ void CheckHeaders() { SpdyHeaderBlock headers; - EXPECT_TRUE(framer_.ParseHeaderBlockInBuffer( + EXPECT_TRUE(framer_->ParseHeaderBlockInBuffer( saved_header_data_.data(), saved_header_data_.length(), &headers)); EXPECT_EQ(headers_, headers); saved_header_data_.clear(); @@ -240,7 +254,7 @@ string body_; string saved_data_; string saved_header_data_; - SpdyFramer framer_; + std::unique_ptr<SpdyFramer> framer_; StrictMock<MockVisitor> visitor_; QuicStreamFrame stream_frame_; QuicStreamId next_promised_stream_id_; @@ -276,8 +290,7 @@ QuicStreamId promised_stream_id = NextPromisedStreamId(); if (perspective() == Perspective::IS_SERVER) { // Write the headers and capture the outgoing data - EXPECT_CALL(session_, - WritevData(kHeadersStreamId, _, _, false, _, nullptr)) + EXPECT_CALL(session_, WritevData(kHeadersStreamId, _, _, false, nullptr)) .WillOnce(WithArgs<1>(Invoke(this, &QuicHeadersStreamTest::SaveIov))); headers_stream_->WritePushPromise(stream_id, promised_stream_id, headers_, nullptr); @@ -288,9 +301,9 @@ EXPECT_CALL(visitor_, OnControlFrameHeaderData(stream_id, _, _)) .WillRepeatedly(WithArgs<1, 2>( Invoke(this, &QuicHeadersStreamTest::SaveHeaderData))); - framer_.ProcessInput(saved_data_.data(), saved_data_.length()); - EXPECT_FALSE(framer_.HasError()) - << SpdyFramer::ErrorCodeToString(framer_.error_code()); + framer_->ProcessInput(saved_data_.data(), saved_data_.length()); + EXPECT_FALSE(framer_->HasError()) + << SpdyFramer::ErrorCodeToString(framer_->error_code()); CheckHeaders(); saved_data_.clear(); } else { @@ -313,13 +326,13 @@ headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); headers_frame.set_has_priority(true); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); } else { SpdyHeadersIR headers_frame(stream_id); headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); } EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)) .WillRepeatedly(WithArgs<1>(Invoke( @@ -345,7 +358,7 @@ scoped_ptr<SpdySerializedFrame> frame; SpdyPushPromiseIR push_promise(stream_id, promised_stream_id); push_promise.set_header_block(headers_); - frame.reset(framer_.SerializeFrame(push_promise)); + frame.reset(framer_->SerializeFrame(push_promise)); if (perspective() == Perspective::IS_SERVER) { EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( QUIC_INVALID_HEADERS_STREAM_DATA, @@ -382,13 +395,13 @@ headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); headers_frame.set_has_priority(true); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); } else { SpdyHeadersIR headers_frame(stream_id); headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); } EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)); EXPECT_CALL(session_, @@ -416,13 +429,13 @@ headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); headers_frame.set_has_priority(true); - frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); + frames[stream_num].reset(framer_->SerializeFrame(headers_frame)); EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)).Times(1); } else { SpdyHeadersIR headers_frame(stream_id); headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); - frames[stream_num].reset(framer_.SerializeFrame(headers_frame)); + frames[stream_num].reset(framer_->SerializeFrame(headers_frame)); } stream_frames[stream_num].stream_id = stream_frame_.stream_id; stream_frames[stream_num].offset = stream_frame_.offset; @@ -466,13 +479,13 @@ headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); headers_frame.set_has_priority(true); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); EXPECT_CALL(session_, OnStreamHeadersPriority(stream_id, 0)); } else { SpdyHeadersIR headers_frame(stream_id); headers_frame.set_header_block(headers_); headers_frame.set_fin(fin); - frame.reset(framer_.SerializeFrame(headers_frame)); + frame.reset(framer_->SerializeFrame(headers_frame)); } EXPECT_CALL(session_, OnStreamHeaders(stream_id, _)) .WillRepeatedly(WithArgs<1>(Invoke( @@ -501,7 +514,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyDataFrame) { SpdyDataIR data(2, ""); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY DATA frame received.")) @@ -514,7 +527,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyRstStreamFrame) { SpdyRstStreamIR data(2, RST_STREAM_PROTOCOL_ERROR); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY RST_STREAM frame received.")) @@ -528,7 +541,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdySettingsFrame) { SpdySettingsIR data; data.AddSetting(SETTINGS_HEADER_TABLE_SIZE, true, true, 0); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY SETTINGS frame received.")) @@ -541,7 +554,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyPingFrame) { SpdyPingIR data(1); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY PING frame received.")) @@ -554,7 +567,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyGoAwayFrame) { SpdyGoAwayIR data(1, GOAWAY_PROTOCOL_ERROR, "go away"); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY GOAWAY frame received.")) @@ -567,7 +580,7 @@ TEST_P(QuicHeadersStreamTest, ProcessSpdyWindowUpdateFrame) { SpdyWindowUpdateIR data(1, 1); - scoped_ptr<SpdySerializedFrame> frame(framer_.SerializeFrame(data)); + scoped_ptr<SpdySerializedFrame> frame(framer_->SerializeFrame(data)); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails( QUIC_INVALID_HEADERS_STREAM_DATA, "SPDY WINDOW_UPDATE frame received."))
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc index 3399cc9..e64a8aa 100644 --- a/net/quic/quic_http_stream_test.cc +++ b/net/quic/quic_http_stream_test.cc
@@ -9,6 +9,7 @@ #include <vector> #include "base/memory/scoped_ptr.h" +#include "base/strings/string_number_conversions.h" #include "base/thread_task_runner_handle.h" #include "net/base/chunked_upload_data_stream.h" #include "net/base/elements_upload_data_stream.h" @@ -580,6 +581,7 @@ SpdyHeaderBlock trailers; size_t spdy_trailers_frame_length; trailers["foo"] = "bar"; + trailers[kFinalOffsetHeaderKey] = base::IntToString(strlen(kResponseBody)); ProcessPacket(ConstructResponseTrailersPacket( 4, kFin, trailers, &spdy_trailers_frame_length, &offset));
diff --git a/net/quic/quic_multipath_received_packet_manager.cc b/net/quic/quic_multipath_received_packet_manager.cc index 6494137..26d7fa0 100644 --- a/net/quic/quic_multipath_received_packet_manager.cc +++ b/net/quic/quic_multipath_received_packet_manager.cc
@@ -57,18 +57,6 @@ manager->RecordPacketReceived(bytes, header, receipt_time); } -void QuicMultipathReceivedPacketManager::RecordPacketRevived( - QuicPathId path_id, - QuicPacketNumber packet_number) { - QuicReceivedPacketManager* manager = path_managers_[path_id]; - if (manager == nullptr) { - QUIC_BUG << "Revived a packet on a non-existent path."; - return; - } - - manager->RecordPacketRevived(packet_number); -} - bool QuicMultipathReceivedPacketManager::IsMissing( QuicPathId path_id, QuicPacketNumber packet_number) {
diff --git a/net/quic/quic_multipath_received_packet_manager.h b/net/quic/quic_multipath_received_packet_manager.h index dba9244..5f1f3a3f 100644 --- a/net/quic/quic_multipath_received_packet_manager.h +++ b/net/quic/quic_multipath_received_packet_manager.h
@@ -40,9 +40,6 @@ const QuicPacketHeader& header, QuicTime receipt_time); - // Called when packet with |packet_number| is revived on path with |path_id|. - void RecordPacketRevived(QuicPathId path_id, QuicPacketNumber packet_number); - // Checks whether |packet_number| is missing on path with |path_id|. bool IsMissing(QuicPathId path_id, QuicPacketNumber packet_number);
diff --git a/net/quic/quic_multipath_received_packet_manager_test.cc b/net/quic/quic_multipath_received_packet_manager_test.cc index e342ae8..8a54a68 100644 --- a/net/quic/quic_multipath_received_packet_manager_test.cc +++ b/net/quic/quic_multipath_received_packet_manager_test.cc
@@ -100,14 +100,6 @@ "Received a packet on a non-existent path"); } -TEST_F(QuicMultipathReceivedPacketManagerTest, RecordPacketRevived) { - EXPECT_CALL(*manager_0_, RecordPacketRevived(_)).Times(1); - multipath_manager_.RecordPacketRevived(kDefaultPathId, header_.packet_number); - EXPECT_DFATAL( - multipath_manager_.RecordPacketRevived(kPathId2, header_.packet_number), - "Revived a packet on a non-existent path"); -} - TEST_F(QuicMultipathReceivedPacketManagerTest, IsMissing) { EXPECT_CALL(*manager_0_, IsMissing(header_.packet_number)) .WillOnce(Return(true));
diff --git a/net/quic/quic_packet_creator.cc b/net/quic/quic_packet_creator.cc index f4e0cf7..a0a38a5 100644 --- a/net/quic/quic_packet_creator.cc +++ b/net/quic/quic_packet_creator.cc
@@ -11,7 +11,6 @@ #include "net/quic/crypto/quic_random.h" #include "net/quic/quic_bug_tracker.h" #include "net/quic/quic_data_writer.h" -#include "net/quic/quic_fec_group.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" @@ -24,29 +23,6 @@ namespace net { -namespace { - -// Default max packets in an FEC group. -static const size_t kDefaultMaxPacketsPerFecGroup = 10; -// Lowest max packets in an FEC group. -static const size_t kLowestMaxPacketsPerFecGroup = 2; - -// We want to put some space between a protected packet and the FEC packet to -// avoid losing them both within the same loss episode. On the other hand, we -// expect to be able to recover from any loss in about an RTT. We resolve this -// tradeoff by sending an FEC packet atmost half an RTT, or equivalently, half -// the max number of in-flight packets, the first protected packet. Since we -// don't want to delay an FEC packet past half an RTT, we set the max FEC group -// size to be half the current congestion window. -const float kMaxPacketsInFlightMultiplierForFecGroupSize = 0.5; -const float kRttMultiplierForFecTimeout = 0.5; - -// Minimum timeout for FEC alarm, set to half the minimum Tail Loss Probe -// timeout of 10ms. -const int64_t kMinFecTimeoutMs = 5u; - -} // namespace - // A QuicRandom wrapper that gets a bucket of entropy and distributes it // bit-by-bit. Replenishes the bucket as needed. Not thread-safe. Expose this // class if single bit randomness is needed elsewhere. @@ -104,13 +80,7 @@ 0, 0, false, - false), - should_fec_protect_next_packet_(false), - fec_protect_(false), - max_packets_per_fec_group_(kDefaultMaxPacketsPerFecGroup), - fec_send_policy_(FEC_ANY_TRIGGER), - fec_timeout_(QuicTime::Delta::Zero()), - rtt_multiplier_for_fec_timeout_(kRttMultiplierForFecTimeout) { + false) { SetMaxPacketLength(kDefaultMaxPacketSize); } @@ -118,15 +88,6 @@ QuicUtils::DeleteFrames(&packet_.retransmittable_frames); } -void QuicPacketCreator::OnBuiltFecProtectedPayload( - const QuicPacketHeader& header, - StringPiece payload) { - if (fec_group_.get() != nullptr) { - DCHECK_NE(0u, header.fec_group); - fec_group_->Update(packet_.encryption_level, header, payload); - } -} - void QuicPacketCreator::SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter) { framer_->SetEncrypter(level, encrypter); @@ -134,8 +95,8 @@ } bool QuicPacketCreator::CanSetMaxPacketLength() const { - // |max_packet_length_| should not be changed mid-packet or mid-FEC group. - return fec_group_.get() == nullptr && queued_frames_.empty(); + // |max_packet_length_| should not be changed mid-packet. + return queued_frames_.empty(); } void QuicPacketCreator::SetMaxPacketLength(QuicByteCount length) { @@ -151,81 +112,14 @@ max_plaintext_size_ = framer_->GetMaxPlaintextSize(max_packet_length_); } -void QuicPacketCreator::set_max_packets_per_fec_group( - size_t max_packets_per_fec_group) { - max_packets_per_fec_group_ = - max(kLowestMaxPacketsPerFecGroup, max_packets_per_fec_group); - DCHECK_LT(0u, max_packets_per_fec_group_); -} - -bool QuicPacketCreator::ShouldSendFec(bool force_close) const { - return !HasPendingFrames() && fec_group_.get() != nullptr && - fec_group_->NumReceivedPackets() > 0 && - (force_close || - fec_group_->NumReceivedPackets() >= max_packets_per_fec_group_); -} - -void QuicPacketCreator::ResetFecGroup() { - if (HasPendingFrames()) { - QUIC_BUG_IF(packet_size_ != 0) - << "Cannot reset FEC group with pending frames."; - return; - } - fec_group_.reset(nullptr); -} - -bool QuicPacketCreator::IsFecGroupOpen() const { - return fec_group_.get() != nullptr; -} - -void QuicPacketCreator::StartFecProtectingPackets() { - if (max_packets_per_fec_group_ == 0) { - QUIC_BUG << "Cannot start FEC protection when FEC is not enabled."; - return; - } - // TODO(jri): This currently requires that the generator flush out any - // pending frames when FEC protection is turned on. If current packet can be - // converted to an FEC protected packet, do it. This will require the - // generator to check if the resulting expansion still allows the incoming - // frame to be added to the packet. - if (HasPendingFrames()) { - QUIC_BUG << "Cannot start FEC protection with pending frames."; - return; - } - DCHECK(!fec_protect_); - fec_protect_ = true; -} - -void QuicPacketCreator::StopFecProtectingPackets() { - if (fec_group_.get() != nullptr) { - QUIC_BUG << "Cannot stop FEC protection with open FEC group."; - return; - } - DCHECK(fec_protect_); - fec_protect_ = false; -} - -InFecGroup QuicPacketCreator::MaybeUpdateLengthsAndStartFec() { - if (fec_group_.get() != nullptr) { - // Don't update any lengths when an FEC group is open, to ensure same - // packet header size in all packets within a group. - return IN_FEC_GROUP; - } +void QuicPacketCreator::MaybeUpdatePacketNumberLength() { if (!queued_frames_.empty()) { // Don't change creator state if there are frames queued. - return NOT_IN_FEC_GROUP; + return; } - // Update packet number length only on packet and FEC group boundaries. + // Update packet number length only on packet boundary. packet_.packet_number_length = next_packet_number_length_; - - if (!fec_protect_) { - return NOT_IN_FEC_GROUP; - } - // Start a new FEC group since protection is on. Set the fec group number to - // the packet number of the next packet. - fec_group_.reset(new QuicFecGroup(packet_.packet_number + 1)); - return IN_FEC_GROUP; } // Stops serializing version of the protocol in packets sent after this call. @@ -244,11 +138,8 @@ QuicPacketNumber least_packet_awaited_by_peer, QuicPacketCount max_packets_in_flight) { DCHECK_LE(least_packet_awaited_by_peer, packet_.packet_number + 1); - // Since the packet creator will not change packet number length mid FEC - // group, include the size of an FEC group to be safe. - const QuicPacketNumber current_delta = max_packets_per_fec_group_ + - packet_.packet_number + 1 - - least_packet_awaited_by_peer; + const QuicPacketNumber current_delta = + packet_.packet_number + 1 - least_packet_awaited_by_peer; const uint64_t delta = max(current_delta, max_packets_in_flight); next_packet_number_length_ = QuicFramer::GetMinSequenceNumberLength(delta * 4); @@ -260,15 +151,10 @@ QuicStreamOffset offset, bool fin, bool needs_padding, - QuicFrame* frame, - FecProtection fec_protection) { + QuicFrame* frame) { if (!HasRoomForStreamFrame(id, offset)) { return false; } - if (fec_protection == MUST_FEC_PROTECT) { - should_fec_protect_next_packet_ = true; - MaybeStartFecProtection(); - } CreateStreamFrame(id, iov, iov_offset, offset, fin, frame); if (!AddFrame(*frame, /*save_retransmittable_frames=*/true)) { // Fails if we try to write unencrypted stream data. @@ -278,23 +164,12 @@ if (needs_padding) { packet_.needs_padding = true; } - if (fec_protection == MUST_FEC_PROTECT && - iov_offset + frame->stream_frame->frame_length == iov.total_length) { - // Turn off FEC protection when we're done writing protected data. - DVLOG(1) << "Turning FEC protection OFF"; - should_fec_protect_next_packet_ = false; - } return true; } bool QuicPacketCreator::HasRoomForStreamFrame(QuicStreamId id, QuicStreamOffset offset) { - // TODO(jri): This is a simple safe decision for now, but make - // is_in_fec_group a parameter. Same as with all public methods in - // QuicPacketCreator. - return BytesFree() > - QuicFramer::GetMinStreamFrameSize( - id, offset, true, fec_protect_ ? IN_FEC_GROUP : NOT_IN_FEC_GROUP); + return BytesFree() > QuicFramer::GetMinStreamFrameSize(id, offset, true); } // static @@ -303,13 +178,11 @@ bool include_version, bool include_path_id, QuicPacketNumberLength packet_number_length, - QuicStreamOffset offset, - InFecGroup is_in_fec_group) { + QuicStreamOffset offset) { return GetPacketHeaderSize(connection_id_length, include_version, - include_path_id, packet_number_length, - is_in_fec_group) + + include_path_id, packet_number_length) + // Assumes this is a stream with a single lone packet. - QuicFramer::GetMinStreamFrameSize(1u, offset, true, is_in_fec_group); + QuicFramer::GetMinStreamFrameSize(1u, offset, true); } size_t QuicPacketCreator::CreateStreamFrame(QuicStreamId id, @@ -319,16 +192,16 @@ bool fin, QuicFrame* frame) { DCHECK_GT(max_packet_length_, - StreamFramePacketOverhead( - connection_id_length_, kIncludeVersion, kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, offset, IN_FEC_GROUP)); + StreamFramePacketOverhead(connection_id_length_, kIncludeVersion, + kIncludePathId, + PACKET_6BYTE_PACKET_NUMBER, offset)); - InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec(); + MaybeUpdatePacketNumberLength(); LOG_IF(DFATAL, !HasRoomForStreamFrame(id, offset)) << "No room for Stream frame, BytesFree: " << BytesFree() << " MinStreamFrameSize: " - << QuicFramer::GetMinStreamFrameSize(id, offset, true, is_in_fec_group); + << QuicFramer::GetMinStreamFrameSize(id, offset, true); if (iov_offset == iov.total_length) { QUIC_BUG_IF(!fin) << "Creating a stream frame with no data or fin."; @@ -339,7 +212,7 @@ const size_t data_size = iov.total_length - iov_offset; size_t min_frame_size = QuicFramer::GetMinStreamFrameSize( - id, offset, /* last_frame_in_packet= */ true, is_in_fec_group); + id, offset, /* last_frame_in_packet= */ true); size_t bytes_consumed = min<size_t>(BytesFree() - min_frame_size, data_size); bool set_fin = fin && bytes_consumed == data_size; // Last frame. @@ -409,20 +282,16 @@ char* buffer, size_t buffer_len) { DCHECK(queued_frames_.empty()); - DCHECK(fec_group_.get() == nullptr); DCHECK(!packet_.needs_padding); QUIC_BUG_IF(retransmission.retransmittable_frames.empty()) << "Attempt to serialize empty packet"; const QuicPacketNumberLength saved_length = packet_.packet_number_length; const QuicPacketNumberLength saved_next_length = next_packet_number_length_; - const bool saved_should_fec_protect = fec_protect_; const EncryptionLevel default_encryption_level = packet_.encryption_level; - // Temporarily set the packet number length, stop FEC protection, - // and change the encryption level. + // Temporarily set the packet number length and change the encryption level. packet_.packet_number_length = retransmission.packet_number_length; next_packet_number_length_ = retransmission.packet_number_length; - fec_protect_ = false; packet_.needs_padding = retransmission.needs_padding; // Only preserve the original encryption level if it's a handshake packet or // if we haven't gone forward secure. @@ -431,7 +300,7 @@ packet_.encryption_level = retransmission.encryption_level; } - // Serialize the packet and restore the FEC and packet number length state. + // Serialize the packet and restore packet number length state. for (const QuicFrame& frame : retransmission.retransmittable_frames) { bool success = AddFrame(frame, false); DCHECK(success); @@ -443,7 +312,6 @@ // Restore old values. packet_.packet_number_length = saved_length; next_packet_number_length_ = saved_next_length; - fec_protect_ = saved_should_fec_protect; packet_.encryption_level = default_encryption_level; } @@ -461,8 +329,7 @@ void QuicPacketCreator::OnSerializedPacket() { if (packet_.encrypted_buffer == nullptr) { - QUIC_BUG << "Failed to SerializePacket. fec_policy:" << fec_send_policy() - << " should_fec_protect_:" << should_fec_protect_next_packet_; + QUIC_BUG << "Failed to SerializePacket."; delegate_->OnUnrecoverableError(QUIC_FAILED_TO_SERIALIZE_PACKET, ConnectionCloseSource::FROM_SELF); return; @@ -470,8 +337,6 @@ delegate_->OnSerializedPacket(&packet_); ClearPacket(); - MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/false, - /*is_fec_timeout=*/false); // Maximum packet size may be only enacted while no packet is currently being // constructed, so here we have a good opportunity to actually change it. if (CanSetMaxPacketLength()) { @@ -484,7 +349,6 @@ packet_.has_stop_waiting = false; packet_.has_crypto_handshake = NOT_HANDSHAKE; packet_.needs_padding = false; - packet_.is_fec_packet = false; packet_.original_packet_number = 0; packet_.transmission_type = NOT_RETRANSMISSION; packet_.encrypted_buffer = nullptr; @@ -502,10 +366,6 @@ } size_t QuicPacketCreator::ExpansionOnNewFrame() const { - // If packet is FEC protected, there's no expansion. - if (fec_protect_) { - return 0; - } // If the last frame in the packet is a stream frame, then it will expand to // include the stream_length field when a new frame is added. bool has_trailing_stream_frame = @@ -523,14 +383,11 @@ if (!queued_frames_.empty()) { return packet_size_; } - if (fec_group_.get() == nullptr) { - // Update packet number length on packet and FEC boundary. - packet_.packet_number_length = next_packet_number_length_; - } - packet_size_ = - GetPacketHeaderSize(connection_id_length_, send_version_in_packet_, - send_path_id_in_packet_, packet_.packet_number_length, - fec_protect_ ? IN_FEC_GROUP : NOT_IN_FEC_GROUP); + // Update packet number length on packet boundary. + packet_.packet_number_length = next_packet_number_length_; + packet_size_ = GetPacketHeaderSize( + connection_id_length_, send_version_in_packet_, send_path_id_in_packet_, + packet_.packet_number_length); return packet_size_; } @@ -556,24 +413,13 @@ size_t encrypted_buffer_len) { DCHECK_LT(0u, encrypted_buffer_len); QUIC_BUG_IF(queued_frames_.empty()) << "Attempt to serialize empty packet"; - if (fec_group_.get() != nullptr) { - DCHECK_GE(packet_.packet_number + 1, fec_group_->FecGroupNumber()); - } QuicPacketHeader header; // FillPacketHeader increments packet_number_. - FillPacketHeader(fec_group_ != nullptr ? fec_group_->FecGroupNumber() : 0, - false, &header); + FillPacketHeader(&header); MaybeAddPadding(); DCHECK_GE(max_plaintext_size_, packet_size_); - // ACK Frames will be truncated due to length only if they're the only frame - // in the packet, and if packet_size_ was set to max_plaintext_size_. If - // truncation due to length occurred, then GetSerializedFrameLength will have - // returned all bytes free. - bool possibly_truncated_by_length = packet_size_ == max_plaintext_size_ && - queued_frames_.size() == 1 && - queued_frames_.back().type == ACK_FRAME; // Use the packet_size_ instead of the buffer size to ensure smaller // packet sizes are properly used. size_t length = framer_->BuildDataPacket(header, queued_frames_, @@ -583,25 +429,36 @@ return; } - // TODO(ianswett) Consider replacing QuicPacket with something else, since - // it's only used to provide convenience methods to FEC and encryption. - QuicPacket packet( - encrypted_buffer, length, - /* owns_buffer */ false, header.public_header.connection_id_length, - header.public_header.version_flag, header.public_header.multipath_flag, - header.public_header.packet_number_length); - OnBuiltFecProtectedPayload(header, packet.FecProtectedData()); - + // ACK Frames will be truncated due to length only if they're the only frame + // in the packet, and if packet_size_ was set to max_plaintext_size_. If + // truncation due to length occurred, then GetSerializedFrameLength will have + // returned all bytes free. + bool possibly_truncated_by_length = packet_size_ == max_plaintext_size_ && + queued_frames_.size() == 1 && + queued_frames_.back().type == ACK_FRAME; // Because of possible truncation, we can't be confident that our // packet size calculation worked correctly. if (!possibly_truncated_by_length) { DCHECK_EQ(packet_size_, length); } - // Immediately encrypt the packet, to ensure we don't encrypt the same - // packet number multiple times. - size_t encrypted_length = framer_->EncryptPayload( - packet_.encryption_level, packet_.path_id, packet_.packet_number, packet, - encrypted_buffer, encrypted_buffer_len); + size_t encrypted_length = 0; + if (FLAGS_quic_inplace_encryption2) { + const size_t ad_len = GetStartOfEncryptedData(header); + encrypted_length = framer_->EncryptInPlace( + packet_.encryption_level, packet_.path_id, packet_.packet_number, + ad_len, length, encrypted_buffer_len, encrypted_buffer); + } else { + QuicPacket packet( + encrypted_buffer, length, + /* owns_buffer */ false, header.public_header.connection_id_length, + header.public_header.version_flag, header.public_header.multipath_flag, + header.public_header.packet_number_length); + // Immediately encrypt the packet, to ensure we don't encrypt the same + // packet number multiple times. + encrypted_length = framer_->EncryptPayload( + packet_.encryption_level, packet_.path_id, packet_.packet_number, + packet, encrypted_buffer, encrypted_buffer_len); + } if (encrypted_length == 0) { QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number; return; @@ -614,44 +471,6 @@ packet_.encrypted_length = encrypted_length; } -void QuicPacketCreator::SerializeFec(char* buffer, size_t buffer_len) { - DCHECK_LT(0u, buffer_len); - if (fec_group_.get() == nullptr || fec_group_->NumReceivedPackets() <= 0) { - QUIC_BUG << "SerializeFEC called but no group or zero packets in group."; - return; - } - if (FLAGS_quic_no_unencrypted_fec && - packet_.encryption_level == ENCRYPTION_NONE) { - QUIC_BUG << "SerializeFEC must be called with encryption."; - delegate_->OnUnrecoverableError(QUIC_UNENCRYPTED_FEC_DATA, - ConnectionCloseSource::FROM_SELF); - return; - } - DCHECK_EQ(0u, queued_frames_.size()); - QuicPacketHeader header; - FillPacketHeader(fec_group_->FecGroupNumber(), true, &header); - scoped_ptr<QuicPacket> packet( - framer_->BuildFecPacket(header, fec_group_->PayloadParity())); - fec_group_.reset(nullptr); - packet_size_ = 0; - QUIC_BUG_IF(packet == nullptr) << "Failed to serialize fec packet for group:" - << fec_group_->FecGroupNumber(); - DCHECK_GE(max_packet_length_, packet->length()); - // Immediately encrypt the packet, to ensure we don't encrypt the same packet - // packet number multiple times. - size_t encrypted_length = framer_->EncryptPayload( - packet_.encryption_level, packet_.path_id, packet_.packet_number, *packet, - buffer, buffer_len); - if (encrypted_length == 0) { - QUIC_BUG << "Failed to encrypt packet number " << packet_.packet_number; - return; - } - packet_.entropy_hash = QuicFramer::GetPacketEntropyHash(header); - packet_.encrypted_buffer = buffer; - packet_.encrypted_length = encrypted_length; - packet_.is_fec_packet = true; -} - QuicEncryptedPacket* QuicPacketCreator::SerializeVersionNegotiationPacket( const QuicVersionVector& supported_versions) { DCHECK_EQ(Perspective::IS_SERVER, framer_->perspective()); @@ -668,21 +487,19 @@ nullptr, 0, 0, false, false); } -void QuicPacketCreator::FillPacketHeader(QuicFecGroupNumber fec_group, - bool fec_flag, - QuicPacketHeader* header) { +void QuicPacketCreator::FillPacketHeader(QuicPacketHeader* header) { header->public_header.connection_id = connection_id_; header->public_header.connection_id_length = connection_id_length_; header->public_header.multipath_flag = send_path_id_in_packet_; header->public_header.reset_flag = false; header->public_header.version_flag = send_version_in_packet_; - header->fec_flag = fec_flag; + header->fec_flag = false; header->path_id = packet_.path_id; header->packet_number = ++packet_.packet_number; header->public_header.packet_number_length = packet_.packet_number_length; header->entropy_flag = random_bool_source_->RandBool(); - header->is_in_fec_group = fec_group == 0 ? NOT_IN_FEC_GROUP : IN_FEC_GROUP; - header->fec_group = fec_group; + header->is_in_fec_group = NOT_IN_FEC_GROUP; + header->fec_group = 0; } bool QuicPacketCreator::ShouldRetransmit(const QuicFrame& frame) { @@ -708,10 +525,10 @@ ConnectionCloseSource::FROM_SELF); return false; } - InFecGroup is_in_fec_group = MaybeUpdateLengthsAndStartFec(); + MaybeUpdatePacketNumberLength(); size_t frame_len = framer_->GetSerializedFrameLength( - frame, BytesFree(), queued_frames_.empty(), true, is_in_fec_group, + frame, BytesFree(), queued_frames_.empty(), true, packet_.packet_number_length); if (frame_len == 0) { // Current open packet is full. @@ -762,64 +579,6 @@ DCHECK(success); } -void QuicPacketCreator::MaybeStartFecProtection() { - if (max_packets_per_fec_group_ == 0 || fec_protect_) { - // Do not start FEC protection when FEC protection is not enabled or FEC - // protection is already on. - return; - } - DVLOG(1) << "Turning FEC protection ON"; - // Flush current open packet. - Flush(); - - StartFecProtectingPackets(); - DCHECK(fec_protect_); -} - -void QuicPacketCreator::MaybeSendFecPacketAndCloseGroup(bool force_send_fec, - bool is_fec_timeout) { - if (ShouldSendFec(force_send_fec)) { - if ((FLAGS_quic_no_unencrypted_fec && - packet_.encryption_level == ENCRYPTION_NONE) || - (fec_send_policy_ == FEC_ALARM_TRIGGER && !is_fec_timeout)) { - ResetFecGroup(); - delegate_->OnResetFecGroup(); - } else { - // TODO(zhongyi): Change the default 64 alignas value (used the default - // value from CACHELINE_SIZE). - ALIGNAS(64) char seralized_fec_buffer[kMaxPacketSize]; - SerializeFec(seralized_fec_buffer, kMaxPacketSize); - OnSerializedPacket(); - } - } - - if (!should_fec_protect_next_packet_ && fec_protect_ && !IsFecGroupOpen()) { - StopFecProtectingPackets(); - } -} - -QuicTime::Delta QuicPacketCreator::GetFecTimeout( - QuicPacketNumber packet_number) { - // Do not set up FEC alarm for |packet_number| it is not the first packet in - // the current group. - if (fec_group_.get() != nullptr && - (packet_number == fec_group_->FecGroupNumber())) { - return QuicTime::Delta::Max( - fec_timeout_, QuicTime::Delta::FromMilliseconds(kMinFecTimeoutMs)); - } - return QuicTime::Delta::Infinite(); -} - -void QuicPacketCreator::OnCongestionWindowChange( - QuicPacketCount max_packets_in_flight) { - set_max_packets_per_fec_group(static_cast<size_t>( - kMaxPacketsInFlightMultiplierForFecGroupSize * max_packets_in_flight)); -} - -void QuicPacketCreator::OnRttChange(QuicTime::Delta rtt) { - fec_timeout_ = rtt.Multiply(rtt_multiplier_for_fec_timeout_); -} - void QuicPacketCreator::SetCurrentPath( QuicPathId path_id, QuicPacketNumber least_packet_awaited_by_peer, @@ -832,10 +591,6 @@ QUIC_BUG << "Unable to change paths when a packet is under construction."; return; } - - // Send FEC packet and close FEC group. - MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); // Save current packet number and load switching path's packet number. multipath_packet_number_[packet_.path_id] = packet_.packet_number; std::unordered_map<QuicPathId, QuicPacketNumber>::iterator it =
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h index fcb4b50..870de4a 100644 --- a/net/quic/quic_packet_creator.h +++ b/net/quic/quic_packet_creator.h
@@ -3,10 +3,9 @@ // found in the LICENSE file. // // Accumulates frames for the next packet until more frames no longer fit or -// it's time to create a packet from them. Also provides packet creation of -// FEC packets based on previously created packets. If multipath enabled, only -// creates packets on one path at the same time. Currently, next packet number -// is tracked per-path. +// it's time to create a packet from them. If multipath enabled, only creates +// packets on one path at the same time. Currently, next packet number is +// tracked per-path. #ifndef NET_QUIC_QUIC_PACKET_CREATOR_H_ #define NET_QUIC_QUIC_PACKET_CREATOR_H_ @@ -21,7 +20,6 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "base/strings/string_piece.h" -#include "net/quic/quic_fec_group.h" #include "net/quic/quic_framer.h" #include "net/quic/quic_protocol.h" @@ -50,9 +48,6 @@ // Called when an unrecoverable error is encountered. virtual void OnUnrecoverableError(QuicErrorCode error, ConnectionCloseSource source) = 0; - - // Called when current FEC group is reset (closed). - virtual void OnResetFecGroup() = 0; }; // Interface which gets callbacks from the QuicPacketCreator at interesting @@ -75,27 +70,6 @@ ~QuicPacketCreator(); - // Checks if it's time to send an FEC packet. |force_close| forces this to - // return true if an FEC group is open. - bool ShouldSendFec(bool force_close) const; - - // If ShouldSendFec returns true, serializes currently constructed FEC packet - // and calls the delegate on the packet. Resets current FEC group if FEC - // protection policy is FEC_ALARM_TRIGGER but |is_fec_timeout| is false. - // Also tries to turn off FEC protection if should_fec_protect_next_packet is - // false. - void MaybeSendFecPacketAndCloseGroup(bool force_send_fec, - bool is_fec_timeout); - - // Returns true if an FEC packet is under construction. - bool IsFecGroupOpen() const; - - // Called after sending |packet_number| to determine whether an FEC alarm - // should be set for sending out an FEC packet. Returns a positive and finite - // timeout if an FEC alarm should be set, and infinite if no alarm should be - // set. - QuicTime::Delta GetFecTimeout(QuicPacketNumber packet_number); - // Makes the framer not serialize the protocol version in sent packets. void StopSendingVersion(); @@ -112,23 +86,20 @@ bool include_version, bool include_path_id, QuicPacketNumberLength packet_number_length, - QuicStreamOffset offset, - InFecGroup is_in_fec_group); + QuicStreamOffset offset); // Returns false and flushes all pending frames if current open packet is // full. // If current packet is not full, converts a raw payload into a stream frame // that fits into the open packet and adds it to the packet. // The payload begins at |iov_offset| into the |iov|. - // Also tries to start FEC protection depends on |fec_protection|. bool ConsumeData(QuicStreamId id, QuicIOVector iov, size_t iov_offset, QuicStreamOffset offset, bool fin, bool needs_padding, - QuicFrame* frame, - FecProtection fec_protection); + QuicFrame* frame); // Returns true if current open packet can accommodate more stream frames of // stream |id| at |offset|, false otherwise. @@ -136,8 +107,6 @@ // Re-serializes frames with the original packet's packet number length. // Used for retransmitting packets to ensure they aren't too long. - // Caller must ensure that any open FEC group is closed before calling this - // method. void ReserializeAllFrames(const PendingRetransmission& retransmission, char* buffer, size_t buffer_len); @@ -161,8 +130,7 @@ // Returns the number of bytes that the packet will expand by if a new frame // is added to the packet. If the last frame was a stream frame, it will // expand slightly when a new frame is added, and this method returns the - // amount of expected expansion. If the packet is in an FEC group, no - // expansion happens and this method always returns zero. + // amount of expected expansion. size_t ExpansionOnNewFrame() const; // Returns the number of bytes in the current packet, including the header, @@ -194,12 +162,6 @@ // Returns a dummy packet that is valid but contains no useful information. static SerializedPacket NoPacket(); - // Called when the congestion window has changed. - void OnCongestionWindowChange(QuicPacketCount max_packets_in_flight); - - // Called when the RTT may have changed. - void OnRttChange(QuicTime::Delta rtt); - // Sets the encryption level that will be applied to new packets. void set_encryption_level(EncryptionLevel level) { packet_.encryption_level = level; @@ -236,35 +198,12 @@ // Sets the path on which subsequent packets will be created. It is the // caller's responsibility to guarantee no packet is under construction before - // calling this function. If |path_id| is different from current_path_, the - // FEC packet (if exists) will be sent and next_packet_number_length_ is - // recalculated. + // calling this function. If |path_id| is different from current_path_, + // next_packet_number_length_ is recalculated. void SetCurrentPath(QuicPathId path_id, QuicPacketNumber least_packet_awaited_by_peer, QuicPacketCount max_packets_in_flight); - // Returns current max number of packets covered by an FEC group. - size_t max_packets_per_fec_group() const { - return max_packets_per_fec_group_; - } - - // Sets creator's max number of packets covered by an FEC group. - // Note: While there are no constraints on |max_packets_per_fec_group|, - // this setter enforces a min value of kLowestMaxPacketsPerFecGroup. - // To turn off FEC protection, use StopFecProtectingPackets(). - void set_max_packets_per_fec_group(size_t max_packets_per_fec_group); - - FecSendPolicy fec_send_policy() { return fec_send_policy_; } - - void set_fec_send_policy(FecSendPolicy fec_send_policy) { - fec_send_policy_ = fec_send_policy; - } - - void set_rtt_multiplier_for_fec_timeout( - float rtt_multiplier_for_fec_timeout) { - rtt_multiplier_for_fec_timeout_ = rtt_multiplier_for_fec_timeout; - } - void set_debug_delegate(DebugDelegate* debug_delegate) { debug_delegate_ = debug_delegate; } @@ -295,18 +234,10 @@ size_t length, char* buffer); - // Updates lengths and also starts an FEC group if FEC protection is on and - // there is not already an FEC group open. - InFecGroup MaybeUpdateLengthsAndStartFec(); + // Updates packet number length on packet boundary. + void MaybeUpdatePacketNumberLength(); - // Called when a data packet is constructed that is part of an FEC group. - // |payload| is the non-encrypted FEC protected payload of the packet. - void OnBuiltFecProtectedPayload(const QuicPacketHeader& header, - base::StringPiece payload); - - void FillPacketHeader(QuicFecGroupNumber fec_group, - bool fec_flag, - QuicPacketHeader* header); + void FillPacketHeader(QuicPacketHeader* header); // Adds a |frame| if there is space and returns false and flushes all pending // frames if there isn't room. If |save_retransmittable_frames| is true, @@ -326,36 +257,12 @@ void SerializePacket(char* encrypted_buffer, size_t buffer_len); // Called after a new SerialiedPacket is created to call the delegate's - // OnSerializedPacket, reset state, and potentially flush FEC groups. + // OnSerializedPacket and reset state. void OnSerializedPacket(); // Clears all fields of packet_ that should be cleared between serializations. void ClearPacket(); - // Turn on FEC protection for subsequent packets. If no FEC group is currently - // open, this method flushes current open packet and then turns FEC on. - void MaybeStartFecProtection(); - - // Turn on FEC protection for subsequently created packets. FEC should be - // enabled first (max_packets_per_fec_group should be non-zero) for FEC - // protection to start. - void StartFecProtectingPackets(); - - // Turn off FEC protection for subsequently created packets. If the creator - // has any open FEC group, call will fail. It is the caller's responsibility - // to flush out FEC packets in generation, and to verify with ShouldSendFec() - // that there is no open FEC group. - void StopFecProtectingPackets(); - - // Resets (closes) the FEC group. This method should only be called on a - // packet boundary. - void ResetFecGroup(); - - // Packetize FEC data. Sets the entropy hash of the serialized packet to a - // random bool. - // Fails if |buffer_len| isn't long enough for the encrypted packet. - void SerializeFec(char* buffer, size_t buffer_len); - // Does not own these delegates or the framer. DelegateInterface* delegate_; DebugDelegate* debug_delegate_; @@ -370,8 +277,8 @@ bool send_path_id_in_packet_; // Staging variable to hold next packet number length. When sequence // number length is to be changed, this variable holds the new length until - // a packet or FEC group boundary, when the creator's packet_number_length_ - // can be changed to this new value. + // a packet boundary, when the creator's packet_number_length_ can be changed + // to this new value. QuicPacketNumberLength next_packet_number_length_; // Maximum length including headers and encryption (UDP payload length.) QuicByteCount max_packet_length_; @@ -394,28 +301,6 @@ // Map mapping path_id to last sent packet number on the path. std::unordered_map<QuicPathId, QuicPacketNumber> multipath_packet_number_; - // FEC related fields. - // True when creator is requested to turn on FEC protection. False otherwise. - // There is a time difference between should_fec_protect_next_packet_ is - // true/false and FEC is actually turned on/off (e.g., The creator may have an - // open FEC group even if this variable is false). - bool should_fec_protect_next_packet_; - // If true, any created packets will be FEC protected. - // TODO(fayang): Combine should_fec_protect_next_packet and fec_protect_ to - // one variable. - bool fec_protect_; - scoped_ptr<QuicFecGroup> fec_group_; - // 0 indicates FEC is disabled. - size_t max_packets_per_fec_group_; - // FEC policy that specifies when to send FEC packet. - FecSendPolicy fec_send_policy_; - // Timeout used for FEC alarm. Can be set to zero initially or if the SRTT has - // not yet been set. - QuicTime::Delta fec_timeout_; - // The multiplication factor for FEC timeout based on RTT. - // TODO(rtenneti): Delete this code after the 0.25 RTT FEC experiment. - float rtt_multiplier_for_fec_timeout_; - DISALLOW_COPY_AND_ASSIGN(QuicPacketCreator); };
diff --git a/net/quic/quic_packet_creator_test.cc b/net/quic/quic_packet_creator_test.cc index b5dddcf..98e1ef2 100644 --- a/net/quic/quic_packet_creator_test.cc +++ b/net/quic/quic_packet_creator_test.cc
@@ -82,7 +82,6 @@ ~MockDelegate() override {} MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); - MOCK_METHOD0(OnResetFecGroup, void()); MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, ConnectionCloseSource source)); @@ -142,7 +141,6 @@ server_framer_.set_visitor(&framer_visitor_); // TODO(ianswett): Fix this test so it uses a non-null encrypter. FLAGS_quic_never_write_unencrypted_data = false; - FLAGS_quic_no_unencrypted_fec = false; } ~QuicPacketCreatorTest() override { @@ -180,11 +178,10 @@ // Returns the number of bytes consumed by the header of packet, including // the version. - size_t GetPacketHeaderOverhead(InFecGroup is_in_fec_group) { + size_t GetPacketHeaderOverhead() { return GetPacketHeaderSize( creator_.connection_id_length(), kIncludeVersion, !kIncludePathId, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_), - is_in_fec_group); + QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); } // Returns the number of bytes of overhead that will be added to a packet @@ -196,9 +193,9 @@ // Returns the number of bytes consumed by the non-data fields of a stream // frame, assuming it is the last frame in the packet - size_t GetStreamFrameOverhead(InFecGroup is_in_fec_group) { + size_t GetStreamFrameOverhead() { return QuicFramer::GetMinStreamFrameSize(kClientDataStreamId1, kOffset, - true, is_in_fec_group); + true); } QuicIOVector MakeIOVector(StringPiece s) { @@ -274,62 +271,6 @@ } } -TEST_P(QuicPacketCreatorTest, SerializeWithFEC) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Should return false since we do not have enough packets in the FEC group to - // trigger an FEC packet. - ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - // Serialize the packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.Flush(); - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteSerializedPacket(); - - // Should return false since we do not have enough packets in the FEC group to - // trigger an FEC packet. - ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - ASSERT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - ASSERT_EQ(2u, serialized_packet_.packet_number); - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecData(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteSerializedPacket(); -} - TEST_P(QuicPacketCreatorTest, SerializeChangingSequenceNumberLength) { frames_.push_back(QuicFrame(new QuicAckFrame(MakeAckFrame(0u)))); creator_.AddSavedFrame(frames_[0]); @@ -460,109 +401,6 @@ delete ack_frame.ack_frame; } -TEST_P(QuicPacketCreatorTest, SerializeWithFECChangingSequenceNumberLength) { - // Test goal is to test the following sequence (P1 => generate Packet 1): - // P1 <change seq num length> P2 FEC, - // and we expect that packet number length should not change until the end - // of the open FEC group. - - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Should return false since we do not have enough packets in the FEC group to - // trigger an FEC packet. - ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - - // Generate Packet 1. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - // Change the packet number length mid-FEC group and it should not change. - QuicPacketCreatorPeer::SetNextPacketNumberLength(&creator_, - PACKET_4BYTE_PACKET_NUMBER); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillRepeatedly( - Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.Flush(); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - serialized_packet_.packet_number_length); - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteSerializedPacket(); - - // Generate Packet 2. - ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - creator_.Flush(); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - serialized_packet_.packet_number_length); - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecProtectedPayload(_)); - EXPECT_CALL(framer_visitor_, OnStreamFrame(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteSerializedPacket(); - - // Should return false since we do not have enough packets in the FEC group to - // trigger an FEC packet. - ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - ASSERT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - // Force generation of FEC packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - // Turn off FEC protection. - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - serialized_packet_.packet_number_length); - ASSERT_EQ(3u, serialized_packet_.packet_number); - - { - InSequence s; - EXPECT_CALL(framer_visitor_, OnPacket()); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedPublicHeader(_)); - EXPECT_CALL(framer_visitor_, OnUnauthenticatedHeader(_)); - EXPECT_CALL(framer_visitor_, OnDecryptedPacket(_)); - EXPECT_CALL(framer_visitor_, OnPacketHeader(_)); - EXPECT_CALL(framer_visitor_, OnFecData(_)); - EXPECT_CALL(framer_visitor_, OnPacketComplete()); - } - ProcessPacket(serialized_packet_); - DeleteSerializedPacket(); - - // Ensure the next FEC group starts using the new packet number length. - ASSERT_TRUE(creator_.ConsumeData(3u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.Flush(); - EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, - serialized_packet_.packet_number_length); - DeleteSerializedPacket(); -} - TEST_P(QuicPacketCreatorTest, ReserializeFramesWithSequenceNumberLength) { // If the original packet number length, the current packet number // length, and the configured send packet number length are different, the @@ -659,9 +497,8 @@ } TEST_P(QuicPacketCreatorTest, ReserializeFramesWithFullPacketAndPadding) { - const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(NOT_IN_FEC_GROUP); + const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead() + + GetStreamFrameOverhead(); size_t capacity = kDefaultMaxPacketSize - overhead; for (int delta = -5; delta <= 0; ++delta) { string data(capacity + delta, 'A'); @@ -722,75 +559,11 @@ ProcessPacket(serialized); } -TEST_P(QuicPacketCreatorTest, SwitchFecOnOffWithGroupInProgress) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - // We do not have enough packets in the FEC group to trigger an FEC packet. - EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - // Switching FEC off should not change creator state, since there is an - // FEC packet under construction. - EXPECT_DFATAL(QuicPacketCreatorPeer::StopFecProtectingPackets(&creator_), - "Cannot stop FEC protection with open FEC group."); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - // Confirm that FEC packet is still under construction. - EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - // Turn off FEC protection. - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); -} - -TEST_P(QuicPacketCreatorTest, SwitchFecOnWithStreamFrameQueued) { - // Add a stream frame to the creator. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - ASSERT_TRUE(frame.stream_frame); - size_t consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - EXPECT_TRUE(creator_.HasPendingFrames()); - - // Enable FEC protection, and send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecEnabled(&creator_)); - EXPECT_DFATAL(QuicPacketCreatorPeer::StartFecProtectingPackets(&creator_), - "Cannot start FEC protection with pending frames."); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - - // Start FEC protection after current open packet is flushed. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); -} - TEST_P(QuicPacketCreatorTest, ConsumeData) { QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -801,8 +574,8 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataFin) { QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 10u, true, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 10u, true, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -813,8 +586,7 @@ TEST_P(QuicPacketCreatorTest, ConsumeDataFinOnly) { QuicFrame frame; QuicIOVector io_vector(nullptr, 0, 0); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(0u, consumed); @@ -822,28 +594,11 @@ EXPECT_TRUE(creator_.HasPendingFrames()); } -TEST_P(QuicPacketCreatorTest, ConsumeDataWithFecProtect) { - creator_.set_max_packets_per_fec_group(6); - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - size_t consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - CheckStreamFrame(frame, 1u, "test", 0u, false); - EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); -} - TEST_P(QuicPacketCreatorTest, CreateAllFreeBytesForStreamFrames) { - const size_t overhead = - GetPacketHeaderOverhead(NOT_IN_FEC_GROUP) + GetEncryptionOverhead(); + const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead(); for (size_t i = overhead; i < overhead + 100; ++i) { creator_.SetMaxPacketLength(i); - const bool should_have_room = - i > overhead + GetStreamFrameOverhead(NOT_IN_FEC_GROUP); + const bool should_have_room = i > overhead + GetStreamFrameOverhead(); ASSERT_EQ(should_have_room, creator_.HasRoomForStreamFrame(kClientDataStreamId1, kOffset)); if (should_have_room) { @@ -853,8 +608,7 @@ .WillRepeatedly( Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u, - kOffset, false, false, &frame, - MAY_FEC_PROTECT)); + kOffset, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t bytes_consumed = frame.stream_frame->frame_length; EXPECT_LT(0u, bytes_consumed); @@ -865,9 +619,8 @@ TEST_P(QuicPacketCreatorTest, StreamFrameConsumption) { // Compute the total overhead for a single frame in packet. - const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(NOT_IN_FEC_GROUP); + const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead() + + GetStreamFrameOverhead(); size_t capacity = kDefaultMaxPacketSize - overhead; // Now, test various sizes around this size. for (int delta = -5; delta <= 5; ++delta) { @@ -876,8 +629,7 @@ QuicFrame frame; QuicIOVector io_vector(MakeIOVector(data)); ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u, - kOffset, false, false, &frame, - MAY_FEC_PROTECT)); + kOffset, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); // BytesFree() returns bytes available for the next frame, which will @@ -893,63 +645,10 @@ } } -TEST_P(QuicPacketCreatorTest, StreamFrameConsumptionWithFec) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - - // Serialize the packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - // Compute the total overhead for a single frame in packet. - const size_t overhead = GetPacketHeaderOverhead(IN_FEC_GROUP) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(IN_FEC_GROUP); - size_t capacity = kDefaultMaxPacketSize - overhead; - // Now, test various sizes around this size. - for (int delta = -5; delta <= 5; ++delta) { - string data(capacity + delta, 'A'); - size_t bytes_free = delta > 0 ? 0 : 0 - delta; - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector(data)); - ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u, - kOffset, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - // BytesFree() returns bytes available for the next frame. Since stream - // frame does not grow for FEC protected packets, this should be the same - // as bytes_free (bound by 0). - EXPECT_EQ(0u, creator_.ExpansionOnNewFrame()); - size_t expected_bytes_free = bytes_free > 0 ? bytes_free : 0; - EXPECT_EQ(expected_bytes_free, creator_.BytesFree()) << "delta: " << delta; - { - InSequence s; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - // Every 6th packet will generate an extra FEC packet. - if (delta == -1 || delta == 5) { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce( - Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - } - } - creator_.Flush(); - ASSERT_TRUE(serialized_packet_.encrypted_buffer); - DeleteSerializedPacket(); - } -} - TEST_P(QuicPacketCreatorTest, CryptoStreamFramePacketPadding) { // Compute the total overhead for a single frame in packet. - const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(NOT_IN_FEC_GROUP); + const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead() + + GetStreamFrameOverhead(); ASSERT_GT(kMaxPacketSize, overhead); size_t capacity = kDefaultMaxPacketSize - overhead; // Now, test various sizes around this size. @@ -963,7 +662,7 @@ .WillRepeatedly( Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); ASSERT_TRUE(creator_.ConsumeData(kCryptoStreamId, io_vector, 0u, kOffset, - false, true, &frame, MAY_FEC_PROTECT)); + false, true, &frame)); ASSERT_TRUE(frame.stream_frame); size_t bytes_consumed = frame.stream_frame->frame_length; EXPECT_LT(0u, bytes_consumed); @@ -984,9 +683,8 @@ TEST_P(QuicPacketCreatorTest, NonCryptoStreamFramePacketNonPadding) { // Compute the total overhead for a single frame in packet. - const size_t overhead = GetPacketHeaderOverhead(NOT_IN_FEC_GROUP) + - GetEncryptionOverhead() + - GetStreamFrameOverhead(NOT_IN_FEC_GROUP); + const size_t overhead = GetPacketHeaderOverhead() + GetEncryptionOverhead() + + GetStreamFrameOverhead(); ASSERT_GT(kDefaultMaxPacketSize, overhead); size_t capacity = kDefaultMaxPacketSize - overhead; // Now, test various sizes around this size. @@ -999,8 +697,7 @@ EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); ASSERT_TRUE(creator_.ConsumeData(kClientDataStreamId1, io_vector, 0u, - kOffset, false, false, &frame, - MAY_FEC_PROTECT)); + kOffset, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t bytes_consumed = frame.stream_frame->frame_length; EXPECT_LT(0u, bytes_consumed); @@ -1037,29 +734,23 @@ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - size_t max_packets_per_fec_group = 10; - creator_.set_max_packets_per_fec_group(max_packets_per_fec_group); - QuicPacketCreatorPeer::SetPacketNumber(&creator_, - 64 - max_packets_per_fec_group); + QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - QuicPacketCreatorPeer::SetPacketNumber(&creator_, - 64 * 256 - max_packets_per_fec_group); + QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - QuicPacketCreatorPeer::SetPacketNumber( - &creator_, 64 * 256 * 256 - max_packets_per_fec_group); + QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 * 256); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); EXPECT_EQ(PACKET_4BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - QuicPacketCreatorPeer::SetPacketNumber( - &creator_, - UINT64_C(64) * 256 * 256 * 256 * 256 - max_packets_per_fec_group); + QuicPacketCreatorPeer::SetPacketNumber(&creator_, + UINT64_C(64) * 256 * 256 * 256 * 256); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); EXPECT_EQ(PACKET_6BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); @@ -1125,14 +816,13 @@ QuicPacketCreatorPeer::SendVersionInPacket(&creator_), QuicPacketCreatorPeer::SendPathIdInPacket(&creator_), creator_.connection_id_length(), PACKET_1BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP, &payload_length)); + &payload_length)); QuicFrame frame; const string too_long_payload(payload_length * 2, 'a'); QuicIOVector io_vector(MakeIOVector(too_long_payload)); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, true, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(payload_length, consumed); @@ -1154,7 +844,7 @@ creator_.connection_id_length(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), QuicPacketCreatorPeer::SendPathIdInPacket(&creator_), - PACKET_1BYTE_PACKET_NUMBER, NOT_IN_FEC_GROUP), + PACKET_1BYTE_PACKET_NUMBER), creator_.BytesFree()); // Add a variety of frame types and then a padding frame. @@ -1164,8 +854,8 @@ QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1195,8 +885,7 @@ GetPacketHeaderSize( creator_.connection_id_length(), QuicPacketCreatorPeer::SendVersionInPacket(&creator_), - /*include_path_id=*/false, PACKET_1BYTE_PACKET_NUMBER, - NOT_IN_FEC_GROUP), + /*include_path_id=*/false, PACKET_1BYTE_PACKET_NUMBER), creator_.BytesFree()); } @@ -1210,7 +899,7 @@ // the number of nack ranges that can be fit in an ack frame. QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u); size_t frame_len = client_framer_.GetSerializedFrameLength( - QuicFrame(&ack_frame), creator_.BytesFree(), true, true, NOT_IN_FEC_GROUP, + QuicFrame(&ack_frame), creator_.BytesFree(), true, true, PACKET_1BYTE_PACKET_NUMBER); EXPECT_GT(creator_.BytesFree(), frame_len); EXPECT_GT(creator_.max_packet_length(), creator_.PacketSize()); @@ -1224,8 +913,8 @@ // Make sure that an additional stream frame can be added to the packet. QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1258,7 +947,7 @@ // the packet size. QuicAckFrame ack_frame = MakeAckFrameWithNackRanges(2000u, 0u); size_t frame_len = client_framer_.GetSerializedFrameLength( - QuicFrame(&ack_frame), creator_.BytesFree(), true, true, NOT_IN_FEC_GROUP, + QuicFrame(&ack_frame), creator_.BytesFree(), true, true, PACKET_1BYTE_PACKET_NUMBER); EXPECT_EQ(creator_.BytesFree(), frame_len); @@ -1305,103 +994,6 @@ delete frames_[0].stream_frame; } -TEST_P(QuicPacketCreatorTest, ResetFecGroup) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Add a stream frame and turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - // Serialize the packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - EXPECT_TRUE(creator_.IsFecGroupOpen()); - // We do not have enough packets in the FEC group to trigger an FEC packet. - EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - // FEC group will be reset if FEC police is alarm trigger but FEC alarm does - // not fire. - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - creator_.set_fec_send_policy(FEC_ALARM_TRIGGER); - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - EXPECT_FALSE(creator_.IsFecGroupOpen()); - // We do not have enough packets in the FEC group to trigger an FEC packet. - EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Confirm that there is no FEC packet under construction. - EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/true)); - - char buffer[kMaxPacketSize]; - EXPECT_DFATAL( - QuicPacketCreatorPeer::SerializeFec(&creator_, buffer, kMaxPacketSize), - "SerializeFEC called but no group or zero packets in group."); - - // Create and send a new FEC protected packet. - ASSERT_TRUE(creator_.ConsumeData(2u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - EXPECT_TRUE(creator_.IsFecGroupOpen()); - // We do not have enough packets in the FEC group to trigger an FEC packet. - EXPECT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - EXPECT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - // Should return false since we do not have enough packets in the FEC group to - // trigger an FEC packet. - ASSERT_FALSE(creator_.ShouldSendFec(/*force_close=*/false)); - // Should return true since there are packets in the FEC group. - ASSERT_TRUE(creator_.ShouldSendFec(/*force_close=*/true)); - - // Change FEC policy, send FEC packet and close FEC group. - creator_.set_fec_send_policy(FEC_ANY_TRIGGER); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::SaveSerializedPacket)); - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - ASSERT_EQ(3u, serialized_packet_.packet_number); - DeleteSerializedPacket(); -} - -TEST_P(QuicPacketCreatorTest, ResetFecGroupWithQueuedFrames) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Add a stream frame to the creator and turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - size_t consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_DFATAL(QuicPacketCreatorPeer::ResetFecGroup(&creator_), - "Cannot reset FEC group with pending frames."); - - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - EXPECT_FALSE(creator_.HasPendingFrames()); - - // FEC group will be reset if FEC police is alarm trigger but FEC alarm does - // not fire. - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - creator_.set_fec_send_policy(FEC_ALARM_TRIGGER); - creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - EXPECT_FALSE(creator_.IsFecGroupOpen()); -} - TEST_P(QuicPacketCreatorTest, SetCurrentPath) { // Current path is the default path. EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); @@ -1411,8 +1003,8 @@ // Add a stream frame to the creator. QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1443,8 +1035,8 @@ EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); // Add a stream frame to the creator. - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1459,95 +1051,24 @@ QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); } -TEST_P(QuicPacketCreatorTest, SetCurrentPathWithFec) { - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Current path is the default path. - EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); - EXPECT_EQ(0u, creator_.packet_number()); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - // Add a stream frame to the creator. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - size_t consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - EXPECT_TRUE(creator_.HasPendingFrames()); - EXPECT_EQ(0u, creator_.packet_number()); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - - // Change current path. - QuicPathId kPathId1 = 1; - EXPECT_DFATAL(creator_.SetCurrentPath(kPathId1, 1, 0), - "Unable to change paths when a packet is under construction"); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .Times(2) - .WillRepeatedly( - Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - EXPECT_FALSE(creator_.HasPendingFrames()); - creator_.SetCurrentPath(kPathId1, 1, 0); - EXPECT_EQ(kPathId1, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); - EXPECT_FALSE(creator_.HasPendingFrames()); - EXPECT_EQ(0u, creator_.packet_number()); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - - // Change current path back. - creator_.SetCurrentPath(kDefaultPathId, 3, 2); - EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); - // FEC packet consumes a packet number. - EXPECT_EQ(2u, creator_.packet_number()); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - // Add a stream frame to the creator. - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); - ASSERT_TRUE(frame.stream_frame); - consumed = frame.stream_frame->frame_length; - EXPECT_EQ(4u, consumed); - EXPECT_TRUE(creator_.HasPendingFrames()); - - // Does not change current path. - creator_.SetCurrentPath(kDefaultPathId, 3, 0); - EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); - EXPECT_TRUE(creator_.HasPendingFrames()); - // FEC packet consumes a packet number. - EXPECT_EQ(2u, creator_.packet_number()); - EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, - QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); -} - TEST_P(QuicPacketCreatorTest, - SetCurrentPathWithFecAndUpdatePacketSequenceNumberLength) { - // Send FEC packet every 10 packets. - size_t max_packets_per_fec_group = 10; - creator_.set_max_packets_per_fec_group(max_packets_per_fec_group); + SetCurrentPathAndUpdatePacketSequenceNumberLength) { // Current path is the default path. EXPECT_EQ(kDefaultPathId, QuicPacketCreatorPeer::GetCurrentPath(&creator_)); EXPECT_EQ(PACKET_1BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); - QuicPacketCreatorPeer::SetPacketNumber( - &creator_, 64 * 256 - max_packets_per_fec_group - 2); + QuicPacketCreatorPeer::SetPacketNumber(&creator_, 64 * 256 - 2); // Add a stream frame to the creator and send the packet. QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MUST_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .Times(2) + .Times(1) .WillRepeatedly( Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); creator_.Flush(); - EXPECT_EQ(64 * 256 - max_packets_per_fec_group - 1, creator_.packet_number()); + EXPECT_EQ(UINT64_C(64 * 256 - 1), creator_.packet_number()); creator_.UpdatePacketNumberLength(2, 10000 / kDefaultMaxPacketSize); EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); @@ -1561,8 +1082,7 @@ // Change current path back. creator_.SetCurrentPath(kDefaultPathId, 2, 10000 / kDefaultMaxPacketSize); - // FEC packet consumes a packet number. - EXPECT_EQ(64 * 256 - max_packets_per_fec_group, creator_.packet_number()); + EXPECT_EQ(UINT64_C(64 * 256 - 1), creator_.packet_number()); EXPECT_EQ(PACKET_2BYTE_PACKET_NUMBER, QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); } @@ -1574,8 +1094,8 @@ // Add a stream frame to the creator and flush the packet. QuicFrame frame; QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); size_t consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1601,8 +1121,8 @@ QuicPacketCreatorPeer::NextPacketNumberLength(&creator_)); // Add a stream frame to the creator and flush the packet. - ASSERT_TRUE(creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame, - MAY_FEC_PROTECT)); + ASSERT_TRUE( + creator_.ConsumeData(1u, io_vector, 0u, 0u, false, false, &frame)); ASSERT_TRUE(frame.stream_frame); consumed = frame.stream_frame->frame_length; EXPECT_EQ(4u, consumed); @@ -1622,56 +1142,6 @@ "Cannot send stream data without encryption."); } -TEST_P(QuicPacketCreatorTest, DontSendUnencryptedFec) { - ValueRestore<bool> old_flag(&FLAGS_quic_no_unencrypted_fec, true); - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Send stream data encrypted with FEC protection. - creator_.set_encryption_level(ENCRYPTION_INITIAL); - // Turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(kHeadersStreamId, io_vector, 0u, 0u, false, - false, &frame, MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - // Serialize the packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - - // The creator will clear the FEC group rather than try to send without - // encryption. - creator_.set_encryption_level(ENCRYPTION_NONE); - EXPECT_CALL(delegate_, OnResetFecGroup()); - creator_.MaybeSendFecPacketAndCloseGroup(true, false); -} - -TEST_P(QuicPacketCreatorTest, SerializeUnencryptedFecClosesConnection) { - ValueRestore<bool> old_flag(&FLAGS_quic_no_unencrypted_fec, true); - // Send FEC packet every 6 packets. - creator_.set_max_packets_per_fec_group(6); - // Send stream data encrypted with FEC protection. - creator_.set_encryption_level(ENCRYPTION_INITIAL); - // Turn on FEC protection. - QuicFrame frame; - QuicIOVector io_vector(MakeIOVector("test")); - ASSERT_TRUE(creator_.ConsumeData(kHeadersStreamId, io_vector, 0u, 0u, false, - false, &frame, MUST_FEC_PROTECT)); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(&creator_)); - // Serialize the packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketCreatorTest::ClearSerializedPacket)); - creator_.Flush(); - - // Try to send an FEC packet unencrypted. - creator_.set_encryption_level(ENCRYPTION_NONE); - EXPECT_CALL(delegate_, OnUnrecoverableError(QUIC_UNENCRYPTED_FEC_DATA, _)); - char seralized_fec_buffer[kMaxPacketSize]; - EXPECT_DFATAL(QuicPacketCreatorPeer::SerializeFec( - &creator_, seralized_fec_buffer, kMaxPacketSize), - "SerializeFEC must be called with encryption."); -} - } // namespace } // namespace test } // namespace net
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc index 75e1c59..908872e0 100644 --- a/net/quic/quic_packet_generator.cc +++ b/net/quic/quic_packet_generator.cc
@@ -6,7 +6,6 @@ #include "base/logging.h" #include "net/quic/quic_bug_tracker.h" -#include "net/quic/quic_fec_group.h" #include "net/quic/quic_flags.h" #include "net/quic/quic_utils.h" @@ -27,22 +26,12 @@ delegate), batch_mode_(false), should_send_ack_(false), - should_send_stop_waiting_(false), - max_packet_length_(kDefaultMaxPacketSize) {} + should_send_stop_waiting_(false) {} QuicPacketGenerator::~QuicPacketGenerator() { QuicUtils::DeleteFrames(&queued_control_frames_); } -void QuicPacketGenerator::OnCongestionWindowChange( - QuicPacketCount max_packets_in_flight) { - packet_creator_.OnCongestionWindowChange(max_packets_in_flight); -} - -void QuicPacketGenerator::OnRttChange(QuicTime::Delta rtt) { - packet_creator_.OnRttChange(rtt); -} - void QuicPacketGenerator::SetShouldSendAck(bool also_send_stop_waiting) { if (packet_creator_.has_ack()) { // Ack already queued, nothing to do. @@ -56,12 +45,12 @@ should_send_ack_ = true; should_send_stop_waiting_ = also_send_stop_waiting; - SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false); + SendQueuedFrames(/*flush=*/false); } void QuicPacketGenerator::AddControlFrame(const QuicFrame& frame) { queued_control_frames_.push_back(frame); - SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false); + SendQueuedFrames(/*flush=*/false); } QuicConsumedData QuicPacketGenerator::ConsumeData( @@ -69,14 +58,13 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* listener) { bool has_handshake = id == kCryptoStreamId; // To make reasoning about crypto frames easier, we don't combine them with // other retransmittable frames in a single packet. const bool flush = has_handshake && packet_creator_.HasPendingRetransmittableFrames(); - SendQueuedFrames(flush, /*is_fec_timeout=*/false); + SendQueuedFrames(flush); size_t total_bytes_consumed = 0; bool fin_consumed = false; @@ -95,7 +83,7 @@ QuicFrame frame; if (!packet_creator_.ConsumeData(id, iov, total_bytes_consumed, offset + total_bytes_consumed, fin, - has_handshake, &frame, fec_protection)) { + has_handshake, &frame)) { // The creator is always flushed if there's not enough room for a new // stream frame before ConsumeData, so ConsumeData should always succeed. QUIC_BUG << "Failed to ConsumeData, stream:" << id; @@ -113,9 +101,6 @@ (bytes_consumed > 0 && packet_creator_.HasPendingFrames())); if (!InBatchMode()) { - // TODO(rtenneti): remove MaybeSendFecPacketAndCloseGroup() from inside - // SerializeAndSendPacket() and make it an explicit call here (and - // elsewhere where we call SerializeAndSendPacket?). packet_creator_.Flush(); } @@ -131,14 +116,9 @@ // Don't allow the handshake to be bundled with other retransmittable frames. if (has_handshake) { - SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false); + SendQueuedFrames(/*flush=*/true); } - // Try to close FEC group since we've either run out of data to send or we're - // blocked. - packet_creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/false, - /*is_fec_timeout=*/false); - DCHECK(InBatchMode() || !packet_creator_.HasPendingFrames()); return QuicConsumedData(total_bytes_consumed, fin_consumed); } @@ -147,8 +127,12 @@ QuicByteCount target_mtu, QuicAckListenerInterface* listener) { // MTU discovery frames must be sent by themselves. - DCHECK(!InBatchMode() && !packet_creator_.HasPendingFrames()); - const QuicByteCount current_mtu = GetMaxPacketLength(); + if (!packet_creator_.CanSetMaxPacketLength()) { + QUIC_BUG << "MTU discovery packets should only be sent when no other " + << "frames needs to be sent."; + return; + } + const QuicByteCount current_mtu = GetCurrentMaxPacketLength(); // The MTU discovery frame is allocated on the stack, since it is going to be // serialized within this function. @@ -156,7 +140,7 @@ QuicFrame frame(mtu_discovery_frame); // Send the probe packet with the new length. - SetMaxPacketLength(target_mtu, /*force=*/true); + SetMaxPacketLength(target_mtu); const bool success = packet_creator_.AddPaddedSavedFrame(frame); if (listener != nullptr) { packet_creator_.AddAckListener(listener, 0); @@ -167,7 +151,7 @@ DCHECK(success); // Reset the packet length back. - SetMaxPacketLength(current_mtu, /*force=*/true); + SetMaxPacketLength(current_mtu); } bool QuicPacketGenerator::CanSendWithNextPendingFrameAddition() const { @@ -182,7 +166,7 @@ return delegate_->ShouldGeneratePacket(retransmittable, NOT_HANDSHAKE); } -void QuicPacketGenerator::SendQueuedFrames(bool flush, bool is_fec_timeout) { +void QuicPacketGenerator::SendQueuedFrames(bool flush) { // Only add pending frames if we are SURE we can then send the whole packet. while (HasPendingFrames() && (flush || CanSendWithNextPendingFrameAddition())) { @@ -191,23 +175,6 @@ if (flush || !InBatchMode()) { packet_creator_.Flush(); } - packet_creator_.MaybeSendFecPacketAndCloseGroup(flush, is_fec_timeout); -} - -void QuicPacketGenerator::OnFecTimeout() { - DCHECK(!InBatchMode()); - if (!packet_creator_.ShouldSendFec(true)) { - QUIC_BUG << "No FEC packet to send on FEC timeout."; - return; - } - // Flush out any pending frames in the generator and the creator, and then - // send out FEC packet. - SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/true); -} - -QuicTime::Delta QuicPacketGenerator::GetFecTimeout( - QuicPacketNumber packet_number) { - return packet_creator_.GetFecTimeout(packet_number); } bool QuicPacketGenerator::InBatchMode() { @@ -220,11 +187,11 @@ void QuicPacketGenerator::FinishBatchOperations() { batch_mode_ = false; - SendQueuedFrames(/*flush=*/false, /*is_fec_timeout=*/false); + SendQueuedFrames(/*flush=*/false); } void QuicPacketGenerator::FlushAllQueuedFrames() { - SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false); + SendQueuedFrames(/*flush=*/true); } bool QuicPacketGenerator::HasQueuedFrames() const { @@ -275,29 +242,13 @@ return packet_creator_.packet_number(); } -QuicByteCount QuicPacketGenerator::GetMaxPacketLength() const { - return max_packet_length_; -} - QuicByteCount QuicPacketGenerator::GetCurrentMaxPacketLength() const { return packet_creator_.max_packet_length(); } -void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length, bool force) { - // If we cannot immediately set new maximum packet length, and the |force| - // flag is set, we have to flush the contents of the queue and close existing - // FEC group. - if (!packet_creator_.CanSetMaxPacketLength() && force) { - SendQueuedFrames(/*flush=*/true, /*is_fec_timeout=*/false); - packet_creator_.MaybeSendFecPacketAndCloseGroup(/*force_send_fec=*/true, - /*is_fec_timeout=*/false); - DCHECK(packet_creator_.CanSetMaxPacketLength()); - } - - max_packet_length_ = length; - if (packet_creator_.CanSetMaxPacketLength()) { - packet_creator_.SetMaxPacketLength(length); - } +void QuicPacketGenerator::SetMaxPacketLength(QuicByteCount length) { + DCHECK(packet_creator_.CanSetMaxPacketLength()); + packet_creator_.SetMaxPacketLength(length); } QuicEncryptedPacket* QuicPacketGenerator::SerializeVersionNegotiationPacket( @@ -348,18 +299,4 @@ max_packets_in_flight); } -void QuicPacketGenerator::set_rtt_multiplier_for_fec_timeout( - float rtt_multiplier_for_fec_timeout) { - packet_creator_.set_rtt_multiplier_for_fec_timeout( - rtt_multiplier_for_fec_timeout); -} - -FecSendPolicy QuicPacketGenerator::fec_send_policy() { - return packet_creator_.fec_send_policy(); -} - -void QuicPacketGenerator::set_fec_send_policy(FecSendPolicy fec_send_policy) { - packet_creator_.set_fec_send_policy(fec_send_policy); -} - } // namespace net
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h index 6d956e3..881d973 100644 --- a/net/quic/quic_packet_generator.h +++ b/net/quic/quic_packet_generator.h
@@ -36,19 +36,6 @@ // full, it will be serialized and sent to the packet. When batch // mode is ended via |FinishBatchOperations|, the current packet // will be serialzied, even if it is not full. -// -// FEC behavior also depends on batch mode. In batch mode, FEC packets -// will be sent after |max_packets_per_group| have been sent, as well -// as after batch operations are complete. When not in batch mode, -// an FEC packet will be sent after each write call completes. -// -// TODO(rch): This behavior should probably be tuned. When not in batch -// mode, we should probably set a timer so that several independent -// operations can be grouped into the same FEC group. -// -// When an FEC packet is generated, it will be send to the Delegate, -// even if the Delegate has become unwritable after handling the -// data packet immediately proceeding the FEC packet. #ifndef NET_QUIC_QUIC_PACKET_GENERATOR_H_ #define NET_QUIC_QUIC_PACKET_GENERATOR_H_ @@ -91,12 +78,6 @@ ~QuicPacketGenerator(); - // Called by the connection in the event of the congestion window changing. - void OnCongestionWindowChange(QuicPacketCount max_packets_in_flight); - - // Called by the connection when the RTT may have changed. - void OnRttChange(QuicTime::Delta rtt); - // Indicates that an ACK frame should be sent. // If |also_send_stop_waiting| is true, then it also indicates that a // STOP_WAITING frame should be sent as well. @@ -115,7 +96,6 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* listener); // Generates an MTU discovery packet of specified size. @@ -146,8 +126,6 @@ // Re-serializes frames with the original packet's packet number length. // Used for retransmitting packets to ensure they aren't too long. - // Caller must ensure that any open FEC group is closed before calling this - // method. void ReserializeAllFrames(const PendingRetransmission& retransmission, char* buffer, size_t buffer_len); @@ -160,16 +138,6 @@ // Set the minimum number of bytes for the connection id length; void SetConnectionIdLength(uint32_t length); - // Called when the FEC alarm fires. - void OnFecTimeout(); - - // Called after sending |packet_number| to determine whether an FEC alarm - // should be set for sending out an FEC packet. Returns a positive and finite - // timeout if an FEC alarm should be set, and infinite if no alarm should be - // set. OnFecTimeout should be called to send the FEC packet when the alarm - // fires. - QuicTime::Delta GetFecTimeout(QuicPacketNumber packet_number); - // Sets the encrypter to use for the encryption level. void SetEncrypter(EncryptionLevel level, QuicEncrypter* encrypter); @@ -180,18 +148,12 @@ // created. QuicPacketNumber packet_number() const; - // Returns the maximum packet length. Note that this is the long-term maximum - // packet length, and it may not be the maximum length of the current packet, - // if the generator is in the middle of the packet (in batch mode) or FEC - // group. - QuicByteCount GetMaxPacketLength() const; - // Returns the maximum length current packet can actually have. + // Returns the maximum length a current packet can actually have. QuicByteCount GetCurrentMaxPacketLength() const; - // Set maximum packet length sent. If |force| is set to true, all pending - // unfinished packets and FEC groups are closed, and the change is enacted - // immediately. Otherwise, it is enacted at the next opportunity. - void SetMaxPacketLength(QuicByteCount length, bool force); + // Set maximum packet length in the creator immediately. May not be called + // when there are frames queued in the creator. + void SetMaxPacketLength(QuicByteCount length); // Sets |path_id| to be the path on which next packet is generated. void SetCurrentPath(QuicPathId path_id, @@ -202,15 +164,10 @@ packet_creator_.set_debug_delegate(debug_delegate); } - void set_rtt_multiplier_for_fec_timeout(float rtt_multiplier_for_fec_timeout); - - FecSendPolicy fec_send_policy(); - void set_fec_send_policy(FecSendPolicy fec_send_policy); - private: friend class test::QuicPacketGeneratorPeer; - void SendQueuedFrames(bool flush, bool is_fec_timeout); + void SendQueuedFrames(bool flush); // Test to see if we have pending ack, or control frames. bool HasPendingFrames() const; @@ -241,11 +198,6 @@ QuicAckFrame pending_ack_frame_; QuicStopWaitingFrame pending_stop_waiting_frame_; - // Stores the maximum packet size we are allowed to send. This might not be - // the maximum size we are actually using now, if we are in the middle of the - // packet. - QuicByteCount max_packet_length_; - DISALLOW_COPY_AND_ASSIGN(QuicPacketGenerator); };
diff --git a/net/quic/quic_packet_generator_test.cc b/net/quic/quic_packet_generator_test.cc index e930bc4..133dad57 100644 --- a/net/quic/quic_packet_generator_test.cc +++ b/net/quic/quic_packet_generator_test.cc
@@ -34,12 +34,6 @@ namespace test { namespace { -const int64_t kMinFecTimeoutMs = 5u; - -static const FecSendPolicy kFecSendPolicyList[] = { - FEC_ANY_TRIGGER, FEC_ALARM_TRIGGER, -}; - class MockDelegate : public QuicPacketGenerator::DelegateInterface { public: MockDelegate() {} @@ -53,7 +47,6 @@ MOCK_METHOD1(OnSerializedPacket, void(SerializedPacket* packet)); MOCK_METHOD2(OnUnrecoverableError, void(QuicErrorCode, ConnectionCloseSource)); - MOCK_METHOD0(OnResetFecGroup, void()); void SetCanWriteAnything() { EXPECT_CALL(*this, ShouldGeneratePacket(_, _)).WillRepeatedly(Return(true)); @@ -92,8 +85,7 @@ num_stop_waiting_frames(0), num_stream_frames(0), num_ping_frames(0), - num_mtu_discovery_frames(0), - fec_group(0) {} + num_mtu_discovery_frames(0) {} size_t num_ack_frames; size_t num_connection_close_frames; @@ -103,13 +95,11 @@ size_t num_stream_frames; size_t num_ping_frames; size_t num_mtu_discovery_frames; - - QuicFecGroupNumber fec_group; }; } // namespace -class QuicPacketGeneratorTest : public ::testing::TestWithParam<FecSendPolicy> { +class QuicPacketGeneratorTest : public ::testing::Test { public: QuicPacketGeneratorTest() : framer_(QuicSupportedVersions(), @@ -117,10 +107,8 @@ Perspective::IS_CLIENT), generator_(42, &framer_, &random_, &buffer_allocator_, &delegate_), creator_(QuicPacketGeneratorPeer::GetPacketCreator(&generator_)) { - generator_.set_fec_send_policy(GetParam()); // TODO(ianswett): Fix this test so it uses a non-null encrypter. FLAGS_quic_never_write_unencrypted_data = false; - FLAGS_quic_no_unencrypted_fec = false; } ~QuicPacketGeneratorTest() override { @@ -181,7 +169,6 @@ simple_framer_.stream_frames().size()); EXPECT_EQ(contents.num_stop_waiting_frames, simple_framer_.stop_waiting_frames().size()); - EXPECT_EQ(contents.fec_group, simple_framer_.header().fec_group); // From the receiver's perspective, MTU discovery frames are ping frames. EXPECT_EQ(contents.num_ping_frames + contents.num_mtu_discovery_frames, @@ -206,16 +193,6 @@ } } - void CheckPacketIsFec(size_t packet_index, QuicPacketNumber fec_group) { - ASSERT_GT(packets_.size(), packet_index); - const SerializedPacket& packet = packets_[packet_index]; - ASSERT_TRUE(packet.retransmittable_frames.empty()); - ASSERT_TRUE(packet.encrypted_buffer != nullptr); - ASSERT_TRUE(simple_framer_.ProcessPacket( - QuicEncryptedPacket(packet.encrypted_buffer, packet.encrypted_length))); - EXPECT_TRUE(simple_framer_.header().fec_flag); - } - QuicIOVector CreateData(size_t len) { data_array_.reset(new char[len]); memset(data_array_.get(), '?', len); @@ -247,19 +224,14 @@ MOCK_METHOD1(OnFrameAddedToPacket, void(const QuicFrame&)); }; -// Run all end to end tests with all supported FEC send polocies. -INSTANTIATE_TEST_CASE_P(FecSendPolicy, - QuicPacketGeneratorTest, - ::testing::ValuesIn(kFecSendPolicyList)); - -TEST_P(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) { +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_NotWritable) { delegate_.SetCanNotWrite(); generator_.SetShouldSendAck(false); EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) { +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldNotFlush) { StrictMock<MockDebugDelegate> debug_delegate; generator_.set_debug_delegate(&debug_delegate); @@ -273,7 +245,7 @@ EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) { +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_WritableAndShouldFlush) { delegate_.SetCanWriteOnlyNonRetransmittable(); EXPECT_CALL(delegate_, PopulateAckFrame(_)); @@ -288,7 +260,7 @@ CheckPacketContains(contents, 0); } -TEST_P(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) { +TEST_F(QuicPacketGeneratorTest, ShouldSendAck_MultipleCalls) { // Make sure that calling SetShouldSendAck multiple times does not result in a // crash. Previously this would result in multiple QuicFrames queued in the // packet generator, with all but the last with internal pointers to freed @@ -307,21 +279,21 @@ generator_.FinishBatchOperations(); } -TEST_P(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { +TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritable) { delegate_.SetCanNotWrite(); generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { +TEST_F(QuicPacketGeneratorTest, AddControlFrame_OnlyAckWritable) { delegate_.SetCanWriteOnlyNonRetransmittable(); generator_.AddControlFrame(QuicFrame(CreateRstStreamFrame())); EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { +TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldNotFlush) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); @@ -329,7 +301,7 @@ EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { +TEST_F(QuicPacketGeneratorTest, AddControlFrame_NotWritableBatchThenFlush) { delegate_.SetCanNotWrite(); generator_.StartBatchOperations(); @@ -348,7 +320,7 @@ CheckPacketContains(contents, 0); } -TEST_P(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { +TEST_F(QuicPacketGeneratorTest, AddControlFrame_WritableAndShouldFlush) { delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) @@ -362,34 +334,34 @@ CheckPacketContains(contents, 0); } -TEST_P(QuicPacketGeneratorTest, ConsumeData_NotWritable) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_NotWritable) { delegate_.SetCanNotWrite(); QuicConsumedData consumed = generator_.ConsumeData( - kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, nullptr); + kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr); EXPECT_EQ(0u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldNotFlush) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); QuicConsumedData consumed = generator_.ConsumeData( - kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, nullptr); + kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_WritableAndShouldFlush) { delegate_.SetCanWriteAnything(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); QuicConsumedData consumed = generator_.ConsumeData( - kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, nullptr); + kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -402,14 +374,14 @@ // Test the behavior of ConsumeData when the data consumed is for the crypto // handshake stream. Ensure that the packet is always sent and padded even if // the generator operates in batch mode. -TEST_P(QuicPacketGeneratorTest, ConsumeData_Handshake) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_Handshake) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); QuicConsumedData consumed = generator_.ConsumeData( - kCryptoStreamId, MakeIOVector("foo"), 0, false, MAY_FEC_PROTECT, nullptr); + kCryptoStreamId, MakeIOVector("foo"), 0, false, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -418,38 +390,38 @@ CheckPacketContains(contents, 0); ASSERT_EQ(1u, packets_.size()); - ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetMaxPacketLength()); + ASSERT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); } -TEST_P(QuicPacketGeneratorTest, ConsumeData_EmptyData) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_EmptyData) { EXPECT_DFATAL(generator_.ConsumeData(kHeadersStreamId, MakeIOVector(""), 0, - false, MAY_FEC_PROTECT, nullptr), + false, nullptr), "Attempt to consume empty data without FIN."); } -TEST_P(QuicPacketGeneratorTest, +TEST_F(QuicPacketGeneratorTest, ConsumeDataMultipleTimes_WritableAndShouldNotFlush) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true, - MAY_FEC_PROTECT, nullptr); - QuicConsumedData consumed = generator_.ConsumeData( - 3, MakeIOVector("quux"), 7, false, MAY_FEC_PROTECT, nullptr); + nullptr); + QuicConsumedData consumed = + generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr); EXPECT_EQ(4u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); } -TEST_P(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_BatchOperations) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 2, true, - MAY_FEC_PROTECT, nullptr); - QuicConsumedData consumed = generator_.ConsumeData( - 3, MakeIOVector("quux"), 7, false, MAY_FEC_PROTECT, nullptr); + nullptr); + QuicConsumedData consumed = + generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr); EXPECT_EQ(4u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); @@ -465,246 +437,19 @@ CheckPacketContains(contents, 0); } -TEST_P(QuicPacketGeneratorTest, ConsumeDataFecOnMaxGroupSize) { - delegate_.SetCanWriteAnything(); - - // Send FEC every two packets. - creator_->set_max_packets_per_fec_group(2); - - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC - // group is closed. - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - - // Send enough data to create 3 packets: two full and one partial. Send with - // MUST_FEC_PROTECT flag. - size_t data_len = 2 * kDefaultMaxPacketSize + 100; - QuicConsumedData consumed = generator_.ConsumeData( - 3, CreateData(data_len), 0, true, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - - CheckPacketHasSingleStreamFrame(0); - CheckPacketHasSingleStreamFrame(1); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER. - CheckPacketHasSingleStreamFrame(2); - } else { - CheckPacketIsFec(2, 1); - CheckPacketHasSingleStreamFrame(3); - } - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // If FEC send policy is FEC_ANY_TRIGGER, then the FEC packet under - // construction will be sent when one more packet is sent (since FEC group - // size is 2), or when OnFecTimeout is called. Send more data with - // MAY_FEC_PROTECT. This packet should also be protected, and FEC packet is - // sent since FEC group size is reached. - // - // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed when the group - // size is reached. FEC packet is not sent. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - } - consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketHasSingleStreamFrame(3); - } else { - CheckPacketHasSingleStreamFrame(4); - CheckPacketIsFec(5, 4); - } - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, ConsumeDataSendsFecOnTimeout) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(1000); - - // Send data with MUST_FEC_PROTECT flag. No FEC packet is emitted, but the - // creator FEC protects all data. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData(3, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - CheckPacketHasSingleStreamFrame(0); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send more data with MAY_FEC_PROTECT. This packet should also be protected, - // and FEC packet is not yet sent. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - CheckPacketHasSingleStreamFrame(1); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Calling OnFecTimeout should cause the FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(2, 1); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Subsequent data is protected under the next FEC group. Send enough data to - // create 2 more packets: one full and one partial. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - size_t data_len = kDefaultMaxPacketSize + 1; - consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - CheckPacketHasSingleStreamFrame(3); - CheckPacketHasSingleStreamFrame(4); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Calling OnFecTimeout should cause the FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(5, 4); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, GetFecTimeoutFiniteOnlyOnFirstPacketInGroup) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(6); - - // Send enough data to create 2 packets: one full and one partial. Send with - // MUST_FEC_PROTECT flag. No FEC packet is emitted yet, but the creator FEC - // protects all data. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - size_t data_len = 1 * kDefaultMaxPacketSize + 100; - QuicConsumedData consumed = generator_.ConsumeData( - 3, CreateData(data_len), 0, true, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - CheckPacketHasSingleStreamFrame(0); - CheckPacketHasSingleStreamFrame(1); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // GetFecTimeout returns finite timeout only for first packet in group. - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kMinFecTimeoutMs), - generator_.GetFecTimeout(/*packet_number=*/1u)); - EXPECT_EQ(QuicTime::Delta::Infinite(), - generator_.GetFecTimeout(/*packet_number=*/2u)); - - // Send more data with MAY_FEC_PROTECT. This packet should also be protected, - // and FEC packet is not yet sent. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - CheckPacketHasSingleStreamFrame(2); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // GetFecTimeout returns finite timeout only for first packet in group. - EXPECT_EQ(QuicTime::Delta::Infinite(), - generator_.GetFecTimeout(/*packet_number=*/3u)); - - // Calling OnFecTimeout should cause the FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(3, /*fec_group=*/1u); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Subsequent data is protected under the next FEC group. Send enough data to - // create 2 more packets: one full and one partial. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - data_len = kDefaultMaxPacketSize + 1u; - consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - CheckPacketHasSingleStreamFrame(4); - CheckPacketHasSingleStreamFrame(5); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // GetFecTimeout returns finite timeout for first packet in the new group. - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(kMinFecTimeoutMs), - generator_.GetFecTimeout(/*packet_number=*/5u)); - EXPECT_EQ(QuicTime::Delta::Infinite(), - generator_.GetFecTimeout(/*packet_number=*/6u)); - - // Calling OnFecTimeout should cause the FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(6, /*fec_group=*/5u); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send more data with MAY_FEC_PROTECT. No FEC protection, so GetFecTimeout - // returns infinite. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - consumed = generator_.ConsumeData(9, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - CheckPacketHasSingleStreamFrame(7); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - EXPECT_EQ(QuicTime::Delta::Infinite(), - generator_.GetFecTimeout(/*packet_number=*/8u)); -} - -TEST_P(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { +TEST_F(QuicPacketGeneratorTest, ConsumeData_FramesPreviouslyQueued) { // Set the packet size be enough for two stream frames with 0 stream offset, // but not enough for a stream frame of 0 offset and one with non-zero offset. size_t length = NullEncrypter().GetCiphertextSize(0) + GetPacketHeaderSize( creator_->connection_id_length(), kIncludeVersion, !kIncludePathId, - QuicPacketCreatorPeer::NextPacketNumberLength(creator_), - NOT_IN_FEC_GROUP) + + QuicPacketCreatorPeer::NextPacketNumberLength(creator_)) + // Add an extra 3 bytes for the payload and 1 byte so BytesFree is larger // than the GetMinStreamFrameSize. - QuicFramer::GetMinStreamFrameSize(1, 0, false, NOT_IN_FEC_GROUP) + 3 + - QuicFramer::GetMinStreamFrameSize(1, 0, true, NOT_IN_FEC_GROUP) + 1; - generator_.SetMaxPacketLength(length, /*force=*/false); + QuicFramer::GetMinStreamFrameSize(1, 0, false) + 3 + + QuicFramer::GetMinStreamFrameSize(1, 0, true) + 1; + generator_.SetMaxPacketLength(length); delegate_.SetCanWriteAnything(); { InSequence dummy; @@ -716,9 +461,8 @@ generator_.StartBatchOperations(); // Queue enough data to prevent a stream frame with a non-zero offset from // fitting. - QuicConsumedData consumed = - generator_.ConsumeData(kHeadersStreamId, MakeIOVector("foo"), 0, false, - MAY_FEC_PROTECT, nullptr); + QuicConsumedData consumed = generator_.ConsumeData( + kHeadersStreamId, MakeIOVector("foo"), 0, false, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); @@ -726,7 +470,7 @@ // This frame will not fit with the existing frame, causing the queued frame // to be serialized, and it will be added to a new open packet. consumed = generator_.ConsumeData(kHeadersStreamId, MakeIOVector("bar"), 3, - true, MAY_FEC_PROTECT, nullptr); + true, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); @@ -740,554 +484,7 @@ CheckPacketContains(contents, 1); } -TEST_P(QuicPacketGeneratorTest, NoFecPacketSentWhenBatchEnds) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(6); - - generator_.StartBatchOperations(); - - generator_.ConsumeData(3, MakeIOVector("foo"), 2, true, MUST_FEC_PROTECT, - nullptr); - QuicConsumedData consumed = generator_.ConsumeData( - 5, MakeIOVector("quux"), 7, false, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(4u, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasQueuedFrames()); - - // Now both frames will be flushed out, but FEC packet is not yet sent. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.FinishBatchOperations(); - EXPECT_FALSE(generator_.HasQueuedFrames()); - - PacketContents contents; - contents.num_stream_frames = 2u; - contents.fec_group = 1u; - CheckPacketContains(contents, 0); - - // Forcing FEC timeout causes FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(1, /*fec_group=*/1u); -} - -TEST_P(QuicPacketGeneratorTest, FecTimeoutOnRttChange) { - EXPECT_EQ(QuicTime::Delta::Zero(), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); - generator_.OnRttChange(QuicTime::Delta::FromMilliseconds(300)); - EXPECT_EQ(QuicTime::Delta::FromMilliseconds(150), - QuicPacketCreatorPeer::GetFecTimeout(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, FecGroupSizeOnCongestionWindowChange) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(50); - EXPECT_EQ(50u, creator_->max_packets_per_fec_group()); - EXPECT_FALSE(creator_->IsFecGroupOpen()); - - // On reduced cwnd. - generator_.OnCongestionWindowChange(7); - EXPECT_EQ(3u, creator_->max_packets_per_fec_group()); - - // On increased cwnd. - generator_.OnCongestionWindowChange(100); - EXPECT_EQ(50u, creator_->max_packets_per_fec_group()); - - // On collapsed cwnd. - generator_.OnCongestionWindowChange(1); - EXPECT_EQ(2u, creator_->max_packets_per_fec_group()); -} - -TEST_P(QuicPacketGeneratorTest, FecGroupSizeChangeWithOpenGroup) { - delegate_.SetCanWriteAnything(); - generator_.StartBatchOperations(); - creator_->set_max_packets_per_fec_group(50); - EXPECT_EQ(50u, creator_->max_packets_per_fec_group()); - EXPECT_FALSE(creator_->IsFecGroupOpen()); - - // Send enough data to create 4 packets with MUST_FEC_PROTECT flag. 3 packets - // are sent, one is queued in the creator. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - size_t data_len = 3 * kDefaultMaxPacketSize + 1; - QuicConsumedData consumed = generator_.ConsumeData( - 7, CreateData(data_len), 0, true, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(creator_->IsFecGroupOpen()); - - // Change FEC groupsize. - generator_.OnCongestionWindowChange(2); - EXPECT_EQ(2u, creator_->max_packets_per_fec_group()); - - // If FEC send policy is FEC_ANY_TRIGGER, then send enough data to trigger one - // unprotected data packet, causing the FEC packet to also be sent. - // - // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed and FEC packet - // is not sent. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - } - consumed = generator_.ConsumeData(7, CreateData(kDefaultMaxPacketSize), 0, - true, MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(kDefaultMaxPacketSize, consumed.bytes_consumed); - if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) { - // Verify that one FEC packet was sent. - CheckPacketIsFec(4, /*fec_group=*/1u); - } - EXPECT_FALSE(creator_->IsFecGroupOpen()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnOff) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(2); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send one unprotected data packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, - MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - // Verify that one data packet was sent. - PacketContents contents; - contents.num_stream_frames = 1; - CheckPacketContains(contents, 0); - - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - // If FEC send policy is FEC_ALARM_TRIGGER, FEC group is closed. - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - // Send enough data to create 3 packets with MUST_FEC_PROTECT flag. - size_t data_len = 2 * kDefaultMaxPacketSize + 100; - consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - - // If FEC send policy is FEC_ANY_TRIGGER, verify that packets sent were 3 data - // and 1 FEC. - // - // If FEC send policy is FEC_ALARM_TRIGGER, verify that packets sent were 3 - // data and FEC group is closed. - CheckPacketHasSingleStreamFrame(1); - CheckPacketHasSingleStreamFrame(2); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketHasSingleStreamFrame(3); - } else { - CheckPacketIsFec(3, /*fec_group=*/2u); - CheckPacketHasSingleStreamFrame(4); - } - - // Calling OnFecTimeout should emit the pending FEC packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketIsFec(4, /*fec_group=*/4u); - } else { - CheckPacketIsFec(5, /*fec_group=*/5u); - } - - // Send one unprotected data packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - consumed = generator_.ConsumeData(7, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - // Verify that one unprotected data packet was sent. - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketContains(contents, 5); - } else { - CheckPacketContains(contents, 6); - } -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnWithPendingFrameInCreator) { - delegate_.SetCanWriteAnything(); - // Enable FEC. - creator_->set_max_packets_per_fec_group(2); - - generator_.StartBatchOperations(); - // Queue enough data to prevent a stream frame with a non-zero offset from - // fitting. - QuicConsumedData consumed = generator_.ConsumeData(7, CreateData(1u), 0, true, - MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - EXPECT_TRUE(creator_->HasPendingFrames()); - - // Queue protected data for sending. Should cause queued frames to be flushed. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - consumed = generator_.ConsumeData(7, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - PacketContents contents; - contents.num_stream_frames = 1; - // Transmitted packet was not FEC protected. - CheckPacketContains(contents, 0); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - EXPECT_TRUE(creator_->HasPendingFrames()); -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnWithPendingFramesInGenerator) { - // Enable FEC. - creator_->set_max_packets_per_fec_group(2); - - // Queue control frames in generator. - delegate_.SetCanNotWrite(); - generator_.SetShouldSendAck(true); - delegate_.SetCanWriteAnything(); - generator_.StartBatchOperations(); - - // Set up frames to write into the creator when control frames are written. - EXPECT_CALL(delegate_, PopulateAckFrame(_)); - EXPECT_CALL(delegate_, PopulateStopWaitingFrame(_)); - - // Generator should have queued control frames, and creator should be empty. - EXPECT_TRUE(generator_.HasQueuedFrames()); - EXPECT_FALSE(creator_->HasPendingFrames()); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Queue protected data for sending. Should cause queued frames to be flushed. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData(7, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - PacketContents contents; - contents.num_ack_frames = 1; - contents.num_stop_waiting_frames = 1; - CheckPacketContains(contents, 0); - - // FEC protection should be on in creator. - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentFramesProtected) { - delegate_.SetCanWriteAnything(); - - // Enable FEC. - creator_->set_max_packets_per_fec_group(2); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Queue stream frame to be protected in creator. - generator_.StartBatchOperations(); - QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - // Creator has a pending protected frame. - EXPECT_TRUE(creator_->HasPendingFrames()); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Add enough unprotected data to exceed size of current packet, so that - // current packet is sent. Both frames will be sent out in a single packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - size_t data_len = kDefaultMaxPacketSize; - consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true, - MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - PacketContents contents; - contents.num_stream_frames = 2u; - contents.fec_group = 1u; - CheckPacketContains(contents, 0); - // FEC protection should still be on in creator. - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffWithSubsequentPacketsProtected) { - delegate_.SetCanWriteAnything(); - - // Enable FEC. - creator_->set_max_packets_per_fec_group(2); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send first packet, FEC protected. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - PacketContents contents; - contents.num_stream_frames = 1u; - contents.fec_group = 1u; - CheckPacketContains(contents, 0); - - // FEC should still be on in creator. - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send unprotected data to cause second packet to be sent, which gets - // protected because it happens to fall within an open FEC group. Data packet - // will be followed by FEC packet. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - } - consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, MAY_FEC_PROTECT, - nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - contents.num_stream_frames = 1u; - CheckPacketContains(contents, 1); - if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) { - // FEC packet is sent when send policy is FEC_ANY_TRIGGER. - CheckPacketIsFec(2, /*fec_group=*/1u); - } - - // FEC protection should be off in creator. - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, SwitchFecOnOffThenOnWithCreatorProtectionOn) { - delegate_.SetCanWriteAnything(); - generator_.StartBatchOperations(); - - // Enable FEC. - creator_->set_max_packets_per_fec_group(2); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Queue one byte of FEC protected data. - QuicConsumedData consumed = generator_.ConsumeData(5, CreateData(1u), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_TRUE(creator_->HasPendingFrames()); - - // Add more unprotected data causing first packet to be sent, FEC protected. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - size_t data_len = kDefaultMaxPacketSize; - consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true, - MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - PacketContents contents; - contents.num_stream_frames = 2u; - contents.fec_group = 1u; - CheckPacketContains(contents, 0); - - // FEC group is still open in creator. - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Add data that should be protected, large enough to cause second packet to - // be sent. Data packet should be followed by FEC packet. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - } - consumed = generator_.ConsumeData(5, CreateData(data_len), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - CheckPacketContains(contents, 1); - if (generator_.fec_send_policy() == FEC_ANY_TRIGGER) { - // FEC packet is sent when send policy is FEC_ANY_TRIGGER. - CheckPacketIsFec(2, /*fec_group=*/1u); - } - - // FEC protection should remain on in creator. - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -TEST_P(QuicPacketGeneratorTest, ResetFecGroupNoTimeout) { - delegate_.SetCanWriteAnything(); - // Send FEC packet after 2 packets. - creator_->set_max_packets_per_fec_group(2); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Send two packets so that when this data is consumed, two packets are sent - // out. In FEC_TRIGGER_ANY, this will cause an FEC packet to be sent out and - // with FEC_TRIGGER_ALARM, this will cause a Reset to be called. In both - // cases, the creator's fec protection will be turned off afterwards. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER, but FEC - // group is closed. - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - // Fin Packet. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - size_t data_len = 2 * kDefaultMaxPacketSize; - QuicConsumedData consumed = generator_.ConsumeData( - 5, CreateData(data_len), 0, true, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - CheckPacketHasSingleStreamFrame(0); - CheckPacketHasSingleStreamFrame(1); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - // FEC packet is not sent when send policy is FEC_ALARM_TRIGGER. - CheckPacketHasSingleStreamFrame(2); - } else { - // FEC packet is sent after 2 packets and when send policy is - // FEC_ANY_TRIGGER. - CheckPacketIsFec(2, 1); - CheckPacketHasSingleStreamFrame(3); - } - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Do the same send (with MUST_FEC_PROTECT) on a different stream id. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - // FEC packet is sent after 2 packets and when send policy is - // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed - // and FEC packet is not sent. - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - // FEC packet is sent after 2 packets and when send policy is - // FEC_ANY_TRIGGER. When policy is FEC_ALARM_TRIGGER, FEC group is closed - // and FEC packet is not sent. - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - EXPECT_CALL(delegate_, OnResetFecGroup()).Times(1); - } else { - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - } - consumed = generator_.ConsumeData(7, CreateData(data_len), 0, true, - MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketHasSingleStreamFrame(3); - CheckPacketHasSingleStreamFrame(4); - CheckPacketHasSingleStreamFrame(5); - } else { - CheckPacketHasSingleStreamFrame(4); - // FEC packet is sent after 2 packets and when send policy is - // FEC_ANY_TRIGGER. - CheckPacketIsFec(5, 4); - CheckPacketHasSingleStreamFrame(6); - CheckPacketHasSingleStreamFrame(7); - // FEC packet is sent after 2 packets and when send policy is - // FEC_ANY_TRIGGER. - CheckPacketIsFec(8, 7); - } - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Do the another send (with MAY_FEC_PROTECT) on a different stream id, which - // should not produce an FEC packet because the last FEC group has been - // closed. - { - InSequence dummy; - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - } - consumed = generator_.ConsumeData(9, CreateData(data_len), 0, true, - MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(data_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_FALSE(generator_.HasQueuedFrames()); - if (generator_.fec_send_policy() == FEC_ALARM_TRIGGER) { - CheckPacketHasSingleStreamFrame(6); - CheckPacketHasSingleStreamFrame(7); - CheckPacketHasSingleStreamFrame(8); - } else { - CheckPacketHasSingleStreamFrame(9); - CheckPacketHasSingleStreamFrame(10); - CheckPacketHasSingleStreamFrame(11); - } - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); -} - -// 1. Create and send one packet with MUST_FEC_PROTECT. -// 2. Call FecTimeout, expect FEC packet is sent. -// 3. Do the same thing over again, with a different stream id. -TEST_P(QuicPacketGeneratorTest, FecPacketSentOnFecTimeout) { - delegate_.SetCanWriteAnything(); - creator_->set_max_packets_per_fec_group(1000); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - for (int i = 1; i < 4; i = i + 2) { - // Send data with MUST_FEC_PROTECT flag. No FEC packet is emitted, but the - // creator FEC protects all data. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - QuicConsumedData consumed = generator_.ConsumeData( - i + 2, CreateData(1u), 0, true, MUST_FEC_PROTECT, nullptr); - EXPECT_EQ(1u, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - CheckPacketHasSingleStreamFrame(0); - EXPECT_TRUE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - - // Calling OnFecTimeout should cause the FEC packet to be emitted. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - generator_.OnFecTimeout(); - CheckPacketIsFec(i, i); - EXPECT_FALSE(QuicPacketCreatorPeer::IsFecProtected(creator_)); - } -} - -TEST_P(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { +TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations) { delegate_.SetCanNotWrite(); generator_.SetShouldSendAck(false); @@ -1302,8 +499,7 @@ EXPECT_CALL(delegate_, PopulateAckFrame(_)); // Send some data and a control frame - generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, MAY_FEC_PROTECT, - nullptr); + generator_.ConsumeData(3, MakeIOVector("quux"), 7, false, nullptr); generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame())); // All five frames will be flushed out in a single packet. @@ -1320,7 +516,7 @@ CheckPacketContains(contents, 0); } -TEST_P(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { +TEST_F(QuicPacketGeneratorTest, NotWritableThenBatchOperations2) { delegate_.SetCanNotWrite(); generator_.SetShouldSendAck(false); @@ -1345,8 +541,8 @@ // Send enough data to exceed one packet size_t data_len = kDefaultMaxPacketSize + 100; - QuicConsumedData consumed = generator_.ConsumeData( - 3, CreateData(data_len), 0, true, MAY_FEC_PROTECT, nullptr); + QuicConsumedData consumed = + generator_.ConsumeData(3, CreateData(data_len), 0, true, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); generator_.AddControlFrame(QuicFrame(CreateGoAwayFrame())); @@ -1368,7 +564,7 @@ CheckPacketContains(contents2, 1); } -TEST_P(QuicPacketGeneratorTest, TestConnectionIdLength) { +TEST_F(QuicPacketGeneratorTest, TestConnectionIdLength) { generator_.SetConnectionIdLength(0); EXPECT_EQ(PACKET_0BYTE_CONNECTION_ID, creator_->connection_id_length()); generator_.SetConnectionIdLength(1); @@ -1393,14 +589,14 @@ // Test whether SetMaxPacketLength() works in the situation when the queue is // empty, and we send three packets worth of data. -TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) { +TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Initial) { delegate_.SetCanWriteAnything(); // Send enough data for three packets. size_t data_len = 3 * kDefaultMaxPacketSize + 1; size_t packet_len = kDefaultMaxPacketSize + 100; ASSERT_LE(packet_len, kMaxPacketSize); - generator_.SetMaxPacketLength(packet_len, /*force=*/false); + generator_.SetMaxPacketLength(packet_len); EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); EXPECT_CALL(delegate_, OnSerializedPacket(_)) @@ -1409,7 +605,7 @@ QuicConsumedData consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), /*offset=*/2, - /*fin=*/true, MAY_FEC_PROTECT, nullptr); + /*fin=*/true, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1426,7 +622,7 @@ // Test whether SetMaxPacketLength() works in the situation when we first write // data, then change packet size, then write data again. -TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) { +TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_Middle) { delegate_.SetCanWriteAnything(); // We send enough data to overflow default packet length, but not the altered @@ -1444,7 +640,7 @@ QuicConsumedData consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), /*offset=*/2, - /*fin=*/false, MAY_FEC_PROTECT, nullptr); + /*fin=*/false, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1453,13 +649,13 @@ ASSERT_EQ(2u, packets_.size()); // Increase packet size. - generator_.SetMaxPacketLength(packet_len, /*force=*/false); + generator_.SetMaxPacketLength(packet_len); EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); // Send a packet after packet size change. consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), 2 + data_len, - /*fin=*/true, MAY_FEC_PROTECT, nullptr); + /*fin=*/true, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1472,63 +668,9 @@ CheckAllPacketsHaveSingleStreamFrame(); } -// Test whether SetMaxPacketLength() works correctly when we change the packet -// size in the middle of the batched packet. -TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_Midpacket) { - delegate_.SetCanWriteAnything(); - generator_.StartBatchOperations(); - - size_t first_write_len = kDefaultMaxPacketSize / 2; - size_t second_write_len = kDefaultMaxPacketSize; - size_t packet_len = kDefaultMaxPacketSize + 100; - ASSERT_LE(packet_len, kMaxPacketSize); - - // First send half of the packet worth of data. We are in the batch mode, so - // should not cause packet serialization. - QuicConsumedData consumed = - generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len), - /*offset=*/2, - /*fin=*/false, MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(first_write_len, consumed.bytes_consumed); - EXPECT_FALSE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasQueuedFrames()); - - // Make sure we have no packets so far. - ASSERT_EQ(0u, packets_.size()); - - // Increase packet size. Ensure it's not immediately enacted. - generator_.SetMaxPacketLength(packet_len, /*force=*/false); - EXPECT_EQ(packet_len, generator_.GetMaxPacketLength()); - EXPECT_EQ(kDefaultMaxPacketSize, generator_.GetCurrentMaxPacketLength()); - - // We expect to see exactly one packet serialized after that, since we are in - // batch mode and we have sent approximately 3/2 of our MTU. - EXPECT_CALL(delegate_, OnSerializedPacket(_)) - .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - - // Send a packet worth of data to the same stream. This should trigger - // serialization of other packet. - consumed = - generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len), - /*offset=*/2 + first_write_len, - /*fin=*/true, MAY_FEC_PROTECT, nullptr); - EXPECT_EQ(second_write_len, consumed.bytes_consumed); - EXPECT_TRUE(consumed.fin_consumed); - EXPECT_TRUE(generator_.HasQueuedFrames()); - - // We expect the first packet to contain two frames, and to not reflect the - // packet size change. - ASSERT_EQ(1u, packets_.size()); - EXPECT_EQ(kDefaultMaxPacketSize, packets_[0].encrypted_length); - - PacketContents contents; - contents.num_stream_frames = 2; - CheckPacketContains(contents, 0); -} - // Test whether SetMaxPacketLength() works correctly when we force the change of // the packet size in the middle of the batched packet. -TEST_P(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) { +TEST_F(QuicPacketGeneratorTest, SetMaxPacketLength_MidpacketFlush) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); @@ -1542,7 +684,7 @@ QuicConsumedData consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(first_write_len), /*offset=*/2, - /*fin=*/false, MAY_FEC_PROTECT, nullptr); + /*fin=*/false, nullptr); EXPECT_EQ(first_write_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); @@ -1554,9 +696,10 @@ EXPECT_CALL(delegate_, OnSerializedPacket(_)) .WillOnce(Invoke(this, &QuicPacketGeneratorTest::SavePacket)); - // Increase packet size. Ensure it's immediately enacted. - generator_.SetMaxPacketLength(packet_len, /*force=*/true); - EXPECT_EQ(packet_len, generator_.GetMaxPacketLength()); + // Increase packet size after flushing all frames. + // Ensure it's immediately enacted. + generator_.FlushAllQueuedFrames(); + generator_.SetMaxPacketLength(packet_len); EXPECT_EQ(packet_len, generator_.GetCurrentMaxPacketLength()); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1571,7 +714,7 @@ consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(second_write_len), /*offset=*/2 + first_write_len, - /*fin=*/true, MAY_FEC_PROTECT, nullptr); + /*fin=*/true, nullptr); EXPECT_EQ(second_write_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames()); @@ -1586,7 +729,7 @@ } // Test sending an MTU probe, without any surrounding data. -TEST_P(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) { +TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_Simple) { delegate_.SetCanWriteAnything(); const size_t target_mtu = kDefaultMaxPacketSize + 100; @@ -1609,7 +752,7 @@ // Test sending an MTU probe. Surround it with data, to ensure that it resets // the MTU to the value before the probe was sent. -TEST_P(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) { +TEST_F(QuicPacketGeneratorTest, GenerateMtuDiscoveryPacket_SurroundedByData) { delegate_.SetCanWriteAnything(); const size_t target_mtu = kDefaultMaxPacketSize + 100; @@ -1629,7 +772,7 @@ QuicConsumedData consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), /*offset=*/2, - /*fin=*/false, MAY_FEC_PROTECT, nullptr); + /*fin=*/false, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_FALSE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1641,7 +784,7 @@ // Send data after the MTU probe. consumed = generator_.ConsumeData(kHeadersStreamId, CreateData(data_len), /*offset=*/2 + data_len, - /*fin=*/true, MAY_FEC_PROTECT, nullptr); + /*fin=*/true, nullptr); EXPECT_EQ(data_len, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_FALSE(generator_.HasQueuedFrames()); @@ -1661,7 +804,7 @@ CheckPacketHasSingleStreamFrame(4); } -TEST_P(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) { +TEST_F(QuicPacketGeneratorTest, DontCrashOnInvalidStopWaiting) { // Test added to ensure the generator does not crash when an invalid frame is // added. Because this is an indication of internal programming errors, // DFATALs are expected. @@ -1689,12 +832,12 @@ "for least_unacked_delta: 1001"); } -TEST_P(QuicPacketGeneratorTest, SetCurrentPath) { +TEST_F(QuicPacketGeneratorTest, SetCurrentPath) { delegate_.SetCanWriteAnything(); generator_.StartBatchOperations(); QuicConsumedData consumed = generator_.ConsumeData( - kHeadersStreamId, MakeIOVector("foo"), 2, true, MAY_FEC_PROTECT, nullptr); + kHeadersStreamId, MakeIOVector("foo"), 2, true, nullptr); EXPECT_EQ(3u, consumed.bytes_consumed); EXPECT_TRUE(consumed.fin_consumed); EXPECT_TRUE(generator_.HasQueuedFrames());
diff --git a/net/quic/quic_protocol.cc b/net/quic/quic_protocol.cc index 7de88d7..d41f8f9 100644 --- a/net/quic/quic_protocol.cc +++ b/net/quic/quic_protocol.cc
@@ -19,41 +19,33 @@ const char* const kFinalOffsetHeaderKey = ":final-offset"; size_t GetPacketHeaderSize(const QuicPacketHeader& header) { - return GetPacketHeaderSize( - header.public_header.connection_id_length, - header.public_header.version_flag, header.public_header.multipath_flag, - header.public_header.packet_number_length, header.is_in_fec_group); + return GetPacketHeaderSize(header.public_header.connection_id_length, + header.public_header.version_flag, + header.public_header.multipath_flag, + header.public_header.packet_number_length); } size_t GetPacketHeaderSize(QuicConnectionIdLength connection_id_length, bool include_version, bool include_path_id, - QuicPacketNumberLength packet_number_length, - InFecGroup is_in_fec_group) { + QuicPacketNumberLength packet_number_length) { return kPublicFlagsSize + connection_id_length + (include_version ? kQuicVersionSize : 0) + (include_path_id ? kQuicPathIdSize : 0) + packet_number_length + - kPrivateFlagsSize + - (is_in_fec_group == IN_FEC_GROUP ? kFecGroupSize : 0); + kPrivateFlagsSize; } -size_t GetStartOfFecProtectedData(QuicConnectionIdLength connection_id_length, - bool include_version, - bool include_path_id, - QuicPacketNumberLength packet_number_length) { - return GetPacketHeaderSize(connection_id_length, include_version, - include_path_id, packet_number_length, - IN_FEC_GROUP); +size_t GetStartOfEncryptedData(const QuicPacketHeader& header) { + return GetPacketHeaderSize(header) - kPrivateFlagsSize; } size_t GetStartOfEncryptedData(QuicConnectionIdLength connection_id_length, bool include_version, bool include_path_id, QuicPacketNumberLength packet_number_length) { - // Don't include the fec size, since encryption starts before private flags. + // Encryption starts before private flags. return GetPacketHeaderSize(connection_id_length, include_version, - include_path_id, packet_number_length, - NOT_IN_FEC_GROUP) - + include_path_id, packet_number_length) - kPrivateFlagsSize; } @@ -296,8 +288,7 @@ entropy_hash(0), is_truncated(false), largest_observed(0), - ack_delay_time(QuicTime::Delta::Infinite()), - latest_revived_packet(0) {} + ack_delay_time(QuicTime::Delta::Infinite()) {} QuicAckFrame::QuicAckFrame(const QuicAckFrame& other) = default; @@ -533,7 +524,6 @@ << " ack_delay_time: " << ack_frame.ack_delay_time.ToMicroseconds() << " missing_packets: [ " << ack_frame.missing_packets << " ] is_truncated: " << ack_frame.is_truncated - << " revived_packet: " << ack_frame.latest_revived_packet << " received_packets: [ "; for (const std::pair<QuicPacketNumber, QuicTime>& p : ack_frame.received_packet_times) { @@ -702,13 +692,6 @@ bool owns_buffer) : QuicData(buffer, length, owns_buffer) {} -StringPiece QuicPacket::FecProtectedData() const { - const size_t start_of_fec = - GetStartOfFecProtectedData(connection_id_length_, includes_version_, - includes_path_id_, packet_number_length_); - return StringPiece(data() + start_of_fec, length() - start_of_fec); -} - StringPiece QuicPacket::AssociatedData() const { return StringPiece(data(), GetStartOfEncryptedData( connection_id_length_, includes_version_, @@ -751,7 +734,6 @@ packet_number_length(packet_number_length), encryption_level(ENCRYPTION_NONE), entropy_hash(entropy_hash), - is_fec_packet(false), has_ack(has_ack), has_stop_waiting(has_stop_waiting), original_packet_number(0), @@ -781,7 +763,6 @@ transmission_type(NOT_RETRANSMISSION), in_flight(false), is_unackable(false), - is_fec_packet(false), has_crypto_handshake(false), needs_padding(false), retransmission(0) {} @@ -791,7 +772,6 @@ TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, - bool is_fec_packet, bool has_crypto_handshake, bool needs_padding) : encryption_level(level), @@ -802,7 +782,6 @@ transmission_type(transmission_type), in_flight(false), is_unackable(false), - is_fec_packet(is_fec_packet), has_crypto_handshake(has_crypto_handshake), needs_padding(needs_padding), retransmission(0) {}
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h index 1b275cb..25fa411 100644 --- a/net/quic/quic_protocol.h +++ b/net/quic/quic_protocol.h
@@ -140,6 +140,9 @@ // Maximum delayed ack time, in ms. const int64_t kMaxDelayedAckTimeMs = 25; +// Minimum tail loss probe time in ms. +static const int64_t kMinTailLossProbeTimeoutMs = 10; + // The timeout before the handshake succeeds. const int64_t kInitialIdleTimeoutSecs = 5; // The default idle timeout. @@ -234,26 +237,6 @@ NET_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os, const Perspective& s); -// Indicates FEC protection level for data being written. -enum FecProtection { - MUST_FEC_PROTECT, // Callee must FEC protect this data. - MAY_FEC_PROTECT // Callee does not have to but may FEC protect this data. -}; - -// Indicates FEC policy. -enum FecPolicy { - FEC_PROTECT_ALWAYS, // All data in the stream should be FEC protected. - FEC_PROTECT_OPTIONAL // Data in the stream does not need FEC protection. -}; - -// Indicates FEC policy about when to send FEC packet. -enum FecSendPolicy { - // Send FEC packet when FEC group is full or when FEC alarm goes off. - FEC_ANY_TRIGGER, - // Send FEC packet only when FEC alarm goes off. - FEC_ALARM_TRIGGER -}; - enum QuicFrameType { // Regular frame types. The values set here cannot change without the // introduction of a new QUIC version. @@ -426,25 +409,20 @@ NET_EXPORT_PRIVATE bool ContainsQuicTag(const QuicTagVector& tag_vector, QuicTag tag); -// Size in bytes of the data or fec packet header. +// Size in bytes of the data packet header. NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(const QuicPacketHeader& header); NET_EXPORT_PRIVATE size_t GetPacketHeaderSize(QuicConnectionIdLength connection_id_length, bool include_version, bool include_path_id, - QuicPacketNumberLength packet_number_length, - InFecGroup is_in_fec_group); - -// Index of the first byte in a QUIC packet of FEC protected data. -NET_EXPORT_PRIVATE size_t -GetStartOfFecProtectedData(QuicConnectionIdLength connection_id_length, - bool include_version, - bool include_path_id, - QuicPacketNumberLength packet_number_length); + QuicPacketNumberLength packet_number_length); // Index of the first byte in a QUIC packet of encrypted data. NET_EXPORT_PRIVATE size_t +GetStartOfEncryptedData(const QuicPacketHeader& header); + +NET_EXPORT_PRIVATE size_t GetStartOfEncryptedData(QuicConnectionIdLength connection_id_length, bool include_version, bool include_path_id, @@ -709,7 +687,7 @@ // An integer which cannot be a packet number. const QuicPacketNumber kInvalidPacketNumber = 0; -// Header for Data or FEC packets. +// Header for Data packets. struct NET_EXPORT_PRIVATE QuicPacketHeader { QuicPacketHeader(); explicit QuicPacketHeader(const QuicPacketPublicHeader& header); @@ -998,10 +976,6 @@ // The set of packets which we're expecting and have not received. PacketNumberQueue missing_packets; - - // Packet most recently revived via FEC, 0 if no packet was revived by FEC. - // If non-zero, must be present in missing_packets. - QuicPacketNumber latest_revived_packet; }; // True if the packet number is greater than largest_observed or is listed @@ -1235,7 +1209,6 @@ bool includes_path_id, QuicPacketNumberLength packet_number_length); - base::StringPiece FecProtectedData() const; base::StringPiece AssociatedData() const; base::StringPiece Plaintext() const; @@ -1326,7 +1299,6 @@ QuicPacketNumberLength packet_number_length; EncryptionLevel encryption_level; QuicPacketEntropyHash entropy_hash; - bool is_fec_packet; bool has_ack; bool has_stop_waiting; QuicPacketNumber original_packet_number; @@ -1347,7 +1319,6 @@ TransmissionType transmission_type, QuicTime sent_time, QuicPacketLength bytes_sent, - bool is_fec_packet, bool has_crypto_handshake, bool needs_padding); @@ -1367,8 +1338,6 @@ bool in_flight; // True if the packet can never be acked, so it can be removed. bool is_unackable; - // True if the packet is an FEC packet. - bool is_fec_packet; // True if the packet contains stream data from the crypto stream. bool has_crypto_handshake; // True if the packet needs padding if it's retransmitted.
diff --git a/net/quic/quic_received_packet_manager.cc b/net/quic/quic_received_packet_manager.cc index 984aa6f..aa3c9fd 100644 --- a/net/quic/quic_received_packet_manager.cc +++ b/net/quic/quic_received_packet_manager.cc
@@ -178,18 +178,6 @@ ack_frame_.received_packet_times.push_back( std::make_pair(packet_number, receipt_time)); - - if (ack_frame_.latest_revived_packet == packet_number) { - ack_frame_.latest_revived_packet = 0; - } -} - -void QuicReceivedPacketManager::RecordPacketRevived( - QuicPacketNumber packet_number) { - QUIC_BUG_IF(!IsAwaitingPacket(packet_number)) << base::StringPrintf( - "Not waiting for %llu", static_cast<unsigned long long>(packet_number)); - ack_frame_updated_ = true; - ack_frame_.latest_revived_packet = packet_number; } bool QuicReceivedPacketManager::IsMissing(QuicPacketNumber packet_number) { @@ -259,9 +247,6 @@ bool QuicReceivedPacketManager::DontWaitForPacketsBefore( QuicPacketNumber least_unacked) { - if (ack_frame_.latest_revived_packet < least_unacked) { - ack_frame_.latest_revived_packet = 0; - } return ack_frame_.missing_packets.RemoveUpTo(least_unacked); } @@ -287,6 +272,10 @@ ack_frame_.missing_packets.Min() >= peer_least_packet_awaiting_ack_); } +bool QuicReceivedPacketManager::HasMissingPackets() const { + return !ack_frame_.missing_packets.Empty(); +} + bool QuicReceivedPacketManager::HasNewMissingPackets() const { return !ack_frame_.missing_packets.Empty() && (ack_frame_.largest_observed - ack_frame_.missing_packets.Max()) <=
diff --git a/net/quic/quic_received_packet_manager.h b/net/quic/quic_received_packet_manager.h index 404f24fd..173e47f 100644 --- a/net/quic/quic_received_packet_manager.h +++ b/net/quic/quic_received_packet_manager.h
@@ -109,8 +109,6 @@ const QuicPacketHeader& header, QuicTime receipt_time); - virtual void RecordPacketRevived(QuicPacketNumber packet_number); - // Checks whether |packet_number| is missing and less than largest observed. virtual bool IsMissing(QuicPacketNumber packet_number); @@ -131,6 +129,9 @@ virtual void UpdatePacketInformationSentByPeer( const QuicStopWaitingFrame& stop_waiting); + // Returns true if there are any missing packets. + bool HasMissingPackets() const; + // Returns true when there are new missing packets to be reported within 3 // packets of the largest observed. virtual bool HasNewMissingPackets() const;
diff --git a/net/quic/quic_received_packet_manager_test.cc b/net/quic/quic_received_packet_manager_test.cc index 4f2443c..535ddab4 100644 --- a/net/quic/quic_received_packet_manager_test.cc +++ b/net/quic/quic_received_packet_manager_test.cc
@@ -203,10 +203,6 @@ received_manager_.RecordPacketReceived(0u, header, receipt_time); } - void RecordPacketRevived(QuicPacketNumber packet_number) { - received_manager_.RecordPacketRevived(packet_number); - } - QuicConnectionStats stats_; QuicReceivedPacketManager received_manager_; }; @@ -354,57 +350,6 @@ EXPECT_EQ(1u, stats_.packets_reordered); } -TEST_F(QuicReceivedPacketManagerTest, RevivedPacket) { - EXPECT_FALSE(received_manager_.ack_frame_updated()); - RecordPacketReceipt(1, 0); - EXPECT_TRUE(received_manager_.ack_frame_updated()); - RecordPacketReceipt(3, 0); - RecordPacketRevived(2); - - QuicAckFrame ack; - received_manager_.UpdateReceivedPacketInfo(&ack, QuicTime::Zero()); - EXPECT_FALSE(received_manager_.ack_frame_updated()); - EXPECT_EQ(1u, ack.missing_packets.NumPacketsSlow()); - EXPECT_EQ(2u, ack.missing_packets.Min()); - EXPECT_EQ(2u, ack.latest_revived_packet); -} - -TEST_F(QuicReceivedPacketManagerTest, PacketRevivedThenReceived) { - EXPECT_FALSE(received_manager_.ack_frame_updated()); - RecordPacketReceipt(1, 0); - EXPECT_TRUE(received_manager_.ack_frame_updated()); - RecordPacketReceipt(3, 0); - RecordPacketRevived(2); - RecordPacketReceipt(2, 0); - - QuicAckFrame ack; - received_manager_.UpdateReceivedPacketInfo(&ack, QuicTime::Zero()); - EXPECT_TRUE(ack.missing_packets.Empty()); - EXPECT_EQ(0u, ack.latest_revived_packet); -} - -TEST_F(QuicReceivedPacketManagerTest, RevivedPacketAckFrameUpdated) { - EXPECT_FALSE(received_manager_.ack_frame_updated()); - RecordPacketReceipt(1, 0); - RecordPacketReceipt(3, 0); - EXPECT_TRUE(received_manager_.ack_frame_updated()); - - QuicAckFrame ack; - received_manager_.UpdateReceivedPacketInfo(&ack, QuicTime::Zero()); - EXPECT_FALSE(received_manager_.ack_frame_updated()); - EXPECT_EQ(1u, ack.missing_packets.NumPacketsSlow()); - EXPECT_EQ(2u, ack.missing_packets.Min()); - EXPECT_EQ(0u, ack.latest_revived_packet); - - RecordPacketRevived(2); - EXPECT_TRUE(received_manager_.ack_frame_updated()); - received_manager_.UpdateReceivedPacketInfo(&ack, QuicTime::Zero()); - EXPECT_FALSE(received_manager_.ack_frame_updated()); - EXPECT_EQ(1u, ack.missing_packets.NumPacketsSlow()); - EXPECT_EQ(2u, ack.missing_packets.Min()); - EXPECT_EQ(2u, ack.latest_revived_packet); -} - } // namespace } // namespace test } // namespace net
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc index fbe446b2..2bdd196 100644 --- a/net/quic/quic_sent_packet_manager.cc +++ b/net/quic/quic_sent_packet_manager.cc
@@ -47,7 +47,6 @@ // Sends up to two tail loss probes before firing an RTO, // per draft RFC draft-dukkipati-tcpm-tcp-loss-probe. static const size_t kDefaultMaxTailLossProbes = 2; -static const int64_t kMinTailLossProbeTimeoutMs = 10; // Number of unpaced packets to send after quiescence. static const size_t kInitialUnpacedBurst = 10; @@ -322,12 +321,6 @@ } MarkPacketHandled(packet_number, &(*it), ack_delay_time); } - - // Discard any retransmittable frames associated with revived packets. - if (ack_frame.latest_revived_packet != 0) { - MarkPacketNotRetransmittable(ack_frame.latest_revived_packet, - ack_delay_time); - } } bool QuicSentPacketManager::HasRetransmittableFrames( @@ -346,9 +339,6 @@ (retransmission_type == ALL_UNACKED_RETRANSMISSION || it->encryption_level == ENCRYPTION_INITIAL)) { MarkForRetransmission(packet_number, retransmission_type); - } else if (it->is_fec_packet) { - // Remove FEC packets from the packet map, since we can't retransmit them. - unacked_packets_.RemoveFromInFlight(packet_number); } } } @@ -487,8 +477,6 @@ pending_retransmissions_.erase(newest_transmission); } - // The AckListener needs to be notified for revived packets, - // since it indicates the packet arrived from the appliction's perspective. unacked_packets_.NotifyAndClearListeners(newest_transmission, ack_delay_time); unacked_packets_.RemoveRetransmittability(packet_number); } @@ -568,16 +556,10 @@ --pending_timer_transmission_count_; } - // Only track packets as in flight that the send algorithm wants us to track. - // Since FEC packets should also be counted towards the congestion window, - // consider them as retransmittable for the purposes of congestion control. - HasRetransmittableData has_congestion_controlled_data = - serialized_packet->is_fec_packet ? HAS_RETRANSMITTABLE_DATA - : has_retransmittable_data; // TODO(ianswett): Remove sent_time, because it's unused. const bool in_flight = send_algorithm_->OnPacketSent( sent_time, unacked_packets_.bytes_in_flight(), packet_number, - serialized_packet->encrypted_length, has_congestion_controlled_data); + serialized_packet->encrypted_length, has_retransmittable_data); unacked_packets_.AddSentPacket(serialized_packet, original_packet_number, transmission_type, sent_time, in_flight); @@ -733,8 +715,8 @@ } else { // Since we will not retransmit this, we need to remove it from // unacked_packets_. This is either the current transmission of - // a packet whose previous transmission has been acked, a packet that - // has been TLP retransmitted, or an FEC packet. + // a packet whose previous transmission has been acked or a packet that + // has been TLP retransmitted. unacked_packets_.RemoveFromInFlight(pair.first); } }
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h index 15b12d6..af3b953 100644 --- a/net/quic/quic_sent_packet_manager.h +++ b/net/quic/quic_sent_packet_manager.h
@@ -133,7 +133,7 @@ // Processes the incoming ack. void OnIncomingAck(const QuicAckFrame& ack_frame, QuicTime ack_receive_time); - // Returns true if the non-FEC packet |packet_number| is unacked. + // Returns true if packet |packet_number| is unacked. bool IsUnacked(QuicPacketNumber packet_number) const; // Requests retransmission of all unacked packets of |retransmission_type|. @@ -337,7 +337,10 @@ QuicByteCount bytes_in_flight); // Called when frames of |packet_number| has been received but the packet - // itself has not been received by the peer (e.g., packet is revived by FEC). + // itself has not been received by the peer. Currently, this method is not + // used. + // TODO(fayang): Update the comment when multipath sent packet manager is + // landed. // The packet needs no longer to be retransmitted, but the packet remains // pending if it is and the congestion control does not consider the packet // acked. @@ -375,8 +378,8 @@ // RTT measurement purposes. void RemoveObsoletePackets(); - // Newly serialized retransmittable and fec packets are added to this map, - // which contains owning pointers to any contained frames. If a packet is + // Newly serialized retransmittable packets are added to this map, which + // contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new // packet. The old packet's retransmittable frames entry will be nullptr, // while the new packet's entry will contain the frames to retransmit.
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc index f8cfce7d..76de6ed 100644 --- a/net/quic/quic_sent_packet_manager_test.cc +++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -206,14 +206,6 @@ return packet; } - SerializedPacket CreateFecPacket(QuicPacketNumber packet_number) { - SerializedPacket serialized(kDefaultPathId, packet_number, - PACKET_6BYTE_PACKET_NUMBER, nullptr, - kDefaultLength, 0u, false, false); - serialized.is_fec_packet = true; - return serialized; - } - void SendDataPacket(QuicPacketNumber packet_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, _, _)) @@ -238,17 +230,6 @@ HAS_RETRANSMITTABLE_DATA); } - void SendFecPacket(QuicPacketNumber packet_number) { - EXPECT_CALL(*send_algorithm_, - OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, - HAS_RETRANSMITTABLE_DATA)) - .Times(1) - .WillOnce(Return(true)); - SerializedPacket packet(CreateFecPacket(packet_number)); - manager_.OnPacketSent(&packet, 0, clock_.Now(), NOT_RETRANSMISSION, - NO_RETRANSMITTABLE_DATA); - } - void SendAckPacket(QuicPacketNumber packet_number) { EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), packet_number, kDefaultLength, @@ -501,76 +482,6 @@ EXPECT_EQ(2u, stats_.packets_spuriously_retransmitted); } -TEST_F(QuicSentPacketManagerTest, LoseButDontRetransmitRevivedPacket) { - StrictMock<MockDebugDelegate> debug_delegate; - manager_.set_debug_delegate(&debug_delegate); - - SendDataPacket(1); - SendDataPacket(2); - SendFecPacket(3); - SendDataPacket(4); - - // Ack 2 and 3, and mark 1 as revived. - QuicAckFrame ack_frame; - ack_frame.largest_observed = 3; - ack_frame.missing_packets.Add(1); - ack_frame.latest_revived_packet = 1; - QuicPacketNumber acked[] = {2, 3}; - ExpectAcksAndLosses(true, acked, arraysize(acked), nullptr, 0); - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); - - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - QuicPacketNumber unacked[] = {1, 4}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - EXPECT_TRUE(QuicSentPacketManagerPeer::HasPendingPackets(&manager_)); - QuicPacketNumber retransmittable[] = {4}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); - - // Ack the 4th packet and expect the 1st to be considered lost. - if (FLAGS_quic_log_loss_event) { - EXPECT_CALL(debug_delegate, OnPacketLoss(1, LOSS_RETRANSMISSION, _)); - } - ack_frame.largest_observed = 4; - ExpectAckAndLoss(true, 4, 1); - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); - - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - VerifyRetransmittablePackets(nullptr, 0); -} - -TEST_F(QuicSentPacketManagerTest, MarkLostThenReviveAndDontRetransmitPacket) { - SendDataPacket(1); - SendDataPacket(2); - SendDataPacket(3); - SendDataPacket(4); - SendFecPacket(5); - - // Ack 2, 3, and 4, and expect the 1st to be considered lost. - QuicAckFrame ack_frame; - ack_frame.largest_observed = 4; - ack_frame.missing_packets.Add(1); - QuicPacketNumber acked[] = {2, 3, 4}; - QuicPacketNumber lost[] = {1}; - ExpectAcksAndLosses(true, acked, arraysize(acked), lost, arraysize(lost)); - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); - - EXPECT_TRUE(manager_.HasPendingRetransmissions()); - QuicPacketNumber unacked[] = {1, 5}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - QuicPacketNumber retransmittable[] = {1}; - VerifyRetransmittablePackets(retransmittable, arraysize(retransmittable)); - - // Ack 5th packet (FEC) and revive 1st packet. 1st packet should now be - // removed from pending retransmissions map. - ack_frame.largest_observed = 5; - ack_frame.latest_revived_packet = 1; - ExpectAck(5); - manager_.OnIncomingAck(ack_frame, clock_.ApproximateNow()); - - EXPECT_FALSE(manager_.HasPendingRetransmissions()); - VerifyRetransmittablePackets(nullptr, 0); -} - TEST_F(QuicSentPacketManagerTest, AckPreviousTransmissionThenTruncatedAck) { SendDataPacket(1); RetransmitAndSendPacket(1, 2); @@ -618,53 +529,6 @@ EXPECT_EQ(1u, manager_.GetLeastUnacked()); } -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedUnackedFec) { - SendFecPacket(1); - EXPECT_EQ(1u, manager_.GetLeastUnacked()); -} - -TEST_F(QuicSentPacketManagerTest, GetLeastUnackedAndDiscard) { - VerifyUnackedPackets(nullptr, 0); - - SendFecPacket(1); - EXPECT_EQ(1u, manager_.GetLeastUnacked()); - - SendFecPacket(2); - EXPECT_EQ(1u, manager_.GetLeastUnacked()); - - SendFecPacket(3); - EXPECT_EQ(1u, manager_.GetLeastUnacked()); - - QuicPacketNumber unacked[] = {1, 2, 3}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyRetransmittablePackets(nullptr, 0); - - // Ack 2, so there's an rtt update. - ExpectAck(2); - QuicAckFrame ack_frame; - ack_frame.largest_observed = 2; - ack_frame.missing_packets.Add(1); - manager_.OnIncomingAck(ack_frame, clock_.Now()); - - EXPECT_EQ(1u, manager_.GetLeastUnacked()); -} - -TEST_F(QuicSentPacketManagerTest, GetSentTime) { - VerifyUnackedPackets(nullptr, 0); - - QuicTime sent_time = clock_.Now(); - SendFecPacket(1); - QuicTime sent_time2 = clock_.Now(); - SendFecPacket(2); - QuicPacketNumber unacked[] = {1, 2}; - VerifyUnackedPackets(unacked, arraysize(unacked)); - VerifyRetransmittablePackets(nullptr, 0); - - EXPECT_TRUE(manager_.HasUnackedPackets()); - EXPECT_EQ(sent_time, QuicSentPacketManagerPeer::GetSentTime(&manager_, 1)); - EXPECT_EQ(sent_time2, QuicSentPacketManagerPeer::GetSentTime(&manager_, 2)); -} - TEST_F(QuicSentPacketManagerTest, AckAckAndUpdateRtt) { SendDataPacket(1); SendAckPacket(2);
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc index d8ec06c..1d880fe 100644 --- a/net/quic/quic_session.cc +++ b/net/quic/quic_session.cc
@@ -239,16 +239,14 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* ack_notifier_delegate) { - if (FLAGS_quic_block_unencrypted_writes && !IsEncryptionEstablished() && - id != kCryptoStreamId) { + if (!IsEncryptionEstablished() && id != kCryptoStreamId) { // Do not let streams write without encryption. The calling stream will end // up write blocked until OnCanWrite is next called. return QuicConsumedData(0, false); } - QuicConsumedData data = connection_->SendStreamData( - id, iov, offset, fin, fec_protection, ack_notifier_delegate); + QuicConsumedData data = + connection_->SendStreamData(id, iov, offset, fin, ack_notifier_delegate); write_blocked_streams_.UpdateBytesForStream(id, data.bytes_consumed); return data; } @@ -530,9 +528,7 @@ // to QuicSession since it is the glue. case ENCRYPTION_FIRST_ESTABLISHED: // Given any streams blocked by encryption a chance to write. - if (FLAGS_quic_block_unencrypted_writes) { - OnCanWrite(); - } + OnCanWrite(); break; case ENCRYPTION_REESTABLISHED: @@ -540,9 +536,7 @@ // decrypted by the peer. connection_->RetransmitUnackedPackets(ALL_INITIAL_RETRANSMISSION); // Given any streams blocked by encryption a chance to write. - if (FLAGS_quic_block_unencrypted_writes) { - OnCanWrite(); - } + OnCanWrite(); break; case HANDSHAKE_CONFIRMED:
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h index e0e3e809..988c000d 100644 --- a/net/quic/quic_session.h +++ b/net/quic/quic_session.h
@@ -94,10 +94,7 @@ // Returns a pair with the number of bytes consumed from data, and a boolean // indicating if the fin bit was consumed. This does not indicate the data // has been sent on the wire: it may have been turned into a packet and queued - // if the socket was unexpectedly blocked. |fec_protection| indicates if - // data is to be FEC protected. Note that data that is sent immediately - // following MUST_FEC_PROTECT data may get protected by falling within the - // same FEC group. + // if the socket was unexpectedly blocked. // If provided, |ack_notifier_delegate| will be registered to be notified when // we have seen ACKs for all packets resulting from this call. virtual QuicConsumedData WritevData( @@ -105,7 +102,6 @@ QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* ack_notifier_delegate); // Called by streams when they want to close the stream in both directions.
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc index a0da6b9..268b5d2 100644 --- a/net/quic/quic_session_test.cc +++ b/net/quic/quic_session_test.cc
@@ -155,12 +155,11 @@ QuicIOVector data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* ack_notifier_delegate) override { QuicConsumedData consumed(data.total_length, fin); if (!writev_consumes_all_data_) { - consumed = QuicSession::WritevData(id, data, offset, fin, fec_protection, - ack_notifier_delegate); + consumed = + QuicSession::WritevData(id, data, offset, fin, ack_notifier_delegate); } QuicSessionPeer::GetWriteBlockedStreams(this)->UpdateBytesForStream( id, consumed.bytes_consumed); @@ -173,8 +172,7 @@ QuicConsumedData SendStreamData(QuicStreamId id) { struct iovec iov; - return WritevData(id, MakeIOVector("not empty", &iov), 0, true, - MAY_FEC_PROTECT, nullptr); + return WritevData(id, MakeIOVector("not empty", &iov), 0, true, nullptr); } QuicConsumedData SendLargeFakeData(QuicStreamId id, int bytes) { @@ -182,8 +180,7 @@ struct iovec iov; iov.iov_base = nullptr; // should not be read. iov.iov_len = static_cast<size_t>(bytes); - return WritevData(id, QuicIOVector(&iov, 1, bytes), 0, true, - MAY_FEC_PROTECT, nullptr); + return WritevData(id, QuicIOVector(&iov, 1, bytes), 0, true, nullptr); } using QuicSession::PostProcessAfterData; @@ -388,29 +385,19 @@ InSequence s; StreamBlocker stream2_blocker(&session_, stream2->id()); - if (FLAGS_quic_batch_writes) { - // Reregister, to test the loop limit. - EXPECT_CALL(*stream2, OnCanWrite()) - .WillOnce(Invoke(&stream2_blocker, - &StreamBlocker::MarkConnectionLevelWriteBlocked)); - // 2 will get called a second time as it didn't finish its block - EXPECT_CALL(*stream2, OnCanWrite()); - EXPECT_CALL(*stream6, OnCanWrite()); - // 4 will not get called, as we exceeded the loop limit. - } else { - // Reregister, to test the loop limit. - EXPECT_CALL(*stream2, OnCanWrite()) - .WillOnce(Invoke(&stream2_blocker, - &StreamBlocker::MarkConnectionLevelWriteBlocked)); - EXPECT_CALL(*stream6, OnCanWrite()); - EXPECT_CALL(*stream4, OnCanWrite()); - } + // Reregister, to test the loop limit. + EXPECT_CALL(*stream2, OnCanWrite()) + .WillOnce(Invoke(&stream2_blocker, + &StreamBlocker::MarkConnectionLevelWriteBlocked)); + // 2 will get called a second time as it didn't finish its block + EXPECT_CALL(*stream2, OnCanWrite()); + EXPECT_CALL(*stream6, OnCanWrite()); + // 4 will not get called, as we exceeded the loop limit. session_.OnCanWrite(); EXPECT_TRUE(session_.WillingAndAbleToWrite()); } TEST_P(QuicSessionTestServer, TestBatchedWrites) { - ValueRestore<bool> old_flag(&FLAGS_quic_batch_writes, true); TestStream* stream2 = session_.CreateOutgoingDynamicStream(kDefaultPriority); TestStream* stream4 = session_.CreateOutgoingDynamicStream(kDefaultPriority); TestStream* stream6 = session_.CreateOutgoingDynamicStream(kDefaultPriority);
diff --git a/net/quic/quic_spdy_stream.cc b/net/quic/quic_spdy_stream.cc index 75b160e..3486593 100644 --- a/net/quic/quic_spdy_stream.cc +++ b/net/quic/quic_spdy_stream.cc
@@ -10,6 +10,7 @@ #include "net/quic/quic_spdy_session.h" #include "net/quic/quic_utils.h" #include "net/quic/quic_write_blocked_list.h" +#include "net/quic/spdy_utils.h" using base::StringPiece; using std::min; @@ -213,7 +214,22 @@ return; } - OnStreamFrame(QuicStreamFrame(id(), fin, stream_bytes_read(), StringPiece())); + size_t final_byte_offset = 0; + SpdyHeaderBlock trailers; + if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(), + decompressed_trailers().length(), + &final_byte_offset, &response_trailers_)) { + DLOG(ERROR) << "Trailers are malformed: " << id(); + session()->connection()->SendConnectionCloseWithDetails( + QUIC_INVALID_HEADERS_STREAM_DATA, "Trailers are malformed"); + return; + } + + // The data on this stream ends at |final_byte_offset|. + DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset + << " currently read: " << stream_bytes_read(); + + OnStreamFrame(QuicStreamFrame(id(), fin, final_byte_offset, StringPiece())); trailers_decompressed_ = true; }
diff --git a/net/quic/quic_spdy_stream.h b/net/quic/quic_spdy_stream.h index 65304d66..a5adfe2 100644 --- a/net/quic/quic_spdy_stream.h +++ b/net/quic/quic_spdy_stream.h
@@ -141,6 +141,11 @@ return decompressed_trailers_; } + // Returns whatever trailers have been received for this stream. + const SpdyHeaderBlock& response_trailers() const { + return response_trailers_; + } + virtual SpdyPriority priority() const; // Sets priority_ to priority. This should only be called before bytes are @@ -182,6 +187,8 @@ // Contains a copy of the decompressed trailers until they are consumed // via ProcessData or Readv. std::string decompressed_trailers_; + // The parsed trailers received from the peer. + SpdyHeaderBlock response_trailers_; DISALLOW_COPY_AND_ASSIGN(QuicSpdyStream); };
diff --git a/net/quic/quic_spdy_stream_test.cc b/net/quic/quic_spdy_stream_test.cc index 54ebb8a..1e7abc6 100644 --- a/net/quic/quic_spdy_stream_test.cc +++ b/net/quic/quic_spdy_stream_test.cc
@@ -363,7 +363,7 @@ GenerateBody(&body, kWindow + kOverflow); EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)); - EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kWindow, true))); stream_->WriteOrBufferData(body, false, nullptr); @@ -609,7 +609,7 @@ bool fin = true; EXPECT_CALL(*connection_, SendBlocked(kClientDataStreamId1)).Times(0); - EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kClientDataStreamId1, _, _, _, _)) .WillOnce(Return(QuicConsumedData(0, fin))); stream_->WriteOrBufferData(body, fin, nullptr); @@ -631,6 +631,7 @@ trailers_block["key1"] = "value1"; trailers_block["key2"] = "value2"; trailers_block["key3"] = "value3"; + trailers_block[kFinalOffsetHeaderKey] = "0"; string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block); stream_->OnStreamHeaders(trailers); stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size()); @@ -709,6 +710,44 @@ stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size()); } +TEST_P(QuicSpdyStreamTest, ReceivingTrailersWithOffset) { + // Test that when receiving trailing headers with an offset before response + // body, stream is closed at the right offset. + Initialize(kShouldProcessData); + + // Receive initial headers. + string headers = SpdyUtils::SerializeUncompressedHeaders(headers_); + stream_->OnStreamHeaders(headers); + stream_->OnStreamHeadersComplete(false, headers.size()); + stream_->MarkHeadersConsumed(stream_->decompressed_headers().size()); + + const string body = "this is the body"; + // Receive trailing headers. + SpdyHeaderBlock trailers_block; + trailers_block["key1"] = "value1"; + trailers_block["key2"] = "value2"; + trailers_block["key3"] = "value3"; + trailers_block[kFinalOffsetHeaderKey] = base::IntToString(body.size()); + string trailers = SpdyUtils::SerializeUncompressedHeaders(trailers_block); + stream_->OnStreamHeaders(trailers); + stream_->OnStreamHeadersComplete(/*fin=*/true, trailers.size()); + + // The trailers should be decompressed, and readable from the stream. + EXPECT_TRUE(stream_->trailers_decompressed()); + const string decompressed_trailers = stream_->decompressed_trailers(); + EXPECT_EQ(trailers, decompressed_trailers); + // Consuming the trailers erases them from the stream. + stream_->MarkTrailersConsumed(decompressed_trailers.size()); + EXPECT_EQ("", stream_->decompressed_trailers()); + + EXPECT_FALSE(stream_->IsDoneReading()); + // Receive and consume body. + QuicStreamFrame frame(kClientDataStreamId1, /*fin=*/false, 0, body); + stream_->OnStreamFrame(frame); + EXPECT_EQ(body, stream_->data()); + EXPECT_TRUE(stream_->IsDoneReading()); +} + TEST_P(QuicSpdyStreamTest, ClosingStreamWithNoTrailers) { // Verify that a stream receiving headers, body, and no trailers is correctly // marked as done reading on consumption of headers and body. @@ -732,7 +771,7 @@ // Test that writing trailers will send a FIN, as Trailers are the last thing // to be sent on a stream. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -753,7 +792,7 @@ // Test that when writing trailers, the trailers that are actually sent to the // peer contain the final offset field indicating last byte of data. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -780,7 +819,7 @@ // Test that if trailers are written after all other data has been written // (headers and body), that this closes the stream for writing. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -805,7 +844,7 @@ // Test that the stream is not closed for writing when trailers are sent // while there are still body bytes queued. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -815,7 +854,7 @@ // Write non-zero body data, but only consume partially, ensuring queueing. const int kBodySize = 1 * 1024; // 1 MB - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kBodySize - 1, false))); stream_->WriteOrBufferData(string(kBodySize, 'x'), false, nullptr); EXPECT_EQ(1u, stream_->queued_data_bytes()); @@ -832,7 +871,7 @@ TEST_P(QuicSpdyStreamTest, WritingTrailersAfterFIN) { // Test that it is not possible to write Trailers after a FIN has been sent. Initialize(kShouldProcessData); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData));
diff --git a/net/quic/quic_unacked_packet_map.cc b/net/quic/quic_unacked_packet_map.cc index c8a32505..fc72388 100644 --- a/net/quic/quic_unacked_packet_map.cc +++ b/net/quic/quic_unacked_packet_map.cc
@@ -49,8 +49,7 @@ packet->has_crypto_handshake == IS_HANDSHAKE; TransmissionInfo info(packet->encryption_level, packet->packet_number_length, transmission_type, sent_time, bytes_sent, - packet->is_fec_packet, has_crypto_handshake, - packet->needs_padding); + has_crypto_handshake, packet->needs_padding); if (old_packet_number > 0) { TransferRetransmissionInfo(old_packet_number, packet_number, transmission_type, &info);
diff --git a/net/quic/quic_unacked_packet_map.h b/net/quic/quic_unacked_packet_map.h index 8ed6d0a0b..31fc7f43 100644 --- a/net/quic/quic_unacked_packet_map.h +++ b/net/quic/quic_unacked_packet_map.h
@@ -175,8 +175,8 @@ QuicPacketNumber largest_sent_packet_; QuicPacketNumber largest_observed_; - // Newly serialized retransmittable and fec packets are added to this map, - // which contains owning pointers to any contained frames. If a packet is + // Newly serialized retransmittable packets are added to this map, which + // contains owning pointers to any contained frames. If a packet is // retransmitted, this map will contain entries for both the old and the new // packet. The old packet's retransmittable frames entry will be nullptr, // while the new packet's entry will contain the frames to retransmit.
diff --git a/net/quic/quic_write_blocked_list.h b/net/quic/quic_write_blocked_list.h index d004452a..2988a9d 100644 --- a/net/quic/quic_write_blocked_list.h +++ b/net/quic/quic_write_blocked_list.h
@@ -135,7 +135,6 @@ return; } bool push_front = - FLAGS_quic_batch_writes && stream_id == batch_write_stream_id_[last_priority_popped_] && bytes_left_for_batch_write_[last_priority_popped_] > 0; priority_write_scheduler_.MarkStreamReady(stream_id, push_front);
diff --git a/net/quic/quic_write_blocked_list_test.cc b/net/quic/quic_write_blocked_list_test.cc index c970a2f..23009c068 100644 --- a/net/quic/quic_write_blocked_list_test.cc +++ b/net/quic/quic_write_blocked_list_test.cc
@@ -115,7 +115,6 @@ } TEST(QuicWriteBlockedListTest, BatchingWrites) { - ValueRestore<bool> old_flag(&FLAGS_quic_batch_writes, true); QuicWriteBlockedList write_blocked_list; const QuicStreamId id1 = kClientDataStreamId1;
diff --git a/net/quic/reliable_quic_stream.cc b/net/quic/reliable_quic_stream.cc index eea769d3..c4c7d5c 100644 --- a/net/quic/reliable_quic_stream.cc +++ b/net/quic/reliable_quic_stream.cc
@@ -66,7 +66,6 @@ fin_received_(false), rst_sent_(false), rst_received_(false), - fec_policy_(FEC_PROTECT_OPTIONAL), perspective_(session_->perspective()), flow_controller_(session_->connection(), id_, @@ -81,11 +80,7 @@ ReliableQuicStream::~ReliableQuicStream() {} -void ReliableQuicStream::SetFromConfig() { - if (session_->config()->HasClientSentConnectionOption(kFSTR, perspective_)) { - fec_policy_ = FEC_PROTECT_ALWAYS; - } -} +void ReliableQuicStream::SetFromConfig() {} void ReliableQuicStream::OnStreamFrame(const QuicStreamFrame& frame) { DCHECK_EQ(frame.stream_id, id_); @@ -311,9 +306,9 @@ write_length = static_cast<size_t>(send_window); } - QuicConsumedData consumed_data = session()->WritevData( - id(), QuicIOVector(iov, iov_count, write_length), stream_bytes_written_, - fin, GetFecProtection(), ack_listener); + QuicConsumedData consumed_data = + session()->WritevData(id(), QuicIOVector(iov, iov_count, write_length), + stream_bytes_written_, fin, ack_listener); stream_bytes_written_ += consumed_data.bytes_consumed; AddBytesSent(consumed_data.bytes_consumed); @@ -343,10 +338,6 @@ return consumed_data; } -FecProtection ReliableQuicStream::GetFecProtection() { - return fec_policy_ == FEC_PROTECT_ALWAYS ? MUST_FEC_PROTECT : MAY_FEC_PROTECT; -} - void ReliableQuicStream::CloseReadSide() { if (read_side_closed_) { return;
diff --git a/net/quic/reliable_quic_stream.h b/net/quic/reliable_quic_stream.h index 8e660b2..e0be70b 100644 --- a/net/quic/reliable_quic_stream.h +++ b/net/quic/reliable_quic_stream.h
@@ -50,7 +50,7 @@ virtual ~ReliableQuicStream(); - // Sets |fec_policy_| parameter from |session_|'s config. + // Not in use currently. void SetFromConfig(); // Called by the session when a (potentially duplicate) stream frame has been @@ -118,9 +118,6 @@ void set_fin_received(bool fin_received) { fin_received_ = fin_received; } void set_rst_sent(bool rst_sent) { rst_sent_ = rst_sent; } - void set_fec_policy(FecPolicy fec_policy) { fec_policy_ = fec_policy; } - FecPolicy fec_policy() const { return fec_policy_; } - void set_rst_received(bool rst_received) { rst_received_ = rst_received; } void set_stream_error(QuicRstStreamErrorCode error) { stream_error_ = error; } @@ -198,9 +195,6 @@ // Does not send a FIN. May cause the stream to be closed. virtual void CloseWriteSide(); - // Helper method that returns FecProtection to use when writing. - FecProtection GetFecProtection(); - bool fin_buffered() const { return fin_buffered_; } const QuicSession* session() const { return session_; } @@ -287,9 +281,6 @@ // True if this stream has received a RST_STREAM frame. bool rst_received_; - // FEC policy to be used for this stream. - FecPolicy fec_policy_; - // Tracks if the session this stream is running under was created by a // server or a client. Perspective perspective_;
diff --git a/net/quic/reliable_quic_stream_test.cc b/net/quic/reliable_quic_stream_test.cc index b0068954..8de1863 100644 --- a/net/quic/reliable_quic_stream_test.cc +++ b/net/quic/reliable_quic_stream_test.cc
@@ -141,7 +141,6 @@ QuicIOVector /*iov*/, QuicStreamOffset /*offset*/, bool /*fin*/, - FecProtection /*fec_protection*/, QuicAckListenerInterface* /*ack_notifier_delegate*/) { session_->CloseStream(id); return QuicConsumedData(1, false); @@ -163,13 +162,12 @@ TEST_F(ReliableQuicStreamTest, WriteAllData) { Initialize(kShouldProcessData); - size_t length = - 1 + QuicPacketCreator::StreamFramePacketOverhead( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, 0u, NOT_IN_FEC_GROUP); + size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead( + PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, 0u); connection_->SetMaxPacketLength(length); - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kDataLen, true))); stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_FALSE(HasWriteBlockedStreams()); @@ -189,7 +187,7 @@ // Write some data and no fin. If we consume some but not all of the data, // we should be write blocked a not all the data was consumed. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(1, false))); stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); @@ -203,7 +201,7 @@ // we should be write blocked because the fin was not consumed. // (This should never actually happen as the fin should be sent out with the // last data) - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(2, false))); stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); @@ -214,7 +212,7 @@ // Write no data and a fin. If we consume nothing we should be write blocked, // as the fin was not consumed. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(0, false))); stream_->WriteOrBufferData(StringPiece(), true, nullptr); ASSERT_EQ(1u, write_blocked_list_->NumBlockedStreams()); @@ -226,7 +224,7 @@ // Write some data and no fin. However, while writing the data // close the stream and verify that MarkConnectionLevelWriteBlocked does not // crash with an unknown stream. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Invoke(this, &ReliableQuicStreamTest::CloseStreamOnWriteError)); stream_->WriteOrBufferData(StringPiece(kData1, 2), false, nullptr); ASSERT_EQ(0u, write_blocked_list_->NumBlockedStreams()); @@ -236,13 +234,12 @@ Initialize(kShouldProcessData); EXPECT_FALSE(HasWriteBlockedStreams()); - size_t length = - 1 + QuicPacketCreator::StreamFramePacketOverhead( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, 0u, NOT_IN_FEC_GROUP); + size_t length = 1 + QuicPacketCreator::StreamFramePacketOverhead( + PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, + !kIncludePathId, PACKET_6BYTE_PACKET_NUMBER, 0u); connection_->SetMaxPacketLength(length); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kDataLen - 1, false))); stream_->WriteOrBufferData(kData1, false, nullptr); EXPECT_TRUE(HasWriteBlockedStreams()); @@ -252,86 +249,14 @@ // Make sure we get the tail of the first write followed by the bytes_consumed InSequence s; - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(1, false))); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); stream_->OnCanWrite(); // And finally the end of the bytes_consumed. - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) - .WillOnce(Return(QuicConsumedData(2, true))); - stream_->OnCanWrite(); -} - -TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectAlways) { - Initialize(kShouldProcessData); - - // Set FEC policy on stream. - ReliableQuicStreamPeer::SetFecPolicy(stream_, FEC_PROTECT_ALWAYS); - - EXPECT_FALSE(HasWriteBlockedStreams()); - size_t length = - 1 + QuicPacketCreator::StreamFramePacketOverhead( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, 0u, IN_FEC_GROUP); - connection_->SetMaxPacketLength(length); - - // Write first data onto stream, which will cause one session write. - EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 1, false))); - stream_->WriteOrBufferData(kData1, false, nullptr); - EXPECT_TRUE(HasWriteBlockedStreams()); - - // Queue a bytes_consumed write. - stream_->WriteOrBufferData(kData2, false, nullptr); - - // Make sure we get the tail of the first write followed by the bytes_consumed - InSequence s; - EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(1, false))); - EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); - stream_->OnCanWrite(); - - // And finally the end of the bytes_consumed. - EXPECT_CALL(*session_, WritevData(_, _, _, _, MUST_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(2, true))); - stream_->OnCanWrite(); -} - -TEST_F(ReliableQuicStreamTest, WriteOrBufferDataWithFecProtectOptional) { - Initialize(kShouldProcessData); - - // Set FEC policy on stream. - ReliableQuicStreamPeer::SetFecPolicy(stream_, FEC_PROTECT_OPTIONAL); - - EXPECT_FALSE(HasWriteBlockedStreams()); - size_t length = - 1 + QuicPacketCreator::StreamFramePacketOverhead( - PACKET_8BYTE_CONNECTION_ID, !kIncludeVersion, !kIncludePathId, - PACKET_6BYTE_PACKET_NUMBER, 0u, NOT_IN_FEC_GROUP); - connection_->SetMaxPacketLength(length); - - // Write first data onto stream, which will cause one session write. - EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 1, false))); - stream_->WriteOrBufferData(kData1, false, nullptr); - EXPECT_TRUE(HasWriteBlockedStreams()); - - // Queue a bytes_consumed write. - stream_->WriteOrBufferData(kData2, false, nullptr); - - // Make sure we get the tail of the first write followed by the bytes_consumed - InSequence s; - EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(1, false))); - EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)) - .WillOnce(Return(QuicConsumedData(kDataLen - 2, false))); - stream_->OnCanWrite(); - - // And finally the end of the bytes_consumed. - EXPECT_CALL(*session_, WritevData(_, _, _, _, MAY_FEC_PROTECT, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillOnce(Return(QuicConsumedData(2, true))); stream_->OnCanWrite(); } @@ -359,7 +284,7 @@ EXPECT_FALSE(rst_sent()); // Write some data, with no FIN. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(1, false))); stream_->WriteOrBufferData(StringPiece(kData1, 1), false, nullptr); EXPECT_FALSE(fin_sent()); @@ -382,7 +307,7 @@ EXPECT_FALSE(rst_sent()); // Write some data, with FIN. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(1, true))); stream_->WriteOrBufferData(StringPiece(kData1, 1), true, nullptr); EXPECT_TRUE(fin_sent()); @@ -476,26 +401,23 @@ scoped_refptr<QuicAckListenerInterface> ack_listener; - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &ack_listener))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &ack_listener))), Return(QuicConsumedData(kFirstWriteSize, false)))); stream_->WriteOrBufferData(kData, false, delegate.get()); EXPECT_TRUE(HasWriteBlockedStreams()); - EXPECT_CALL(*session_, - WritevData(kTestStreamId, _, _, _, _, ack_listener.get())) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, ack_listener.get())) .WillOnce(Return(QuicConsumedData(kSecondWriteSize, false))); stream_->OnCanWrite(); // No ack expected for an empty write. - EXPECT_CALL(*session_, - WritevData(kTestStreamId, _, _, _, _, ack_listener.get())) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, ack_listener.get())) .WillOnce(Return(QuicConsumedData(0, false))); stream_->OnCanWrite(); - EXPECT_CALL(*session_, - WritevData(kTestStreamId, _, _, _, _, ack_listener.get())) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, ack_listener.get())) .WillOnce(Return(QuicConsumedData(kLastWriteSize, false))); stream_->OnCanWrite(); } @@ -518,16 +440,16 @@ scoped_refptr<QuicAckListenerInterface> proxy_delegate; - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(kInitialWriteSize, false)))); stream_->WriteOrBufferData(kData, false, ack_listener.get()); EXPECT_TRUE(HasWriteBlockedStreams()); - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(kDataSize - kInitialWriteSize, false)))); stream_->OnCanWrite(); } @@ -540,9 +462,9 @@ scoped_refptr<QuicAckListenerInterface> proxy_delegate; - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(kDataLen, true)))); stream_->WriteOrBufferData(kData1, true, delegate.get()); EXPECT_FALSE(HasWriteBlockedStreams()); @@ -556,14 +478,14 @@ scoped_refptr<QuicAckListenerInterface> proxy_delegate; - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(0, false))); stream_->WriteOrBufferData(kData1, true, delegate.get()); EXPECT_TRUE(HasWriteBlockedStreams()); - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(kDataLen, true)))); stream_->OnCanWrite(); } @@ -577,16 +499,16 @@ scoped_refptr<QuicAckListenerInterface> proxy_delegate; - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(kDataLen, false)))); stream_->WriteOrBufferData(kData1, true, delegate.get()); EXPECT_TRUE(HasWriteBlockedStreams()); - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(DoAll( - WithArgs<5>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), + WithArgs<4>(Invoke(CreateFunctor(SaveAckListener, &proxy_delegate))), Return(QuicConsumedData(0, true)))); stream_->OnCanWrite(); } @@ -678,7 +600,7 @@ EXPECT_EQ(1u, session_->GetNumOpenIncomingStreams()); // Outgoing data with FIN. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(2, true))); stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr); EXPECT_TRUE(stream_->write_side_closed()); @@ -693,7 +615,7 @@ Initialize(kShouldNotProcessData); // Outgoing data with FIN. - EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(kTestStreamId, _, _, _, _)) .WillOnce(Return(QuicConsumedData(2, true))); stream_->WriteOrBufferData(StringPiece(kData1, 2), true, nullptr); EXPECT_TRUE(stream_->write_side_closed()); @@ -714,26 +636,13 @@ EXPECT_EQ(0u, session_->GetNumOpenIncomingStreams()); } -TEST_F(ReliableQuicStreamTest, FecSendPolicyReceivedConnectionOption) { - Initialize(kShouldProcessData); - - // Test ReceivedConnectionOptions. - QuicConfig* config = session_->config(); - QuicTagVector copt; - copt.push_back(kFSTR); - QuicConfigPeer::SetReceivedConnectionOptions(config, copt); - EXPECT_EQ(FEC_PROTECT_OPTIONAL, stream_->fec_policy()); - stream_->SetFromConfig(); - EXPECT_EQ(FEC_PROTECT_ALWAYS, stream_->fec_policy()); -} - TEST_F(ReliableQuicStreamTest, EarlyResponseFinHandling) { // Verify that if the server completes the response before reading the end of // the request, the received FIN is recorded. Initialize(kShouldProcessData); EXPECT_CALL(*connection_, SendConnectionCloseWithDetails(_, _)).Times(0); - EXPECT_CALL(*session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(*session_, WritevData(_, _, _, _, _)) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); // Receive data for the request.
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc index 4d18cca2..bb5f36b 100644 --- a/net/quic/test_tools/crypto_test_utils.cc +++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -136,11 +136,14 @@ QuicCryptoServerConfig crypto_config(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), ProofSourceForTesting()); + QuicCompressedCertsCache compressed_certs_cache( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize); SetupCryptoServerConfigForTest(server_conn->clock(), server_conn->random_generator(), &config, &crypto_config, options); - TestQuicSpdyServerSession server_session(server_conn, config, &crypto_config); + TestQuicSpdyServerSession server_session(server_conn, config, &crypto_config, + &compressed_certs_cache); // The client's handshake must have been started already. CHECK_NE(0u, client_conn->encrypted_packets_.size());
diff --git a/net/quic/test_tools/mock_quic_dispatcher.cc b/net/quic/test_tools/mock_quic_dispatcher.cc index 66b940b8..a3136519 100644 --- a/net/quic/test_tools/mock_quic_dispatcher.cc +++ b/net/quic/test_tools/mock_quic_dispatcher.cc
@@ -13,10 +13,7 @@ const QuicConfig& config, const QuicCryptoServerConfig* crypto_config, QuicConnectionHelperInterface* helper) - : QuicDispatcher(config, - crypto_config, - QuicSupportedVersions(), - helper) {} + : QuicDispatcher(config, crypto_config, QuicSupportedVersions(), helper) {} MockQuicDispatcher::~MockQuicDispatcher() {}
diff --git a/net/quic/test_tools/quic_connection_peer.cc b/net/quic/test_tools/quic_connection_peer.cc index f171bff8..8f16fc8d 100644 --- a/net/quic/test_tools/quic_connection_peer.cc +++ b/net/quic/test_tools/quic_connection_peer.cc
@@ -6,7 +6,6 @@ #include "base/stl_util.h" #include "net/quic/congestion_control/send_algorithm_interface.h" -#include "net/quic/quic_connection.h" #include "net/quic/quic_packet_writer.h" #include "net/quic/quic_received_packet_manager.h" #include "net/quic/test_tools/quic_framer_peer.h" @@ -151,13 +150,6 @@ } // static -QuicFecGroup* QuicConnectionPeer::GetFecGroup(QuicConnection* connection, - int fec_group) { - connection->last_header_.fec_group = fec_group; - return connection->GetFecGroup(); -} - -// static QuicAlarm* QuicConnectionPeer::GetAckAlarm(QuicConnection* connection) { return connection->ack_alarm_.get(); } @@ -168,11 +160,6 @@ } // static -QuicAlarm* QuicConnectionPeer::GetFecAlarm(QuicConnection* connection) { - return connection->fec_alarm_.get(); -} - -// static QuicAlarm* QuicConnectionPeer::GetResumeWritesAlarm( QuicConnection* connection) { return connection->resume_writes_alarm_.get(); @@ -268,8 +255,9 @@ } // static -void QuicConnectionPeer::EnableAckDecimation(QuicConnection* connection) { - connection->ack_decimation_enabled_ = true; +void QuicConnectionPeer::SetAckMode(QuicConnection* connection, + QuicConnection::AckMode ack_mode) { + connection->ack_mode_ = ack_mode; } } // namespace test
diff --git a/net/quic/test_tools/quic_connection_peer.h b/net/quic/test_tools/quic_connection_peer.h index 524eb159..d547dc4 100644 --- a/net/quic/test_tools/quic_connection_peer.h +++ b/net/quic/test_tools/quic_connection_peer.h
@@ -7,6 +7,7 @@ #include "base/macros.h" #include "net/base/ip_endpoint.h" +#include "net/quic/quic_connection.h" #include "net/quic/quic_connection_stats.h" #include "net/quic/quic_protocol.h" @@ -15,11 +16,9 @@ struct QuicAckFrame; struct QuicPacketHeader; class QuicAlarm; -class QuicConnection; class QuicConnectionHelperInterface; class QuicConnectionVisitorInterface; class QuicEncryptedPacket; -class QuicFecGroup; class QuicFramer; class QuicPacketCreator; class QuicPacketGenerator; @@ -88,12 +87,8 @@ static QuicFramer* GetFramer(QuicConnection* connection); - // Set last_header_->fec_group = fec_group and return connection->GetFecGroup - static QuicFecGroup* GetFecGroup(QuicConnection* connection, int fec_group); - static QuicAlarm* GetAckAlarm(QuicConnection* connection); static QuicAlarm* GetPingAlarm(QuicConnection* connection); - static QuicAlarm* GetFecAlarm(QuicConnection* connection); static QuicAlarm* GetResumeWritesAlarm(QuicConnection* connection); static QuicAlarm* GetRetransmissionAlarm(QuicConnection* connection); static QuicAlarm* GetSendAlarm(QuicConnection* connection); @@ -122,7 +117,8 @@ QuicPacketCount packets); static void SetNextMtuProbeAt(QuicConnection* connection, QuicPacketNumber number); - static void EnableAckDecimation(QuicConnection* connection); + static void SetAckMode(QuicConnection* connection, + QuicConnection::AckMode ack_mode); private: DISALLOW_COPY_AND_ASSIGN(QuicConnectionPeer);
diff --git a/net/quic/test_tools/quic_packet_creator_peer.cc b/net/quic/test_tools/quic_packet_creator_peer.cc index 6ec2a724..83b783c4 100644 --- a/net/quic/test_tools/quic_packet_creator_peer.cc +++ b/net/quic/test_tools/quic_packet_creator_peer.cc
@@ -65,10 +65,8 @@ // static void QuicPacketCreatorPeer::FillPacketHeader(QuicPacketCreator* creator, - QuicFecGroupNumber fec_group, - bool fec_flag, QuicPacketHeader* header) { - creator->FillPacketHeader(fec_group, fec_flag, header); + creator->FillPacketHeader(header); } // static @@ -83,35 +81,6 @@ } // static -bool QuicPacketCreatorPeer::IsFecProtected(QuicPacketCreator* creator) { - return creator->fec_protect_; -} - -// static -bool QuicPacketCreatorPeer::IsFecEnabled(QuicPacketCreator* creator) { - return creator->max_packets_per_fec_group_ > 0; -} - -// static -void QuicPacketCreatorPeer::StartFecProtectingPackets( - QuicPacketCreator* creator) { - creator->StartFecProtectingPackets(); -} - -// static -void QuicPacketCreatorPeer::StopFecProtectingPackets( - QuicPacketCreator* creator) { - creator->StopFecProtectingPackets(); -} - -// static -void QuicPacketCreatorPeer::SerializeFec(QuicPacketCreator* creator, - char* buffer, - size_t buffer_len) { - creator->SerializeFec(buffer, buffer_len); -} - -// static SerializedPacket QuicPacketCreatorPeer::SerializeAllFrames( QuicPacketCreator* creator, const QuicFrames& frames, @@ -132,23 +101,6 @@ } // static -void QuicPacketCreatorPeer::ResetFecGroup(QuicPacketCreator* creator) { - creator->ResetFecGroup(); -} - -// static -QuicTime::Delta QuicPacketCreatorPeer::GetFecTimeout( - QuicPacketCreator* creator) { - return creator->fec_timeout_; -} - -// static -float QuicPacketCreatorPeer::GetRttMultiplierForFecTimeout( - QuicPacketCreator* creator) { - return creator->rtt_multiplier_for_fec_timeout_; -} - -// static EncryptionLevel QuicPacketCreatorPeer::GetEncryptionLevel( QuicPacketCreator* creator) { return creator->packet_.encryption_level;
diff --git a/net/quic/test_tools/quic_packet_creator_peer.h b/net/quic/test_tools/quic_packet_creator_peer.h index cc17ca9..6849c1f 100644 --- a/net/quic/test_tools/quic_packet_creator_peer.h +++ b/net/quic/test_tools/quic_packet_creator_peer.h
@@ -36,8 +36,6 @@ QuicPacketCreator* creator); static void SetPacketNumber(QuicPacketCreator* creator, QuicPacketNumber s); static void FillPacketHeader(QuicPacketCreator* creator, - QuicFecGroupNumber fec_group, - bool fec_flag, QuicPacketHeader* header); static size_t CreateStreamFrame(QuicPacketCreator* creator, QuicStreamId id, @@ -46,21 +44,10 @@ QuicStreamOffset offset, bool fin, QuicFrame* frame); - static bool IsFecProtected(QuicPacketCreator* creator); - static bool IsFecEnabled(QuicPacketCreator* creator); - static void StartFecProtectingPackets(QuicPacketCreator* creator); - static void StopFecProtectingPackets(QuicPacketCreator* creator); - static void SerializeFec(QuicPacketCreator* creator, - char* buffer, - size_t buffer_len); static SerializedPacket SerializeAllFrames(QuicPacketCreator* creator, const QuicFrames& frames, char* buffer, size_t buffer_len); - static void ResetFecGroup(QuicPacketCreator* creator); - static QuicTime::Delta GetFecTimeout(QuicPacketCreator* creator); - // TODO(rtenneti): Delete this code after the 0.25 RTT FEC experiment. - static float GetRttMultiplierForFecTimeout(QuicPacketCreator* creator); static EncryptionLevel GetEncryptionLevel(QuicPacketCreator* creator); static QuicPathId GetCurrentPath(QuicPacketCreator* creator);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc index 9911757c..10415690 100644 --- a/net/quic/test_tools/quic_test_utils.cc +++ b/net/quic/test_tools/quic_test_utils.cc
@@ -61,7 +61,7 @@ bool last_frame = i == frames.size() - 1; const size_t frame_size = framer->GetSerializedFrameLength( frames[i], max_plaintext_size - packet_size, first_frame, last_frame, - header.is_in_fec_group, header.public_header.packet_number_length); + header.public_header.packet_number_length); DCHECK(frame_size); packet_size += frame_size; } @@ -309,7 +309,7 @@ : QuicSpdySession(connection, DefaultQuicConfig()) { crypto_stream_.reset(new QuicCryptoStream(this)); Initialize(); - ON_CALL(*this, WritevData(_, _, _, _, _, _)) + ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } @@ -321,7 +321,6 @@ const QuicIOVector& data, QuicStreamOffset /*offset*/, bool fin, - FecProtection /*fec_protection*/, QuicAckListenerInterface* /*ack_notifier_delegate*/) { return QuicConsumedData(data.total_length, fin); } @@ -329,8 +328,13 @@ TestQuicSpdyServerSession::TestQuicSpdyServerSession( QuicConnection* connection, const QuicConfig& config, - const QuicCryptoServerConfig* crypto_config) - : QuicServerSessionBase(config, connection, &visitor_, crypto_config) { + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicServerSessionBase(config, + connection, + &visitor_, + crypto_config, + compressed_certs_cache) { Initialize(); } @@ -338,8 +342,11 @@ QuicCryptoServerStreamBase* TestQuicSpdyServerSession::CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) { - return new QuicCryptoServerStream(crypto_config, this); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) { + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, + this); } QuicCryptoServerStream* TestQuicSpdyServerSession::GetCryptoStream() { @@ -672,20 +679,18 @@ bool include_path_id, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - InFecGroup is_in_fec_group, size_t* payload_length) { *payload_length = 1; const size_t stream_length = NullEncrypter().GetCiphertextSize(*payload_length) + QuicPacketCreator::StreamFramePacketOverhead( PACKET_8BYTE_CONNECTION_ID, include_version, include_path_id, - packet_number_length, 0u, is_in_fec_group); + packet_number_length, 0u); const size_t ack_length = NullEncrypter().GetCiphertextSize( QuicFramer::GetMinAckFrameSize(PACKET_1BYTE_PACKET_NUMBER)) + GetPacketHeaderSize(connection_id_length, include_version, - include_path_id, packet_number_length, - is_in_fec_group); + include_path_id, packet_number_length); if (stream_length < ack_length) { *payload_length = 1 + ack_length - stream_length; } @@ -693,7 +698,7 @@ return NullEncrypter().GetCiphertextSize(*payload_length) + QuicPacketCreator::StreamFramePacketOverhead( connection_id_length, include_version, include_path_id, - packet_number_length, 0u, is_in_fec_group); + packet_number_length, 0u); } TestEntropyCalculator::TestEntropyCalculator() {} @@ -766,13 +771,15 @@ (*client_connection)->AdvanceTime(connection_start_time); } -void CreateServerSessionForTest(QuicServerId server_id, - QuicTime::Delta connection_start_time, - QuicVersionVector supported_versions, - MockConnectionHelper* helper, - QuicCryptoServerConfig* server_crypto_config, - PacketSavingConnection** server_connection, - TestQuicSpdyServerSession** server_session) { +void CreateServerSessionForTest( + QuicServerId server_id, + QuicTime::Delta connection_start_time, + QuicVersionVector supported_versions, + MockConnectionHelper* helper, + QuicCryptoServerConfig* server_crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, + PacketSavingConnection** server_connection, + TestQuicSpdyServerSession** server_session) { CHECK(server_crypto_config); CHECK(server_connection); CHECK(server_session); @@ -783,7 +790,8 @@ *server_connection = new PacketSavingConnection( helper, Perspective::IS_SERVER, supported_versions); *server_session = new TestQuicSpdyServerSession( - *server_connection, DefaultQuicConfig(), server_crypto_config); + *server_connection, DefaultQuicConfig(), server_crypto_config, + compressed_certs_cache); // We advance the clock initially because the default time is zero and the // strike register worries that we've just overflowed a uint32_t time.
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h index e669b0c4..276490b3 100644 --- a/net/quic/test_tools/quic_test_utils.h +++ b/net/quic/test_tools/quic_test_utils.h
@@ -142,7 +142,6 @@ bool include_path_id, QuicConnectionIdLength connection_id_length, QuicPacketNumberLength packet_number_length, - InFecGroup is_in_fec_group, size_t* payload_length); // Returns QuicConfig set to default values. @@ -221,7 +220,6 @@ MOCK_METHOD1(OnPublicResetPacket, void(const QuicPublicResetPacket& header)); MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket& packet)); - MOCK_METHOD0(OnRevivedPacket, void()); // The constructor sets this up to return true by default. MOCK_METHOD1(OnUnauthenticatedHeader, bool(const QuicPacketHeader& header)); // The constructor sets this up to return true by default. @@ -229,12 +227,10 @@ bool(const QuicPacketPublicHeader& header)); MOCK_METHOD1(OnDecryptedPacket, void(EncryptionLevel level)); MOCK_METHOD1(OnPacketHeader, bool(const QuicPacketHeader& header)); - MOCK_METHOD1(OnFecProtectedPayload, void(base::StringPiece payload)); MOCK_METHOD1(OnStreamFrame, bool(const QuicStreamFrame& frame)); MOCK_METHOD1(OnAckFrame, bool(const QuicAckFrame& frame)); MOCK_METHOD1(OnStopWaitingFrame, bool(const QuicStopWaitingFrame& frame)); MOCK_METHOD1(OnPingFrame, bool(const QuicPingFrame& frame)); - MOCK_METHOD1(OnFecData, void(StringPiece redundancy)); MOCK_METHOD1(OnRstStreamFrame, bool(const QuicRstStreamFrame& frame)); MOCK_METHOD1(OnConnectionCloseFrame, bool(const QuicConnectionCloseFrame& frame)); @@ -257,19 +253,16 @@ void OnPublicResetPacket(const QuicPublicResetPacket& packet) override {} void OnVersionNegotiationPacket( const QuicVersionNegotiationPacket& packet) override {} - void OnRevivedPacket() override {} bool OnProtocolVersionMismatch(QuicVersion version) override; bool OnUnauthenticatedHeader(const QuicPacketHeader& header) override; bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header) override; void OnDecryptedPacket(EncryptionLevel level) override {} bool OnPacketHeader(const QuicPacketHeader& header) override; - void OnFecProtectedPayload(base::StringPiece payload) override {} bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnAckFrame(const QuicAckFrame& frame) override; bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override; bool OnPingFrame(const QuicPingFrame& frame) override; - void OnFecData(StringPiece redundancy) override {} bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override; bool OnConnectionCloseFrame(const QuicConnectionCloseFrame& frame) override; bool OnGoAwayFrame(const QuicGoAwayFrame& frame) override; @@ -461,13 +454,13 @@ MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); - MOCK_METHOD6(WritevData, + MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id, QuicIOVector data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface*)); + MOCK_METHOD3(SendRstStream, void(QuicStreamId stream_id, QuicRstStreamErrorCode error, @@ -503,7 +496,6 @@ const QuicIOVector& data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* ack_notifier_delegate); private: @@ -516,14 +508,16 @@ public: TestQuicSpdyServerSession(QuicConnection* connection, const QuicConfig& config, - const QuicCryptoServerConfig* crypto_config); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache); ~TestQuicSpdyServerSession() override; MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); MOCK_METHOD1(CreateOutgoingDynamicStream, QuicSpdyStream*(SpdyPriority priority)); QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) override; + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override; QuicCryptoServerStream* GetCryptoStream() override; @@ -742,9 +736,6 @@ MOCK_METHOD1(OnVersionNegotiationPacket, void(const QuicVersionNegotiationPacket&)); - - MOCK_METHOD2(OnRevivedPacket, - void(const QuicPacketHeader&, StringPiece payload)); }; class MockReceivedPacketManager : public QuicReceivedPacketManager { @@ -756,7 +747,6 @@ void(QuicByteCount bytes, const QuicPacketHeader& header, QuicTime receipt_time)); - MOCK_METHOD1(RecordPacketRevived, void(QuicPacketNumber packet_number)); MOCK_METHOD1(IsMissing, bool(QuicPacketNumber packet_number)); MOCK_METHOD1(IsAwaitingPacket, bool(QuicPacketNumber packet_number)); MOCK_METHOD1(UpdatePacketInformationSentByPeer, @@ -805,13 +795,15 @@ // server_session. // server_session: Pointer reference for the newly created server // session. The new object will be owned by the caller. -void CreateServerSessionForTest(QuicServerId server_id, - QuicTime::Delta connection_start_time, - QuicVersionVector supported_versions, - MockConnectionHelper* helper, - QuicCryptoServerConfig* crypto_server_config, - PacketSavingConnection** server_connection, - TestQuicSpdyServerSession** server_session); +void CreateServerSessionForTest( + QuicServerId server_id, + QuicTime::Delta connection_start_time, + QuicVersionVector supported_versions, + MockConnectionHelper* helper, + QuicCryptoServerConfig* crypto_server_config, + QuicCompressedCertsCache* compressed_certs_cache, + PacketSavingConnection** server_connection, + TestQuicSpdyServerSession** server_session); // Helper to generate client side stream ids, generalizes // kClientDataStreamId1 etc. above.
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.cc b/net/quic/test_tools/reliable_quic_stream_peer.cc index 97a7278c..2b419bfd 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.cc +++ b/net/quic/test_tools/reliable_quic_stream_peer.cc
@@ -79,12 +79,6 @@ } // static -void ReliableQuicStreamPeer::SetFecPolicy(ReliableQuicStream* stream, - FecPolicy fec_policy) { - stream->set_fec_policy(fec_policy); -} - -// static bool ReliableQuicStreamPeer::StreamContributesToConnectionFlowControl( ReliableQuicStream* stream) { return stream->stream_contributes_to_connection_flow_control_;
diff --git a/net/quic/test_tools/reliable_quic_stream_peer.h b/net/quic/test_tools/reliable_quic_stream_peer.h index db172da1..04bbe7b4 100644 --- a/net/quic/test_tools/reliable_quic_stream_peer.h +++ b/net/quic/test_tools/reliable_quic_stream_peer.h
@@ -35,8 +35,6 @@ static uint32_t SizeOfQueuedData(ReliableQuicStream* stream); - static void SetFecPolicy(ReliableQuicStream* stream, FecPolicy fec_policy); - static bool StreamContributesToConnectionFlowControl( ReliableQuicStream* stream);
diff --git a/net/quic/test_tools/simple_quic_framer.cc b/net/quic/test_tools/simple_quic_framer.cc index 977a367..dd0e0cb 100644 --- a/net/quic/test_tools/simple_quic_framer.cc +++ b/net/quic/test_tools/simple_quic_framer.cc
@@ -37,7 +37,6 @@ const QuicVersionNegotiationPacket& packet) override { version_negotiation_packet_.reset(new QuicVersionNegotiationPacket(packet)); } - void OnRevivedPacket() override {} bool OnUnauthenticatedPublicHeader( const QuicPacketPublicHeader& header) override { @@ -53,8 +52,6 @@ return true; } - void OnFecProtectedPayload(StringPiece payload) override {} - bool OnStreamFrame(const QuicStreamFrame& frame) override { // Save a copy of the data so it is valid after the packet is processed. string* string_data = new string(); @@ -82,10 +79,6 @@ return true; } - void OnFecData(StringPiece redundancy) override { - fec_redundancy_ = redundancy.as_string(); - } - bool OnRstStreamFrame(const QuicRstStreamFrame& frame) override { rst_stream_frames_.push_back(frame); return true; @@ -136,7 +129,6 @@ return stop_waiting_frames_; } const vector<QuicPingFrame>& ping_frames() const { return ping_frames_; } - StringPiece fec_data() const { return fec_redundancy_; } const QuicVersionNegotiationPacket* version_negotiation_packet() const { return version_negotiation_packet_.get(); } @@ -147,7 +139,6 @@ QuicPacketHeader header_; scoped_ptr<QuicVersionNegotiationPacket> version_negotiation_packet_; scoped_ptr<QuicPublicResetPacket> public_reset_packet_; - string fec_redundancy_; vector<QuicAckFrame> ack_frames_; vector<QuicStopWaitingFrame> stop_waiting_frames_; vector<QuicPingFrame> ping_frames_; @@ -187,10 +178,6 @@ return visitor_->header(); } -StringPiece SimpleQuicFramer::fec_data() const { - return visitor_->fec_data(); -} - const QuicVersionNegotiationPacket* SimpleQuicFramer::version_negotiation_packet() const { return visitor_->version_negotiation_packet();
diff --git a/net/quic/test_tools/simple_quic_framer.h b/net/quic/test_tools/simple_quic_framer.h index c476550..f09db61e 100644 --- a/net/quic/test_tools/simple_quic_framer.h +++ b/net/quic/test_tools/simple_quic_framer.h
@@ -46,7 +46,6 @@ const std::vector<QuicGoAwayFrame>& goaway_frames() const; const std::vector<QuicRstStreamFrame>& rst_stream_frames() const; const std::vector<QuicStreamFrame*>& stream_frames() const; - base::StringPiece fec_data() const; const QuicVersionNegotiationPacket* version_negotiation_packet() const; QuicFramer* framer();
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc index 8a860f3..15531d0 100644 --- a/net/socket/ssl_client_socket_openssl.cc +++ b/net/socket/ssl_client_socket_openssl.cc
@@ -971,11 +971,13 @@ SSL_set_mode(ssl_, mode.set_mask); SSL_clear_mode(ssl_, mode.clear_mask); - // See SSLConfig::disabled_cipher_suites for description of the suites - // disabled by default. Note that SHA256 and SHA384 only select HMAC-SHA256 - // and HMAC-SHA384 cipher suites, not GCM cipher suites with SHA256 or SHA384 - // as the handshake hash. - std::string command("DEFAULT:!SHA256:-SHA384:!AESGCM+AES256:!aPSK"); + // Use BoringSSL defaults, but disable HMAC-SHA256 and HMAC-SHA384 ciphers + // (note that SHA256 and SHA384 only select legacy CBC ciphers). Also disable + // DHE_RSA_WITH_AES_256_GCM_SHA384. Historically, AES_256_GCM was not + // supported. As DHE is being deprecated, don't add a cipher only to remove it + // immediately. + std::string command( + "DEFAULT:!SHA256:!SHA384:!DHE-RSA-AES256-GCM-SHA384:!aPSK"); if (ssl_config_.require_ecdhe) command.append(":!kRSA:!kDHE"); @@ -1081,6 +1083,13 @@ return network_moved; } +uint16_t SSLClientSocketOpenSSL::GetCipherSuite() { + const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl_); + if (!cipher) + return 0; + return static_cast<uint16_t>(SSL_CIPHER_get_id(cipher)); +} + // TODO(cbentzel): Remove including "base/threading/thread_local.h" and // g_first_run_completed once crbug.com/424386 is fixed. base::LazyInstance<base::ThreadLocalBoolean>::Leaky g_first_run_completed = @@ -1167,6 +1176,14 @@ } else { ssl_failure_state_ = SSL_FAILURE_UNKNOWN; } + + // TODO(davidben): Remove this once https://crbug.com/593963 is resolved. + if (net_error == ERR_SSL_PROTOCOL_ERROR) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolErrorCipher.Connect", + GetCipherSuite()); + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolErrorReason.Connect", + ERR_GET_REASON(error_info.error_code)); + } } GotoState(STATE_HANDSHAKE_COMPLETE); @@ -1645,6 +1662,15 @@ net_log_.AddByteTransferEvent(NetLog::TYPE_SSL_SOCKET_BYTES_RECEIVED, rv, user_read_buf_->data()); } else if (rv != ERR_IO_PENDING) { + // TODO(davidben): Remove this once https://crbug.com/593963 is resolved. + if (rv == ERR_SSL_PROTOCOL_ERROR) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolErrorCipher.Read", + GetCipherSuite()); + UMA_HISTOGRAM_SPARSE_SLOWLY( + "Net.SSLProtocolErrorReason.Read", + ERR_GET_REASON(pending_read_error_info_.error_code)); + } + net_log_.AddEvent( NetLog::TYPE_SSL_READ_ERROR, CreateNetLogOpenSSLErrorCallback(rv, pending_read_ssl_error_, @@ -1673,6 +1699,14 @@ &error_info); if (net_error != ERR_IO_PENDING) { + // TODO(davidben): Remove this once https://crbug.com/593963 is resolved. + if (net_error == ERR_SSL_PROTOCOL_ERROR) { + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolErrorCipher.Write", + GetCipherSuite()); + UMA_HISTOGRAM_SPARSE_SLOWLY("Net.SSLProtocolErrorReason.Write", + ERR_GET_REASON(error_info.error_code)); + } + net_log_.AddEvent( NetLog::TYPE_SSL_WRITE_ERROR, CreateNetLogOpenSSLErrorCallback(net_error, ssl_error, error_info));
diff --git a/net/socket/ssl_client_socket_openssl.h b/net/socket/ssl_client_socket_openssl.h index d1078a9..bf286e6 100644 --- a/net/socket/ssl_client_socket_openssl.h +++ b/net/socket/ssl_client_socket_openssl.h
@@ -127,6 +127,8 @@ void DoReadCallback(int result); void DoWriteCallback(int result); + uint16_t GetCipherSuite(); + bool DoTransportIO(); int DoHandshake(); int DoHandshakeComplete(int result);
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc index e76b83d7..e7e3d3d 100644 --- a/net/spdy/buffered_spdy_framer.cc +++ b/net/spdy/buffered_spdy_framer.cc
@@ -202,7 +202,7 @@ } void BufferedSpdyFramer::OnStreamEnd(SpdyStreamId stream_id) { - LOG(DFATAL) << "Unimplemented"; + visitor_->OnStreamFrameData(stream_id, nullptr, 0, true); } void BufferedSpdyFramer::OnStreamPadding(SpdyStreamId stream_id, size_t len) {
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc index e34345a..5c8d011 100644 --- a/net/spdy/spdy_framer.cc +++ b/net/spdy/spdy_framer.cc
@@ -14,6 +14,7 @@ #include "base/lazy_instance.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/histogram_macros.h" +#include "net/quic/quic_flags.h" #include "net/spdy/hpack/hpack_constants.h" #include "net/spdy/spdy_frame_builder.h" #include "net/spdy/spdy_frame_reader.h" @@ -171,7 +172,8 @@ enable_compression_(true), syn_frame_processed_(false), probable_http_response_(false), - end_stream_when_done_(false) { + end_stream_when_done_(false), + spdy_on_stream_end_(FLAGS_spdy_on_stream_end) { DCHECK(protocol_version_ == SPDY3 || protocol_version_ == HTTP2); DCHECK_LE(kMaxControlFrameSize, SpdyConstants::GetFrameMaximumSize(protocol_version_) + @@ -830,8 +832,12 @@ } else { // Empty data frame. if (current_frame_flags_ & DATA_FLAG_FIN) { - visitor_->OnStreamFrameData( - current_frame_stream_id_, NULL, 0, true); + if (spdy_on_stream_end_) { + visitor_->OnStreamEnd(current_frame_stream_id_); + } else { + visitor_->OnStreamFrameData(current_frame_stream_id_, nullptr, 0, + true); + } } CHANGE_STATE(SPDY_FRAME_COMPLETE); } @@ -2099,7 +2105,11 @@ ((current_frame_flags_ & CONTROL_FLAG_FIN) != 0 || end_stream_when_done_)) { end_stream_when_done_ = false; - visitor_->OnStreamFrameData(current_frame_stream_id_, NULL, 0, true); + if (spdy_on_stream_end_) { + visitor_->OnStreamEnd(current_frame_stream_id_); + } else { + visitor_->OnStreamFrameData(current_frame_stream_id_, nullptr, 0, true); + } } CHANGE_STATE(SPDY_FRAME_COMPLETE); }
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h index 30e7899b..6261777 100644 --- a/net/spdy/spdy_framer.h +++ b/net/spdy/spdy_framer.h
@@ -795,6 +795,11 @@ // If true, then ProcessInput returns after processing a full frame, // rather than reading all available input. bool process_single_input_frame_ = false; + + // Latched value of --FLAGS_spdy_on_stream_end. + // If true, OnStreamEnd will be called instead of the sentinel call of + // OnStreamFrameData(stream_id, nullptr, 0, true) + bool spdy_on_stream_end_; }; } // namespace net
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc index 2dcc855b..5e413272 100644 --- a/net/spdy/spdy_framer_test.cc +++ b/net/spdy/spdy_framer_test.cc
@@ -16,6 +16,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "net/quic/quic_flags.h" #include "net/spdy/hpack/hpack_constants.h" #include "net/spdy/mock_spdy_framer_visitor.h" #include "net/spdy/spdy_frame_builder.h" @@ -281,7 +282,7 @@ fin_frame_count_(0), fin_opaque_data_(), fin_flag_count_(0), - zero_length_data_frame_count_(0), + end_of_stream_count_(0), control_frame_header_data_count_(0), zero_length_control_frame_header_data_count_(0), data_frame_count_(0), @@ -312,8 +313,10 @@ size_t len, bool fin) override { EXPECT_EQ(header_stream_id_, stream_id); - if (len == 0) { - ++zero_length_data_frame_count_; + if (!FLAGS_spdy_on_stream_end) { + if (len == 0) { + ++end_of_stream_count_; + } } data_bytes_ += len; @@ -328,7 +331,9 @@ } void OnStreamEnd(SpdyStreamId stream_id) override { - LOG(DFATAL) << "Unimplemented."; + LOG(INFO) << "OnStreamEnd(" << stream_id << ")"; + EXPECT_EQ(header_stream_id_, stream_id); + ++end_of_stream_count_; } void OnStreamPadding(SpdyStreamId stream_id, size_t len) override { @@ -587,7 +592,7 @@ int fin_frame_count_; // The count of RST_STREAM type frames received. string fin_opaque_data_; int fin_flag_count_; // The count of frames with the FIN flag set. - int zero_length_data_frame_count_; // The count of zero-length data frames. + int end_of_stream_count_; // The count of zero-length data frames. int control_frame_header_data_count_; // The count of chunks received. // The count of zero-length control frame header data chunks received. int zero_length_control_frame_header_data_count_; @@ -1207,7 +1212,7 @@ } EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(0, visitor.zero_length_data_frame_count_); + EXPECT_EQ(0, visitor.end_of_stream_count_); EXPECT_EQ(4, visitor.data_frame_count_); visitor.fin_opaque_data_.clear(); } @@ -1289,7 +1294,7 @@ EXPECT_EQ(16, visitor.data_bytes_); EXPECT_EQ(0, visitor.fin_frame_count_); EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.zero_length_data_frame_count_); + EXPECT_EQ(1, visitor.end_of_stream_count_); EXPECT_EQ(2, visitor.data_frame_count_); } @@ -1348,7 +1353,7 @@ EXPECT_EQ(0, visitor.data_bytes_); EXPECT_EQ(0, visitor.fin_frame_count_); EXPECT_EQ(1, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.zero_length_data_frame_count_); + EXPECT_EQ(1, visitor.end_of_stream_count_); EXPECT_EQ(0, visitor.data_frame_count_); } @@ -1466,7 +1471,7 @@ EXPECT_EQ(arraysize(bytes), static_cast<unsigned>(visitor.data_bytes_)); EXPECT_EQ(0, visitor.fin_frame_count_); EXPECT_EQ(0, visitor.fin_flag_count_); - EXPECT_EQ(1, visitor.zero_length_data_frame_count_); + EXPECT_EQ(1, visitor.end_of_stream_count_); EXPECT_EQ(1, visitor.data_frame_count_); } @@ -3196,7 +3201,7 @@ // at least twice. EXPECT_LE(2, visitor.control_frame_header_data_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.zero_length_data_frame_count_); + EXPECT_EQ(0, visitor.end_of_stream_count_); EXPECT_EQ(headers, visitor.headers_); } @@ -3221,7 +3226,7 @@ // at least twice. EXPECT_LE(2, visitor.control_frame_header_data_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(1, visitor.zero_length_data_frame_count_); + EXPECT_EQ(1, visitor.end_of_stream_count_); EXPECT_EQ(headers, visitor.headers_); } @@ -3258,7 +3263,7 @@ EXPECT_EQ(0, visitor.error_count_); EXPECT_EQ(1, visitor.syn_frame_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.zero_length_data_frame_count_); + EXPECT_EQ(0, visitor.end_of_stream_count_); EXPECT_LT(kBigValueSize, visitor.header_buffer_length_); } @@ -3403,7 +3408,7 @@ EXPECT_EQ(0, visitor.zero_length_control_frame_header_data_count_); // The framer should not have sent half-close to the visitor. - EXPECT_EQ(0, visitor.zero_length_data_frame_count_); + EXPECT_EQ(0, visitor.end_of_stream_count_); } TEST_P(SpdyFramerTest, DecompressCorruptHeaderBlock) { @@ -3860,7 +3865,7 @@ EXPECT_EQ(2, visitor.continuation_count_); EXPECT_EQ(1, visitor.fin_flag_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(1, visitor.zero_length_data_frame_count_); + EXPECT_EQ(1, visitor.end_of_stream_count_); EXPECT_THAT(visitor.headers_, testing::ElementsAre( @@ -3910,7 +3915,7 @@ EXPECT_EQ(42u, visitor.last_push_promise_promised_stream_); EXPECT_EQ(2, visitor.continuation_count_); EXPECT_EQ(1, visitor.zero_length_control_frame_header_data_count_); - EXPECT_EQ(0, visitor.zero_length_data_frame_count_); + EXPECT_EQ(0, visitor.end_of_stream_count_); EXPECT_THAT(visitor.headers_, testing::ElementsAre( @@ -4384,6 +4389,50 @@ } TEST_P(SpdyFramerTest, DataFrameFlagsV2V3) { + FLAGS_spdy_on_stream_end = true; + + if (!IsSpdy3()) { + return; + } + + uint8_t flags = 0; + do { + SCOPED_TRACE(testing::Message() << "Flags " << flags); + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + + SpdyDataIR data_ir(1, "hello"); + scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); + SetFrameFlags(frame.get(), flags, spdy_version_); + + if (flags & ~DATA_FLAG_FIN) { + EXPECT_CALL(visitor, OnError(_)); + } else { + EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); + EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false)); + if (flags & DATA_FLAG_FIN) { + EXPECT_CALL(visitor, OnStreamEnd(_)); + } + } + + framer.ProcessInput(frame->data(), frame->size()); + if (flags & ~DATA_FLAG_FIN) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } + } while (++flags != 0); +} + +TEST_P(SpdyFramerTest, DataFrameFlagsV2V3disabled) { + FLAGS_spdy_on_stream_end = false; + if (!IsSpdy3()) { return; } @@ -4425,6 +4474,60 @@ } TEST_P(SpdyFramerTest, DataFrameFlagsV4) { + FLAGS_spdy_on_stream_end = true; + + if (!IsHttp2()) { + return; + } + + uint8_t valid_data_flags = + DATA_FLAG_FIN | DATA_FLAG_END_SEGMENT | DATA_FLAG_PADDED; + + uint8_t flags = 0; + do { + SCOPED_TRACE(testing::Message() << "Flags " << flags); + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + + SpdyDataIR data_ir(1, "hello"); + scoped_ptr<SpdyFrame> frame(framer.SerializeData(data_ir)); + SetFrameFlags(frame.get(), flags, spdy_version_); + + if (flags & ~valid_data_flags) { + EXPECT_CALL(visitor, OnError(_)); + } else { + EXPECT_CALL(visitor, OnDataFrameHeader(1, 5, flags & DATA_FLAG_FIN)); + if (flags & DATA_FLAG_PADDED) { + // The first byte of payload is parsed as padding length. + EXPECT_CALL(visitor, OnStreamPadding(_, 1)); + // Expect Error since the frame ends prematurely. + EXPECT_CALL(visitor, OnError(_)); + } else { + EXPECT_CALL(visitor, OnStreamFrameData(_, _, 5, false)); + if (flags & DATA_FLAG_FIN) { + EXPECT_CALL(visitor, OnStreamEnd(_)); + } + } + } + + framer.ProcessInput(frame->data(), frame->size()); + if ((flags & ~valid_data_flags) || (flags & DATA_FLAG_PADDED)) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_DATA_FRAME_FLAGS, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } + } while (++flags != 0); +} + +TEST_P(SpdyFramerTest, DataFrameFlagsV4disabled) { + FLAGS_spdy_on_stream_end = false; + if (!IsHttp2()) { return; } @@ -4475,6 +4578,64 @@ } TEST_P(SpdyFramerTest, SynStreamFrameFlags) { + FLAGS_spdy_on_stream_end = true; + + if (!IsSpdy3()) { + return; + } + + uint8_t flags = 0; + do { + SCOPED_TRACE(testing::Message() << "Flags " << flags); + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + testing::StrictMock<test::MockDebugVisitor> debug_visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + framer.set_debug_visitor(&debug_visitor); + + EXPECT_CALL(debug_visitor, OnSendCompressedFrame(8, SYN_STREAM, _, _)); + + SpdySynStreamIR syn_stream(8); + syn_stream.set_associated_to_stream_id(3); + syn_stream.set_priority(1); + syn_stream.SetHeader("foo", "bar"); + scoped_ptr<SpdyFrame> frame(framer.SerializeSynStream(syn_stream)); + SetFrameFlags(frame.get(), flags, spdy_version_); + + if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { + EXPECT_CALL(visitor, OnError(_)); + } else { + EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(8, SYN_STREAM, _)); + EXPECT_CALL(visitor, OnSynStream(8, 3, 1, flags & CONTROL_FLAG_FIN, + flags & CONTROL_FLAG_UNIDIRECTIONAL)); + EXPECT_CALL(visitor, OnControlFrameHeaderData(8, _, _)) + .WillRepeatedly(testing::Return(true)); + if (flags & DATA_FLAG_FIN) { + EXPECT_CALL(visitor, OnStreamEnd(_)); + } else { + // Do not close the stream if we are expecting a CONTINUATION frame. + EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0); + } + } + + framer.ProcessInput(frame->data(), frame->size()); + if (flags & ~(CONTROL_FLAG_FIN | CONTROL_FLAG_UNIDIRECTIONAL)) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, + framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } + } while (++flags != 0); +} + +TEST_P(SpdyFramerTest, SynStreamFrameFlagsDisabled) { + FLAGS_spdy_on_stream_end = false; + if (!IsSpdy3()) { return; } @@ -4529,6 +4690,53 @@ } TEST_P(SpdyFramerTest, SynReplyFrameFlags) { + FLAGS_spdy_on_stream_end = true; + + if (!IsSpdy3()) { + return; + } + + uint8_t flags = 0; + do { + SCOPED_TRACE(testing::Message() << "Flags " << flags); + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + + SpdySynReplyIR syn_reply(37); + syn_reply.SetHeader("foo", "bar"); + scoped_ptr<SpdyFrame> frame(framer.SerializeSynReply(syn_reply)); + SetFrameFlags(frame.get(), flags, spdy_version_); + + if (flags & ~CONTROL_FLAG_FIN) { + EXPECT_CALL(visitor, OnError(_)); + } else { + EXPECT_CALL(visitor, OnSynReply(37, flags & CONTROL_FLAG_FIN)); + EXPECT_CALL(visitor, OnControlFrameHeaderData(37, _, _)) + .WillRepeatedly(testing::Return(true)); + if (flags & DATA_FLAG_FIN) { + EXPECT_CALL(visitor, OnStreamEnd(_)); + } + } + + framer.ProcessInput(frame->data(), frame->size()); + if (flags & ~CONTROL_FLAG_FIN) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, + framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } + } while (++flags != 0); +} + +TEST_P(SpdyFramerTest, SynReplyFrameFlagsDisabled) { + FLAGS_spdy_on_stream_end = false; + if (!IsSpdy3()) { return; } @@ -4729,6 +4937,99 @@ } TEST_P(SpdyFramerTest, HeadersFrameFlags) { + FLAGS_spdy_on_stream_end = true; + + uint8_t flags = 0; + do { + SCOPED_TRACE(testing::Message() << "Flags " << flags); + + testing::StrictMock<test::MockSpdyFramerVisitor> visitor; + SpdyFramer framer(spdy_version_); + framer.set_visitor(&visitor); + + SpdyHeadersIR headers_ir(57); + if (IsHttp2() && (flags & HEADERS_FLAG_PRIORITY)) { + headers_ir.set_priority(3); + headers_ir.set_has_priority(true); + headers_ir.set_parent_stream_id(5); + headers_ir.set_exclusive(true); + } + headers_ir.SetHeader("foo", "bar"); + std::unique_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir)); + uint8_t set_flags = flags; + if (IsHttp2()) { + // TODO(jgraettinger): Add padding to SpdyHeadersIR, + // and implement framing. + set_flags &= ~HEADERS_FLAG_PADDED; + } + SetFrameFlags(frame.get(), set_flags, spdy_version_); + + if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) { + EXPECT_CALL(visitor, OnError(_)); + } else if (IsHttp2() && + flags & + ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS | + HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED | + HEADERS_FLAG_PRIORITY)) { + EXPECT_CALL(visitor, OnError(_)); + } else { + // Expected callback values + SpdyStreamId stream_id = 57; + bool has_priority = false; + SpdyPriority priority = 0; + SpdyStreamId parent_stream_id = 0; + bool exclusive = false; + bool fin = flags & CONTROL_FLAG_FIN; + bool end = IsSpdy3() || (flags & HEADERS_FLAG_END_HEADERS); + if (IsHttp2() && flags & HEADERS_FLAG_PRIORITY) { + has_priority = true; + priority = 3; + parent_stream_id = 5; + exclusive = true; + } + EXPECT_CALL(visitor, OnHeaders(stream_id, has_priority, priority, + parent_stream_id, exclusive, fin, end)); + EXPECT_CALL(visitor, OnControlFrameHeaderData(57, _, _)) + .WillRepeatedly(testing::Return(true)); + if (flags & DATA_FLAG_FIN && + (IsSpdy3() || flags & HEADERS_FLAG_END_HEADERS)) { + EXPECT_CALL(visitor, OnStreamEnd(_)); + } else { + // Do not close the stream if we are expecting a CONTINUATION frame. + EXPECT_CALL(visitor, OnStreamEnd(_)).Times(0); + } + } + + framer.ProcessInput(frame->data(), frame->size()); + if (IsSpdy3() && flags & ~CONTROL_FLAG_FIN) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, + framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else if (IsHttp2() && + flags & + ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS | + HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED | + HEADERS_FLAG_PRIORITY)) { + EXPECT_EQ(SpdyFramer::SPDY_ERROR, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_INVALID_CONTROL_FRAME_FLAGS, + framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else if (IsHttp2() && ~(flags & HEADERS_FLAG_END_HEADERS)) { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } else { + EXPECT_EQ(SpdyFramer::SPDY_READY_FOR_FRAME, framer.state()); + EXPECT_EQ(SpdyFramer::SPDY_NO_ERROR, framer.error_code()) + << SpdyFramer::ErrorCodeToString(framer.error_code()); + } + } while (++flags != 0); +} + +TEST_P(SpdyFramerTest, HeadersFrameFlagsDisabled) { + FLAGS_spdy_on_stream_end = false; + uint8_t flags = 0; do { SCOPED_TRACE(testing::Message() << "Flags " << flags); @@ -4756,11 +5057,11 @@ if (!IsHttp2() && flags & ~CONTROL_FLAG_FIN) { EXPECT_CALL(visitor, OnError(_)); - } else if (IsHttp2() && flags & ~(CONTROL_FLAG_FIN | - HEADERS_FLAG_END_HEADERS | - HEADERS_FLAG_END_SEGMENT | - HEADERS_FLAG_PADDED | - HEADERS_FLAG_PRIORITY)) { + } else if (IsHttp2() && + flags & + ~(CONTROL_FLAG_FIN | HEADERS_FLAG_END_HEADERS | + HEADERS_FLAG_END_SEGMENT | HEADERS_FLAG_PADDED | + HEADERS_FLAG_PRIORITY)) { EXPECT_CALL(visitor, OnError(_)); } else { // Expected callback values
diff --git a/net/ssl/scoped_openssl_types.h b/net/ssl/scoped_openssl_types.h index 92ce7d7..8bee498 100644 --- a/net/ssl/scoped_openssl_types.h +++ b/net/ssl/scoped_openssl_types.h
@@ -21,8 +21,6 @@ sk_X509_NAME_pop_free(ptr, X509_NAME_free); } -using ScopedPKCS8_PRIV_KEY_INFO = - crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; using ScopedSSL = crypto::ScopedOpenSSL<SSL, SSL_free>; using ScopedSSL_CTX = crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free>; using ScopedSSL_SESSION = crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free>;
diff --git a/net/ssl/ssl_config.h b/net/ssl/ssl_config.h index 0a5a83d..21f4cccb 100644 --- a/net/ssl/ssl_config.h +++ b/net/ssl/ssl_config.h
@@ -97,19 +97,6 @@ // Presorted list of cipher suites which should be explicitly prevented from // being used in addition to those disabled by the net built-in policy. // - // By default, all cipher suites supported by the underlying SSL - // implementation will be enabled except for: - // - Null encryption cipher suites. - // - Weak cipher suites: < 80 bits of security strength. - // - FORTEZZA cipher suites (obsolete). - // - IDEA cipher suites (RFC 5469 explains why). - // - Anonymous cipher suites. - // - ECDSA cipher suites on platforms that do not support ECDSA signed - // certificates, as servers may use the presence of such ciphersuites as a - // hint to send an ECDSA certificate. - // The ciphers listed in |disabled_cipher_suites| will be removed in addition - // to the above list. - // // Though cipher suites are sent in TLS as "uint8_t CipherSuite[2]", in // big-endian form, they should be declared in host byte order, with the // first uint8_t occupying the most significant byte.
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc index 08e2c8b..441a5d9 100644 --- a/net/tools/quic/end_to_end_test.cc +++ b/net/tools/quic/end_to_end_test.cc
@@ -92,7 +92,6 @@ TestParams(const QuicVersionVector& client_supported_versions, const QuicVersionVector& server_supported_versions, QuicVersion negotiated_version, - bool use_fec, bool client_supports_stateless_rejects, bool server_uses_stateless_rejects_if_peer_supported, QuicTag congestion_control_tag, @@ -100,7 +99,6 @@ : client_supported_versions(client_supported_versions), server_supported_versions(server_supported_versions), negotiated_version(negotiated_version), - use_fec(use_fec), client_supports_stateless_rejects(client_supports_stateless_rejects), server_uses_stateless_rejects_if_peer_supported( server_uses_stateless_rejects_if_peer_supported), @@ -117,7 +115,6 @@ << p.client_supports_stateless_rejects; os << " server_uses_stateless_rejects_if_peer_supported: " << p.server_uses_stateless_rejects_if_peer_supported; - os << " use_fec: " << p.use_fec; os << " congestion_control_tag: " << QuicUtils::TagToString(p.congestion_control_tag); os << " auto_tune_flow_control_window: " << p.auto_tune_flow_control_window @@ -128,7 +125,6 @@ QuicVersionVector client_supported_versions; QuicVersionVector server_supported_versions; QuicVersion negotiated_version; - bool use_fec; bool client_supports_stateless_rejects; bool server_uses_stateless_rejects_if_peer_supported; QuicTag congestion_control_tag; @@ -164,62 +160,56 @@ // TODO(rtenneti): Add kTBBR after BBR code is checked in. for (const QuicTag congestion_control_tag : {kRENO, kQBIC}) { for (bool auto_tune_flow_control_window : {true, false}) { - for (const bool use_fec : {false, true}) { - const int kMaxEnabledOptions = 5; - int enabled_options = 0; - if (congestion_control_tag != kQBIC) { - ++enabled_options; - } - if (use_fec) { - ++enabled_options; - } - if (auto_tune_flow_control_window) { - ++enabled_options; - } - if (client_supports_stateless_rejects) { - ++enabled_options; - } - if (server_uses_stateless_rejects_if_peer_supported) { - ++enabled_options; - } - CHECK_GE(kMaxEnabledOptions, enabled_options); + const int kMaxEnabledOptions = 5; + int enabled_options = 0; + if (congestion_control_tag != kQBIC) { + ++enabled_options; + } + if (auto_tune_flow_control_window) { + ++enabled_options; + } + if (client_supports_stateless_rejects) { + ++enabled_options; + } + if (server_uses_stateless_rejects_if_peer_supported) { + ++enabled_options; + } + CHECK_GE(kMaxEnabledOptions, enabled_options); - // Run tests with no options, a single option, or all the options - // enabled to avoid a combinatorial explosion. - if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { + // Run tests with no options, a single option, or all the options + // enabled to avoid a combinatorial explosion. + if (enabled_options > 1 && enabled_options < kMaxEnabledOptions) { + continue; + } + + for (const QuicVersionVector& client_versions : version_buckets) { + CHECK(!client_versions.empty()); + // Add an entry for server and client supporting all versions. + params.push_back(TestParams( + client_versions, all_supported_versions, + client_versions.front(), client_supports_stateless_rejects, + server_uses_stateless_rejects_if_peer_supported, + congestion_control_tag, auto_tune_flow_control_window)); + + // Run version negotiation tests tests with no options, or all + // the options enabled to avoid a combinatorial explosion. + if (enabled_options > 0 && enabled_options < kMaxEnabledOptions) { continue; } - for (const QuicVersionVector& client_versions : version_buckets) { - CHECK(!client_versions.empty()); - // Add an entry for server and client supporting all versions. + // Test client supporting all versions and server supporting 1 + // version. Simulate an old server and exercise version downgrade + // in the client. Protocol negotiation should occur. Skip the i = + // 0 case because it is essentially the same as the default case. + for (size_t i = 1; i < client_versions.size(); ++i) { + QuicVersionVector server_supported_versions; + server_supported_versions.push_back(client_versions[i]); params.push_back(TestParams( - client_versions, all_supported_versions, - client_versions.front(), use_fec, + client_versions, server_supported_versions, + server_supported_versions.front(), client_supports_stateless_rejects, server_uses_stateless_rejects_if_peer_supported, congestion_control_tag, auto_tune_flow_control_window)); - - // Run version negotiation tests tests with no options, or all - // the options enabled to avoid a combinatorial explosion. - if (enabled_options > 0 && enabled_options < kMaxEnabledOptions) { - continue; - } - - // Test client supporting all versions and server supporting 1 - // version. Simulate an old server and exercise version downgrade - // in the client. Protocol negotiation should occur. Skip the i = - // 0 case because it is essentially the same as the default case. - for (size_t i = 1; i < client_versions.size(); ++i) { - QuicVersionVector server_supported_versions; - server_supported_versions.push_back(client_versions[i]); - params.push_back(TestParams( - client_versions, server_supported_versions, - server_supported_versions.front(), use_fec, - client_supports_stateless_rejects, - server_uses_stateless_rejects_if_peer_supported, - congestion_control_tag, auto_tune_flow_control_window)); - } } } } @@ -352,10 +342,6 @@ // client as well according to the test parameter. copt.push_back(GetParam().congestion_control_tag); - if (GetParam().use_fec) { - // Set FEC config in client's connection options and in client session. - copt.push_back(kFHDR); - } if (GetParam().client_supports_stateless_rejects) { copt.push_back(kSREJ); } @@ -801,14 +787,9 @@ client_->WaitForResponseForMs(-1); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); - if (FLAGS_require_strike_register_or_server_nonce) { - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); - } else { - EXPECT_EQ(1, client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); - } + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->session()->GetNumSentClientHellos()); + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); client_->Disconnect(); @@ -859,14 +840,9 @@ client_->WaitForInitialResponse(); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendSynchronousRequest("/foo")); - if (FLAGS_require_strike_register_or_server_nonce) { - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); - } else { - EXPECT_EQ(1, client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); - } + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->session()->GetNumSentClientHellos()); + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); client_->Disconnect(); @@ -923,14 +899,9 @@ client_->WaitForInitialResponse(); ASSERT_TRUE(client_->client()->connected()); EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request)); - if (FLAGS_require_strike_register_or_server_nonce) { - EXPECT_EQ(expected_num_hellos_latest_session, - client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); - } else { - EXPECT_EQ(1, client_->client()->session()->GetNumSentClientHellos()); - EXPECT_EQ(1, client_->client()->GetNumSentClientHellos()); - } + EXPECT_EQ(expected_num_hellos_latest_session, + client_->client()->session()->GetNumSentClientHellos()); + EXPECT_EQ(2, client_->client()->GetNumSentClientHellos()); client_->Disconnect(); @@ -988,30 +959,6 @@ ContainsQuicTag(server_config_.ReceivedConnectionOptions(), kPRST)); } -TEST_P(EndToEndTest, CorrectlyConfiguredFec) { - ASSERT_TRUE(Initialize()); - client_->client()->WaitForCryptoHandshakeConfirmed(); - server_thread_->WaitForCryptoHandshakeConfirmed(); - - FecPolicy expected_policy = FEC_PROTECT_OPTIONAL; - - // Verify that server's FEC configuration is correct. - server_thread_->Pause(); - QuicDispatcher* dispatcher = - QuicServerPeer::GetDispatcher(server_thread_->server()); - ASSERT_EQ(1u, dispatcher->session_map().size()); - QuicSpdySession* session = dispatcher->session_map().begin()->second; - EXPECT_EQ(expected_policy, - QuicSpdySessionPeer::GetHeadersStream(session)->fec_policy()); - server_thread_->Resume(); - - // Verify that client's FEC configuration is correct. - EXPECT_EQ(expected_policy, - QuicSpdySessionPeer::GetHeadersStream(client_->client()->session()) - ->fec_policy()); - EXPECT_EQ(expected_policy, client_->GetOrCreateStream()->fec_policy()); -} - TEST_P(EndToEndTest, LargePostSmallBandwidthLargeBuffer) { ASSERT_TRUE(Initialize()); SetPacketSendDelay(QuicTime::Delta::FromMicroseconds(1));
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc index 56514ae..04b7d2f 100644 --- a/net/tools/quic/quic_client.cc +++ b/net/tools/quic/quic_client.cc
@@ -434,7 +434,8 @@ latest_response_code_ = headers.parsed_response_code(); headers.DumpHeadersToString(&latest_response_headers_); latest_response_body_ = client_stream->data(); - latest_response_trailers_ = client_stream->trailers().DebugString(); + latest_response_trailers_ = + client_stream->response_trailers().DebugString(); } }
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc index ac65bf59..aef861cd 100644 --- a/net/tools/quic/quic_client_session_test.cc +++ b/net/tools/quic/quic_client_session_test.cc
@@ -137,7 +137,6 @@ } TEST_P(QuicClientSessionTest, NoEncryptionAfterInitialEncryption) { - ValueRestore<bool> old_flag(&FLAGS_quic_block_unencrypted_writes, true); // Complete a handshake in order to prime the crypto config for 0-RTT. CompleteCryptoHandshake(); @@ -171,8 +170,8 @@ char data[] = "hello world"; struct iovec iov = {data, arraysize(data)}; QuicIOVector iovector(&iov, 1, iov.iov_len); - QuicConsumedData consumed = session_->WritevData( - stream->id(), iovector, 0, false, MAY_FEC_PROTECT, nullptr); + QuicConsumedData consumed = + session_->WritevData(stream->id(), iovector, 0, false, nullptr); EXPECT_FALSE(consumed.fin_consumed); EXPECT_EQ(0u, consumed.bytes_consumed); }
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index 9cb1059aa..f662ee3 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -30,11 +30,7 @@ explicit DeleteSessionsAlarm(QuicDispatcher* dispatcher) : dispatcher_(dispatcher) {} - QuicTime OnAlarm() override { - dispatcher_->DeleteSessions(); - // Let the dispatcher register the alarm at appropriate time. - return QuicTime::Zero(); - } + void OnAlarm() override { dispatcher_->DeleteSessions(); } private: // Not owned. @@ -51,6 +47,8 @@ QuicConnectionHelperInterface* helper) : config_(config), crypto_config_(crypto_config), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), helper_(helper), delete_sessions_alarm_( helper_->CreateAlarm(new DeleteSessionsAlarm(this))), @@ -387,14 +385,6 @@ return false; } -void QuicDispatcher::OnRevivedPacket() { - DCHECK(false); -} - -void QuicDispatcher::OnFecProtectedPayload(StringPiece /*payload*/) { - DCHECK(false); -} - bool QuicDispatcher::OnStreamFrame(const QuicStreamFrame& /*frame*/) { DCHECK(false); return false; @@ -447,10 +437,6 @@ return false; } -void QuicDispatcher::OnFecData(StringPiece /*redundancy*/) { - DCHECK(false); -} - void QuicDispatcher::OnPacketComplete() { DCHECK(false); } @@ -463,8 +449,8 @@ connection_id, client_address, helper_.get(), CreatePerConnectionWriter(), /* owns_writer= */ true, Perspective::IS_SERVER, supported_versions_); - QuicServerSessionBase* session = - new QuicSimpleServerSession(config_, connection, this, crypto_config_); + QuicServerSessionBase* session = new QuicSimpleServerSession( + config_, connection, this, crypto_config_, &compressed_certs_cache_); session->Initialize(); return session; }
diff --git a/net/tools/quic/quic_dispatcher.h b/net/tools/quic/quic_dispatcher.h index 3a96176a..6ba8f2b 100644 --- a/net/tools/quic/quic_dispatcher.h +++ b/net/tools/quic/quic_dispatcher.h
@@ -16,6 +16,7 @@ #include "base/memory/scoped_ptr.h" #include "net/base/ip_endpoint.h" #include "net/base/linked_hash_map.h" +#include "net/quic/crypto/quic_compressed_certs_cache.h" #include "net/quic/quic_blocked_writer_interface.h" #include "net/quic/quic_connection.h" #include "net/quic/quic_protocol.h" @@ -131,8 +132,6 @@ const QuicVersionNegotiationPacket& packet) override; void OnDecryptedPacket(EncryptionLevel level) override; bool OnPacketHeader(const QuicPacketHeader& header) override; - void OnRevivedPacket() override; - void OnFecProtectedPayload(base::StringPiece payload) override; bool OnStreamFrame(const QuicStreamFrame& frame) override; bool OnAckFrame(const QuicAckFrame& frame) override; bool OnStopWaitingFrame(const QuicStopWaitingFrame& frame) override; @@ -143,7 +142,6 @@ bool OnWindowUpdateFrame(const QuicWindowUpdateFrame& frame) override; bool OnBlockedFrame(const QuicBlockedFrame& frame) override; bool OnPathCloseFrame(const QuicPathCloseFrame& frame) override; - void OnFecData(base::StringPiece redundancy) override; void OnPacketComplete() override; protected: @@ -190,6 +188,10 @@ const QuicCryptoServerConfig* crypto_config() const { return crypto_config_; } + QuicCompressedCertsCache* compressed_certs_cache() { + return &compressed_certs_cache_; + } + QuicFramer* framer() { return &framer_; } QuicConnectionHelperInterface* helper() { return helper_.get(); } @@ -223,6 +225,9 @@ const QuicCryptoServerConfig* crypto_config_; + // The cache for most recently compressed certs. + QuicCompressedCertsCache compressed_certs_cache_; + // The list of connections waiting to write. WriteBlockedList write_blocked_list_;
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc index 169dc63..67fb2d6 100644 --- a/net/tools/quic/quic_dispatcher_test.cc +++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -50,8 +50,13 @@ public: TestQuicSpdyServerSession(const QuicConfig& config, QuicConnection* connection, - const QuicCryptoServerConfig* crypto_config) - : QuicServerSessionBase(config, connection, nullptr, crypto_config), + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicServerSessionBase(config, + connection, + nullptr, + crypto_config, + compressed_certs_cache), crypto_stream_(QuicServerSessionBase::GetCryptoStream()) {} ~TestQuicSpdyServerSession() override{}; @@ -62,8 +67,11 @@ QuicSpdyStream*(SpdyPriority priority)); QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) override { - return new QuicCryptoServerStream(crypto_config, this); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override { + return new QuicCryptoServerStream( + crypto_config, compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, this); } void SetCryptoStream(QuicCryptoServerStream* crypto_stream) { @@ -126,10 +134,12 @@ const IPEndPoint& client_address, MockConnectionHelper* helper, const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, TestQuicSpdyServerSession** session) { MockServerConnection* connection = new MockServerConnection(connection_id, helper, dispatcher); - *session = new TestQuicSpdyServerSession(config, connection, crypto_config); + *session = new TestQuicSpdyServerSession(config, connection, crypto_config, + compressed_certs_cache); connection->set_visitor(*session); ON_CALL(*connection, SendConnectionCloseWithDetails(_, _)) .WillByDefault(WithoutArgs(Invoke( @@ -255,17 +265,19 @@ server_address_ = IPEndPoint(net::test::Any4(), 5); EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1, - client_address, &mock_helper_, - &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 1, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session1_))); ProcessPacket(client_address, 1, true, false, "foo"); EXPECT_EQ(client_address, dispatcher_.current_client_address()); EXPECT_EQ(server_address_, dispatcher_.current_server_address()); EXPECT_CALL(dispatcher_, CreateQuicSession(2, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 2, - client_address, &mock_helper_, - &crypto_config_, &session2_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 2, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session2_))); ProcessPacket(client_address, 2, true, false, "bar"); EXPECT_CALL(*reinterpret_cast<MockConnection*>(session1_->connection()), @@ -293,9 +305,10 @@ server_address_ = IPEndPoint(net::test::Any4(), 5); EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1, - client_address, &mock_helper_, - &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 1, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session1_))); QuicVersion version = static_cast<QuicVersion>(QuicVersionMin() - 1); ProcessPacket(client_address, 1, true, version, "foo", PACKET_8BYTE_CONNECTION_ID, PACKET_6BYTE_PACKET_NUMBER, 1); @@ -305,9 +318,10 @@ IPEndPoint client_address(net::test::Loopback4(), 1); EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1, - client_address, &mock_helper_, - &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 1, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session1_))); ProcessPacket(client_address, 1, true, false, "foo"); @@ -324,9 +338,10 @@ IPEndPoint client_address(net::test::Loopback4(), 1); QuicConnectionId connection_id = 1; EXPECT_CALL(dispatcher_, CreateQuicSession(connection_id, client_address)) - .WillOnce(testing::Return( - CreateSession(&dispatcher_, config_, connection_id, client_address, - &mock_helper_, &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, connection_id, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session1_))); ProcessPacket(client_address, connection_id, true, false, "foo"); // Close the connection by sending public reset packet. @@ -382,8 +397,12 @@ class MockQuicCryptoServerStream : public QuicCryptoServerStream { public: MockQuicCryptoServerStream(const QuicCryptoServerConfig& crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, QuicSession* session) - : QuicCryptoServerStream(&crypto_config, session) {} + : QuicCryptoServerStream(&crypto_config, + compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, + session) {} void set_handshake_confirmed_for_testing(bool handshake_confirmed) { handshake_confirmed_ = handshake_confirmed; } @@ -468,9 +487,11 @@ QuicConnectionId connection_id, const IPEndPoint& client_address) { CreateSession(&dispatcher_, config_, connection_id, client_address, - &mock_helper_, &crypto_config_, &session1_); + &mock_helper_, &crypto_config_, + QuicDispatcherPeer::GetCache(&dispatcher_), &session1_); - crypto_stream1_ = new MockQuicCryptoServerStream(crypto_config_, session1_); + crypto_stream1_ = new MockQuicCryptoServerStream( + crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), session1_); session1_->SetCryptoStream(crypto_stream1_); crypto_stream1_->set_handshake_confirmed_for_testing( GetParam().crypto_handshake_successful); @@ -502,9 +523,10 @@ server_address_ = IPEndPoint(net::test::Any4(), 5); EXPECT_CALL(dispatcher_, CreateQuicSession(1, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1, - client_address, &mock_helper_, - &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 1, client_address, &mock_helper_, + &crypto_config_, QuicDispatcherPeer::GetCache(&dispatcher_), + &session1_))); // A packet whose packet number is the largest that is allowed to start a // connection. ProcessPacket(client_address, connection_id, true, false, "data", @@ -650,15 +672,15 @@ IPEndPoint client_address(net::test::Loopback4(), 1); EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 1, - client_address, &helper_, - &crypto_config_, &session1_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 1, client_address, &helper_, &crypto_config_, + QuicDispatcherPeer::GetCache(&dispatcher_), &session1_))); ProcessPacket(client_address, 1, true, false, "foo"); EXPECT_CALL(dispatcher_, CreateQuicSession(_, client_address)) - .WillOnce(testing::Return(CreateSession(&dispatcher_, config_, 2, - client_address, &helper_, - &crypto_config_, &session2_))); + .WillOnce(testing::Return(CreateSession( + &dispatcher_, config_, 2, client_address, &helper_, &crypto_config_, + QuicDispatcherPeer::GetCache(&dispatcher_), &session2_))); ProcessPacket(client_address, 2, true, false, "bar"); blocked_list_ = QuicDispatcherPeer::GetWriteBlockedList(&dispatcher_);
diff --git a/net/tools/quic/quic_epoll_connection_helper_test.cc b/net/tools/quic/quic_epoll_connection_helper_test.cc index 1e1d22eb..f79e0ff 100644 --- a/net/tools/quic/quic_epoll_connection_helper_test.cc +++ b/net/tools/quic/quic_epoll_connection_helper_test.cc
@@ -18,10 +18,7 @@ public: TestDelegate() : fired_(false) {} - QuicTime OnAlarm() override { - fired_ = true; - return QuicTime::Zero(); - } + void OnAlarm() override { fired_ = true; } bool fired() const { return fired_; }
diff --git a/net/tools/quic/quic_server_session_base.cc b/net/tools/quic/quic_server_session_base.cc index 63618d41..c8a6dfb8 100644 --- a/net/tools/quic/quic_server_session_base.cc +++ b/net/tools/quic/quic_server_session_base.cc
@@ -18,9 +18,11 @@ const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config) + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) : QuicSpdySession(connection, config), crypto_config_(crypto_config), + compressed_certs_cache_(compressed_certs_cache), visitor_(visitor), bandwidth_resumption_enabled_(false), bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()), @@ -30,7 +32,8 @@ QuicServerSessionBase::~QuicServerSessionBase() {} void QuicServerSessionBase::Initialize() { - crypto_stream_.reset(CreateQuicCryptoServerStream(crypto_config_)); + crypto_stream_.reset( + CreateQuicCryptoServerStream(crypto_config_, compressed_certs_cache_)); QuicSpdySession::Initialize(); }
diff --git a/net/tools/quic/quic_server_session_base.h b/net/tools/quic/quic_server_session_base.h index ddfaa98..a93fd9c 100644 --- a/net/tools/quic/quic_server_session_base.h +++ b/net/tools/quic/quic_server_session_base.h
@@ -16,6 +16,7 @@ #include "base/containers/hash_tables.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "net/quic/crypto/quic_compressed_certs_cache.h" #include "net/quic/quic_crypto_server_stream.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_spdy_session.h" @@ -58,7 +59,8 @@ QuicServerSessionBase(const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache); // Override the base class to notify the owner of the connection close. void OnConnectionClosed(QuicErrorCode error, @@ -77,7 +79,8 @@ return crypto_stream_.get(); } - // Override base class to process FEC config received from client. + // Override base class to process bandwidth related config received from + // client. void OnConfigNegotiated() override; void set_serving_region(const std::string& serving_region) { @@ -92,7 +95,7 @@ // Return false when connection is closed or forward secure encryption hasn't // established yet or number of server initiated streams already reaches the // upper limit. - bool ShouldCreateOutgoingDynamicStream(); + virtual bool ShouldCreateOutgoingDynamicStream(); // If we should create an incoming stream, returns true. Otherwise // does error handling, including communicating the error to the client and @@ -100,7 +103,8 @@ virtual bool ShouldCreateIncomingDynamicStream(QuicStreamId id); virtual QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) = 0; + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) = 0; const QuicCryptoServerConfig* crypto_config() { return crypto_config_; } @@ -109,6 +113,11 @@ friend class test::QuicSimpleServerSessionPeer; const QuicCryptoServerConfig* crypto_config_; + + // The cache which contains most recently compressed certs. + // Owned by QuicDispatcher. + QuicCompressedCertsCache* compressed_certs_cache_; + scoped_ptr<QuicCryptoServerStreamBase> crypto_stream_; QuicServerSessionVisitor* visitor_;
diff --git a/net/tools/quic/quic_server_session_base_test.cc b/net/tools/quic/quic_server_session_base_test.cc index 1d4ed11..4de21a3 100644 --- a/net/tools/quic/quic_server_session_base_test.cc +++ b/net/tools/quic/quic_server_session_base_test.cc
@@ -73,8 +73,13 @@ TestServerSession(const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config) - : QuicServerSessionBase(config, connection, visitor, crypto_config) {} + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicServerSessionBase(config, + connection, + visitor, + crypto_config, + compressed_certs_cache) {} ~TestServerSession() override{}; @@ -101,8 +106,11 @@ } QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) override { - return new QuicCryptoServerStream(crypto_config, this); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override { + return new QuicCryptoServerStream( + crypto_config, compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, this); } }; @@ -113,7 +121,10 @@ QuicServerSessionBaseTest() : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()) { + CryptoTestUtils::ProofSourceForTesting()), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { + FLAGS_quic_always_log_bugs_for_tests = true; config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); config_.SetInitialStreamFlowControlWindowToSend( kInitialStreamFlowControlWindowForTest); @@ -122,8 +133,9 @@ connection_ = new StrictMock<MockConnection>( &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); - session_.reset( - new TestServerSession(config_, connection_, &owner_, &crypto_config_)); + session_.reset(new TestServerSession(config_, connection_, &owner_, + &crypto_config_, + &compressed_certs_cache_)); MockClock clock; handshake_message_.reset(crypto_config_.AddDefaultConfig( QuicRandom::GetInstance(), &clock, @@ -137,6 +149,7 @@ StrictMock<MockConnection>* connection_; QuicConfig config_; QuicCryptoServerConfig crypto_config_; + QuicCompressedCertsCache compressed_certs_cache_; scoped_ptr<TestServerSession> session_; scoped_ptr<CryptoHandshakeMessage> handshake_message_; QuicConnectionVisitorInterface* visitor_; @@ -331,8 +344,12 @@ public: explicit MockQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, QuicSession* session) - : QuicCryptoServerStream(crypto_config, session) {} + : QuicCryptoServerStream(crypto_config, + compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, + session) {} ~MockQuicCryptoServerStream() override {} MOCK_METHOD1(SendServerConfigUpdate, @@ -366,8 +383,8 @@ const string serving_region = "not a real region"; session_->set_serving_region(serving_region); - MockQuicCryptoServerStream* crypto_stream = - new MockQuicCryptoServerStream(&crypto_config_, session_.get()); + MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream( + &crypto_config_, &compressed_certs_cache_, session_.get()); QuicServerSessionBasePeer::SetCryptoStream(session_.get(), crypto_stream); // Set some initial bandwidth values.
diff --git a/net/tools/quic/quic_simple_server_session.cc b/net/tools/quic/quic_simple_server_session.cc index e72383a..5b5b57e 100644 --- a/net/tools/quic/quic_simple_server_session.cc +++ b/net/tools/quic/quic_simple_server_session.cc
@@ -20,16 +20,24 @@ const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config) - : QuicServerSessionBase(config, connection, visitor, crypto_config), + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicServerSessionBase(config, + connection, + visitor, + crypto_config, + compressed_certs_cache), highest_promised_stream_id_(0) {} QuicSimpleServerSession::~QuicSimpleServerSession() {} QuicCryptoServerStreamBase* QuicSimpleServerSession::CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) { - return new QuicCryptoServerStream(crypto_config, this); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) { + return new QuicCryptoServerStream(crypto_config, compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, + this); } void QuicSimpleServerSession::StreamDraining(QuicStreamId id) {
diff --git a/net/tools/quic/quic_simple_server_session.h b/net/tools/quic/quic_simple_server_session.h index 0329a665..ea7860dd 100644 --- a/net/tools/quic/quic_simple_server_session.h +++ b/net/tools/quic/quic_simple_server_session.h
@@ -59,7 +59,8 @@ QuicSimpleServerSession(const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache); ~QuicSimpleServerSession() override; @@ -97,7 +98,8 @@ // QuicServerSessionBaseMethod: QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) override; + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override; private: friend class test::QuicSimpleServerSessionPeer;
diff --git a/net/tools/quic/quic_simple_server_session_test.cc b/net/tools/quic/quic_simple_server_session_test.cc index e6dcdc9..029fa11 100644 --- a/net/tools/quic/quic_simple_server_session_test.cc +++ b/net/tools/quic/quic_simple_server_session_test.cc
@@ -83,8 +83,12 @@ public: explicit MockQuicCryptoServerStream( const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, QuicSession* session) - : QuicCryptoServerStream(crypto_config, session) {} + : QuicCryptoServerStream(crypto_config, + compressed_certs_cache, + FLAGS_enable_quic_stateless_reject_support, + session) {} ~MockQuicCryptoServerStream() override {} MOCK_METHOD1(SendServerConfigUpdate, @@ -105,12 +109,11 @@ const QuicVersionVector& supported_versions) : MockConnection(helper, perspective, supported_versions) {} - MOCK_METHOD6(SendStreamData, + MOCK_METHOD5(SendStreamData, QuicConsumedData(QuicStreamId id, QuicIOVector iov, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface* listern)); }; @@ -153,7 +156,9 @@ QuicSimpleServerSessionTest() : crypto_config_(QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), - CryptoTestUtils::ProofSourceForTesting()) { + CryptoTestUtils::ProofSourceForTesting()), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize) { FLAGS_quic_always_log_bugs_for_tests = true; config_.SetMaxStreamsPerConnection(kMaxStreamsForTest, kMaxStreamsForTest); config_.SetInitialStreamFlowControlWindowToSend( @@ -164,7 +169,8 @@ connection_ = new StrictMock<MockConnectionWithSendStreamData>( &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_, - &crypto_config_)); + &crypto_config_, + &compressed_certs_cache_)); MockClock clock; handshake_message_.reset(crypto_config_.AddDefaultConfig( QuicRandom::GetInstance(), &clock, @@ -182,6 +188,7 @@ StrictMock<MockConnectionWithSendStreamData>* connection_; QuicConfig config_; QuicCryptoServerConfig crypto_config_; + QuicCompressedCertsCache compressed_certs_cache_; scoped_ptr<QuicSimpleServerSession> session_; scoped_ptr<CryptoHandshakeMessage> handshake_message_; QuicConnectionVisitorInterface* visitor_; @@ -323,8 +330,8 @@ EXPECT_EQ(0u, session_->GetNumOpenOutgoingStreams()); // Assume encryption already established. - MockQuicCryptoServerStream* crypto_stream = - new MockQuicCryptoServerStream(&crypto_config_, session_.get()); + MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream( + &crypto_config_, &compressed_certs_cache_, session_.get()); crypto_stream->set_encryption_established(true); QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); @@ -398,7 +405,8 @@ connection_ = new StrictMock<MockConnectionWithSendStreamData>( &helper_, Perspective::IS_SERVER, SupportedVersions(GetParam())); session_.reset(new QuicSimpleServerSession(config_, connection_, &owner_, - &crypto_config_)); + &crypto_config_, + &compressed_certs_cache_)); session_->Initialize(); // Needed to make new session flow control window work. session_->OnConfigNegotiated(); @@ -408,8 +416,8 @@ QuicSpdySessionPeer::SetHeadersStream(session_.get(), headers_stream_); // Assume encryption already established. - MockQuicCryptoServerStream* crypto_stream = - new MockQuicCryptoServerStream(&crypto_config_, session_.get()); + MockQuicCryptoServerStream* crypto_stream = new MockQuicCryptoServerStream( + &crypto_config_, &compressed_certs_cache_, session_.get()); crypto_stream->set_encryption_established(true); QuicSimpleServerSessionPeer::SetCryptoStream(session_.get(), crypto_stream); } @@ -455,7 +463,7 @@ // Since flow control window is smaller than response body, not the // whole body will be sent. EXPECT_CALL(*connection_, - SendStreamData(stream_id, _, 0, false, _, nullptr)) + SendStreamData(stream_id, _, 0, false, nullptr)) .WillOnce( Return(QuicConsumedData(kStreamFlowControlWindowSize, false))); EXPECT_CALL(*connection_, SendBlocked(stream_id)); @@ -492,7 +500,7 @@ EXPECT_CALL(*headers_stream_, WriteHeaders(next_out_going_stream_id, _, false, kDefaultPriority, nullptr)); EXPECT_CALL(*connection_, - SendStreamData(next_out_going_stream_id, _, 0, false, _, nullptr)) + SendStreamData(next_out_going_stream_id, _, 0, false, nullptr)) .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false))); EXPECT_CALL(*connection_, SendBlocked(next_out_going_stream_id)); session_->StreamDraining(2); @@ -526,7 +534,7 @@ EXPECT_CALL(*headers_stream_, WriteHeaders(stream_not_reset, _, false, kDefaultPriority, nullptr)); EXPECT_CALL(*connection_, - SendStreamData(stream_not_reset, _, 0, false, _, nullptr)) + SendStreamData(stream_not_reset, _, 0, false, nullptr)) .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false))); EXPECT_CALL(*connection_, SendBlocked(stream_not_reset)); EXPECT_CALL(*headers_stream_, WriteHeaders(stream_got_reset, _, false, @@ -553,7 +561,7 @@ EXPECT_CALL(*headers_stream_, WriteHeaders(stream_to_open, _, false, kDefaultPriority, nullptr)); EXPECT_CALL(*connection_, - SendStreamData(stream_to_open, _, 0, false, _, nullptr)) + SendStreamData(stream_to_open, _, 0, false, nullptr)) .WillOnce(Return(QuicConsumedData(kStreamFlowControlWindowSize, false))); EXPECT_CALL(*connection_, SendBlocked(stream_to_open));
diff --git a/net/tools/quic/quic_simple_server_stream_test.cc b/net/tools/quic/quic_simple_server_stream_test.cc index 91b8ada..594e34c 100644 --- a/net/tools/quic/quic_simple_server_stream_test.cc +++ b/net/tools/quic/quic_simple_server_stream_test.cc
@@ -84,16 +84,19 @@ public: const size_t kMaxStreamsForTest = 100; - explicit MockQuicSimpleServerSession(QuicConnection* connection, - MockQuicServerSessionVisitor* owner, - QuicCryptoServerConfig* crypto_config) - : QuicSimpleServerSession(::net::test::DefaultQuicConfig(), + explicit MockQuicSimpleServerSession( + QuicConnection* connection, + MockQuicServerSessionVisitor* owner, + QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicSimpleServerSession(DefaultQuicConfig(), connection, owner, - crypto_config) { + crypto_config, + compressed_certs_cache) { set_max_open_incoming_streams(kMaxStreamsForTest); set_max_open_outgoing_streams(kMaxStreamsForTest); - ON_CALL(*this, WritevData(_, _, _, _, _, _)) + ON_CALL(*this, WritevData(_, _, _, _, _)) .WillByDefault(testing::Return(QuicConsumedData(0, false))); } @@ -102,12 +105,11 @@ MOCK_METHOD2(OnConnectionClosed, void(QuicErrorCode error, ConnectionCloseSource source)); MOCK_METHOD1(CreateIncomingDynamicStream, QuicSpdyStream*(QuicStreamId id)); - MOCK_METHOD6(WritevData, + MOCK_METHOD5(WritevData, QuicConsumedData(QuicStreamId id, QuicIOVector data, QuicStreamOffset offset, bool fin, - FecProtection fec_protection, QuicAckListenerInterface*)); MOCK_METHOD2(OnStreamHeaders, void(QuicStreamId stream_id, StringPiece headers_data)); @@ -153,7 +155,12 @@ QuicCryptoServerConfig::TESTING, QuicRandom::GetInstance(), ::net::test::CryptoTestUtils::ProofSourceForTesting())), - session_(connection_, session_owner_, crypto_config_.get()), + compressed_certs_cache_( + QuicCompressedCertsCache::kQuicCompressedCertsCacheSize), + session_(connection_, + session_owner_, + crypto_config_.get(), + &compressed_certs_cache_), body_("hello world") { FLAGS_quic_always_log_bugs_for_tests = true; SpdyHeaderBlock request_headers; @@ -198,6 +205,7 @@ StrictMock<MockConnection>* connection_; StrictMock<MockQuicServerSessionVisitor>* session_owner_; std::unique_ptr<QuicCryptoServerConfig> crypto_config_; + QuicCompressedCertsCache compressed_certs_cache_; StrictMock<MockQuicSimpleServerSession> session_; QuicSimpleServerStreamPeer* stream_; // Owned by session_. string headers_string_; @@ -209,7 +217,7 @@ ::testing::ValuesIn(QuicSupportedVersions())); TEST_P(QuicSimpleServerStreamTest, TestFraming) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); stream_->OnStreamHeaders(headers_string_); @@ -223,7 +231,7 @@ } TEST_P(QuicSimpleServerStreamTest, TestFramingOnePacket) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -238,7 +246,7 @@ } TEST_P(QuicSimpleServerStreamTest, SendQuicRstStreamNoErrorInStopReading) { - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); @@ -261,7 +269,7 @@ // We'll automatically write out an error (headers + body) EXPECT_CALL(session_, WriteHeaders(_, _, _, _, _)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .WillOnce(Invoke(MockQuicSpdySession::ConsumeAllData)); EXPECT_CALL(session_, SendRstStream(_, QUIC_STREAM_NO_ERROR, _)).Times(0); @@ -298,7 +306,7 @@ InSequence s; EXPECT_CALL(session_, WriteHeaders(stream_->id(), _, false, _, nullptr)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData( strlen(QuicSimpleServerStream::kErrorResponseBody), true))); @@ -355,7 +363,7 @@ InSequence s; EXPECT_CALL(session_, WriteHeaders(stream_->id(), _, false, _, nullptr)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData(body.length(), true))); @@ -394,7 +402,7 @@ ::net::test::kClientDataStreamId1, *request_headers)); EXPECT_CALL(session_, WriteHeaders(stream_->id(), _, false, _, nullptr)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData(body.length(), true))); QuicSimpleServerStreamPeer::SendResponse(stream_); @@ -440,7 +448,7 @@ EXPECT_CALL(session_, WriteHeaders(kServerInitiatedStreamId, _, false, server_initiated_stream->priority(), nullptr)); - EXPECT_CALL(session_, WritevData(kServerInitiatedStreamId, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(kServerInitiatedStreamId, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData(kBody.size(), true))); server_initiated_stream->PushResponse(headers); @@ -462,7 +470,7 @@ InSequence s; EXPECT_CALL(session_, WriteHeaders(_, _, _, _, _)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData(3, true))); @@ -482,7 +490,7 @@ headers_string_ = SpdyUtils::SerializeUncompressedHeaders(request_headers); EXPECT_CALL(session_, WriteHeaders(_, _, _, _, _)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); stream_->OnStreamHeaders(headers_string_); @@ -503,7 +511,7 @@ headers_string_ = SpdyUtils::SerializeUncompressedHeaders(request_headers); EXPECT_CALL(session_, WriteHeaders(_, _, _, _, _)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(AnyNumber()) .WillRepeatedly(Invoke(MockQuicSpdySession::ConsumeAllData)); stream_->OnStreamHeaders(headers_string_); @@ -537,7 +545,7 @@ InSequence s; EXPECT_CALL(session_, WriteHeaders(stream_->id(), _, _, _, _)); - EXPECT_CALL(session_, WritevData(_, _, _, _, _, _)) + EXPECT_CALL(session_, WritevData(_, _, _, _, _)) .Times(1) .WillOnce(Return(QuicConsumedData(3, true))); if (GetParam() > QUIC_VERSION_28) {
diff --git a/net/tools/quic/quic_socket_utils.cc b/net/tools/quic/quic_socket_utils.cc index 42141dfa..9c8cac7e 100644 --- a/net/tools/quic/quic_socket_utils.cc +++ b/net/tools/quic/quic_socket_utils.cc
@@ -213,7 +213,10 @@ hdr.msg_controllen = cmsg->cmsg_len; } - int rc = sendmsg(fd, &hdr, 0); + int rc; + do { + rc = sendmsg(fd, &hdr, 0); + } while (rc < 0 && errno == EINTR); if (rc >= 0) { return WriteResult(WRITE_STATUS_OK, rc); }
diff --git a/net/tools/quic/quic_spdy_client_stream.cc b/net/tools/quic/quic_spdy_client_stream.cc index 12289364..615fab4 100644 --- a/net/tools/quic/quic_spdy_client_stream.cc +++ b/net/tools/quic/quic_spdy_client_stream.cc
@@ -72,20 +72,8 @@ void QuicSpdyClientStream::OnTrailingHeadersComplete(bool fin, size_t frame_len) { - size_t final_byte_offset = 0; - if (!SpdyUtils::ParseTrailers(decompressed_trailers().data(), - decompressed_trailers().length(), - &final_byte_offset, &response_trailers_)) { - Reset(QUIC_BAD_APPLICATION_PAYLOAD); - return; - } + QuicSpdyStream::OnTrailingHeadersComplete(fin, frame_len); MarkTrailersConsumed(decompressed_trailers().length()); - - // The data on this stream ends at |final_byte_offset|. - DVLOG(1) << "Stream ends at byte offset: " << final_byte_offset - << " currently read: " << stream_bytes_read(); - OnStreamFrame( - QuicStreamFrame(id(), /*fin=*/true, final_byte_offset, StringPiece())); } void QuicSpdyClientStream::OnPromiseHeadersComplete(QuicStreamId promised_id,
diff --git a/net/tools/quic/quic_spdy_client_stream.h b/net/tools/quic/quic_spdy_client_stream.h index 7268ff02..dcb8896 100644 --- a/net/tools/quic/quic_spdy_client_stream.h +++ b/net/tools/quic/quic_spdy_client_stream.h
@@ -64,9 +64,6 @@ // Returns whatever headers have been received for this stream. const SpdyHeaderBlock& headers() { return response_headers_; } - // Returns whatever trailers have been received for this stream. - const SpdyHeaderBlock& trailers() { return response_trailers_; } - size_t header_bytes_read() const { return header_bytes_read_; } size_t header_bytes_written() const { return header_bytes_written_; } @@ -89,9 +86,6 @@ // The parsed headers received from the server. SpdyHeaderBlock response_headers_; - // The parsed trailers received from the server. - SpdyHeaderBlock response_trailers_; - // The parsed content-length, or -1 if none is specified. int content_length_; int response_code_;
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc index 64ff05e..91c48d0 100644 --- a/net/tools/quic/quic_time_wait_list_manager.cc +++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -34,10 +34,8 @@ QuicTimeWaitListManager* time_wait_list_manager) : time_wait_list_manager_(time_wait_list_manager) {} - QuicTime OnAlarm() override { + void OnAlarm() override { time_wait_list_manager_->CleanUpOldConnectionIds(); - // Let the time wait manager register the alarm at appropriate time. - return QuicTime::Zero(); } private:
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.cc b/net/tools/quic/test_tools/packet_dropping_test_writer.cc index ed46a07..3858b78 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.cc +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.cc
@@ -20,10 +20,9 @@ explicit WriteUnblockedAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {} - QuicTime OnAlarm() override { + void OnAlarm() override { DVLOG(1) << "Unblocking socket."; writer_->OnCanWrite(); - return QuicTime::Zero(); } private: @@ -36,7 +35,12 @@ public: explicit DelayAlarm(PacketDroppingTestWriter* writer) : writer_(writer) {} - QuicTime OnAlarm() override { return writer_->ReleaseOldPackets(); } + void OnAlarm() override { + QuicTime new_deadline = writer_->ReleaseOldPackets(); + if (new_deadline.IsInitialized()) { + writer_->SetDelayAlarm(new_deadline); + } + } private: PacketDroppingTestWriter* writer_; @@ -203,6 +207,10 @@ return QuicTime::Zero(); } +void PacketDroppingTestWriter::SetDelayAlarm(QuicTime new_deadline) { + delay_alarm_->Set(new_deadline); +} + void PacketDroppingTestWriter::OnCanWrite() { on_can_write_->OnCanWrite(); }
diff --git a/net/tools/quic/test_tools/packet_dropping_test_writer.h b/net/tools/quic/test_tools/packet_dropping_test_writer.h index be948f6..20d2c27 100644 --- a/net/tools/quic/test_tools/packet_dropping_test_writer.h +++ b/net/tools/quic/test_tools/packet_dropping_test_writer.h
@@ -63,6 +63,9 @@ // for the next delayed packet to be written. QuicTime ReleaseOldPackets(); + // Sets |delay_alarm_| to fire at |new_deadline|. + void SetDelayAlarm(QuicTime new_deadline); + void OnCanWrite(); // The percent of time a packet is simulated as being lost.
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.cc b/net/tools/quic/test_tools/quic_dispatcher_peer.cc index 03e8e46..232043fb 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.cc +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.cc
@@ -30,6 +30,12 @@ } // static +QuicCompressedCertsCache* QuicDispatcherPeer::GetCache( + QuicDispatcher* dispatcher) { + return dispatcher->compressed_certs_cache(); +} + +// static QuicConnectionHelperInterface* QuicDispatcherPeer::GetHelper( QuicDispatcher* dispatcher) { return dispatcher->helper_.get();
diff --git a/net/tools/quic/test_tools/quic_dispatcher_peer.h b/net/tools/quic/test_tools/quic_dispatcher_peer.h index 7c3536f..cbd60e2 100644 --- a/net/tools/quic/test_tools/quic_dispatcher_peer.h +++ b/net/tools/quic/test_tools/quic_dispatcher_peer.h
@@ -28,6 +28,8 @@ static QuicPacketWriter* GetWriter(QuicDispatcher* dispatcher); + static QuicCompressedCertsCache* GetCache(QuicDispatcher* dispatcher); + static QuicConnectionHelperInterface* GetHelper(QuicDispatcher* dispatcher); static QuicDispatcher::WriteBlockedList* GetWriteBlockedList(
diff --git a/net/tools/quic/test_tools/quic_test_client.cc b/net/tools/quic/test_tools/quic_test_client.cc index cf1abec..fad3ab9 100644 --- a/net/tools/quic/test_tools/quic_test_client.cc +++ b/net/tools/quic/test_tools/quic_test_client.cc
@@ -201,7 +201,6 @@ connect_attempted_ = false; auto_reconnect_ = false; buffer_body_ = true; - fec_policy_ = FEC_PROTECT_OPTIONAL; ClearPerRequestState(); // As chrome will generally do this, we want it to be the default when it's // not overridden. @@ -394,8 +393,6 @@ QuicSpdyClientStream* cs = reinterpret_cast<QuicSpdyClientStream*>(stream_); cs->SetPriority(priority_); cs->set_allow_bidirectional_data(allow_bidirectional_data_); - // Set FEC policy on stream. - ReliableQuicStreamPeer::SetFecPolicy(stream_, fec_policy_); } return stream_; @@ -571,7 +568,7 @@ response_complete_ = true; response_headers_complete_ = stream_->headers_decompressed(); SpdyBalsaUtils::SpdyHeadersToResponseHeaders(stream_->headers(), &headers_); - response_trailers_ = stream_->trailers(); + response_trailers_ = stream_->response_trailers(); stream_error_ = stream_->stream_error(); bytes_read_ = stream_->stream_bytes_read() + stream_->header_bytes_read(); bytes_written_ = @@ -651,15 +648,6 @@ } } -void QuicTestClient::SetFecPolicy(FecPolicy fec_policy) { - fec_policy_ = fec_policy; - // Set policy for headers and crypto streams. - ReliableQuicStreamPeer::SetFecPolicy( - QuicSpdySessionPeer::GetHeadersStream(client()->session()), fec_policy); - ReliableQuicStreamPeer::SetFecPolicy(client()->session()->GetCryptoStream(), - fec_policy); -} - void QuicTestClient::TestClientDataToResend::Resend() { test_client_->GetOrCreateStreamAndSendRequest(headers_, body_, fin_, delegate_);
diff --git a/net/tools/quic/test_tools/quic_test_client.h b/net/tools/quic/test_tools/quic_test_client.h index 6dc3ea5e..93cc385 100644 --- a/net/tools/quic/test_tools/quic_test_client.h +++ b/net/tools/quic/test_tools/quic_test_client.h
@@ -185,10 +185,6 @@ void set_priority(SpdyPriority priority) { priority_ = priority; } - // Sets client's FEC policy. This policy applies to the data stream(s), and - // also to the headers and crypto streams. - void SetFecPolicy(FecPolicy fec_policy); - void WaitForWriteToFlush(); EpollServer* epoll_server() { return &epoll_server_; } @@ -265,8 +261,6 @@ bool auto_reconnect_; // Should we buffer the response body? Defaults to true. bool buffer_body_; - // FEC policy for data sent by this client. - FecPolicy fec_policy_; // When true allows the sending of a request to continue while the response is // arriving. bool allow_bidirectional_data_;
diff --git a/net/tools/quic/test_tools/quic_test_server.cc b/net/tools/quic/test_tools/quic_test_server.cc index 31ddef8b..d513a696 100644 --- a/net/tools/quic/test_tools/quic_test_server.cc +++ b/net/tools/quic/test_tools/quic_test_server.cc
@@ -33,9 +33,14 @@ QuicConnection* connection, QuicServerSessionVisitor* visitor, const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache, QuicTestServer::StreamFactory* factory, QuicTestServer::CryptoStreamFactory* crypto_stream_factory) - : QuicSimpleServerSession(config, connection, visitor, crypto_config), + : QuicSimpleServerSession(config, + connection, + visitor, + crypto_config, + compressed_certs_cache), stream_factory_(factory), crypto_stream_factory_(crypto_stream_factory) {} @@ -52,11 +57,13 @@ } QuicCryptoServerStreamBase* CreateQuicCryptoServerStream( - const QuicCryptoServerConfig* crypto_config) override { + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) override { if (crypto_stream_factory_) { return crypto_stream_factory_->CreateCryptoStream(crypto_config, this); } - return QuicSimpleServerSession::CreateQuicCryptoServerStream(crypto_config); + return QuicSimpleServerSession::CreateQuicCryptoServerStream( + crypto_config, compressed_certs_cache); } private: @@ -88,12 +95,13 @@ QuicServerSessionBase* session = nullptr; if (stream_factory_ != nullptr || crypto_stream_factory_ != nullptr) { - session = - new CustomStreamSession(config(), connection, this, crypto_config(), - stream_factory_, crypto_stream_factory_); + session = new CustomStreamSession( + config(), connection, this, crypto_config(), compressed_certs_cache(), + stream_factory_, crypto_stream_factory_); } else { session = session_factory_->CreateSession(config(), connection, this, - crypto_config()); + crypto_config(), + compressed_certs_cache()); } session->Initialize(); return session; @@ -165,8 +173,13 @@ const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config) - : QuicSimpleServerSession(config, connection, visitor, crypto_config) { + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) + : QuicSimpleServerSession(config, + connection, + visitor, + crypto_config, + compressed_certs_cache) { SendGoAway(QUIC_PEER_GOING_AWAY, ""); }
diff --git a/net/tools/quic/test_tools/quic_test_server.h b/net/tools/quic/test_tools/quic_test_server.h index ac02682..7af5f51 100644 --- a/net/tools/quic/test_tools/quic_test_server.h +++ b/net/tools/quic/test_tools/quic_test_server.h
@@ -35,7 +35,8 @@ const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config) = 0; + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache) = 0; }; // Factory for creating QuicSimpleServerStreams. @@ -89,7 +90,8 @@ ImmediateGoAwaySession(const QuicConfig& config, QuicConnection* connection, QuicServerSessionVisitor* visitor, - const QuicCryptoServerConfig* crypto_config); + const QuicCryptoServerConfig* crypto_config, + QuicCompressedCertsCache* compressed_certs_cache); }; } // namespace test
diff --git a/remoting/client/chromoting_client.cc b/remoting/client/chromoting_client.cc index 9239a35..71d020f 100644 --- a/remoting/client/chromoting_client.cc +++ b/remoting/client/chromoting_client.cc
@@ -53,7 +53,7 @@ void ChromotingClient::Start( SignalStrategy* signal_strategy, - scoped_ptr<protocol::Authenticator> authenticator, + const protocol::ClientAuthenticationConfig& client_auth_config, scoped_refptr<protocol::TransportContext> transport_context, const std::string& host_jid, const std::string& capabilities) { @@ -89,7 +89,7 @@ session_manager_.reset(new protocol::JingleSessionManager(signal_strategy)); session_manager_->set_protocol_config(std::move(protocol_config_)); - authenticator_ = std::move(authenticator); + client_auth_config_ = client_auth_config; transport_context_ = transport_context; signal_strategy_ = signal_strategy; @@ -212,7 +212,10 @@ void ChromotingClient::StartConnection() { DCHECK(thread_checker_.CalledOnValidThread()); connection_->Connect( - session_manager_->Connect(host_jid_, std::move(authenticator_)), + session_manager_->Connect( + host_jid_, + make_scoped_ptr(new protocol::NegotiatingClientAuthenticator( + client_auth_config_))), transport_context_, this); }
diff --git a/remoting/client/chromoting_client.h b/remoting/client/chromoting_client.h index 48cd5f9..6563720 100644 --- a/remoting/client/chromoting_client.h +++ b/remoting/client/chromoting_client.h
@@ -16,6 +16,7 @@ #include "remoting/protocol/clipboard_stub.h" #include "remoting/protocol/connection_to_host.h" #include "remoting/protocol/input_stub.h" +#include "remoting/protocol/negotiating_client_authenticator.h" #include "remoting/protocol/performance_tracker.h" #include "remoting/protocol/session_config.h" #include "remoting/protocol/video_stub.h" @@ -63,7 +64,7 @@ // Start the client. Must be called on the main thread. |signal_strategy| // must outlive the client. void Start(SignalStrategy* signal_strategy, - scoped_ptr<protocol::Authenticator> authenticator, + const protocol::ClientAuthenticationConfig& client_auth_config, scoped_refptr<protocol::TransportContext> transport_context, const std::string& host_jid, const std::string& capabilities); @@ -121,7 +122,7 @@ SignalStrategy* signal_strategy_ = nullptr; std::string host_jid_; - scoped_ptr<protocol::Authenticator> authenticator_; + protocol::ClientAuthenticationConfig client_auth_config_; scoped_refptr<protocol::TransportContext> transport_context_; scoped_ptr<protocol::SessionManager> session_manager_;
diff --git a/remoting/client/jni/chromoting_jni_instance.cc b/remoting/client/jni/chromoting_jni_instance.cc index d1602110..00066ed 100644 --- a/remoting/client/jni/chromoting_jni_instance.cc +++ b/remoting/client/jni/chromoting_jni_instance.cc
@@ -57,11 +57,8 @@ const std::string& capabilities, const std::string& flags) : jni_runtime_(jni_runtime), - host_id_(host_id), host_jid_(host_jid), flags_(flags), - create_pairing_(false), - stats_logging_enabled_(false), capabilities_(capabilities), weak_factory_(this) { DCHECK(jni_runtime_->ui_task_runner()->BelongsToCurrentThread()); @@ -73,13 +70,14 @@ xmpp_config_.username = username; xmpp_config_.auth_token = auth_token; - // Initialize |authenticator_|. - authenticator_.reset(new protocol::NegotiatingClientAuthenticator( - pairing_id, pairing_secret, host_id_, - base::Bind(&ChromotingJniInstance::FetchSecret, - weak_factory_.GetWeakPtr()), + client_auth_config_.host_id = host_id; + client_auth_config_.pairing_client_id = pairing_id; + client_auth_config_.pairing_secret = pairing_secret; + client_auth_config_.fetch_secret_callback = base::Bind( + &ChromotingJniInstance::FetchSecret, weak_factory_.GetWeakPtr()); + client_auth_config_.fetch_third_party_token_callback = base::Bind(&ChromotingJniInstance::FetchThirdPartyToken, - weak_factory_.GetWeakPtr(), host_pubkey))); + weak_factory_.GetWeakPtr(), host_pubkey); // Post a task to start connection jni_runtime_->network_task_runner()->PostTask( @@ -94,7 +92,6 @@ DCHECK(!view_); DCHECK(!client_context_); DCHECK(!video_renderer_); - DCHECK(!authenticator_); DCHECK(!client_); DCHECK(!signaling_); DCHECK(!client_status_logger_); @@ -108,8 +105,6 @@ return; } - host_id_.clear(); - stats_logging_enabled_ = false; // |client_| must be torn down before |signaling_|. @@ -117,7 +112,6 @@ client_status_logger_.reset(); video_renderer_.reset(); view_.reset(); - authenticator_.reset(); signaling_.reset(); perf_tracker_.reset(); client_context_.reset(); @@ -333,30 +327,25 @@ void ChromotingJniInstance::SetCapabilities(const std::string& capabilities) { jni_runtime_->ui_task_runner()->PostTask( - FROM_HERE, - base::Bind(&ChromotingJniRuntime::SetCapabilities, - base::Unretained(jni_runtime_), - capabilities)); + FROM_HERE, base::Bind(&ChromotingJniRuntime::SetCapabilities, + base::Unretained(jni_runtime_), capabilities)); } void ChromotingJniInstance::SetPairingResponse( const protocol::PairingResponse& response) { - jni_runtime_->ui_task_runner()->PostTask( FROM_HERE, base::Bind(&ChromotingJniRuntime::CommitPairingCredentials, - base::Unretained(jni_runtime_), - host_id_, response.client_id(), response.shared_secret())); + base::Unretained(jni_runtime_), client_auth_config_.host_id, + response.client_id(), response.shared_secret())); } void ChromotingJniInstance::DeliverHostMessage( const protocol::ExtensionMessage& message) { jni_runtime_->ui_task_runner()->PostTask( - FROM_HERE, - base::Bind(&ChromotingJniRuntime::HandleExtensionMessage, - base::Unretained(jni_runtime_), - message.type(), - message.data())); + FROM_HERE, base::Bind(&ChromotingJniRuntime::HandleExtensionMessage, + base::Unretained(jni_runtime_), message.type(), + message.data())); } protocol::ClipboardStub* ChromotingJniInstance::GetClipboardStub() { @@ -398,16 +387,15 @@ video_renderer_.reset(new SoftwareVideoRenderer( client_context_->decode_task_runner(), view_.get(), perf_tracker_.get())); - client_.reset(new ChromotingClient( - client_context_.get(), this, video_renderer_.get(), nullptr)); + client_.reset(new ChromotingClient(client_context_.get(), this, + video_renderer_.get(), nullptr)); - signaling_.reset(new XmppSignalStrategy( - net::ClientSocketFactory::GetDefaultFactory(), - jni_runtime_->url_requester(), xmpp_config_)); + signaling_.reset( + new XmppSignalStrategy(net::ClientSocketFactory::GetDefaultFactory(), + jni_runtime_->url_requester(), xmpp_config_)); client_status_logger_.reset( - new ClientStatusLogger(ServerLogEntry::ME2ME, - signaling_.get(), + new ClientStatusLogger(ServerLogEntry::ME2ME, signaling_.get(), ServiceUrls::GetInstance()->directory_bot_jid())); scoped_refptr<protocol::TransportContext> transport_context = @@ -429,7 +417,7 @@ client_->set_protocol_config(std::move(protocol_config)); } - client_->Start(signaling_.get(), std::move(authenticator_), transport_context, + client_->Start(signaling_.get(), client_auth_config_, transport_context, host_jid_, capabilities_); } @@ -444,7 +432,7 @@ } // Delete pairing credentials if they exist. - jni_runtime_->CommitPairingCredentials(host_id_, "", ""); + jni_runtime_->CommitPairingCredentials(client_auth_config_.host_id, "", ""); pin_callback_ = callback; jni_runtime_->DisplayAuthenticationPrompt(pairable);
diff --git a/remoting/client/jni/chromoting_jni_instance.h b/remoting/client/jni/chromoting_jni_instance.h index 9eab8d97..ae2c8626 100644 --- a/remoting/client/jni/chromoting_jni_instance.h +++ b/remoting/client/jni/chromoting_jni_instance.h
@@ -147,9 +147,10 @@ ChromotingJniRuntime* jni_runtime_; // ID of the host we are connecting to. - std::string host_id_; std::string host_jid_; + protocol::ClientAuthenticationConfig client_auth_config_; + std::string flags_; // This group of variables is to be used on the network thread. @@ -157,7 +158,6 @@ scoped_ptr<protocol::PerformanceTracker> perf_tracker_; scoped_ptr<JniFrameConsumer> view_; scoped_ptr<protocol::VideoRenderer> video_renderer_; - scoped_ptr<protocol::Authenticator> authenticator_; scoped_ptr<ChromotingClient> client_; XmppSignalStrategy::XmppServerConfig xmpp_config_; scoped_ptr<XmppSignalStrategy> signaling_; // Must outlive client_ @@ -172,7 +172,7 @@ // modified in ProvideSecret(), but thereafter to be used only from the // network thread. (This is safe because ProvideSecret() is invoked at most // once per run, and always before any reference to this flag.) - bool create_pairing_; + bool create_pairing_ = false; // The device name to appear in the paired-clients list. Accessed on the // network thread. @@ -180,7 +180,7 @@ // If this is true, performance statistics will be periodically written to // the Android log. Used on the network thread. - bool stats_logging_enabled_; + bool stats_logging_enabled_ = false; // The set of capabilities supported by the client. Accessed on the network // thread. Once SetCapabilities() is called, this will contain the negotiated
diff --git a/remoting/client/plugin/chromoting_instance.cc b/remoting/client/plugin/chromoting_instance.cc index 1365821..e0ca0d5 100644 --- a/remoting/client/plugin/chromoting_instance.cc +++ b/remoting/client/plugin/chromoting_instance.cc
@@ -579,26 +579,24 @@ } void ChromotingInstance::HandleConnect(const base::DictionaryValue& data) { + protocol::ClientAuthenticationConfig client_auth_config; + std::string local_jid; std::string host_jid; std::string host_public_key; - std::string authentication_tag; if (!data.GetString("hostJid", &host_jid) || !data.GetString("hostPublicKey", &host_public_key) || !data.GetString("localJid", &local_jid) || - !data.GetString("authenticationTag", &authentication_tag)) { + !data.GetString("hostId", &client_auth_config.host_id)) { LOG(ERROR) << "Invalid connect() data."; return; } - std::string client_pairing_id; - data.GetString("clientPairingId", &client_pairing_id); - std::string client_paired_secret; - data.GetString("clientPairedSecret", &client_paired_secret); + data.GetString("clientPairingId", &client_auth_config.pairing_client_id); + data.GetString("clientPairedSecret", &client_auth_config.pairing_secret); - protocol::FetchSecretCallback fetch_secret_callback; if (use_async_pin_dialog_) { - fetch_secret_callback = base::Bind( + client_auth_config.fetch_secret_callback = base::Bind( &ChromotingInstance::FetchSecretFromDialog, weak_factory_.GetWeakPtr()); } else { std::string shared_secret; @@ -606,10 +604,14 @@ LOG(ERROR) << "sharedSecret not specified in connect()."; return; } - fetch_secret_callback = + client_auth_config.fetch_secret_callback = base::Bind(&ChromotingInstance::FetchSecretFromString, shared_secret); } + client_auth_config.fetch_third_party_token_callback = + base::Bind(&ChromotingInstance::FetchThirdPartyToken, + weak_factory_.GetWeakPtr(), host_public_key); + // Read the list of capabilities, if any. std::string capabilities; if (data.HasKey("capabilities")) { @@ -695,16 +697,6 @@ protocol::NetworkSettings::NAT_TRAVERSAL_FULL), protocol::TransportRole::CLIENT)); - // Create Authenticator. - protocol::FetchThirdPartyTokenCallback fetch_third_party_token_callback = - base::Bind(&ChromotingInstance::FetchThirdPartyToken, - weak_factory_.GetWeakPtr(), host_public_key); - - scoped_ptr<protocol::Authenticator> authenticator( - new protocol::NegotiatingClientAuthenticator( - client_pairing_id, client_paired_secret, authentication_tag, - fetch_secret_callback, fetch_third_party_token_callback)); - scoped_ptr<protocol::CandidateSessionConfig> config = protocol::CandidateSessionConfig::CreateDefault(); if (std::find(experiments_list.begin(), experiments_list.end(), "vp9") != @@ -714,8 +706,8 @@ client_->set_protocol_config(std::move(config)); // Kick off the connection. - client_->Start(signal_strategy_.get(), std::move(authenticator), - transport_context, host_jid, capabilities); + client_->Start(signal_strategy_.get(), client_auth_config, transport_context, + host_jid, capabilities); // Connect the input pipeline to the protocol stub. mouse_input_filter_.set_input_stub(client_->input_stub());
diff --git a/remoting/protocol/negotiating_authenticator_base.h b/remoting/protocol/negotiating_authenticator_base.h index a920af4..1a43a9e 100644 --- a/remoting/protocol/negotiating_authenticator_base.h +++ b/remoting/protocol/negotiating_authenticator_base.h
@@ -13,7 +13,10 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "remoting/protocol/authenticator.h" -#include "third_party/webrtc/libjingle/xmllite/xmlelement.h" + +namespace buzz { +struct StaticQName; +} // namespace buzz namespace remoting { namespace protocol {
diff --git a/remoting/protocol/negotiating_authenticator_unittest.cc b/remoting/protocol/negotiating_authenticator_unittest.cc index 0161e65..534eecc 100644 --- a/remoting/protocol/negotiating_authenticator_unittest.cc +++ b/remoting/protocol/negotiating_authenticator_unittest.cc
@@ -65,14 +65,17 @@ host_cert_, key_pair_, host_secret_hash, pairing_registry_); } + + protocol::ClientAuthenticationConfig client_auth_config; + client_auth_config.host_id = kTestHostId; + client_auth_config.pairing_client_id = client_id; + client_auth_config.pairing_secret= client_paired_secret; bool pairing_expected = pairing_registry_.get() != nullptr; - FetchSecretCallback fetch_secret_callback = + client_auth_config.fetch_secret_callback = base::Bind(&NegotiatingAuthenticatorTest::FetchSecret, - client_interactive_pin, - pairing_expected); - client_as_negotiating_authenticator_ = new NegotiatingClientAuthenticator( - client_id, client_paired_secret, kTestHostId, fetch_secret_callback, - FetchThirdPartyTokenCallback()); + client_interactive_pin, pairing_expected); + client_as_negotiating_authenticator_ = + new NegotiatingClientAuthenticator(client_auth_config); client_.reset(client_as_negotiating_authenticator_); }
diff --git a/remoting/protocol/negotiating_client_authenticator.cc b/remoting/protocol/negotiating_client_authenticator.cc index c6cda5d..11dd49a 100644 --- a/remoting/protocol/negotiating_client_authenticator.cc +++ b/remoting/protocol/negotiating_client_authenticator.cc
@@ -21,20 +21,15 @@ namespace remoting { namespace protocol { +ClientAuthenticationConfig::ClientAuthenticationConfig() {} +ClientAuthenticationConfig::~ClientAuthenticationConfig() {} + NegotiatingClientAuthenticator::NegotiatingClientAuthenticator( - const std::string& client_pairing_id, - const std::string& shared_secret, - const std::string& authentication_tag, - const FetchSecretCallback& fetch_secret_callback, - const FetchThirdPartyTokenCallback& fetch_third_party_token_callback) + const ClientAuthenticationConfig& config) : NegotiatingAuthenticatorBase(MESSAGE_READY), - client_pairing_id_(client_pairing_id), - shared_secret_(shared_secret), - authentication_tag_(authentication_tag), - fetch_secret_callback_(fetch_secret_callback), - fetch_third_party_token_callback_(fetch_third_party_token_callback), + config_(config), weak_factory_(this) { - if (!fetch_third_party_token_callback.is_null()) + if (!config_.fetch_third_party_token_callback.is_null()) AddMethod(Method::THIRD_PARTY); AddMethod(Method::SPAKE2_PAIR); AddMethod(Method::SPAKE2_SHARED_SECRET_HMAC); @@ -115,7 +110,7 @@ if (current_method_ == Method::THIRD_PARTY) { current_authenticator_.reset(new ThirdPartyClientAuthenticator( base::Bind(&V2Authenticator::CreateForClient), - fetch_third_party_token_callback_)); + config_.fetch_third_party_token_callback)); resume_callback.Run(); } else { DCHECK(current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN || @@ -125,20 +120,20 @@ SecretFetchedCallback callback = base::Bind( &NegotiatingClientAuthenticator::CreateV2AuthenticatorWithSecret, weak_factory_.GetWeakPtr(), preferred_initial_state, resume_callback); - fetch_secret_callback_.Run(pairing_supported, callback); + config_.fetch_secret_callback.Run(pairing_supported, callback); } } void NegotiatingClientAuthenticator::CreatePreferredAuthenticator() { - if (!client_pairing_id_.empty() && !shared_secret_.empty() && + if (!config_.pairing_client_id.empty() && !config_.pairing_secret.empty() && std::find(methods_.begin(), methods_.end(), Method::SPAKE2_PAIR) != methods_.end()) { // If the client specified a pairing id and shared secret, then create a // PairingAuthenticator. current_authenticator_.reset(new PairingClientAuthenticator( - client_pairing_id_, shared_secret_, - base::Bind(&V2Authenticator::CreateForClient), fetch_secret_callback_, - authentication_tag_)); + config_.pairing_client_id, config_.pairing_secret, + base::Bind(&V2Authenticator::CreateForClient), + config_.fetch_secret_callback, config_.host_id)); current_method_ = Method::SPAKE2_PAIR; } } @@ -150,7 +145,7 @@ current_authenticator_ = V2Authenticator::CreateForClient( (current_method_ == Method::SPAKE2_SHARED_SECRET_PLAIN) ? shared_secret - : GetSharedSecretHash(authentication_tag_, shared_secret), + : GetSharedSecretHash(config_.host_id, shared_secret), initial_state); resume_callback.Run(); }
diff --git a/remoting/protocol/negotiating_client_authenticator.h b/remoting/protocol/negotiating_client_authenticator.h index abdb58ca..0867d10 100644 --- a/remoting/protocol/negotiating_client_authenticator.h +++ b/remoting/protocol/negotiating_client_authenticator.h
@@ -18,18 +18,30 @@ namespace remoting { namespace protocol { +struct ClientAuthenticationConfig { + ClientAuthenticationConfig(); + ~ClientAuthenticationConfig(); + + // Used for all authenticators. + std::string host_id; + + // Used for pairing authenticators + std::string pairing_client_id; + std::string pairing_secret; + + // Used for shared secret authenticators. + FetchSecretCallback fetch_secret_callback; + + // Used for third party authenticators. + FetchThirdPartyTokenCallback fetch_third_party_token_callback; +}; + // Client-side implementation of NegotiatingAuthenticatorBase. // See comments in negotiating_authenticator_base.h for a general explanation. class NegotiatingClientAuthenticator : public NegotiatingAuthenticatorBase { public: - // TODO(jamiewalch): Pass ClientConfig instead of separate parameters. - NegotiatingClientAuthenticator( - const std::string& client_pairing_id, - const std::string& shared_secret, - const std::string& authentication_tag, - const FetchSecretCallback& fetch_secret_callback, - const FetchThirdPartyTokenCallback& fetch_third_party_token_callback); - + explicit NegotiatingClientAuthenticator( + const ClientAuthenticationConfig& config); ~NegotiatingClientAuthenticator() override; // Overriden from Authenticator. @@ -64,18 +76,7 @@ const base::Closure& resume_callback, const std::string& shared_secret); - // Used for pairing authenticators - std::string client_pairing_id_; - std::string shared_secret_; - - // Used for all authenticators. - std::string authentication_tag_; - - // Used for shared secret authenticators. - FetchSecretCallback fetch_secret_callback_; - - // Used for third party authenticators. - FetchThirdPartyTokenCallback fetch_third_party_token_callback_; + ClientAuthenticationConfig config_; // Internal NegotiatingClientAuthenticator data. bool method_set_by_host_ = false;
diff --git a/remoting/test/protocol_perftest.cc b/remoting/test/protocol_perftest.cc index cfbe304..d8a9643 100644 --- a/remoting/test/protocol_perftest.cc +++ b/remoting/test/protocol_perftest.cc
@@ -388,17 +388,15 @@ host_signaling_.get(), std::move(port_allocator_factory), nullptr, network_settings, protocol::TransportRole::CLIENT)); - scoped_ptr<protocol::Authenticator> client_authenticator( - new protocol::NegotiatingClientAuthenticator( - std::string(), // client_pairing_id - std::string(), // client_pairing_secret - kHostId, - base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)), - protocol::FetchThirdPartyTokenCallback())); + protocol::ClientAuthenticationConfig client_auth_config; + client_auth_config.host_id = kHostId; + client_auth_config.fetch_secret_callback = + base::Bind(&ProtocolPerfTest::FetchPin, base::Unretained(this)); + client_.reset( new ChromotingClient(client_context_.get(), this, this, nullptr)); client_->set_protocol_config(protocol_config_->Clone()); - client_->Start(client_signaling_.get(), std::move(client_authenticator), + client_->Start(client_signaling_.get(), client_auth_config, transport_context, kHostJid, std::string()); }
diff --git a/remoting/test/test_chromoting_client.cc b/remoting/test/test_chromoting_client.cc index 917980ca..9bc33ca 100644 --- a/remoting/test/test_chromoting_client.cc +++ b/remoting/test/test_chromoting_client.cc
@@ -126,25 +126,23 @@ new ChromiumUrlRequestFactory(request_context_getter)), network_settings, protocol::TransportRole::CLIENT)); - protocol::FetchSecretCallback fetch_secret_callback; + protocol::ClientAuthenticationConfig client_auth_config; + client_auth_config.host_id = connection_setup_info.host_id; + client_auth_config.pairing_client_id = connection_setup_info.pairing_id; + client_auth_config.pairing_secret = connection_setup_info.shared_secret; + if (!connection_setup_info.pin.empty()) { - fetch_secret_callback = base::Bind(&FetchSecret, connection_setup_info.pin); + client_auth_config.fetch_secret_callback = + base::Bind(&FetchSecret, connection_setup_info.pin); } - protocol::FetchThirdPartyTokenCallback fetch_third_party_token_callback = - base::Bind(&FetchThirdPartyToken, - connection_setup_info.authorization_code, - connection_setup_info.shared_secret); + client_auth_config.fetch_third_party_token_callback = base::Bind( + &FetchThirdPartyToken, connection_setup_info.authorization_code, + connection_setup_info.shared_secret); - scoped_ptr<protocol::Authenticator> authenticator( - new protocol::NegotiatingClientAuthenticator( - connection_setup_info.pairing_id, connection_setup_info.shared_secret, - connection_setup_info.host_id, fetch_secret_callback, - fetch_third_party_token_callback)); - - chromoting_client_->Start( - signal_strategy_.get(), std::move(authenticator), transport_context, - connection_setup_info.host_jid, connection_setup_info.capabilities); + chromoting_client_->Start(signal_strategy_.get(), client_auth_config, + transport_context, connection_setup_info.host_jid, + connection_setup_info.capabilities); } void TestChromotingClient::EndConnection() {
diff --git a/remoting/webapp/base/js/client_plugin_impl.js b/remoting/webapp/base/js/client_plugin_impl.js index 0157cbcf..626c5d9e 100644 --- a/remoting/webapp/base/js/client_plugin_impl.js +++ b/remoting/webapp/base/js/client_plugin_impl.js
@@ -449,11 +449,11 @@ this.plugin_.postMessage(JSON.stringify({ method: 'connect', data: { + hostId: host.hostId, hostJid: host.jabberId, hostPublicKey: host.publicKey, localJid: localJid, sharedSecret: '', - authenticationTag: host.hostId, capabilities: this.capabilities_.join(" "), clientPairingId: credentialsProvider.getPairingInfo().clientId, clientPairedSecret: credentialsProvider.getPairingInfo().sharedSecret,
diff --git a/sql/BUILD.gn b/sql/BUILD.gn index 4ffa421d..8c1cbb7 100644 --- a/sql/BUILD.gn +++ b/sql/BUILD.gn
@@ -113,6 +113,8 @@ # '../testing/android/native_test.gyp:native_test_native_code', # ], #}], + + # TODO(GYP): dep on copy_test_data_ios action. } if (is_android) {
diff --git a/sql/recovery.cc b/sql/recovery.cc index b79fe08..7b9ca9f 100644 --- a/sql/recovery.cc +++ b/sql/recovery.cc
@@ -98,11 +98,7 @@ // static bool Recovery::FullRecoverySupported() { // TODO(shess): See comment in Init(). -#if defined(USE_SYSTEM_SQLITE) - return false; -#else return true; -#endif } // static @@ -203,16 +199,7 @@ return false; } - // TODO(shess): Figure out a story for USE_SYSTEM_SQLITE. The - // virtual table implementation relies on SQLite internals for some - // types and functions, which could be copied inline to make it - // standalone. Or an alternate implementation could try to read - // through errors entirely at the SQLite level. - // - // For now, defer to the caller. The setup will succeed, but the - // later CREATE VIRTUAL TABLE call will fail, at which point the - // caller can fire Unrecoverable(). -#if !defined(USE_SYSTEM_SQLITE) + // Enable the recover virtual table for this connection. int rc = recoverVtableInit(recover_db_.db_); if (rc != SQLITE_OK) { RecordRecoveryEvent(RECOVERY_FAILED_VIRTUAL_TABLE_INIT); @@ -220,10 +207,6 @@ << recover_db_.GetErrorMessage(); return false; } -#else - // If this is infrequent enough, just wire it to Raze(). - RecordRecoveryEvent(RECOVERY_FAILED_VIRTUAL_TABLE_SYSTEM_SQLITE); -#endif // Turn on |SQLITE_RecoveryMode| for the handle, which allows // reading certain broken databases.
diff --git a/sql/recovery_unittest.cc b/sql/recovery_unittest.cc index e4fdb7b1..d3b04b1e 100644 --- a/sql/recovery_unittest.cc +++ b/sql/recovery_unittest.cc
@@ -172,9 +172,6 @@ ExecuteWithResults(&db(), kXSql, "|", "\n")); } -// The recovery virtual table is only supported for Chromium's SQLite. -#if !defined(USE_SYSTEM_SQLITE) - // Test operation of the virtual table used by sql::Recovery. TEST_F(SQLRecoveryTest, VirtualTable) { const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; @@ -737,7 +734,6 @@ EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); } } -#endif // !defined(USE_SYSTEM_SQLITE) // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery // database doesn't accidentally enable it.
diff --git a/sql/sql.gyp b/sql/sql.gyp index 30bd76d..cde3057 100644 --- a/sql/sql.gyp +++ b/sql/sql.gyp
@@ -114,6 +114,18 @@ '../testing/android/native_test.gyp:native_test_native_code', ], }], + ['OS == "ios"', { + 'actions': [{ + 'action_name': 'copy_test_data', + 'variables': { + 'test_data_files': [ + 'test/data', + ], + 'test_data_prefix' : 'sql', + }, + 'includes': [ '../build/copy_test_data_ios.gypi' ], + }], + }], ], # TODO(jschuh): crbug.com/167187 fix size_t to int truncations. 'msvs_disabled_warnings': [4267, ],
diff --git a/storage/browser/quota/quota_manager.cc b/storage/browser/quota/quota_manager.cc index 5000061..cb1add8 100644 --- a/storage/browser/quota/quota_manager.cc +++ b/storage/browser/quota/quota_manager.cc
@@ -1282,8 +1282,8 @@ QuotaManager::~QuotaManager() { proxy_->manager_ = NULL; - std::for_each(clients_.begin(), clients_.end(), - std::mem_fun(&QuotaClient::OnQuotaManagerDestroyed)); + for (auto* client : clients_) + client->OnQuotaManagerDestroyed(); if (database_) db_thread_->DeleteSoon(FROM_HERE, database_.release()); }
diff --git a/storage/browser/quota/quota_task.cc b/storage/browser/quota/quota_task.cc index a0bda59..55ade2b 100644 --- a/storage/browser/quota/quota_task.cc +++ b/storage/browser/quota/quota_task.cc
@@ -58,9 +58,8 @@ // QuotaTaskObserver ------------------------------------------------------- QuotaTaskObserver::~QuotaTaskObserver() { - std::for_each(running_quota_tasks_.begin(), - running_quota_tasks_.end(), - std::mem_fun(&QuotaTask::Abort)); + for (auto* task : running_quota_tasks_) + task->Abort(); } QuotaTaskObserver::QuotaTaskObserver() {
diff --git a/sync/internal_api/processor_entity_tracker.cc b/sync/internal_api/processor_entity_tracker.cc index 87c400c..67853791 100644 --- a/sync/internal_api/processor_entity_tracker.cc +++ b/sync/internal_api/processor_entity_tracker.cc
@@ -78,6 +78,10 @@ return RequiresCommitRequest() && !HasCommitData() && !metadata_.is_deleted(); } +bool ProcessorEntityTracker::CanClearMetadata() const { + return metadata_.is_deleted() && !IsUnsynced(); +} + bool ProcessorEntityTracker::UpdateIsReflection(int64_t update_version) const { return metadata_.server_version() >= update_version; } @@ -103,6 +107,7 @@ metadata_.set_acked_sequence_number(metadata_.sequence_number()); commit_requested_sequence_number_ = metadata_.sequence_number(); + metadata_.set_is_deleted(response_data.entity->is_deleted()); metadata_.set_server_version(response_data.response_version); metadata_.set_modification_time( syncer::TimeToProtoTime(response_data.entity->modification_time));
diff --git a/sync/internal_api/public/processor_entity_tracker.h b/sync/internal_api/public/processor_entity_tracker.h index a3c1d00..18a44c0 100644 --- a/sync/internal_api/public/processor_entity_tracker.h +++ b/sync/internal_api/public/processor_entity_tracker.h
@@ -61,6 +61,11 @@ // created. Note that deletions do not require cached data. bool RequiresCommitData() const; + // Whether it's safe to clear the metadata for this entity. This means that + // the entity is deleted and either knowledge of this entity has never left + // this client or it is up to date with the server. + bool CanClearMetadata() const; + // Returns true if the specified update version does not contain new data. bool UpdateIsReflection(int64_t update_version) const; @@ -118,6 +123,12 @@ ProcessorEntityTracker(const std::string& client_tag, sync_pb::EntityMetadata* metadata); + // Whether knowledge of this entity has never gone past the processor. This + // means that no commits have been queued and it did not originate at the + // server. This is used to determine whether it is safe to delete the tracker + // and metadata for this entity. + bool IsLocalOnly() const; + // Increment sequence number in the metadata. void IncrementSequenceNumber();
diff --git a/sync/internal_api/shared_model_type_processor.cc b/sync/internal_api/shared_model_type_processor.cc index 93fcdac..cb51cb72 100644 --- a/sync/internal_api/shared_model_type_processor.cc +++ b/sync/internal_api/shared_model_type_processor.cc
@@ -271,6 +271,7 @@ } entity->Delete(); + metadata_change_list->UpdateMetadata(tag, entity->metadata()); FlushPendingCommitRequests(); } @@ -326,10 +327,13 @@ entity->ReceiveCommitResponse(data.id, data.sequence_number, data.response_version, data_type_state_.encryption_key_name()); - // TODO(stanisc): crbug.com/573333: Delete case. - // This might be the right place to clear a metadata entry that has - // been deleted locally and confirmed deleted by the server. - change_list->UpdateMetadata(entity->client_tag(), entity->metadata()); + + if (entity->CanClearMetadata()) { + change_list->ClearMetadata(entity->client_tag()); + entities_.erase(entity->metadata().client_tag_hash()); + } else { + change_list->UpdateMetadata(entity->client_tag(), entity->metadata()); + } } // TODO(stanisc): crbug.com/570085: Error handling. @@ -382,13 +386,6 @@ } entity->ApplyUpdateFromServer(update); - // TODO(stanisc): crbug.com/573333: Delete case. - // This might be the right place to clear metadata entry instead of - // updating it. - metadata_changes->UpdateMetadata(entity->client_tag(), entity->metadata()); - - // TODO(stanisc): crbug.com/521867: Do something special when conflicts are - // detected. // If the received entity has out of date encryption, we schedule another // commit to fix it. @@ -400,6 +397,16 @@ it2->second->UpdateDesiredEncryptionKey( data_type_state_.encryption_key_name()); } + + if (entity->CanClearMetadata()) { + metadata_changes->ClearMetadata(entity->client_tag()); + entities_.erase(entity->metadata().client_tag_hash()); + } else { + // TODO(stanisc): crbug.com/521867: Do something special when conflicts + // are detected. + metadata_changes->UpdateMetadata(entity->client_tag(), + entity->metadata()); + } } if (got_new_encryption_requirements) {
diff --git a/sync/internal_api/shared_model_type_processor_unittest.cc b/sync/internal_api/shared_model_type_processor_unittest.cc index 53d17353..ce86190 100644 --- a/sync/internal_api/shared_model_type_processor_unittest.cc +++ b/sync/internal_api/shared_model_type_processor_unittest.cc
@@ -224,6 +224,19 @@ } } + // Wipes existing DB and simulates one commited item. + void ResetStateWriteAckedItem(const std::string& tag, + const std::string& value) { + clear_change_processor(); + db_.Reset(); + InitializeToReadyState(); + EXPECT_EQ(0U, ProcessorEntityCount()); + WriteItemAndAck(tag, "acked-value"); + WriteItem(tag, value); + EXPECT_EQ(1U, ProcessorEntityCount()); + clear_change_processor(); + } + // Wipes existing DB and simulates one uncommited item. void ResetStateWriteItem(const std::string& tag, const std::string& value) { clear_change_processor(); @@ -552,8 +565,9 @@ } // This test covers race conditions during loading pending data. All cases -// start with no processor and one item with a pending commit. There are three -// different events that can occur in any order once metadata is loaded: +// start with no processor and one acked (committed to the server) item with a +// pending commit. There are three different events that can occur in any order +// once metadata is loaded: // // - Pending commit data is loaded. // - Sync gets connected. @@ -562,7 +576,7 @@ // This results in 2 + 12 = 14 orderings of the events. TEST_F(SharedModelTypeProcessorTest, LoadPendingCommit) { // Data, connect. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnDataLoaded(); OnSyncStarting(); @@ -570,7 +584,7 @@ ExpectNthCommitRequestList(0, "tag1", "value1"); // Connect, data. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnSyncStarting(); EXPECT_EQ(0U, GetNumCommitRequestLists()); @@ -579,7 +593,7 @@ ExpectNthCommitRequestList(0, "tag1", "value1"); // Data, connect, put. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnDataLoaded(); OnSyncStarting(); @@ -589,7 +603,7 @@ ExpectNthCommitRequestList(1, "tag1", "value2"); // Data, put, connect. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnDataLoaded(); WriteItem("tag1", "value2"); @@ -598,7 +612,7 @@ ExpectNthCommitRequestList(0, "tag1", "value2"); // Connect, data, put. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnSyncStarting(); OnDataLoaded(); @@ -608,7 +622,7 @@ ExpectNthCommitRequestList(1, "tag1", "value2"); // Connect, put, data. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnSyncStarting(); WriteItem("tag1", "value2"); @@ -618,7 +632,7 @@ ExpectNthCommitRequestList(0, "tag1", "value2"); // Put, data, connect. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); WriteItem("tag1", "value2"); OnDataLoaded(); @@ -627,7 +641,7 @@ ExpectNthCommitRequestList(0, "tag1", "value2"); // Put, connect, data. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); WriteItem("tag1", "value2"); OnSyncStarting(); @@ -637,7 +651,7 @@ ExpectNthCommitRequestList(0, "tag1", "value2"); // Data, connect, delete. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnDataLoaded(); OnSyncStarting(); @@ -647,7 +661,7 @@ ExpectNthCommitRequestList(1, "tag1", ""); // Data, delete, connect. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnDataLoaded(); DeleteItem("tag1"); @@ -656,7 +670,7 @@ ExpectNthCommitRequestList(0, "tag1", ""); // Connect, data, delete. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnSyncStarting(); OnDataLoaded(); @@ -666,7 +680,7 @@ ExpectNthCommitRequestList(1, "tag1", ""); // Connect, delete, data. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); OnSyncStarting(); DeleteItem("tag1"); @@ -676,7 +690,7 @@ ExpectNthCommitRequestList(0, "tag1", ""); // Delete, data, connect. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); DeleteItem("tag1"); OnDataLoaded(); @@ -685,7 +699,7 @@ ExpectNthCommitRequestList(0, "tag1", ""); // Delete, connect, data. - ResetStateWriteItem("tag1", "value1"); + ResetStateWriteAckedItem("tag1", "value1"); InitializeToMetadataLoaded(); DeleteItem("tag1"); OnSyncStarting(); @@ -753,10 +767,7 @@ // Test that loading a committed item does not queue another commit. TEST_F(SharedModelTypeProcessorTest, LoadCommited) { InitializeToReadyState(); - WriteItem("tag1", "value1"); - // Complete the commit. - EXPECT_TRUE(HasCommitRequestForTag("tag1")); - SuccessfulCommitResponse(GetLatestCommitRequestForTag("tag1")); + WriteItemAndAck("tag1", "value1"); clear_change_processor(); // Test that a new processor loads the metadata without committing. @@ -910,35 +921,24 @@ EXPECT_NE(metadata_v1.specifics_hash(), metadata_v2.specifics_hash()); } -// Deletes an item we've never seen before. -// Should have no effect and not crash. -TEST_F(SharedModelTypeProcessorTest, DeleteUnknown) { - InitializeToReadyState(); - DeleteItem("tag1"); - EXPECT_EQ(0U, GetNumCommitRequestLists()); - EXPECT_EQ(0U, db().MetadataCount()); -} - // Creates an item locally then deletes it. // -// In this test, no commit responses are received, so the deleted item is -// server-unknown as far as the model thread is concerned. That behavior -// is race-dependent; other tests are used to test other races. -TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown) { +// The item is created locally then enqueued for commit. The sync thread +// successfully commits it, but, before the commit response is picked up +// by the model thread, the item is deleted by the model thread. Commit +// responses for both commits are then generated to ensure things are handled +// correctly. +TEST_F(SharedModelTypeProcessorTest, DeleteItem) { InitializeToReadyState(); - - // TODO(stanisc): crbug.com/573333: Review this case. If the flush of - // all locally modified items was scheduled to run on a separate task, than - // the correct behavior would be to commit just the detele, or perhaps no - // commit at all. - WriteItem("tag1", "value1"); - EXPECT_EQ(1U, db().MetadataCount()); ExpectCommitRequests({"tag1"}); const CommitRequestData& data_v1 = GetLatestCommitRequestForTag("tag1"); const sync_pb::EntityMetadata metadata_v1 = db().GetMetadata("tag1"); DeleteItem("tag1"); + EXPECT_EQ(0U, db().DataCount()); + // A commit was queued so the metadata should still exist. + EXPECT_EQ(1U, ProcessorEntityCount()); EXPECT_EQ(1U, db().MetadataCount()); ExpectCommitRequests({"tag1", "tag1"}); const CommitRequestData& data_v2 = GetLatestCommitRequestForTag("tag1"); @@ -955,63 +955,44 @@ EXPECT_EQ(0, metadata_v1.acked_sequence_number()); EXPECT_EQ(kUncommittedVersion, metadata_v1.server_version()); - // TODO(stanisc): crbug.com/573333: Review this case. Depending on the - // implementation the second action performed on metadata change list might - // be CLEAR_METADATA. For a real implementation of MetadataChangeList this - // might also mean that the change list wouldn't contain any metadata - // records at all - the first call would create an entry and the second would - // remove it. - EXPECT_TRUE(metadata_v2.is_deleted()); EXPECT_EQ(2, metadata_v2.sequence_number()); EXPECT_EQ(0, metadata_v2.acked_sequence_number()); EXPECT_EQ(kUncommittedVersion, metadata_v2.server_version()); -} -// Creates an item locally then deletes it. -// -// The item is created locally then enqueued for commit. The sync thread -// successfully commits it, but, before the commit response is picked up -// by the model thread, the item is deleted by the model thread. -TEST_F(SharedModelTypeProcessorTest, DeleteServerUnknown_RacyCommitResponse) { - InitializeToReadyState(); - - WriteItem("tag1", "value1"); - EXPECT_EQ(1U, db().DataCount()); - EXPECT_EQ(1U, db().MetadataCount()); - ExpectCommitRequests({"tag1"}); - const CommitRequestData& data_v1 = GetLatestCommitRequestForTag("tag1"); - EXPECT_FALSE(db().GetMetadata("tag1").is_deleted()); - - DeleteItem("tag1"); - EXPECT_EQ(0U, db().DataCount()); - EXPECT_EQ(1U, db().MetadataCount()); - ExpectCommitRequests({"tag1", "tag1"}); - EXPECT_TRUE(db().GetMetadata("tag1").is_deleted()); - - // This commit happened while the deletion was in progress, but the commit - // response didn't arrive on our thread until after the delete was issued to - // the sync thread. It will update some metadata, but won't do much else. + // A response for the first commit doesn't change much. SuccessfulCommitResponse(data_v1); EXPECT_EQ(0U, db().DataCount()); + EXPECT_EQ(1U, ProcessorEntityCount()); EXPECT_EQ(1U, db().MetadataCount()); - // In reality the change list used to commit local changes should never - // overlap with the changelist used to deliver commit confirmation. In this - // test setup the two change lists are isolated - one is on the stack and - // another is the class member. + SuccessfulCommitResponse(data_v2); + // The delete was acked so the metadata should now be cleared. + EXPECT_EQ(0U, ProcessorEntityCount()); + EXPECT_EQ(0U, db().MetadataCount()); +} - const sync_pb::EntityMetadata metadata_v2 = db().GetMetadata("tag1"); - // Deleted from the second local modification. - EXPECT_TRUE(metadata_v2.is_deleted()); - // sequence_number = 2 from the second local modification. - EXPECT_EQ(2, metadata_v2.sequence_number()); - // acked_sequence_number = 1 from the first commit response. - EXPECT_EQ(1, metadata_v2.acked_sequence_number()); +TEST_F(SharedModelTypeProcessorTest, ServerDeleteItem) { + InitializeToReadyState(); + WriteItemAndAck("tag1", "value1"); + EXPECT_EQ(1U, ProcessorEntityCount()); + EXPECT_EQ(1U, db().MetadataCount()); + EXPECT_EQ(1U, db().DataCount()); - // TODO(rlarocque): Verify the state of the item is correct once we get - // storage hooked up in these tests. For example, verify the item is still - // marked as deleted. + TombstoneFromServer(5, "tag1"); + // Delete from server should clear the data and all the metadata. + EXPECT_EQ(0U, db().DataCount()); + EXPECT_EQ(0U, ProcessorEntityCount()); + EXPECT_EQ(0U, db().MetadataCount()); +} + +// Deletes an item we've never seen before. +// Should have no effect and not crash. +TEST_F(SharedModelTypeProcessorTest, DeleteUnknown) { + InitializeToReadyState(); + DeleteItem("tag1"); + EXPECT_EQ(0U, GetNumCommitRequestLists()); + EXPECT_EQ(0U, db().MetadataCount()); } // Creates two different sync items.
diff --git a/testing/variations/fieldtrial_testing_config_android.json b/testing/variations/fieldtrial_testing_config_android.json index 365fe5e..caed77c 100644 --- a/testing/variations/fieldtrial_testing_config_android.json +++ b/testing/variations/fieldtrial_testing_config_android.json
@@ -381,6 +381,11 @@ } } ], + "UnifiedMediaPipeline": [ + { + "group_name": "Enabled" + } + ], "UpdateMenuItem": [ { "group_name": "Enabled",
diff --git a/third_party/WebKit/LayoutTests/SlowTests b/third_party/WebKit/LayoutTests/SlowTests index 3fcee72..a9113f27 100644 --- a/third_party/WebKit/LayoutTests/SlowTests +++ b/third_party/WebKit/LayoutTests/SlowTests
@@ -284,3 +284,5 @@ crbug.com/584807 virtual/threaded/printing/webgl-oversized-printing.html [ Slow ] crbug.com/592183 usb/usbDevice.html [ Slow ] + +crbug.com/594189 virtual/spv2/fast/overflow/lots-of-sibling-inline-boxes.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index b418031..1c440cf9 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1449,6 +1449,8 @@ crbug.com/591821 virtual/trustedeventsdefaultaction/fast/events/scale-and-scroll-iframe-body.html [ Failure Pass ] crbug.com/591821 virtual/trustedeventsdefaultaction/fast/events/updateLayoutForHitTest.html [ Failure Pass ] +crbug.com/594196 virtual/threaded/fast/canvas-toBlob/canvas-createImageBitmap-blob-in-workers.html [ Failure Pass ] + crbug.com/593888 [ Linux Debug ] fast/dom/htmlcollection-reachable.html [ Timeout ] crbug.com/593917 fast/writing-mode/japanese-rl-selection.html [ NeedsRebaseline ] @@ -1459,6 +1461,10 @@ crbug.com/591825 [ Mac10.11 Debug ] fast/text/selection-multiple-runs.html [ Failure ] +crbug.com/594230 [ Linux Debug ] fast/files/workers/worker-read-blob-async-crash.html [ Crash Pass ] +crbug.com/594230 [ Linux Debug ] http/tests/fetch/serviceworker/fetch.html [ Crash Pass ] +crbug.com/594230 [ Linux Debug ] http/tests/fetch/serviceworker/fetch-base-https-other-https.html [ Crash Pass ] + crbug.com/593567 [ Linux Win Debug ] virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure ] crbug.com/593567 [ Linux Win Debug ] virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure ] crbug.com/593567 [ Linux Win Debug ] virtual/scalefactor150/fast/hidpi/static/popup-menu-appearance.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface-expected.txt b/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface-expected.txt new file mode 100644 index 0000000..9eb0b03 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface-expected.txt
@@ -0,0 +1,11 @@ +Tests that unused font with a data: URL is not loaded. No console warning for font load error is expected. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS faces.length is 1 +PASS faces[0].status is "unloaded" +PASS successfullyParsed is true + +TEST COMPLETE +
diff --git a/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface.html b/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface.html new file mode 100644 index 0000000..398693e --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/css/unused-data-url-fontface.html
@@ -0,0 +1,31 @@ +<html> +<head> +<script src="../../resources/js-test.js"></script> +<style> +@font-face { + font-family: Unused; + src: url("data:font/ttf,unused-font"); +} +</style> +<script> +description("Tests that unused font with a data: URL is not loaded. " + + "No console warning for font load error is expected."); +window.jsTestIsAsync = true; + +function getDocumentFontFaces() { + var faces = []; + document.fonts.forEach(function(face) { faces.push(face); }); + return faces; +} + +function doTest() { + faces = getDocumentFontFaces(); + shouldBeEqualToNumber('faces.length', 1); + shouldBeEqualToString('faces[0].status', 'unloaded'); + finishJSTest(); +} +</script> +</head> +<body onload="doTest()"> +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/fast/events/before-unload-reloads-expected.txt b/third_party/WebKit/LayoutTests/fast/events/before-unload-reloads-expected.txt index 41933ec3c..6a1b4a8 100644 --- a/third_party/WebKit/LayoutTests/fast/events/before-unload-reloads-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/before-unload-reloads-expected.txt
@@ -1,3 +1,3 @@ -CONFIRM NAVIGATION: +CONFIRM NAVIGATION This test passes if the FAIL changes to PASS after clicking "Stay on this page". PASS
diff --git a/third_party/WebKit/LayoutTests/fast/events/before-unload-returnValue-expected.txt b/third_party/WebKit/LayoutTests/fast/events/before-unload-returnValue-expected.txt index 46b00e6..6aaad7a 100644 --- a/third_party/WebKit/LayoutTests/fast/events/before-unload-returnValue-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/events/before-unload-returnValue-expected.txt
@@ -1,4 +1,4 @@ -CONFIRM NAVIGATION: This is beforeunload from the top level frame. +CONFIRM NAVIGATION Tests the returnValue attribute of the BeforeUnloadEvent. On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div-expected.txt b/third_party/WebKit/LayoutTests/fast/events/panScroll-drag-scrollable-iframe-div-expected.txt similarity index 100% copy from third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div-expected.txt copy to third_party/WebKit/LayoutTests/fast/events/panScroll-drag-scrollable-iframe-div-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html b/third_party/WebKit/LayoutTests/fast/events/panScroll-drag-scrollable-iframe-div.html similarity index 93% rename from third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html rename to third_party/WebKit/LayoutTests/fast/events/panScroll-drag-scrollable-iframe-div.html index 4f81b02..a870a1e 100644 --- a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html +++ b/third_party/WebKit/LayoutTests/fast/events/panScroll-drag-scrollable-iframe-div.html
@@ -36,7 +36,11 @@ var testCompleted = document.getElementById("testCompletedButton"); var h = testCompleted.offsetTop - document.scrollingElement.scrollTop + 10; eventSender.dragMode = false; - eventSender.mouseMoveTo(20, testCompleted.offsetTop); + eventSender.mouseMoveTo(20, h); + // This click exits the pan scroll mode. + eventSender.mouseDown(); + eventSender.mouseUp(); + // This click actually clicks the button. eventSender.mouseDown(); eventSender.mouseUp(); testRunner.runAfterLayoutAndPaint(checkButtonClicked);
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div-expected.txt b/third_party/WebKit/LayoutTests/fast/events/panScroll-modal-scrollable-iframe-div-expected.txt similarity index 100% rename from third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div-expected.txt rename to third_party/WebKit/LayoutTests/fast/events/panScroll-modal-scrollable-iframe-div-expected.txt
diff --git a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html b/third_party/WebKit/LayoutTests/fast/events/panScroll-modal-scrollable-iframe-div.html similarity index 93% copy from third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html copy to third_party/WebKit/LayoutTests/fast/events/panScroll-modal-scrollable-iframe-div.html index 4f81b02..bfcd0b1 100644 --- a/third_party/WebKit/LayoutTests/fast/events/autoscroll-scrollable-iframe-div.html +++ b/third_party/WebKit/LayoutTests/fast/events/panScroll-modal-scrollable-iframe-div.html
@@ -21,8 +21,8 @@ eventSender.dragMode = false; eventSender.mouseMoveTo(x, y); eventSender.mouseDown(1); - eventSender.mouseMoveTo(x + 220, y + 220); eventSender.mouseUp(1); + eventSender.mouseMoveTo(x + 220, y + 220); testRunner.layoutAndPaintAsyncThen(autoscrollTestPart2); }); } @@ -36,7 +36,11 @@ var testCompleted = document.getElementById("testCompletedButton"); var h = testCompleted.offsetTop - document.scrollingElement.scrollTop + 10; eventSender.dragMode = false; - eventSender.mouseMoveTo(20, testCompleted.offsetTop); + eventSender.mouseMoveTo(20, h); + // This click exits the pan scroll mode. + eventSender.mouseDown(); + eventSender.mouseUp(); + // This click actually clicks the button. eventSender.mouseDown(); eventSender.mouseUp(); testRunner.runAfterLayoutAndPaint(checkButtonClicked);
diff --git a/third_party/WebKit/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel-expected.txt b/third_party/WebKit/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel-expected.txt index 7ce1153..823a068b 100644 --- a/third_party/WebKit/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/loader/form-submission-after-beforeunload-cancel-expected.txt
@@ -1,3 +1,3 @@ -CONFIRM NAVIGATION: Click 'Stay on Page' -CONFIRM NAVIGATION: Click 'Leave Page' +CONFIRM NAVIGATION +CONFIRM NAVIGATION PASS
diff --git a/third_party/WebKit/LayoutTests/fast/loader/show-only-one-beforeunload-dialog-expected.txt b/third_party/WebKit/LayoutTests/fast/loader/show-only-one-beforeunload-dialog-expected.txt index f2bf112..d1c57c7 100644 --- a/third_party/WebKit/LayoutTests/fast/loader/show-only-one-beforeunload-dialog-expected.txt +++ b/third_party/WebKit/LayoutTests/fast/loader/show-only-one-beforeunload-dialog-expected.txt
@@ -1,4 +1,4 @@ -CONFIRM NAVIGATION: This is beforeunload from the top level frame. +CONFIRM NAVIGATION CONSOLE ERROR: Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation. CONSOLE ERROR: Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation.
diff --git a/third_party/WebKit/LayoutTests/fast/pagination/auto-height-with-break.html b/third_party/WebKit/LayoutTests/fast/pagination/auto-height-with-break.html index be1da94..12b5cc9 100644 --- a/third_party/WebKit/LayoutTests/fast/pagination/auto-height-with-break.html +++ b/third_party/WebKit/LayoutTests/fast/pagination/auto-height-with-break.html
@@ -7,7 +7,7 @@ <br> <br> <br> - <div style="break-before:always; -webkit-column-break-before:always;">FAIL</div> + <div style="break-before:page;">FAIL</div> </div> </body> </html>
diff --git a/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow-expected.html b/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow-expected.html new file mode 100644 index 0000000..0e56f32 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow-expected.html
@@ -0,0 +1,43 @@ +<!DOCTYPE html> +<style> + .container { + overflow-x: auto; + float: left; + width: 5em; + height: 5em; + line-height: 2em; + margin: 2px; + border: 1px solid hotpink; + } + .filler { width:200%; height:1px; } +</style> +<p>There should be 7 boxes below. Each should contain the word "PASS" + once, and no "FAIL". Scrollbars may or may not be present. The + exact position of the word "PASS" will vary from box to box.</p> +<div class="container"> + <div>PASS<br></div> + <div class="filler"></div> +</div> +<div class="container"> + <div style="break-after:page;">PASS<br></div> + <div class="filler"></div> +</div> +<div class="container"> + <br>PASS +</div> +<div class="container"> + <br>PASS +</div> +<div class="container"> + PASS<br> + <div class="filler"></div> +</div> +<div class="container"> + PASS<br> + <div class="filler"></div> +</div> +<div class="container"> + <br> + PASS<br> + <div class="filler"></div> +</div>
diff --git a/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow.html b/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow.html new file mode 100644 index 0000000..7ed6f96 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/pagination/break-in-paged-overflow.html
@@ -0,0 +1,53 @@ +<!DOCTYPE html> +<style> + .container { + overflow: -webkit-paged-x; + float: left; + width: 5em; + height: 5em; + line-height: 2em; + margin: 2px; + border: 1px solid hotpink; + column-gap: 0; /* See crbug.com/460106 */ + } +</style> +<p>There should be 7 boxes below. Each should contain the word "PASS" + once, and no "FAIL". Scrollbars may or may not be present. The + exact position of the word "PASS" will vary from box to box.</p> +<div class="container"> + <div>PASS<br></div> + <div style="break-before:page;">FAIL</div> +</div> +<div class="container"> + <div style="break-after:page;">PASS<br></div> + <div>FAIL</div> +</div> +<div class="container"> + <div style="break-after:column;"><br></div> <!-- declaration should have no effect --> + <div>PASS</div> +</div> +<div class="container"> + <div><br></div> + <div style="break-before:column;">PASS</div> <!-- declaration should have no effect --> +</div> +<div class="container"> + PASS<br> + <div style="break-inside:avoid;"> + FAIL<br> + FAIL<br> + </div> +</div> +<div class="container"> + PASS<br> + <div style="break-inside:avoid-page;"> + FAIL<br> + FAIL<br> + </div> +</div> +<div class="container"> + <br> + <div style="break-inside:avoid-column;"> <!-- declaration should have no effect --> + PASS<br> + <br> + </div> +</div>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/edit-css-with-source-url.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/edit-css-with-source-url.html index 896e1bdc..145442f9 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/edit-css-with-source-url.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/edit-css-with-source-url.html
@@ -50,7 +50,7 @@ { dumpUISourceCodeContents(); InspectorTest.addResult("Loading stylesheet with sourceURL:"); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, stylesheetLoaded); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, stylesheetLoaded); InspectorTest.evaluateInPage("loadStylesheet()"); } @@ -58,7 +58,7 @@ { if (!event.data.sourceURL.includes("foo.css")) return; - InspectorTest.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, stylesheetLoaded); + InspectorTest.cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, stylesheetLoaded); InspectorTest.addResult("Stylesheet loaded."); InspectorTest.selectNodeAndWaitForStyles("inspected", nodeSelected); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/selector-line-deprecated.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/selector-line-deprecated.html index e342e4ab..4bc11a0 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/selector-line-deprecated.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/selector-line-deprecated.html
@@ -20,7 +20,7 @@ function test() { - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, step1, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, step1, this); InspectorTest.evaluateInPage("addStylesheet()"); function step1()
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/stylesheet-tracking.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/stylesheet-tracking.html index 4b029e5..52ae18c 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/stylesheet-tracking.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/stylesheet-tracking.html
@@ -69,8 +69,8 @@ { var inspectedNode; - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetAdded, null); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, styleSheetRemoved, null); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetAdded, null); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, styleSheetRemoved, null); var headers = InspectorTest.cssModel.styleSheetHeaders(); InspectorTest.addResult(headers.length + " headers known:"); sortAndDumpData(headers);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html index 2bf2629..00874ae 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/elements/styles/update-locations-on-filesystem-scss-load.html
@@ -24,7 +24,7 @@ function fileSystemCreated() { InspectorTest.addResult("Loading raw css with mapping..."); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetAdded); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetAdded); InspectorTest.evaluateInPage("loadCSS()"); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js index 1db91d7..9e8fd2a 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/inspector-test.js
@@ -971,7 +971,7 @@ InspectorTest.debuggerModel = WebInspector.DebuggerModel.fromTarget(target); InspectorTest.runtimeModel = target.runtimeModel; InspectorTest.domModel = WebInspector.DOMModel.fromTarget(target); - InspectorTest.cssModel = WebInspector.CSSStyleModel.fromTarget(target); + InspectorTest.cssModel = WebInspector.CSSModel.fromTarget(target); InspectorTest.workerManager = target.workerManager; InspectorTest.powerProfiler = target.powerProfiler; InspectorTest.cpuProfilerModel = target.cpuProfilerModel;
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/modify-cross-domain-rule.html b/third_party/WebKit/LayoutTests/http/tests/inspector/modify-cross-domain-rule.html index 4e480b8a6..6d67687 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/modify-cross-domain-rule.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/modify-cross-domain-rule.html
@@ -12,7 +12,7 @@ var rule; var matchedStyleResult; - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, onStyleSheetChanged, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, onStyleSheetChanged, this); function onStyleSheetChanged(event) {
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch-expected.txt b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch-expected.txt new file mode 100644 index 0000000..2f0919f --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch-expected.txt
@@ -0,0 +1,8 @@ +Tests asynchronous call stacks for fetch. + +Set timer for test function. +Captured call stacks in no particular order: +Call stack: + 0) catchCallback (async-callstack-fetch.html:22) + +
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html new file mode 100644 index 0000000..bb4ea84c --- /dev/null +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/sources/debugger/async-callstack-fetch.html
@@ -0,0 +1,42 @@ +<html> +<head> +<script src="../../inspector-test.js"></script> +<script src="../../debugger-test.js"></script> +<script> + +function testFunction() +{ + setTimeout(doFetch, 0); +} + +function doFetch() +{ + fetch("../debugger/resources/script1.js").then(function chained1() { + }).then(function chained2() { + }).then(function chained3() { + throw Error("thrown from chained3"); + }).then(function chained4() { + }).then(function chained5() { + }).then(function chained6() { + }).catch(function catchCallback() { + debugger; + }); +} + +var test = function() +{ + var totalDebuggerStatements = 1; + var maxAsyncCallStackDepth = 4; + InspectorTest.runAsyncCallStacksTest(totalDebuggerStatements, maxAsyncCallStackDepth); +} + +</script> +</head> + +<body onload="runTest()"> +<p> + Tests asynchronous call stacks for fetch. +</p> + +</body> +</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html b/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html index 8fff590f..5789084f 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/stylesheet-source-mapping.html
@@ -10,7 +10,7 @@ var contentReceived; var finalMappedLocation; var target = InspectorTest.createWorkspaceWithTarget(); - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); WebInspector.cssWorkspaceBinding = InspectorTest.testCSSWorkspaceBinding; InspectorTest.waitForWorkspaceUISourceCodeAddedEvent(cssUISourceCodeAdded);
diff --git a/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js b/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js index 74401e5..72be254d 100644 --- a/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js +++ b/third_party/WebKit/LayoutTests/http/tests/inspector/workspace-test.js
@@ -49,7 +49,7 @@ this.resourceTreeModel._cachedResourcesProcessed = true; this.resourceTreeModel._frameAttached("42", 0); this.domModel = new WebInspector.DOMModel(this); - this.cssModel = new WebInspector.CSSStyleModel(this); + this.cssModel = new WebInspector.CSSModel(this); this.runtimeModel = new WebInspector.RuntimeModel(this); this.consoleModel = new WebInspector.ConsoleModel(this); }
diff --git a/third_party/WebKit/LayoutTests/http/tests/misc/reentrant-beforeunload-expected.txt b/third_party/WebKit/LayoutTests/http/tests/misc/reentrant-beforeunload-expected.txt index cdde7b4..c4388bc6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/misc/reentrant-beforeunload-expected.txt +++ b/third_party/WebKit/LayoutTests/http/tests/misc/reentrant-beforeunload-expected.txt
@@ -1,2 +1,2 @@ -CONFIRM NAVIGATION: This should only appear once. +CONFIRM NAVIGATION
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-multiple-style-texts-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-multiple-style-texts-expected.txt index 233674bd..bfbbd59 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-multiple-style-texts-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/css/css-set-multiple-style-texts-expected.txt
@@ -25,13 +25,13 @@ Running test: testMalformedArguments1 -Expected protocol error: Invalid request (edits.[1].styleSheetId: string value expected) +Expected protocol error: Invalid request (edits.1.styleSheetId: string value expected) Running test: testMalformedArguments2 -Expected protocol error: Invalid request (edits.[0].range: object expected; edits.[0].text: string value expected; edits.[2].styleSheetId: string value expected) +Expected protocol error: Invalid request (edits.0.range: object expected; edits.0.text: string value expected; edits.2.styleSheetId: string value expected) Running test: testMalformedArguments3 -Expected protocol error: Invalid request (edits.[0].range.startLine: integer value expected) +Expected protocol error: Invalid request (edits.0.range.startLine: integer value expected) Running test: testFirstEditDoesNotApply Expected protocol error: Failed applying edit #0: SyntaxError Style text is not valid.
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt index 46a17a6e..baa38fa3 100644 --- a/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector-protocol/page/javascriptDialogEvents-expected.txt
@@ -1,4 +1,4 @@ -CONFIRM NAVIGATION: beforeunload in javascriptDialogEvents +CONFIRM NAVIGATION ALERT: alert CONFIRM: confirm PROMPT: prompt, default text:
diff --git a/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-functional.html b/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-functional.html index cf5eb7db..11ab274 100644 --- a/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-functional.html +++ b/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-functional.html
@@ -53,7 +53,7 @@ { InspectorTest.reloadPage(onPageReloaded); var pendingStyleSheetsCount = 4; - InspectorTest.addSniffer(WebInspector.CSSStyleModel.prototype, "_styleSheetAdded", maybeStylesheetsLoaded, true); + InspectorTest.addSniffer(WebInspector.CSSModel.prototype, "_styleSheetAdded", maybeStylesheetsLoaded, true); var pageReloaded = false; function onPageReloaded()
diff --git a/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-noimages-functional.html b/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-noimages-functional.html index 2e66e10..5596e66 100644 --- a/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-noimages-functional.html +++ b/third_party/WebKit/LayoutTests/inspector/audits/audits-panel-noimages-functional.html
@@ -22,7 +22,7 @@ var test = function() { InspectorTest.reloadPage(); - InspectorTest.addSniffer(WebInspector.CSSStyleModel.prototype, "_styleSheetAdded", onStyleSheetAdded, true); + InspectorTest.addSniffer(WebInspector.CSSModel.prototype, "_styleSheetAdded", onStyleSheetAdded, true); var pendingStyleSheetsCount = 5; function onStyleSheetAdded()
diff --git a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt index 8fd4c3da..7688bbd 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners-expected.txt
@@ -6,83 +6,83 @@ [page] keydown: { [page] 0: { [page] listener: function listener1() { } -[page] useCapture: false -[page] type: "keydown" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "keydown" +[page] useCapture: false [page] } [page] 1: { [page] listener: function listener2() { } -[page] useCapture: true -[page] type: "keydown" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "keydown" +[page] useCapture: true [page] } [page] } [page] - inner after a removal - [page] keydown: { [page] 0: { [page] listener: function listener2() { } -[page] useCapture: true -[page] type: "keydown" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "keydown" +[page] useCapture: true [page] } [page] } [page] - outer - [page] keydown: { [page] 0: { [page] listener: function listener2() { } -[page] useCapture: true -[page] type: "keydown" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "keydown" +[page] useCapture: true [page] } [page] } [page] mousedown: { [page] 0: { [page] listener: function listener2() { } -[page] useCapture: true -[page] type: "mousedown" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "mousedown" +[page] useCapture: true [page] } [page] } [page] mousemove: { [page] 0: { [page] listener: function listener1() { } -[page] useCapture: false -[page] type: "mousemove" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "mousemove" +[page] useCapture: false [page] } [page] } [page] - attribute event listeners - [page] click: { [page] 0: { [page] listener: function onclick(event) { alert(1) } -[page] useCapture: false -[page] type: "click" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "click" +[page] useCapture: false [page] } [page] } [page] mouseover: { [page] 0: { [page] listener: function onmouseover(event) { listener2() } -[page] useCapture: false -[page] type: "mouseover" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "mouseover" +[page] useCapture: false [page] } [page] } [page] - window - [page] load: { [page] 0: { [page] listener: function onload(event) { runTest() } -[page] useCapture: false -[page] type: "load" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "load" +[page] useCapture: false [page] } [page] } [page] popstate: { [page] 0: { [page] listener: function listener1() { } -[page] useCapture: false -[page] type: "popstate" [page] remove: function () {node.removeEventListener(this.type,this.listener,this.useCapture);} +[page] type: "popstate" +[page] useCapture: false [page] } [page] } [page] - empty -
diff --git a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html index 2e0efe02..860e42f 100644 --- a/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html +++ b/third_party/WebKit/LayoutTests/inspector/console/command-line-api-getEventListeners.html
@@ -47,6 +47,7 @@ } prefix = prefix || ""; var keys = Object.keys(object); + keys.sort(); for (var i = 0; i < keys.length; ++i) { var value = object[keys[i]]; var nameWithPrefix = prefix + keys[i] + ": ";
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-inline-style-csp.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-inline-style-csp.html index fd924b2f..651b388b 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-inline-style-csp.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-inline-style-csp.html
@@ -79,7 +79,7 @@ { var inlineStyle; InspectorTest.cssModel.inlineStylesPromise(nodeId).then(stylesCallback); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, onStyleSheetChanged); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, onStyleSheetChanged); function onStyleSheetChanged(event) { if (event.data && event.data.edit)
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-with-style-after-body.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-with-style-after-body.html index 4c3300e..dcb6816 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-with-style-after-body.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/add-new-rule-with-style-after-body.html
@@ -12,12 +12,12 @@ function test() { - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, stylesheetAdded); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, stylesheetAdded); InspectorTest.evaluateInPage("addStyle()"); function stylesheetAdded() { - InspectorTest.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, stylesheetAdded); + InspectorTest.cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, stylesheetAdded); InspectorTest.selectNodeAndWaitForStyles("inspected", step1); }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-live-edit.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-live-edit.html index f43ae42a..831cf9e 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-live-edit.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/css-live-edit.html
@@ -17,7 +17,7 @@ function didShowResource(sourceFrame) { - InspectorTest.addSniffer(WebInspector.CSSStyleModel.prototype, "_fireStyleSheetChanged", didEditResource); + InspectorTest.addSniffer(WebInspector.CSSModel.prototype, "_fireStyleSheetChanged", didEditResource); InspectorTest.replaceInSource(sourceFrame, "font-size: 12px;", "font-size: 20px;"); }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/edit-resource-referred-by-multiple-styletags.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/edit-resource-referred-by-multiple-styletags.html index 5cf832f..a794b6ae 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-1/edit-resource-referred-by-multiple-styletags.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-1/edit-resource-referred-by-multiple-styletags.html
@@ -23,7 +23,7 @@ function onEditorOpened(sourceFrame) { - InspectorTest.addSniffer(WebInspector.CSSStyleModel.prototype, "_fireStyleSheetChanged", didEditStyleSheet); + InspectorTest.addSniffer(WebInspector.CSSModel.prototype, "_fireStyleSheetChanged", didEditStyleSheet); InspectorTest.replaceInSource(sourceFrame, "100px", "2em"); }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/get-set-stylesheet-text.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/get-set-stylesheet-text.html index 2f6ea3d..68d6ee05 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/get-set-stylesheet-text.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/get-set-stylesheet-text.html
@@ -32,7 +32,7 @@ foundStyleSheetHeader.requestContent().then(callback); } if (!foundStyleSheetHeader) - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetAdded); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetAdded); } function callback(content) @@ -43,7 +43,7 @@ function styleSheetAdded() { - InspectorTest.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetAdded); + InspectorTest.cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetAdded); findStyleSheet(); } } @@ -60,7 +60,7 @@ InspectorTest.addResult("=== Original stylesheet text: ==="); InspectorTest.addResult(foundStyleSheetText); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, next, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, next, this); InspectorTest.cssModel.setStyleSheetText(foundStyleSheetHeader.id, "h1 { COLOR: Red; }", true).then(callback); }
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/multiple-imports-edit-crash.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/multiple-imports-edit-crash.html index eac755f..3e8e11d 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-2/multiple-imports-edit-crash.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-2/multiple-imports-edit-crash.html
@@ -14,8 +14,8 @@ function test() { - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetAdded, this); - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, styleSheetRemoved, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetAdded, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, styleSheetRemoved, this); InspectorTest.nodeWithId("inspected", nodeFound); function nodeFound(node)
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/disable-last-property-without-semicolon.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/disable-last-property-without-semicolon.html index ddcc665..c5e4739 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/disable-last-property-without-semicolon.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/disable-last-property-without-semicolon.html
@@ -9,7 +9,7 @@ { var formattedStyle; - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, onStyleSheetChanged, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, onStyleSheetChanged, this); function onStyleSheetChanged(event) {
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html index 05e7db4..7e1f7b7 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles-4/styles-formatting.html
@@ -11,7 +11,7 @@ var unformattedStyle; - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, onStyleSheetChanged, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, onStyleSheetChanged, this); function onStyleSheetChanged(event) {
diff --git a/third_party/WebKit/LayoutTests/inspector/elements/styles/styles-test.js b/third_party/WebKit/LayoutTests/inspector/elements/styles/styles-test.js index 6b6d4f08..674573ad 100644 --- a/third_party/WebKit/LayoutTests/inspector/elements/styles/styles-test.js +++ b/third_party/WebKit/LayoutTests/inspector/elements/styles/styles-test.js
@@ -15,12 +15,12 @@ if (styleSheets.length < styleSheetsCount) return; - InspectorTest.cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, onStyleSheetAdded, this); + InspectorTest.cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, onStyleSheetAdded, this); styleSheets.sort(styleSheetComparator); callback(null, styleSheets); } - InspectorTest.cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, onStyleSheetAdded, this); + InspectorTest.cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, onStyleSheetAdded, this); } }
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-eval-expected.txt b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-eval-expected.txt index eabcad1c..9616b89 100644 --- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-eval-expected.txt +++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-eval-expected.txt
@@ -11,8 +11,8 @@ RUNNING TEST: extension_testEvalStatement Evaluate: 0 (exception: undefined) RUNNING TEST: extension_testEvalStringifyingLoopFailed -log: Extension server error: Inspector protocol error: Object has too long reference chain(must not be longer than 1000) -Evaluate: undefined (exception: {"code":"E_PROTOCOLERROR","description":"Inspector protocol error: %s","details":["Object has too long reference chain(must not be longer than 1000)"],"isError":true}) +log: Extension server error: Inspector protocol error: Object has too long reference chain +Evaluate: undefined (exception: {"code":"E_PROTOCOLERROR","description":"Inspector protocol error: %s","details":["Object has too long reference chain"],"isError":true}) RUNNING TEST: extension_testEvalThrows Evaluate: undefined (exception: {"isException":true,"value":"testExceptionString"}) RUNNING TEST: extension_testEvalUndefined
diff --git a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html index 40cb0389..7585744 100644 --- a/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html +++ b/third_party/WebKit/LayoutTests/inspector/extensions/extensions-resources.html
@@ -36,7 +36,7 @@ { var originalSetTimeout = WebInspector.Throttler.prototype._setTimeout; WebInspector.Throttler.prototype._setTimeout = innerSetTimeout; - InspectorTest.addSniffer(WebInspector.CSSStyleModel.prototype, "_fireStyleSheetChanged", onStyleSheetChanged); + InspectorTest.addSniffer(WebInspector.CSSModel.prototype, "_fireStyleSheetChanged", onStyleSheetChanged); function onStyleSheetChanged() {
diff --git a/third_party/WebKit/LayoutTests/inspector/resources/example-fileset-for-test.js b/third_party/WebKit/LayoutTests/inspector/resources/example-fileset-for-test.js index 6bae1077..2ff4c510 100644 --- a/third_party/WebKit/LayoutTests/inspector/resources/example-fileset-for-test.js +++ b/third_party/WebKit/LayoutTests/inspector/resources/example-fileset-for-test.js
@@ -185,7 +185,7 @@ "./Source/devtools/front_end/CSSNamedFlowCollectionsView.pl", "./Source/devtools/front_end/CSSNamedFlowView.pl", "./Source/devtools/front_end/CSSSelectorProfileView.pl", - "./Source/devtools/front_end/CSSStyleModel.pl", + "./Source/devtools/front_end/CSSModel.pl", "./Source/devtools/front_end/CSSStyleSheetMapping.pl", "./Source/devtools/front_end/CallStackSidebarPane.pl", "./Source/devtools/front_end/CanvasProfileView.pl",
diff --git a/third_party/WebKit/LayoutTests/inspector/sources/debugger/network-uisourcecode-provider.html b/third_party/WebKit/LayoutTests/inspector/sources/debugger/network-uisourcecode-provider.html index eeb2e87..e95a17a 100644 --- a/third_party/WebKit/LayoutTests/inspector/sources/debugger/network-uisourcecode-provider.html +++ b/third_party/WebKit/LayoutTests/inspector/sources/debugger/network-uisourcecode-provider.html
@@ -122,13 +122,13 @@ InspectorTest.addResult("Creating stylesheet resource."); createResourceMock(WebInspector.resourceTypes.Stylesheet, "<stylesheet resource content>"); - WebInspector.CSSStyleModel.fromTarget(target)._styleSheetAdded(mockStyleSheetHeader); + WebInspector.CSSModel.fromTarget(target)._styleSheetAdded(mockStyleSheetHeader); function uiSourceCodeAdded(uiSourceCode) { InspectorTest.addResult("Added uiSourceCode: " + InspectorTest.uiSourceCodeURL(uiSourceCode)); InspectorTest.waitForWorkspaceUISourceCodeRemovedEvent(uiSourceCodeRemoved); - WebInspector.CSSStyleModel.fromTarget(target)._styleSheetRemoved(mockStyleSheetHeader.styleSheetId); + WebInspector.CSSModel.fromTarget(target)._styleSheetRemoved(mockStyleSheetHeader.styleSheetId); } function uiSourceCodeRemoved(uiSourceCode)
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt b/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt index b614c5d8..a6e1ece1 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt +++ b/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules-expected.txt
@@ -2,6 +2,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + PASS connections: 1, max, speakers PASS connections: 2, max, speakers PASS connections: 3, max, speakers
diff --git a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html b/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html index 7dcce63..1644c06bc9 100644 --- a/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html +++ b/third_party/WebKit/LayoutTests/webaudio/audionode-channel-rules.html
@@ -4,12 +4,11 @@ <head> <script src="../resources/js-test.js"></script> <script src="resources/compatibility.js"></script> -<script type="text/javascript" src="resources/audio-testing.js"></script> +<script src="resources/audio-testing.js"></script> +<script src="resources/mixing-rules.js"></script> </head> <body> -<div id="description"></div> -<div id="console"></div> <script> description("Channel mixing rules for AudioNodes."); @@ -45,96 +44,13 @@ var numberOfTests = mixingRulesList.length * connectionsList.length; -// Create an n-channel buffer, with all sample data zero except for a shifted impulse. -// The impulse position depends on the channel index. -// For example, for a 4-channel buffer: -// channel0: 1 0 0 0 0 0 0 0 -// channel1: 0 1 0 0 0 0 0 0 -// channel2: 0 0 1 0 0 0 0 0 -// channel3: 0 0 0 1 0 0 0 0 -function createTestBuffer(numberOfChannels) { - var buffer = context.createBuffer(numberOfChannels, singleTestFrameLength, context.sampleRate); - for (var i = 0; i < numberOfChannels; ++i) { - var data = buffer.getChannelData(i); - data[i] = 1; - } - return buffer; -} - -// Discrete channel interpretation mixing: -// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix -// up-mix by filling channels until they run out then ignore remaining dest channels. -// down-mix by filling as many channels as possible, then dropping remaining source channels. -function discreteSum(sourceBuffer, destBuffer) { - if (sourceBuffer.length != destBuffer.length) { - alert("discreteSum(): invalid AudioBuffer!"); - return; - } - - var numberOfChannels = sourceBuffer.numberOfChannels < destBuffer.numberOfChannels ? sourceBuffer.numberOfChannels : destBuffer.numberOfChannels; - var length = numberOfChannels; - - for (var c = 0; c < numberOfChannels; ++c) { - var source = sourceBuffer.getChannelData(c); - var dest = destBuffer.getChannelData(c); - for (var i = 0; i < length; ++i) { - dest[i] += source[i]; - } - } -} - -// Speaker channel interpretation mixing: -// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html#UpMix -function speakersSum(sourceBuffer, destBuffer) -{ - var numberOfSourceChannels = sourceBuffer.numberOfChannels; - var numberOfDestinationChannels = destBuffer.numberOfChannels; - var length = destBuffer.length; - - if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) { - // Handle mono -> stereo case (summing mono channel into both left and right). - var source = sourceBuffer.getChannelData(0); - var destL = destBuffer.getChannelData(0); - var destR = destBuffer.getChannelData(1); - - for (var i = 0; i < length; ++i) { - destL[i] += source[i]; - destR[i] += source[i]; - } - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) { - // Handle stereo -> mono case. output += 0.5 * (input.L + input.R). - var sourceL = sourceBuffer.getChannelData(0); - var sourceR = sourceBuffer.getChannelData(1); - var dest = destBuffer.getChannelData(0); - - for (var i = 0; i < length; ++i) { - dest[i] += 0.5 * (sourceL[i] + sourceR[i]); - } - } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) { - // Handle mono -> 5.1 case, sum mono channel into center. - var source = sourceBuffer.getChannelData(0); - var dest = destBuffer.getChannelData(2); - - for (var i = 0; i < length; ++i) { - dest[i] += source[i]; - } - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) { - // Handle 5.1 -> mono. - var sourceL = sourceBuffer.getChannelData(0); - var sourceR = sourceBuffer.getChannelData(1); - var sourceC = sourceBuffer.getChannelData(2); - // skip LFE for now, according to current spec. - var sourceSL = sourceBuffer.getChannelData(4); - var sourceSR = sourceBuffer.getChannelData(5); - var dest = destBuffer.getChannelData(0); - - for (var i = 0; i < length; ++i) { - dest[i] += 0.7071 * (sourceL[i] + sourceR[i]) + sourceC[i] + 0.5 * (sourceSL[i] + sourceSR[i]); - } - } else { - // Fallback for unknown combinations. - discreteSum(sourceBuffer, destBuffer); - } +// Print out the information for an individual test case. +function printTestInformation(testNumber, actualBuffer, expectedBuffer, frameLength, frameOffset) { + var actual = stringifyBuffer(actualBuffer, frameLength); + var expected = stringifyBuffer(expectedBuffer, frameLength, frameOffset); + debug('TEST CASE #' + testNumber + '\n'); + debug('actual channels:\n' + actual); + debug('expected channels:\n' + expected); } function scheduleTest(testNumber, connections, channelCount, channelCountMode, channelInterpretation) { @@ -160,24 +76,6 @@ } } -function computeNumberOfChannels(connections, channelCount, channelCountMode) { - if (channelCountMode == "explicit") - return channelCount; - - var computedNumberOfChannels = 1; // Must have at least one channel. - - // Compute "computedNumberOfChannels" based on all the connections. - for (var i = 0; i < connections.length; ++i) { - var connectionNumberOfChannels = connections.charCodeAt(i) - "0".charCodeAt(0); - computedNumberOfChannels = Math.max(computedNumberOfChannels, connectionNumberOfChannels); - } - - if (channelCountMode == "clamped-max") - computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCount); - - return computedNumberOfChannels; -} - function checkTestResult(renderedBuffer, testNumber, connections, channelCount, channelCountMode, channelInterpretation) { var s = "connections: " + connections + ", " + channelCountMode; @@ -190,21 +88,6 @@ var computedNumberOfChannels = computeNumberOfChannels(connections, channelCount, channelCountMode); - // Show rendered output for this test: - // - // console.log(s); - // var sampleFrameOffset = testNumber * singleTestFrameLength; - // for (var c = 0; c < renderNumberOfChannels; ++c) { - // var data = renderedBuffer.getChannelData(c); - // var s = ""; - // for (var sampleFrame = 0; sampleFrame < singleTestFrameLength; ++sampleFrame) { - // s += data[sampleFrame + sampleFrameOffset] + " "; - // } - // s += "\n"; - // console.log(s); - // } - // return; - // Create a zero-initialized silent AudioBuffer with computedNumberOfChannels. var destBuffer = context.createBuffer(computedNumberOfChannels, singleTestFrameLength, context.sampleRate); @@ -222,6 +105,9 @@ } } + // Use this when debugging mixing rules. + // printTestInformation(testNumber, renderedBuffer, destBuffer, singleTestFrameLength, sampleFrameOffset); + // Validate that destBuffer matches the rendered output. // We need to check the rendered output at a specific sample-frame-offset corresponding // to the specific test case we're checking for based on testNumber. @@ -293,7 +179,7 @@ // Create test buffers from 1 to 8 channels. testBuffers = new Array(); for (var i = 0; i < renderNumberOfChannels; ++i) { - testBuffers[i] = createTestBuffer(i + 1); + testBuffers[i] = createShiftedImpulseBuffer(context, i + 1, singleTestFrameLength); } // Schedule all the tests.
diff --git a/third_party/WebKit/LayoutTests/webaudio/resources/mixing-rules.js b/third_party/WebKit/LayoutTests/webaudio/resources/mixing-rules.js new file mode 100644 index 0000000..bf9a8dd4 --- /dev/null +++ b/third_party/WebKit/LayoutTests/webaudio/resources/mixing-rules.js
@@ -0,0 +1,346 @@ +// Utilities for mixing rule testing. +// http://webaudio.github.io/web-audio-api/#channel-up-mixing-and-down-mixing + + +/** + * Create an n-channel buffer, with all sample data zero except for a shifted + * impulse. The impulse position depends on the channel index. For example, for + * a 4-channel buffer: + * channel 0: 1 0 0 0 0 0 0 0 + * channel 1: 0 1 0 0 0 0 0 0 + * channel 2: 0 0 1 0 0 0 0 0 + * channel 3: 0 0 0 1 0 0 0 0 + * @param {AudioContext} context Associated AudioContext. + * @param {Number} numberOfChannels Number of channels of test buffer. + * @param {Number} frameLength Buffer length in frames. + * @return {AudioBuffer} + */ +function createShiftedImpulseBuffer(context, numberOfChannels, frameLength) { + var shiftedImpulseBuffer = context.createBuffer(numberOfChannels, frameLength, context.sampleRate); + for (var channel = 0; channel < numberOfChannels; ++channel) { + var data = shiftedImpulseBuffer.getChannelData(channel); + data[channel] = 1; + } + + return shiftedImpulseBuffer; +} + +/** + * Create a string that displays the content of AudioBuffer. + * @param {AudioBuffer} audioBuffer AudioBuffer object to stringify. + * @param {Number} frameLength Number of frames to be printed. + * @param {Number} frameOffset Starting frame position for printing. + * @return {String} + */ +function stringifyBuffer(audioBuffer, frameLength, frameOffset) { + frameOffset = (frameOffset || 0); + + var stringifiedBuffer = ''; + for (var channel = 0; channel < audioBuffer.numberOfChannels; ++channel) { + var channelData = audioBuffer.getChannelData(channel); + for (var i = 0; i < frameLength; ++i) + stringifiedBuffer += channelData[i + frameOffset] + ' '; + stringifiedBuffer += '\n'; + } + + return stringifiedBuffer; +} + +/** + * Compute number of channels from the connection. + * http://webaudio.github.io/web-audio-api/#dfn-computednumberofchannels + * @param {String} connections A string specifies the connection. For + * example, the string "128" means 3 + * connections, having 1, 2, and 8 channels + * respectively. + * @param {Number} channelCount Channel count. + * @param {String} channelCountMode Channel count mode. + * @return {Number} Computed number of channels. + */ +function computeNumberOfChannels(connections, channelCount, channelCountMode) { + if (channelCountMode == "explicit") + return channelCount; + + // Must have at least one channel. + var computedNumberOfChannels = 1; + + // Compute "computedNumberOfChannels" based on all the connections. + for (var i = 0; i < connections.length; ++i) { + var connectionNumberOfChannels = parseInt(connections[i]); + computedNumberOfChannels = Math.max(computedNumberOfChannels, connectionNumberOfChannels); + } + + if (channelCountMode == "clamped-max") + computedNumberOfChannels = Math.min(computedNumberOfChannels, channelCount); + + return computedNumberOfChannels; +} + +/** + * Apply up/down-mixing (in-place summing) based on 'speaker' interpretation. + * @param {AudioBuffer} input Input audio buffer. + * @param {AudioBuffer} output Output audio buffer. + */ +function speakersSum(input, output) { + if (input.length != output.length) { + throw '[mixing-rules.js] speakerSum(): buffer lengths mismatch (input: ' + + input.length + ', output: ' + output.length + ')'; + } + + if (input.numberOfChannels === output.numberOfChannels) { + for (var channel = 0; channel < output.numberOfChannels; ++channel) { + var inputChannel = input.getChannelData(channel); + var outputChannel = output.getChannelData(channel); + for (var i = 0; i < outputChannel.length; i++) + outputChannel[i] += inputChannel[i]; + } + } else if (input.numberOfChannels < output.numberOfChannels) { + processUpMix(input, output); + } else { + processDownMix(input, output); + } +} + +/** + * In-place summing to |output| based on 'discrete' channel interpretation. + * @param {AudioBuffer} input Input audio buffer. + * @param {AudioBuffer} output Output audio buffer. + */ +function discreteSum(input, output) { + if (input.length != output.length) { + throw '[mixing-rules.js] speakerSum(): buffer lengths mismatch (input: ' + + input.length + ', output: ' + output.length + ')'; + } + + var numberOfChannels = Math.min(input.numberOfChannels, output.numberOfChannels) + + for (var channel = 0; channel < numberOfChannels; ++channel) { + var inputChannel = input.getChannelData(channel); + var outputChannel = output.getChannelData(channel); + for (var i = 0; i < outputChannel.length; i++) + outputChannel[i] += inputChannel[i]; + } +} + +/** + * Perform up-mix by in-place summing to |output| buffer. + * @param {AudioBuffer} input Input audio buffer. + * @param {AudioBuffer} output Output audio buffer. + */ +function processUpMix(input, output) { + var numberOfInputChannels = input.numberOfChannels; + var numberOfOutputChannels = output.numberOfChannels; + var i, length = output.length; + + // Up-mixing: 1 -> 2, 1 -> 4 + // output.L += input + // output.R += input + // output.SL += 0 (in the case of 1 -> 4) + // output.SR += 0 (in the case of 1 -> 4) + if ((numberOfInputChannels === 1 && numberOfOutputChannels === 2) || + (numberOfInputChannels === 1 && numberOfOutputChannels === 4)) { + var inputChannel = input.getChannelData(0); + var outputChannel0 = output.getChannelData(0); + var outputChannel1 = output.getChannelData(1); + for (i = 0; i < length; i++) { + outputChannel0[i] += inputChannel[i]; + outputChannel1[i] += inputChannel[i]; + } + + return; + } + + // Up-mixing: 1 -> 5.1 + // output.L += 0 + // output.R += 0 + // output.C += input + // output.LFE += 0 + // output.SL += 0 + // output.SR += 0 + if (numberOfInputChannels == 1 && numberOfOutputChannels == 6) { + var inputChannel = input.getChannelData(0); + var outputChannel2 = output.getChannelData(2); + for (i = 0; i < length; i++) + outputChannel2[i] += inputChannel[i]; + + return; + } + + // Up-mixing: 2 -> 4, 2 -> 5.1 + // output.L += input.L + // output.R += input.R + // output.C += 0 (in the case of 2 -> 5.1) + // output.LFE += 0 (in the case of 2 -> 5.1) + // output.SL += 0 + // output.SR += 0 + if ((numberOfInputChannels === 2 && numberOfOutputChannels === 4) || + (numberOfInputChannels === 2 && numberOfOutputChannels === 6)) { + var inputChannel0 = input.getChannelData(0); + var inputChannel1 = input.getChannelData(1); + var outputChannel0 = output.getChannelData(0); + var outputChannel1 = output.getChannelData(1); + for (i = 0; i < length; i++) { + outputChannel0[i] += inputChannel0[i]; + outputChannel1[i] += inputChannel1[i]; + } + + return; + } + + // Up-mixing: 4 -> 5.1 + // output.L += input.L + // output.R += input.R + // output.C += 0 + // output.LFE += 0 + // output.SL += input.SL + // output.SR += input.SR + if (numberOfInputChannels === 4 && numberOfOutputChannels === 6) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.SL + var inputChannel3 = input.getChannelData(3); // input.SR + var outputChannel0 = output.getChannelData(0); // output.L + var outputChannel1 = output.getChannelData(1); // output.R + var outputChannel4 = output.getChannelData(4); // output.SL + var outputChannel5 = output.getChannelData(5); // output.SR + for (i = 0; i < length; i++) { + outputChannel0[i] += inputChannel0[i]; + outputChannel1[i] += inputChannel1[i]; + outputChannel4[i] += inputChannel2[i]; + outputChannel5[i] += inputChannel3[i]; + } + + return; + } + + // All other cases, fall back to the discrete sum. + discreteSum(input, output); +} + +/** + * Perform down-mix by in-place summing to |output| buffer. + * @param {AudioBuffer} input Input audio buffer. + * @param {AudioBuffer} output Output audio buffer. + */ +function processDownMix(input, output) { + var numberOfInputChannels = input.numberOfChannels; + var numberOfOutputChannels = output.numberOfChannels; + var i, length = output.length; + + // Down-mixing: 2 -> 1 + // output += 0.5 * (input.L + input.R) + if (numberOfInputChannels === 2 && numberOfOutputChannels === 1) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var outputChannel0 = output.getChannelData(0); + for (i = 0; i < length; i++) + outputChannel0[i] += 0.5 * (inputChannel0[i] + inputChannel1[i]); + + return; + } + + // Down-mixing: 4 -> 1 + // output += 0.25 * (input.L + input.R + input.SL + input.SR) + if (numberOfInputChannels === 4 && numberOfOutputChannels === 1) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.SL + var inputChannel3 = input.getChannelData(3); // input.SR + var outputChannel0 = output.getChannelData(0); + for (i = 0; i < length; i++) { + outputChannel0[i] += 0.25 * (inputChannel0[i] + inputChannel1[i] + + inputChannel2[i] + inputChannel3[i]); + } + + return; + } + + // Down-mixing: 5.1 -> 1 + // output += sqrt(1/2) * (input.L + input.R) + input.C + // + 0.5 * (input.SL + input.SR) + if (numberOfInputChannels === 6 && numberOfOutputChannels === 1) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.C + var inputChannel4 = input.getChannelData(4); // input.SL + var inputChannel5 = input.getChannelData(5); // input.SR + var outputChannel0 = output.getChannelData(0); + var scaleSqrtHalf = Math.sqrt(0.5); + for (i = 0; i < length; i++) { + outputChannel0[i] += + scaleSqrtHalf * (inputChannel0[i] + inputChannel1[i]) + + inputChannel2[i] + 0.5 * (inputChannel4[i] + inputChannel5[i]); + } + + return; + } + + // Down-mixing: 4 -> 2 + // output.L += 0.5 * (input.L + input.SL) + // output.R += 0.5 * (input.R + input.SR) + if (numberOfInputChannels == 4 && numberOfOutputChannels == 2) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.SL + var inputChannel3 = input.getChannelData(3); // input.SR + var outputChannel0 = output.getChannelData(0); // output.L + var outputChannel1 = output.getChannelData(1); // output.R + for (i = 0; i < length; i++) { + outputChannel0[i] += 0.5 * (inputChannel0[i] + inputChannel2[i]); + outputChannel1[i] += 0.5 * (inputChannel1[i] + inputChannel3[i]); + } + + return; + } + + // Down-mixing: 5.1 -> 2 + // output.L += input.L + sqrt(1/2) * (input.C + input.SL) + // output.R += input.R + sqrt(1/2) * (input.C + input.SR) + if (numberOfInputChannels == 6 && numberOfOutputChannels == 2) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.C + var inputChannel4 = input.getChannelData(4); // input.SL + var inputChannel5 = input.getChannelData(5); // input.SR + var outputChannel0 = output.getChannelData(0); // output.L + var outputChannel1 = output.getChannelData(1); // output.R + var scaleSqrtHalf = Math.sqrt(0.5); + for (i = 0; i < length; i++) { + outputChannel0[i] += inputChannel0[i] + + scaleSqrtHalf * (inputChannel2[i] + inputChannel4[i]); + outputChannel1[i] += inputChannel1[i] + + scaleSqrtHalf * (inputChannel2[i] + inputChannel5[i]); + } + + return; + } + + // Down-mixing: 5.1 -> 4 + // output.L += input.L + sqrt(1/2) * input.C + // output.R += input.R + sqrt(1/2) * input.C + // output.SL += input.SL + // output.SR += input.SR + if (numberOfInputChannels === 6 && numberOfOutputChannels === 4) { + var inputChannel0 = input.getChannelData(0); // input.L + var inputChannel1 = input.getChannelData(1); // input.R + var inputChannel2 = input.getChannelData(2); // input.C + var inputChannel4 = input.getChannelData(4); // input.SL + var inputChannel5 = input.getChannelData(5); // input.SR + var outputChannel0 = output.getChannelData(0); // output.L + var outputChannel1 = output.getChannelData(1); // output.R + var outputChannel2 = output.getChannelData(2); // output.SL + var outputChannel3 = output.getChannelData(3); // output.SR + var scaleSqrtHalf = Math.sqrt(0.5); + for (i = 0; i < length; i++) { + outputChannel0[i] += inputChannel0[i] + scaleSqrtHalf * inputChannel2[i]; + outputChannel1[i] += inputChannel1[i] + scaleSqrtHalf * inputChannel2[i]; + outputChannel2[i] += inputChannel4[i]; + outputChannel3[i] += inputChannel5[i]; + } + + return; + } + + // All other cases, fall back to the discrete sum. + discreteSum(input, output); +}
diff --git a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp index 19e6242..3362b49 100644 --- a/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp +++ b/third_party/WebKit/Source/bindings/core/v8/WindowProxy.cpp
@@ -110,7 +110,7 @@ LocalFrame* frame = toLocalFrame(m_frame); // The embedder could run arbitrary code in response to the willReleaseScriptContext callback, so all disposing should happen after it returns. frame->loader().client()->willReleaseScriptContext(context, m_world->worldId()); - InspectorInstrumentation::willReleaseScriptContext(frame, m_scriptState.get()); + MainThreadDebugger::contextWillBeDestroyed(m_scriptState.get()); } m_document.clear(); @@ -269,8 +269,7 @@ } if (m_frame->isLocalFrame()) { LocalFrame* frame = toLocalFrame(m_frame); - MainThreadDebugger::initializeContext(context, frame, m_world->worldId()); - InspectorInstrumentation::didCreateScriptContext(frame, m_scriptState.get(), origin, m_world->worldId()); + MainThreadDebugger::contextCreated(m_scriptState.get(), frame, origin); frame->loader().client()->didCreateScriptContext(context, m_world->extensionGroup(), m_world->worldId()); } return true;
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index f2a70fe..b12b0d6 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -396,7 +396,6 @@ , m_frame(initializer.frame()) , m_domWindow(m_frame ? m_frame->localDOMWindow() : 0) , m_importsController(initializer.importsController()) - , m_activeParserCount(0) , m_contextFeatures(ContextFeatures::defaultSwitch()) , m_wellFormed(false) , m_printing(false) @@ -5508,11 +5507,6 @@ return s_threadedParsingEnabledForTesting; } -bool Document::hasActiveParser() -{ - return m_activeParserCount || (m_parser && m_parser->processingData()); -} - void Document::setContextFeatures(ContextFeatures& features) { m_contextFeatures = PassRefPtrWillBeRawPtr<ContextFeatures>(features);
diff --git a/third_party/WebKit/Source/core/dom/Document.h b/third_party/WebKit/Source/core/dom/Document.h index 49e3bf2..06db633f 100644 --- a/third_party/WebKit/Source/core/dom/Document.h +++ b/third_party/WebKit/Source/core/dom/Document.h
@@ -952,11 +952,6 @@ void adjustFloatQuadsForScrollAndAbsoluteZoom(Vector<FloatQuad>&, LayoutObject&); void adjustFloatRectForScrollAndAbsoluteZoom(FloatRect&, LayoutObject&); - bool hasActiveParser(); - unsigned activeParserCount() { return m_activeParserCount; } - void incrementActiveParserCount() { ++m_activeParserCount; } - void decrementActiveParserCount() { --m_activeParserCount; } - void setContextFeatures(ContextFeatures&); ContextFeatures& contextFeatures() const { return *m_contextFeatures; } @@ -1185,7 +1180,6 @@ PersistentWillBeMember<ResourceFetcher> m_fetcher; RefPtrWillBeMember<DocumentParser> m_parser; - unsigned m_activeParserCount; RefPtrWillBeMember<ContextFeatures> m_contextFeatures; bool m_wellFormed;
diff --git a/third_party/WebKit/Source/core/dom/DocumentParser.h b/third_party/WebKit/Source/core/dom/DocumentParser.h index b5ff387f..abbf48d 100644 --- a/third_party/WebKit/Source/core/dom/DocumentParser.h +++ b/third_party/WebKit/Source/core/dom/DocumentParser.h
@@ -61,11 +61,6 @@ virtual void finish() = 0; - // FIXME: processingData() is only used by DocumentLoader::isLoadingInAPISense - // and is very unclear as to what it actually means. The LegacyHTMLDocumentParser - // used to implement it. - virtual bool processingData() const { return false; } - // document() will return 0 after detach() is called. Document* document() const { ASSERT(m_document); return m_document; }
diff --git a/third_party/WebKit/Source/core/fetch/RawResource.cpp b/third_party/WebKit/Source/core/fetch/RawResource.cpp index 278fda7..e885514 100644 --- a/third_party/WebKit/Source/core/fetch/RawResource.cpp +++ b/third_party/WebKit/Source/core/fetch/RawResource.cpp
@@ -130,12 +130,13 @@ void RawResource::willFollowRedirect(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) { + Resource::willFollowRedirect(newRequest, redirectResponse); + RefPtrWillBeRawPtr<RawResource> protect(this); ASSERT(!redirectResponse.isNull()); ResourceClientWalker<RawResourceClient> w(m_clients); while (RawResourceClient* c = w.next()) c->redirectReceived(this, newRequest, redirectResponse); - Resource::willFollowRedirect(newRequest, redirectResponse); } void RawResource::responseReceived(const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
diff --git a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.h b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.h index bb1bfab..0aa1f11 100644 --- a/third_party/WebKit/Source/core/fileapi/FileReaderLoader.h +++ b/third_party/WebKit/Source/core/fileapi/FileReaderLoader.h
@@ -122,7 +122,7 @@ KURL m_urlForReading; bool m_urlForReadingIsStream; - RefPtr<ThreadableLoader> m_loader; + OwnPtr<ThreadableLoader> m_loader; OwnPtr<ArrayBufferBuilder> m_rawData; bool m_isRawDataConverted;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp index 0ed9b64..3f1e1957 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -259,11 +259,6 @@ return m_treeBuilder->isParsingFragment(); } -bool HTMLDocumentParser::processingData() const -{ - return isScheduledForResume() || inPumpSession() || m_haveBackgroundParser; -} - void HTMLDocumentParser::pumpTokenizerIfPossible() { if (isStopped() || isWaitingForScripts()) @@ -434,7 +429,8 @@ TRACE_EVENT0("blink", "HTMLDocumentParser::processParsedChunkFromBackgroundParser"); TemporaryChange<bool> hasLineNumber(m_isParsingAtLineNumber, true); - ASSERT_WITH_SECURITY_IMPLICATION(document()->activeParserCount() == 1); + ASSERT_WITH_SECURITY_IMPLICATION(m_pumpSpeculationsSessionNestingLevel == 1); + ASSERT_WITH_SECURITY_IMPLICATION(!inPumpSession()); ASSERT(!isParsingFragment()); ASSERT(!isWaitingForScripts()); ASSERT(!isStopped()); @@ -550,7 +546,7 @@ // FIXME: Pass in current input length. TRACE_EVENT_BEGIN1("devtools.timeline", "ParseHTML", "beginData", InspectorParseHtmlEvent::beginData(document(), lineNumber().zeroBasedInt())); - SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel, contextForParsingSession()); + SpeculationsPumpSession session(m_pumpSpeculationsSessionNestingLevel); while (!m_speculations.isEmpty()) { ASSERT(!isScheduledForResume()); size_t elementTokenCount = processParsedChunkFromBackgroundParser(m_speculations.takeFirst().release()); @@ -584,15 +580,6 @@ m_tokenizer->setState(HTMLTokenizer::PLAINTEXTState); } -Document* HTMLDocumentParser::contextForParsingSession() -{ - // The parsing session should interact with the document only when parsing - // non-fragments. Otherwise, we might delay the load event mistakenly. - if (isParsingFragment()) - return nullptr; - return document(); -} - void HTMLDocumentParser::pumpTokenizer() { ASSERT(!isStopped()); @@ -603,7 +590,7 @@ ASSERT(m_tokenizer); ASSERT(m_token); - PumpSession session(m_pumpSessionNestingLevel, contextForParsingSession()); + PumpSession session(m_pumpSessionNestingLevel); // We tell the InspectorInstrumentation about every pump, even if we // end up pumping nothing. It can filter out empty pumps itself. @@ -1061,7 +1048,6 @@ RefPtrWillBeRawPtr<HTMLDocumentParser> parser = HTMLDocumentParser::create(fragment, contextElement, parserContentPolicy); parser->append(source); parser->finish(); - ASSERT(!parser->processingData()); // Make sure we're done. <rdar://problem/3963151> parser->detach(); // Allows ~DocumentParser to assert it was detached before destruction. }
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h index 513e130..8849292e 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h +++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
@@ -110,8 +110,6 @@ void flush() final; void setDecoder(PassOwnPtr<TextResourceDecoder>) final; - UseCounter* useCounter() { return UseCounter::getFrom(contextForParsingSession()); } - protected: void insert(const SegmentedString&) final; void append(const String&) override; @@ -133,7 +131,6 @@ // DocumentParser void detach() final; bool hasInsertionPoint() final; - bool processingData() const final; void prepareToStopParsing() final; void stopParsing() final; bool isWaitingForScripts() const final; @@ -153,8 +150,6 @@ size_t processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk>); void pumpPendingSpeculations(); - Document* contextForParsingSession(); - bool canTakeNextToken(); void pumpTokenizer(); void pumpTokenizerIfPossible();
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp index 70b70ad..ae74514 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp
@@ -35,24 +35,8 @@ namespace blink { -ActiveParserSession::ActiveParserSession(unsigned& nestingLevel, Document* document) +PumpSession::PumpSession(unsigned& nestingLevel) : NestingLevelIncrementer(nestingLevel) - , m_document(document) -{ - if (!m_document) - return; - m_document->incrementActiveParserCount(); -} - -ActiveParserSession::~ActiveParserSession() -{ - if (!m_document) - return; - m_document->decrementActiveParserCount(); -} - -PumpSession::PumpSession(unsigned& nestingLevel, Document* document) - : ActiveParserSession(nestingLevel, document) { } @@ -60,8 +44,8 @@ { } -SpeculationsPumpSession::SpeculationsPumpSession(unsigned& nestingLevel, Document* document) - : ActiveParserSession(nestingLevel, document) +SpeculationsPumpSession::SpeculationsPumpSession(unsigned& nestingLevel) + : NestingLevelIncrementer(nestingLevel) , m_startTime(currentTime()) , m_processedElementTokens(0) {
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h b/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h index da8cddc..0445b84 100644 --- a/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h +++ b/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h
@@ -34,31 +34,20 @@ namespace blink { -class Document; class HTMLDocumentParser; class WebTaskRunner; -class ActiveParserSession : public NestingLevelIncrementer { +class PumpSession : public NestingLevelIncrementer { STACK_ALLOCATED(); public: - ActiveParserSession(unsigned& nestingLevel, Document*); - ~ActiveParserSession(); - -private: - RefPtrWillBeMember<Document> m_document; -}; - -class PumpSession : public ActiveParserSession { - STACK_ALLOCATED(); -public: - PumpSession(unsigned& nestingLevel, Document*); + PumpSession(unsigned& nestingLevel); ~PumpSession(); }; -class SpeculationsPumpSession : public ActiveParserSession { +class SpeculationsPumpSession : public NestingLevelIncrementer { STACK_ALLOCATED(); public: - SpeculationsPumpSession(unsigned& nestingLevel, Document*); + SpeculationsPumpSession(unsigned& nestingLevel); ~SpeculationsPumpSession(); double elapsedTime() const;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp index 84867dc..7b34592 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.cpp
@@ -89,7 +89,7 @@ return adoptPtrWillBeNoop(new InspectorDOMDebuggerAgent(isolate, domAgent, runtimeAgent, debuggerAgent)); } -void InspectorDOMDebuggerAgent::eventListenersInfoForTarget(v8::Isolate* isolate, v8::Local<v8::Value> value, V8EventListenerInfoMap& eventInformation) +void InspectorDOMDebuggerAgent::eventListenersInfoForTarget(v8::Isolate* isolate, v8::Local<v8::Value> value, V8EventListenerInfoList& eventInformation) { EventTarget* target = V8EventTarget::toImplWithTypeCheck(isolate, value); // We need to handle LocalDOMWindow specially, because LocalDOMWindow wrapper exists on prototype chain. @@ -122,9 +122,7 @@ v8::Local<v8::Object> handler = v8Listener->getListenerObject(executionContext); if (handler.IsEmpty()) continue; - if (!eventInformation.get(type)) - eventInformation.set(type, adoptPtr(new protocol::Vector<V8EventListenerInfo>())); - eventInformation.get(type)->append(V8EventListenerInfo(type, listeners->at(k).useCapture, handler)); + eventInformation.append(V8EventListenerInfo(type, listeners->at(k).useCapture, handler)); } } } @@ -373,23 +371,21 @@ void InspectorDOMDebuggerAgent::eventListeners(v8::Local<v8::Context> context, v8::Local<v8::Value> object, const String16& objectGroup, protocol::Array<protocol::DOMDebugger::EventListener>* listenersArray) { - V8EventListenerInfoMap eventInformation; + V8EventListenerInfoList eventInformation; InspectorDOMDebuggerAgent::eventListenersInfoForTarget(context->GetIsolate(), object, eventInformation); - for (const auto& it : eventInformation) { - for (const auto& it2 : *it.second) { - if (!it2.useCapture) - continue; - OwnPtr<protocol::DOMDebugger::EventListener> listenerObject = buildObjectForEventListener(context, it2, objectGroup); - if (listenerObject) - listenersArray->addItem(listenerObject.release()); - } - for (auto& it2 : *it.second) { - if (it2.useCapture) - continue; - OwnPtr<protocol::DOMDebugger::EventListener> listenerObject = buildObjectForEventListener(context, it2, objectGroup); - if (listenerObject) - listenersArray->addItem(listenerObject.release()); - } + for (const auto& info : eventInformation) { + if (!info.useCapture) + continue; + OwnPtr<protocol::DOMDebugger::EventListener> listenerObject = buildObjectForEventListener(context, info, objectGroup); + if (listenerObject) + listenersArray->addItem(listenerObject.release()); + } + for (const auto& info : eventInformation) { + if (info.useCapture) + continue; + OwnPtr<protocol::DOMDebugger::EventListener> listenerObject = buildObjectForEventListener(context, info, objectGroup); + if (listenerObject) + listenersArray->addItem(listenerObject.release()); } }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h index 714ea1a80..479efc7 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorDOMDebuggerAgent.h
@@ -61,7 +61,7 @@ public: static PassOwnPtrWillBeRawPtr<InspectorDOMDebuggerAgent> create(v8::Isolate*, InspectorDOMAgent*, V8RuntimeAgent*, V8DebuggerAgent*); - static void eventListenersInfoForTarget(v8::Isolate*, v8::Local<v8::Value>, V8EventListenerInfoMap& listeners); + static void eventListenersInfoForTarget(v8::Isolate*, v8::Local<v8::Value>, V8EventListenerInfoList& listeners); ~InspectorDOMDebuggerAgent() override; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp index 4621ec2c..0b1114c 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.cpp
@@ -43,10 +43,9 @@ static const char debuggerEnabled[] = "debuggerEnabled"; } -InspectorDebuggerAgent::InspectorDebuggerAgent(V8RuntimeAgent* runtimeAgent, V8Debugger* debugger, int contextGroupId) +InspectorDebuggerAgent::InspectorDebuggerAgent(V8RuntimeAgent* runtimeAgent) : InspectorBaseAgent<InspectorDebuggerAgent, protocol::Frontend::Debugger>("Debugger") - , m_v8DebuggerAgent(V8DebuggerAgent::create(runtimeAgent, contextGroupId)) - , m_debugger(debugger) + , m_v8DebuggerAgent(V8DebuggerAgent::create(runtimeAgent)) { } @@ -360,6 +359,11 @@ setTrackingAsyncCalls(m_v8DebuggerAgent->trackingAsyncCalls()); } +void InspectorDebuggerAgent::discardAgent() +{ + m_v8DebuggerAgent.clear(); +} + void InspectorDebuggerAgent::setTrackingAsyncCalls(bool tracking) { m_asyncCallTracker->asyncCallTrackingStateChanged(tracking);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.h index 34017c2..3353951 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorDebuggerAgent.h
@@ -93,22 +93,21 @@ void setFrontend(protocol::Frontend*) override; void clearFrontend() override; void restore() override; + void discardAgent() override; V8DebuggerAgent* v8Agent() const { return m_v8DebuggerAgent.get(); } virtual void muteConsole() = 0; virtual void unmuteConsole() = 0; - V8Debugger* debugger() { return m_debugger; } protected: - InspectorDebuggerAgent(V8RuntimeAgent*, V8Debugger*, int contextGroupId); + explicit InspectorDebuggerAgent(V8RuntimeAgent*); OwnPtr<V8DebuggerAgent> m_v8DebuggerAgent; OwnPtrWillBeMember<AsyncCallTracker> m_asyncCallTracker; private: void setTrackingAsyncCalls(bool); - V8Debugger* m_debugger; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.cpp index 5b61f07c..2116fb3 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.cpp
@@ -114,6 +114,11 @@ startUpdateStatsTimer(); } +void InspectorHeapProfilerAgent::discardAgent() +{ + m_v8HeapProfilerAgent.clear(); +} + // Protocol implementation. void InspectorHeapProfilerAgent::collectGarbage(ErrorString* error) { @@ -167,7 +172,7 @@ void InspectorHeapProfilerAgent::getObjectByHeapObjectId(ErrorString* error, const String16& heapSnapshotObjectId, const protocol::Maybe<String16>& objectGroup, OwnPtr<protocol::Runtime::RemoteObject>* result) { bool ok; - unsigned id = heapSnapshotObjectId.toUInt(&ok); + int id = heapSnapshotObjectId.toInt(&ok); if (!ok) { *error = "Invalid heap snapshot object id"; return; @@ -184,7 +189,7 @@ void InspectorHeapProfilerAgent::addInspectedHeapObject(ErrorString* error, const String16& inspectedHeapObjectId) { bool ok; - unsigned id = inspectedHeapObjectId.toUInt(&ok); + int id = inspectedHeapObjectId.toInt(&ok); if (!ok) { *error = "Invalid heap snapshot object id"; return; @@ -203,11 +208,11 @@ m_v8HeapProfilerAgent->getHeapObjectId(errorString, objectId, heapSnapshotObjectId); } -bool InspectorHeapProfilerAgent::isInspectableHeapObject(unsigned id) +bool InspectorHeapProfilerAgent::isInspectableHeapObject(int id) { v8::HandleScope scope(m_isolate); v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); - v8::Local<v8::Value> value = profiler->FindObjectById(id); + v8::Local<v8::Value> value = profiler->FindObjectById(static_cast<unsigned>(id)); if (value.IsEmpty() || !value->IsObject()) return false; v8::Local<v8::Object> object = value.As<v8::Object>();
diff --git a/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.h index 593de17..84f2442 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorHeapProfilerAgent.h
@@ -59,6 +59,7 @@ void setFrontend(protocol::Frontend*) override; void clearFrontend() override; void restore() override; + void discardAgent() override; void enable(ErrorString*) override; void disable(ErrorString*) override; @@ -79,7 +80,7 @@ void startUpdateStatsTimer(); void stopUpdateStatsTimer(); - bool isInspectableHeapObject(unsigned id); + bool isInspectableHeapObject(int id); OwnPtr<V8HeapProfilerAgent> m_v8HeapProfilerAgent; OwnPtr<HeapStatsUpdateTask> m_heapStatsUpdateTask;
diff --git a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl index a1aeedf..431f2ea 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl +++ b/third_party/WebKit/Source/core/inspector/InspectorInstrumentation.idl
@@ -182,12 +182,6 @@ [DOMDebugger, Inline=FastReturn] void willEvaluateScript(ExecutionContext*); - [PageRuntime] - void didCreateScriptContext([Keep] LocalFrame*, ScriptState*, SecurityOrigin*, int worldId); - - [PageRuntime, Inline=FastReturn] - void willReleaseScriptContext([Keep] LocalFrame*, ScriptState*); - [AsyncCallTracker, DOMDebugger, Inline=FastReturn] InspectorInstrumentationCookie willFireTimer([Keep] ExecutionContext*, int timerId);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp index cbe1efe..a2b8831a 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorPageAgent.cpp
@@ -550,7 +550,7 @@ } OwnPtr<protocol::Array<protocol::Debugger::SearchMatch>> results; - results = V8ContentSearchUtil::searchInTextByLines(m_debuggerAgent->debugger(), content, query, caseSensitive, isRegex); + results = V8ContentSearchUtil::searchInTextByLines(&m_debuggerAgent->v8Agent()->debugger(), content, query, caseSensitive, isRegex); callback->sendSuccess(results.release()); }
diff --git a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp index b221302d..5540da77 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.cpp
@@ -85,6 +85,11 @@ enable(&errorString); } +void InspectorProfilerAgent::discardAgent() +{ + m_v8ProfilerAgent.clear(); +} + // Protocol implementation. void InspectorProfilerAgent::consoleProfile(ExecutionContext* context, const String16& title) {
diff --git a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h index 47c815a..91d79cd 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorProfilerAgent.h
@@ -64,6 +64,7 @@ void setFrontend(protocol::Frontend*) override; void clearFrontend() override; void restore() override; + void discardAgent() override; void consoleProfile(ExecutionContext*, const String16& title); void consoleProfileEnd(const String16& title);
diff --git a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp index 1e20884..b96d9ce9 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.cpp
@@ -43,10 +43,10 @@ static const char runtimeEnabled[] = "runtimeEnabled"; }; -InspectorRuntimeAgent::InspectorRuntimeAgent(V8Debugger* debugger, Client* client) +InspectorRuntimeAgent::InspectorRuntimeAgent(V8Debugger* debugger, Client* client, int contextGroupId) : InspectorBaseAgent<InspectorRuntimeAgent, protocol::Frontend::Runtime>("Runtime") , m_enabled(false) - , m_v8RuntimeAgent(V8RuntimeAgent::create(debugger, this)) + , m_v8RuntimeAgent(V8RuntimeAgent::create(debugger, contextGroupId)) , m_client(client) { } @@ -83,6 +83,11 @@ enable(&errorString); } +void InspectorRuntimeAgent::discardAgent() +{ + m_v8RuntimeAgent.clear(); +} + void InspectorRuntimeAgent::evaluate(ErrorString* errorString, const String16& expression, const Maybe<String16>& objectGroup, @@ -205,16 +210,4 @@ m_v8RuntimeAgent->disable(errorString); } -void InspectorRuntimeAgent::reportExecutionContextCreated(ScriptState* scriptState, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId) -{ - v8::HandleScope handles(scriptState->isolate()); - m_v8RuntimeAgent->reportExecutionContextCreated(scriptState->context(), type, origin, humanReadableName, frameId); -} - -void InspectorRuntimeAgent::reportExecutionContextDestroyed(ScriptState* scriptState) -{ - v8::HandleScope handles(scriptState->isolate()); - m_v8RuntimeAgent->reportExecutionContextDestroyed(scriptState->context()); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.h b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.h index 48fb70a9..7c92b68 100644 --- a/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.h +++ b/third_party/WebKit/Source/core/inspector/InspectorRuntimeAgent.h
@@ -52,8 +52,7 @@ class CORE_EXPORT InspectorRuntimeAgent : public InspectorBaseAgent<InspectorRuntimeAgent, protocol::Frontend::Runtime> - , public protocol::Dispatcher::RuntimeCommandHandler - , public V8RuntimeAgent::Client { + , public protocol::Dispatcher::RuntimeCommandHandler { WTF_MAKE_NONCOPYABLE(InspectorRuntimeAgent); public: class Client { @@ -65,14 +64,12 @@ ~InspectorRuntimeAgent() override; - // V8RuntimeAgent::Client. - void reportExecutionContexts() override { } - // InspectorBaseAgent overrides. void setState(protocol::DictionaryValue*) override; void setFrontend(protocol::Frontend*) override; void clearFrontend() override; void restore() override; + void discardAgent() override; // Part of the protocol. void evaluate(ErrorString*, const String16& expression, const Maybe<String16>& objectGroup, const Maybe<bool>& includeCommandLineAPI, const Maybe<bool>& doNotPauseOnExceptionsAndMuteConsole, const Maybe<int>& contextId, const Maybe<bool>& returnByValue, const Maybe<bool>& generatePreview, OwnPtr<protocol::Runtime::RemoteObject>* result, Maybe<bool>* wasThrown, Maybe<protocol::Runtime::ExceptionDetails>*) override; @@ -93,12 +90,9 @@ V8RuntimeAgent* v8Agent() { return m_v8RuntimeAgent.get(); } protected: - InspectorRuntimeAgent(V8Debugger*, Client*); + InspectorRuntimeAgent(V8Debugger*, Client*, int contextGroupId); virtual ScriptState* defaultScriptState() = 0; - void reportExecutionContextCreated(ScriptState*, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId); - void reportExecutionContextDestroyed(ScriptState*); - bool m_enabled; OwnPtr<V8RuntimeAgent> m_v8RuntimeAgent; Client* m_client;
diff --git a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp index c827274a..d0b647b2 100644 --- a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp +++ b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.cpp
@@ -32,11 +32,14 @@ #include "bindings/core/v8/BindingSecurity.h" #include "bindings/core/v8/DOMWrapperWorld.h" +#include "bindings/core/v8/ScriptController.h" #include "bindings/core/v8/V8Window.h" #include "core/frame/FrameConsole.h" #include "core/frame/LocalDOMWindow.h" #include "core/frame/LocalFrame.h" #include "core/frame/UseCounter.h" +#include "core/inspector/IdentifiersFactory.h" +#include "core/inspector/InspectedFrames.h" #include "core/inspector/InspectorTaskRunner.h" #include "platform/UserGestureIndicator.h" #include "platform/v8_inspector/public/V8Debugger.h" @@ -83,10 +86,22 @@ return mutex; } -void MainThreadDebugger::initializeContext(v8::Local<v8::Context> context, LocalFrame* frame, int worldId) +void MainThreadDebugger::contextCreated(ScriptState* scriptState, LocalFrame* frame, SecurityOrigin* origin) { - String type = worldId == MainWorldId ? "page" : "injected"; - V8Debugger::setContextDebugData(context, type, contextGroupId(frame)); + ASSERT(isMainThread()); + v8::HandleScope handles(scriptState->isolate()); + DOMWrapperWorld& world = scriptState->world(); + V8Debugger::setContextDebugData(scriptState->context(), world.isMainWorld() ? "page" : "injected", contextGroupId(frame)); + if (s_instance) + s_instance->debugger()->contextCreated(V8ContextInfo(scriptState->context(), world.isMainWorld() ? "" : "Extension", origin ? origin->toRawString() : "", world.isIsolatedWorld() ? world.isolatedWorldHumanReadableName() : "", IdentifiersFactory::frameId(frame))); +} + +void MainThreadDebugger::contextWillBeDestroyed(ScriptState* scriptState) +{ + if (s_instance) { + v8::HandleScope handles(scriptState->isolate()); + s_instance->debugger()->contextDestroyed(scriptState->context()); + } } int MainThreadDebugger::contextGroupId(LocalFrame* frame) @@ -147,4 +162,42 @@ return window && BindingSecurity::shouldAllowAccessTo(m_isolate, toLocalDOMWindow(toDOMWindow(calling)), window, DoNotReportSecurityError); } +void MainThreadDebugger::contextsToReport(int contextGroupId, V8ContextInfoVector& contexts) +{ + LocalFrame* root = WeakIdentifierMap<LocalFrame>::lookup(contextGroupId); + if (!root) + return; + + // Only report existing contexts if the page did commit load, otherwise we may + // unintentionally initialize contexts in the frames which may trigger some listeners + // that are expected to be triggered only after the load is committed, see http://crbug.com/131623 + if (!root->loader().stateMachine()->committedFirstRealDocumentLoad()) + return; + + OwnPtrWillBeRawPtr<InspectedFrames> inspectedFrames = InspectedFrames::create(root); + + Vector<std::pair<ScriptState*, SecurityOrigin*>> isolatedContexts; + for (LocalFrame* frame : *inspectedFrames) { + if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) + continue; + String frameId = IdentifiersFactory::frameId(frame); + + // Ensure execution context is created. + // If initializeMainWorld returns true, then is registered by didCreateScriptContext + if (!frame->script().initializeMainWorld()) { + ScriptState* scriptState = ScriptState::forMainWorld(frame); + contexts.append(V8ContextInfo(scriptState->context(), "", "", "", frameId)); + } + frame->script().collectIsolatedContexts(isolatedContexts); + if (isolatedContexts.isEmpty()) + continue; + for (const auto& pair : isolatedContexts) { + String originString = pair.second ? pair.second->toRawString() : ""; + ScriptState* scriptState = pair.first; + contexts.append(V8ContextInfo(scriptState->context(), "Extension", originString, scriptState->world().isolatedWorldHumanReadableName(), frameId)); + } + isolatedContexts.clear(); + } +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.h b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.h index ae6cab7..b84b25fd 100644 --- a/third_party/WebKit/Source/core/inspector/MainThreadDebugger.h +++ b/third_party/WebKit/Source/core/inspector/MainThreadDebugger.h
@@ -31,6 +31,7 @@ #ifndef MainThreadDebugger_h #define MainThreadDebugger_h +#include "bindings/core/v8/ScriptState.h" #include "core/CoreExport.h" #include "core/inspector/InspectorTaskRunner.h" #include "core/inspector/ThreadDebugger.h" @@ -45,6 +46,7 @@ class LocalFrame; class V8Debugger; +class SecurityOrigin; class CORE_EXPORT MainThreadDebugger final : public ThreadDebugger { WTF_MAKE_NONCOPYABLE(MainThreadDebugger); @@ -64,7 +66,8 @@ ~MainThreadDebugger() override; - static void initializeContext(v8::Local<v8::Context>, LocalFrame*, int worldId); + static void contextCreated(ScriptState*, LocalFrame*, SecurityOrigin*); + static void contextWillBeDestroyed(ScriptState*); static int contextGroupId(LocalFrame*); static MainThreadDebugger* instance(); @@ -82,6 +85,7 @@ void muteWarningsAndDeprecations() override; void unmuteWarningsAndDeprecations() override; bool callingContextCanAccessContext(v8::Local<v8::Context> calling, v8::Local<v8::Context> target) override; + void contextsToReport(int contextGroupId, V8ContextInfoVector&) override; static WTF::Mutex& creationMutex();
diff --git a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp index b9c0bb8..27ee93da 100644 --- a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.cpp
@@ -40,7 +40,6 @@ #include "core/inspector/InspectorInstrumentation.h" #include "core/inspector/InspectorTraceEvents.h" #include "core/inspector/InstrumentingAgents.h" -#include "core/inspector/MainThreadDebugger.h" #include "core/loader/DocumentLoader.h" #include "core/page/Page.h" @@ -48,13 +47,13 @@ namespace blink { -PassOwnPtrWillBeRawPtr<PageDebuggerAgent> PageDebuggerAgent::create(MainThreadDebugger* mainThreadDebugger, InspectedFrames* inspectedFrames, V8RuntimeAgent* runtimeAgent) +PassOwnPtrWillBeRawPtr<PageDebuggerAgent> PageDebuggerAgent::create(InspectedFrames* inspectedFrames, V8RuntimeAgent* runtimeAgent) { - return adoptPtrWillBeNoop(new PageDebuggerAgent(mainThreadDebugger, inspectedFrames, runtimeAgent)); + return adoptPtrWillBeNoop(new PageDebuggerAgent(inspectedFrames, runtimeAgent)); } -PageDebuggerAgent::PageDebuggerAgent(MainThreadDebugger* mainThreadDebugger, InspectedFrames* inspectedFrames, V8RuntimeAgent* runtimeAgent) - : InspectorDebuggerAgent(runtimeAgent, mainThreadDebugger->debugger(), mainThreadDebugger->contextGroupId(inspectedFrames->root())) +PageDebuggerAgent::PageDebuggerAgent(InspectedFrames* inspectedFrames, V8RuntimeAgent* runtimeAgent) + : InspectorDebuggerAgent(runtimeAgent) , m_inspectedFrames(inspectedFrames) { }
diff --git a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h index d2d4eba..ec6c98c 100644 --- a/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h +++ b/third_party/WebKit/Source/core/inspector/PageDebuggerAgent.h
@@ -42,14 +42,13 @@ class DocumentLoader; class InspectedFrames; -class MainThreadDebugger; class CORE_EXPORT PageDebuggerAgent final : public InspectorDebuggerAgent { WTF_MAKE_NONCOPYABLE(PageDebuggerAgent); USING_FAST_MALLOC_WILL_BE_REMOVED(PageDebuggerAgent); public: - static PassOwnPtrWillBeRawPtr<PageDebuggerAgent> create(MainThreadDebugger*, InspectedFrames*, V8RuntimeAgent*); + static PassOwnPtrWillBeRawPtr<PageDebuggerAgent> create(InspectedFrames*, V8RuntimeAgent*); ~PageDebuggerAgent() override; DECLARE_VIRTUAL_TRACE(); @@ -61,7 +60,7 @@ void didClearDocumentOfWindowObject(LocalFrame*); private: - PageDebuggerAgent(MainThreadDebugger*, InspectedFrames*, V8RuntimeAgent*); + PageDebuggerAgent(InspectedFrames*, V8RuntimeAgent*); void muteConsole() override; void unmuteConsole() override;
diff --git a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp index c9b25d1..fc7a77c 100644 --- a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.cpp
@@ -35,7 +35,6 @@ #include "bindings/core/v8/ScriptState.h" #include "core/frame/FrameConsole.h" #include "core/frame/LocalFrame.h" -#include "core/inspector/IdentifiersFactory.h" #include "core/inspector/InspectedFrames.h" #include "core/inspector/InstrumentingAgents.h" #include "core/page/Page.h" @@ -46,10 +45,9 @@ namespace blink { -PageRuntimeAgent::PageRuntimeAgent(Client* client, V8Debugger* debugger, InspectedFrames* inspectedFrames) - : InspectorRuntimeAgent(debugger, client) +PageRuntimeAgent::PageRuntimeAgent(Client* client, V8Debugger* debugger, InspectedFrames* inspectedFrames, int contextGroupId) + : InspectorRuntimeAgent(debugger, client, contextGroupId) , m_inspectedFrames(inspectedFrames) - , m_mainWorldContextCreated(false) { } @@ -89,8 +87,6 @@ void PageRuntimeAgent::didClearDocumentOfWindowObject(LocalFrame* frame) { - m_mainWorldContextCreated = true; - if (!m_enabled) return; ASSERT(frontend()); @@ -100,22 +96,6 @@ frame->script().initializeMainWorld(); } -void PageRuntimeAgent::didCreateScriptContext(LocalFrame* frame, ScriptState* scriptState, SecurityOrigin* origin, int worldId) -{ - if (!m_enabled) - return; - ASSERT(frontend()); - bool isMainWorld = worldId == MainWorldId; - String originString = origin ? origin->toRawString() : ""; - String frameId = IdentifiersFactory::frameId(frame); - reportExecutionContext(scriptState, isMainWorld, originString, frameId); -} - -void PageRuntimeAgent::willReleaseScriptContext(LocalFrame* frame, ScriptState* scriptState) -{ - reportExecutionContextDestroyed(scriptState); -} - ScriptState* PageRuntimeAgent::defaultScriptState() { ScriptState* scriptState = ScriptState::forMainWorld(m_inspectedFrames->root()); @@ -133,43 +113,4 @@ FrameConsole::unmute(); } -void PageRuntimeAgent::reportExecutionContexts() -{ - // Only report existing contexts if the page did commit load, otherwise we may - // unintentionally initialize contexts in the frames which may trigger some listeners - // that are expected to be triggered only after the load is committed, see http://crbug.com/131623 - if (!m_mainWorldContextCreated) - return; - - Vector<std::pair<ScriptState*, SecurityOrigin*>> isolatedContexts; - for (LocalFrame* frame : *m_inspectedFrames) { - if (!frame->script().canExecuteScripts(NotAboutToExecuteScript)) - continue; - String frameId = IdentifiersFactory::frameId(frame); - - // Ensure execution context is created. - // If initializeMainWorld returns true, then is registered by didCreateScriptContext - if (!frame->script().initializeMainWorld()) { - ScriptState* scriptState = ScriptState::forMainWorld(frame); - reportExecutionContext(scriptState, true, "", frameId); - } - frame->script().collectIsolatedContexts(isolatedContexts); - if (isolatedContexts.isEmpty()) - continue; - for (const auto& pair : isolatedContexts) { - String originString = pair.second ? pair.second->toRawString() : ""; - reportExecutionContext(pair.first, false, originString, frameId); - } - isolatedContexts.clear(); - } -} - -void PageRuntimeAgent::reportExecutionContext(ScriptState* scriptState, bool isPageContext, const String& origin, const String& frameId) -{ - DOMWrapperWorld& world = scriptState->world(); - String humanReadableName = world.isIsolatedWorld() ? world.isolatedWorldHumanReadableName() : ""; - String type = isPageContext ? "" : "Extension"; - InspectorRuntimeAgent::reportExecutionContextCreated(scriptState, type, origin, humanReadableName, frameId); -} - } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h index b807813..d4129c56 100644 --- a/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h +++ b/third_party/WebKit/Source/core/inspector/PageRuntimeAgent.h
@@ -39,13 +39,12 @@ namespace blink { class InspectedFrames; -class SecurityOrigin; class CORE_EXPORT PageRuntimeAgent final : public InspectorRuntimeAgent { public: - static PassOwnPtrWillBeRawPtr<PageRuntimeAgent> create(InspectorRuntimeAgent::Client* client, V8Debugger* debugger, InspectedFrames* inspectedFrames) + static PassOwnPtrWillBeRawPtr<PageRuntimeAgent> create(InspectorRuntimeAgent::Client* client, V8Debugger* debugger, InspectedFrames* inspectedFrames, int contextGroupId) { - return adoptPtrWillBeNoop(new PageRuntimeAgent(client, debugger, inspectedFrames)); + return adoptPtrWillBeNoop(new PageRuntimeAgent(client, debugger, inspectedFrames, contextGroupId)); } ~PageRuntimeAgent() override; DECLARE_VIRTUAL_TRACE(); @@ -53,22 +52,15 @@ void enable(ErrorString*) override; void disable(ErrorString*) override; void didClearDocumentOfWindowObject(LocalFrame*); - void didCreateScriptContext(LocalFrame*, ScriptState*, SecurityOrigin*, int worldId); - void willReleaseScriptContext(LocalFrame*, ScriptState*); private: - PageRuntimeAgent(Client*, V8Debugger*, InspectedFrames*); - - // V8RuntimeAgent::Client. - void reportExecutionContexts() override; + PageRuntimeAgent(Client*, V8Debugger*, InspectedFrames*, int contextGroupId); ScriptState* defaultScriptState() override; void muteConsole() override; void unmuteConsole() override; - void reportExecutionContext(ScriptState*, bool isPageContext, const String& origin, const String& frameId); RawPtrWillBeMember<InspectedFrames> m_inspectedFrames; - bool m_mainWorldContextCreated; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp index 5d8a1d1..cf188fa 100644 --- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp +++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.cpp
@@ -29,7 +29,7 @@ { } -void ThreadDebugger::eventListeners(v8::Local<v8::Value> value, V8EventListenerInfoMap& result) +void ThreadDebugger::eventListeners(v8::Local<v8::Value> value, V8EventListenerInfoList& result) { InspectorDOMDebuggerAgent::eventListenersInfoForTarget(m_isolate, value, result); }
diff --git a/third_party/WebKit/Source/core/inspector/ThreadDebugger.h b/third_party/WebKit/Source/core/inspector/ThreadDebugger.h index 962e1c84..19eec3e 100644 --- a/third_party/WebKit/Source/core/inspector/ThreadDebugger.h +++ b/third_party/WebKit/Source/core/inspector/ThreadDebugger.h
@@ -25,7 +25,7 @@ // V8DebuggerClient implementation. void muteWarningsAndDeprecations() override { }; void unmuteWarningsAndDeprecations() override { }; - void eventListeners(v8::Local<v8::Value>, V8EventListenerInfoMap&) override; + void eventListeners(v8::Local<v8::Value>, V8EventListenerInfoList&) override; v8::MaybeLocal<v8::Object> instantiateObject(v8::Local<v8::Function>) override; v8::MaybeLocal<v8::Value> runCompiledScript(v8::Local<v8::Context>, v8::Local<v8::Script>) override; v8::MaybeLocal<v8::Value> compileAndRunInternalScript(v8::Local<v8::String>) override;
diff --git a/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.cpp b/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.cpp index e9004a353..fdbf967 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.cpp
@@ -30,19 +30,17 @@ #include "core/inspector/WorkerDebuggerAgent.h" -#include "core/inspector/WorkerThreadDebugger.h" #include "core/workers/WorkerGlobalScope.h" -#include "platform/v8_inspector/public/V8Debugger.h" namespace blink { -PassOwnPtrWillBeRawPtr<WorkerDebuggerAgent> WorkerDebuggerAgent::create(V8Debugger* debugger, WorkerGlobalScope* inspectedWorkerGlobalScope, V8RuntimeAgent* runtimeAgent) +PassOwnPtrWillBeRawPtr<WorkerDebuggerAgent> WorkerDebuggerAgent::create(WorkerGlobalScope* inspectedWorkerGlobalScope, V8RuntimeAgent* runtimeAgent) { - return adoptPtrWillBeNoop(new WorkerDebuggerAgent(debugger, inspectedWorkerGlobalScope, runtimeAgent)); + return adoptPtrWillBeNoop(new WorkerDebuggerAgent(inspectedWorkerGlobalScope, runtimeAgent)); } -WorkerDebuggerAgent::WorkerDebuggerAgent(V8Debugger* debugger, WorkerGlobalScope* inspectedWorkerGlobalScope, V8RuntimeAgent* runtimeAgent) - : InspectorDebuggerAgent(runtimeAgent, debugger, WorkerThreadDebugger::contextGroupId()) +WorkerDebuggerAgent::WorkerDebuggerAgent(WorkerGlobalScope* inspectedWorkerGlobalScope, V8RuntimeAgent* runtimeAgent) + : InspectorDebuggerAgent(runtimeAgent) , m_inspectedWorkerGlobalScope(inspectedWorkerGlobalScope) { }
diff --git a/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.h b/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.h index cb8355e..4bc9a54 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.h +++ b/third_party/WebKit/Source/core/inspector/WorkerDebuggerAgent.h
@@ -35,20 +35,18 @@ namespace blink { -class V8Debugger; class WorkerGlobalScope; -class WorkerThreadDebugger; class WorkerDebuggerAgent final : public InspectorDebuggerAgent { WTF_MAKE_NONCOPYABLE(WorkerDebuggerAgent); USING_FAST_MALLOC_WILL_BE_REMOVED(WorkerDebuggerAgent); public: - static PassOwnPtrWillBeRawPtr<WorkerDebuggerAgent> create(V8Debugger*, WorkerGlobalScope*, V8RuntimeAgent*); + static PassOwnPtrWillBeRawPtr<WorkerDebuggerAgent> create(WorkerGlobalScope*, V8RuntimeAgent*); ~WorkerDebuggerAgent() override; DECLARE_VIRTUAL_TRACE(); private: - WorkerDebuggerAgent(V8Debugger*, WorkerGlobalScope*, V8RuntimeAgent*); + WorkerDebuggerAgent(WorkerGlobalScope*, V8RuntimeAgent*); // V8DebuggerAgent::Client implemntation. void muteConsole() override;
diff --git a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp index 1d10f94..58de4e9 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp +++ b/third_party/WebKit/Source/core/inspector/WorkerInspectorController.cpp
@@ -66,11 +66,11 @@ V8Debugger* debugger = data->threadDebugger()->debugger(); - OwnPtrWillBeRawPtr<WorkerRuntimeAgent> workerRuntimeAgent = WorkerRuntimeAgent::create(debugger, workerGlobalScope, this); + OwnPtrWillBeRawPtr<WorkerRuntimeAgent> workerRuntimeAgent = WorkerRuntimeAgent::create(debugger, workerGlobalScope, this, WorkerThreadDebugger::contextGroupId()); m_workerRuntimeAgent = workerRuntimeAgent.get(); m_agents.append(workerRuntimeAgent.release()); - OwnPtrWillBeRawPtr<WorkerDebuggerAgent> workerDebuggerAgent = WorkerDebuggerAgent::create(debugger, workerGlobalScope, m_workerRuntimeAgent->v8Agent()); + OwnPtrWillBeRawPtr<WorkerDebuggerAgent> workerDebuggerAgent = WorkerDebuggerAgent::create(workerGlobalScope, m_workerRuntimeAgent->v8Agent()); m_workerDebuggerAgent = workerDebuggerAgent.get(); m_agents.append(workerDebuggerAgent.release()); @@ -120,8 +120,9 @@ void WorkerInspectorController::dispose() { - m_instrumentingAgents->reset(); disconnectFrontend(); + m_instrumentingAgents->reset(); + m_agents.discardAgents(); } void WorkerInspectorController::resumeStartup()
diff --git a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp index d5540d2..70af1be 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp +++ b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.cpp
@@ -35,8 +35,8 @@ namespace blink { -WorkerRuntimeAgent::WorkerRuntimeAgent(V8Debugger* debugger, WorkerGlobalScope* workerGlobalScope, InspectorRuntimeAgent::Client* client) - : InspectorRuntimeAgent(debugger, client) +WorkerRuntimeAgent::WorkerRuntimeAgent(V8Debugger* debugger, WorkerGlobalScope* workerGlobalScope, InspectorRuntimeAgent::Client* client, int contextGroupId) + : InspectorRuntimeAgent(debugger, client, contextGroupId) , m_workerGlobalScope(workerGlobalScope) { } @@ -57,8 +57,6 @@ return; InspectorRuntimeAgent::enable(errorString); - ScriptState* scriptState = m_workerGlobalScope->scriptController()->getScriptState(); - reportExecutionContextCreated(scriptState, "", m_workerGlobalScope->url().getString(), "", ""); } ScriptState* WorkerRuntimeAgent::defaultScriptState()
diff --git a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.h b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.h index 73b1696..c97d9ce 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.h +++ b/third_party/WebKit/Source/core/inspector/WorkerRuntimeAgent.h
@@ -40,9 +40,9 @@ class WorkerRuntimeAgent final : public InspectorRuntimeAgent { public: - static PassOwnPtrWillBeRawPtr<WorkerRuntimeAgent> create(V8Debugger* debugger, WorkerGlobalScope* context, InspectorRuntimeAgent::Client* client) + static PassOwnPtrWillBeRawPtr<WorkerRuntimeAgent> create(V8Debugger* debugger, WorkerGlobalScope* context, InspectorRuntimeAgent::Client* client, int contextGroupId) { - return adoptPtrWillBeNoop(new WorkerRuntimeAgent(debugger, context, client)); + return adoptPtrWillBeNoop(new WorkerRuntimeAgent(debugger, context, client, contextGroupId)); } ~WorkerRuntimeAgent() override; DECLARE_VIRTUAL_TRACE(); @@ -50,7 +50,7 @@ void enable(ErrorString*) final; private: - WorkerRuntimeAgent(V8Debugger*, WorkerGlobalScope*, InspectorRuntimeAgent::Client*); + WorkerRuntimeAgent(V8Debugger*, WorkerGlobalScope*, InspectorRuntimeAgent::Client*, int contextGroupId); ScriptState* defaultScriptState() override; void muteConsole() override; void unmuteConsole() override;
diff --git a/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.cpp b/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.cpp index 877b5d5..edef49a8 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.cpp +++ b/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.cpp
@@ -75,4 +75,11 @@ return true; } +void WorkerThreadDebugger::contextsToReport(int contextGroupId, V8ContextInfoVector& contexts) +{ + ASSERT(contextGroupId == workerContextGroupId); + ScriptState* scriptState = m_workerThread->workerGlobalScope()->scriptController()->getScriptState(); + contexts.append(V8ContextInfo(scriptState->context(), "", m_workerThread->workerGlobalScope()->url().getString(), "", "")); +} + } // namespace blink
diff --git a/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.h b/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.h index 2e0419f..63710af4 100644 --- a/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.h +++ b/third_party/WebKit/Source/core/inspector/WorkerThreadDebugger.h
@@ -50,6 +50,7 @@ void runMessageLoopOnPause(int contextGroupId) override; void quitMessageLoopOnPause() override; bool callingContextCanAccessContext(v8::Local<v8::Context> calling, v8::Local<v8::Context> target) override; + void contextsToReport(int contextGroupId, V8ContextInfoVector&) override; private: WorkerThread* m_workerThread;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp index ce2fe9ff..438077b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -2773,7 +2773,7 @@ RootInlineBox* LayoutBlockFlow::createRootInlineBox() { - return new RootInlineBox(*this); + return new RootInlineBox(LineLayoutItem(this)); } bool LayoutBlockFlow::isPagedOverflow(const ComputedStyle& style)
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp index 71fc424..7d6b873 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -907,7 +907,7 @@ delta.setWidth(0); if (abs(delta.height()) <= AutoscrollController::noPanScrollRadius) delta.setHeight(0); - scrollByRecursively(adjustedScrollDelta(delta), ScrollOffsetClamped); + scroll(ScrollByPixel, FloatSize(adjustedScrollDelta(delta))); } void LayoutBox::scrollByRecursively(const DoubleSize& delta, ScrollOffsetClamping clamp) @@ -1739,7 +1739,7 @@ InlineBox* LayoutBox::createInlineBox() { - return new InlineBox(*this); + return new InlineBox(LineLayoutItem(this)); } void LayoutBox::dirtyLineBoxes(bool fullLayout) @@ -1828,44 +1828,102 @@ ensureRareData().m_paginationStrut = strut; } -static bool isForcedBreakAllowed(const LayoutBox* child) +bool LayoutBox::isBreakBetweenControllable(EBreak breakValue) const { - // We currently only support forced breaks on in-flow block level elements, which is the minimum - // requirement according to the spec. - if (child->isInline() || child->isFloatingOrOutOfFlowPositioned()) + if (breakValue == BreakAuto) + return true; + // We currently only support non-auto break-before and break-after values on in-flow block + // level elements, which is the minimum requirement according to the spec. + if (isInline() || isFloatingOrOutOfFlowPositioned()) return false; - const LayoutBlock* curr = child->containingBlock(); + const LayoutBlock* curr = containingBlock(); if (!curr || !curr->isLayoutBlockFlow()) return false; - const LayoutView* layoutView = child->view(); - while (curr && curr != layoutView) { - if (curr->isLayoutFlowThread()) - return true; + const LayoutView* layoutView = view(); + bool viewIsPaginated = layoutView->fragmentationContext(); + if (!viewIsPaginated && !flowThreadContainingBlock()) + return false; + while (curr) { + if (curr == layoutView) + return viewIsPaginated && breakValue != BreakColumn && breakValue != BreakAvoidColumn; + if (curr->isLayoutFlowThread()) { + if (breakValue == BreakAvoid) // Valid in any kind of fragmentation context. + return true; + bool isMulticolValue = breakValue == BreakColumn || breakValue == BreakAvoidColumn; + if (toLayoutFlowThread(curr)->isLayoutPagedFlowThread()) + return !isMulticolValue; + if (isMulticolValue) + return true; + // If this is a flow thread for a multicol container, and we have a break value for + // paged, we need to keep looking. + } if (curr->isFloatingOrOutOfFlowPositioned()) return false; curr = curr->containingBlock(); } - return true; + ASSERT_NOT_REACHED(); + return false; +} + +bool LayoutBox::isBreakInsideControllable(EBreak breakValue) const +{ + ASSERT(!isForcedFragmentainerBreakValue(breakValue)); + if (breakValue == BreakAuto) + return true; + // First check multicol. + const LayoutFlowThread* flowThread = flowThreadContainingBlock(); + // 'avoid-column' is only valid in a multicol context. + if (breakValue == BreakAvoidColumn) + return flowThread && !flowThread->isLayoutPagedFlowThread(); + // 'avoid' is valid in any kind of fragmentation context. + if (breakValue == BreakAvoid && flowThread) + return true; + ASSERT(breakValue == BreakAvoidPage || breakValue == BreakAvoid); + if (view()->fragmentationContext()) + return true; // The view is paginated, probably because we're printing. + if (!flowThread) + return false; // We're not inside any pagination context + // We're inside a flow thread. We need to be contained by a flow thread for paged overflow in + // order for pagination values to be valid, though. + for (const LayoutBlock* ancestor = flowThread; ancestor; ancestor = ancestor->containingBlock()) { + if (ancestor->isLayoutFlowThread() && toLayoutFlowThread(ancestor)->isLayoutPagedFlowThread()) + return true; + } + return false; +} + +EBreak LayoutBox::breakAfter() const +{ + EBreak breakValue = style()->breakAfter(); + if (breakValue == BreakAuto || isBreakBetweenControllable(breakValue)) + return breakValue; + return BreakAuto; +} + +EBreak LayoutBox::breakBefore() const +{ + EBreak breakValue = style()->breakBefore(); + if (breakValue == BreakAuto || isBreakBetweenControllable(breakValue)) + return breakValue; + return BreakAuto; +} + +EBreak LayoutBox::breakInside() const +{ + EBreak breakValue = style()->breakInside(); + if (breakValue == BreakAuto || isBreakInsideControllable(breakValue)) + return breakValue; + return BreakAuto; } bool LayoutBox::hasForcedBreakBefore() const { - LayoutFlowThread* flowThread = flowThreadContainingBlock(); - bool checkColumnBreaks = flowThread; - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // TODO(mstensho): Once columns can print, we have to check this. - bool checkBeforeAlways = (checkColumnBreaks && style()->breakBefore() == BreakColumn) - || (checkPageBreaks && style()->breakBefore() == BreakPage); - return checkBeforeAlways && isForcedBreakAllowed(this); + return isForcedFragmentainerBreakValue(breakBefore()); } bool LayoutBox::hasForcedBreakAfter() const { - LayoutFlowThread* flowThread = flowThreadContainingBlock(); - bool checkColumnBreaks = flowThread; - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // TODO(mstensho): Once columns can print, we have to check this. - bool checkAfterAlways = (checkColumnBreaks && style()->breakAfter() == BreakColumn) - || (checkPageBreaks && style()->breakAfter() == BreakPage); - return checkAfterAlways && isForcedBreakAllowed(this); + return isForcedFragmentainerBreakValue(breakAfter()); } LayoutRect LayoutBox::clippedOverflowRectForPaintInvalidation(const LayoutBoxModelObject* paintInvalidationContainer, const PaintInvalidationState* paintInvalidationState) const @@ -4178,12 +4236,8 @@ || (isOutOfFlowPositioned() && style()->position() == FixedPosition)) return ForbidBreaks; - bool checkColumnBreaks = flowThreadContainingBlock(); - bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); - EBreak breakInside = style()->breakInside(); - bool isUnsplittable = (checkColumnBreaks && (breakInside == BreakAvoid || breakInside == BreakAvoidColumn)) - || (checkPageBreaks && (breakInside == BreakAvoid || breakInside == BreakAvoidPage)); - if (isUnsplittable) + EBreak breakValue = breakInside(); + if (breakValue == BreakAvoid || breakValue == BreakAvoidPage || breakValue == BreakAvoidColumn) return AvoidBreaks; return AllowAnyBreaks; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h index c2d018d..f3c2703 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -620,6 +620,20 @@ m_rareData->m_paginationStrut = LayoutUnit(); } + // Is the specified break-before or break-after value supported on this object? It needs to be + // in-flow all the way up to a fragmentation context that supports the specified value. + bool isBreakBetweenControllable(EBreak) const; + + // Is the specified break-inside value supported on this object? It needs to be contained by a + // fragmentation context that supports the specified value. + bool isBreakInsideControllable(EBreak) const; + + EBreak breakAfter() const; + EBreak breakBefore() const; + EBreak breakInside() const; + + static bool isForcedFragmentainerBreakValue(EBreak); + bool hasForcedBreakBefore() const; bool hasForcedBreakAfter() const; @@ -1136,6 +1150,16 @@ m_inlineBoxWrapper = boxWrapper; } +inline bool LayoutBox::isForcedFragmentainerBreakValue(EBreak breakValue) +{ + return breakValue == BreakColumn + || breakValue == BreakLeft + || breakValue == BreakPage + || breakValue == BreakRecto + || breakValue == BreakRight + || breakValue == BreakVerso; +} + } // namespace blink #endif // LayoutBox_h
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp index c4d964b..7010410 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -1026,6 +1026,40 @@ return std::max(childSize, minExtent); } +LayoutUnit LayoutFlexibleBox::computeDefiniteLogicalWidth() +{ + const Length& widthLength = styleRef().logicalWidth(); + if (widthLength.hasPercent() && !hasDefiniteLogicalWidth()) + return LayoutUnit(-1); + + if (widthLength.isAuto()) { + // We can still have a definite width even with width: auto if we're a flex item ourselves + if (!isFlexItem()) + return LayoutUnit(-1); + return toLayoutFlexibleBox(parent())->childLogicalWidthForPercentageResolution(*this); + } + LogicalExtentComputedValues computedValues; + computeLogicalWidth(computedValues); + return computedValues.m_extent; +} + +LayoutUnit LayoutFlexibleBox::computeDefiniteLogicalHeight() +{ + const Length& heightLength = styleRef().logicalHeight(); + if (heightLength.hasPercent()) { + return computePercentageLogicalHeight(heightLength); + } + if (heightLength.isAuto()) { + // We can still have a definite height even with height: auto if we're a flex item ourselves + if (!isFlexItem()) + return LayoutUnit(-1); + return toLayoutFlexibleBox(parent())->childLogicalHeightForPercentageResolution(*this); + } + LogicalExtentComputedValues computedValues; + computeLogicalHeight(LayoutUnit(-1), LayoutUnit(), computedValues); + return computedValues.m_extent; +} + LayoutUnit LayoutFlexibleBox::crossSizeForPercentageResolution(const LayoutBox& child) { // This function implements section 9.8. Definite and Indefinite Sizes, case @@ -1044,42 +1078,18 @@ LayoutUnit childCrossSize; - LogicalExtentComputedValues computedValues; if (isColumnFlow()) { - const Length& widthLength = styleRef().logicalWidth(); - if (widthLength.hasPercent() && !hasDefiniteLogicalWidth()) - return LayoutUnit(-1); - - if (widthLength.isAuto()) { - // We can still have a definite width even with width: auto if we're a flex item ourselves - if (!isFlexItem()) - return LayoutUnit(-1); - computedValues.m_extent = toLayoutFlexibleBox(parent())->childLogicalWidthForPercentageResolution(*this); - if (computedValues.m_extent == LayoutUnit(-1)) - return computedValues.m_extent; - } else { - computeLogicalWidth(computedValues); - } - if (computedValues.m_extent == LayoutUnit(-1)) - return LayoutUnit(-1); - childCrossSize = computedValues.m_extent - borderAndPaddingLogicalWidth() - scrollbarLogicalWidth(); + LayoutUnit definiteWidth = computeDefiniteLogicalWidth(); + if (definiteWidth == LayoutUnit(-1)) + return definiteWidth; + childCrossSize = definiteWidth - borderAndPaddingLogicalWidth() - scrollbarLogicalWidth(); childCrossSize = child.constrainLogicalWidthByMinMax(childCrossSize, childCrossSize, this) - child.scrollbarLogicalWidth() - child.borderAndPaddingLogicalWidth(); } else { - const Length& heightLength = styleRef().logicalHeight(); - if (heightLength.hasPercent()) { - computedValues.m_extent = computePercentageLogicalHeight(heightLength); - } else if (heightLength.isAuto()) { - // We can still have a definite height even with height: auto if we're a flex item ourselves - if (!isFlexItem()) - return LayoutUnit(-1); - computedValues.m_extent = toLayoutFlexibleBox(parent())->childLogicalHeightForPercentageResolution(*this); - } else { - computeLogicalHeight(LayoutUnit(-1), LayoutUnit(), computedValues); - } - if (computedValues.m_extent == LayoutUnit(-1)) - return computedValues.m_extent; + LayoutUnit definiteHeight = computeDefiniteLogicalHeight(); + if (definiteHeight == LayoutUnit(-1)) + return definiteHeight; - childCrossSize = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(); + childCrossSize = definiteHeight - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(); childCrossSize = child.constrainLogicalHeightByMinMax(childCrossSize, LayoutUnit(-1)) - child.scrollbarLogicalHeight() - child.borderAndPaddingLogicalHeight(); } return childCrossSize;
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h index 50c202c..5057496 100644 --- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.h
@@ -60,6 +60,10 @@ const OrderIterator& orderIterator() const { return m_orderIterator; } + // Returns -1 if the height of this flexbox is indefinite + LayoutUnit computeDefiniteLogicalWidth(); + LayoutUnit computeDefiniteLogicalHeight(); + LayoutUnit crossSizeForPercentageResolution(const LayoutBox& child); LayoutUnit childLogicalHeightForPercentageResolution(const LayoutBox& child); LayoutUnit childLogicalWidthForPercentageResolution(const LayoutBox& child);
diff --git a/third_party/WebKit/Source/core/layout/LayoutInline.cpp b/third_party/WebKit/Source/core/layout/LayoutInline.cpp index 897fc332..489d47b 100644 --- a/third_party/WebKit/Source/core/layout/LayoutInline.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutInline.cpp
@@ -1232,7 +1232,7 @@ InlineFlowBox* LayoutInline::createInlineFlowBox() { - return new InlineFlowBox(*this); + return new InlineFlowBox(LineLayoutItem(this)); } InlineFlowBox* LayoutInline::createAndAppendInlineFlowBox()
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp index 1ff2599..3099e44 100644 --- a/third_party/WebKit/Source/core/layout/LayoutText.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -1436,7 +1436,7 @@ InlineTextBox* LayoutText::createTextBox(int start, unsigned short length) { - return new InlineTextBox(*this, start, length); + return new InlineTextBox(LineLayoutItem(this), start, length); } InlineTextBox* LayoutText::createInlineTextBox(int start, unsigned short length)
diff --git a/third_party/WebKit/Source/core/layout/PaginationTest.cpp b/third_party/WebKit/Source/core/layout/PaginationTest.cpp index 3c1e97d..7df64f8 100644 --- a/third_party/WebKit/Source/core/layout/PaginationTest.cpp +++ b/third_party/WebKit/Source/core/layout/PaginationTest.cpp
@@ -90,7 +90,7 @@ setBodyInnerHTML( "<div style='overflow:-webkit-paged-y; height:400px; line-height:50px;'>" " <div id='block1'>line1</div>" - " <div id='block2' style='-webkit-column-break-before:always;'>line2</div>" + " <div id='block2' style='break-before:page;'>line2</div>" "</div>"); EXPECT_EQ(0, strutForBox("block1")); EXPECT_EQ(0, strutForLine("block1", 0)); @@ -120,7 +120,7 @@ "<div style='overflow:-webkit-paged-y; height:400px; line-height:150px;'>" " <div id='block1'>line1</div>" " <div id='block2' style='padding-top:2px;'>" - " <div id='innerBlock' style='padding-top:2px; -webkit-column-break-inside:avoid;'>" + " <div id='innerBlock' style='padding-top:2px; break-inside:avoid;'>" " line2<br>" " line3<br>" " </div>" @@ -140,7 +140,7 @@ "<div style='overflow:-webkit-paged-y; height:200px; line-height:150px;'>" " <div id='block1'>line1</div>" " <div id='block2' style='padding-top:2px;'>" - " <div id='innerBlock' style='padding-top:2px; -webkit-column-break-before:always;'>line2</div>" + " <div id='innerBlock' style='padding-top:2px; break-before:page;'>line2</div>" " </div>" "</div>"); EXPECT_EQ(0, strutForBox("block1"));
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h index 0243253..81812c25 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutBlockItem.h
@@ -21,7 +21,7 @@ explicit LayoutBlockItem(const LayoutBoxItem& item) : LayoutBoxItem(item) { - ASSERT(!item || item.isLayoutBlock()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutBlock()); } explicit LayoutBlockItem(std::nullptr_t) : LayoutBoxItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h index 69827e9..155fbf4 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutBoxItem.h
@@ -21,7 +21,7 @@ explicit LayoutBoxItem(const LayoutItem& item) : LayoutBoxModel(item) { - ASSERT(!item || item.isBox()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isBox()); } explicit LayoutBoxItem(std::nullptr_t) : LayoutBoxModel(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h b/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h index 478d2f66..98c2754 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutBoxModel.h
@@ -22,7 +22,7 @@ explicit LayoutBoxModel(const LayoutItem& item) : LayoutItem(item) { - ASSERT(!item || item.isBoxModelObject()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isBoxModelObject()); } explicit LayoutBoxModel(std::nullptr_t) : LayoutItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutEmbeddedItem.h b/third_party/WebKit/Source/core/layout/api/LayoutEmbeddedItem.h index ab038e5..563bf6a7 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutEmbeddedItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutEmbeddedItem.h
@@ -20,7 +20,7 @@ explicit LayoutEmbeddedItem(const LayoutItem& item) : LayoutPartItem(item) { - ASSERT(!item || item.isEmbeddedObject()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isEmbeddedObject()); } explicit LayoutEmbeddedItem(std::nullptr_t) : LayoutPartItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h b/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h index 29877de..87413b2 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutFullScreenItem.h
@@ -21,7 +21,7 @@ explicit LayoutFullScreenItem(const LayoutBlockItem& item) : LayoutBlockItem(item) { - ASSERT(!item || item.isLayoutFullScreen()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutFullScreen()); } explicit LayoutFullScreenItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h b/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h index 704ac3e..76c2a27 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutImageItem.h
@@ -20,7 +20,7 @@ explicit LayoutImageItem(const LayoutItem& item) : LayoutBoxItem(item) { - ASSERT(!item || item.isImage()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isImage()); } explicit LayoutImageItem(std::nullptr_t) : LayoutBoxItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h b/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h index 3bbce4e..8b2b097e 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutLIItem.h
@@ -20,7 +20,7 @@ explicit LayoutLIItem(const LayoutItem& item) : LayoutBoxItem(item) { - ASSERT(!item || item.isListItem()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isListItem()); } explicit LayoutLIItem(std::nullptr_t) : LayoutBoxItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutMediaItem.h b/third_party/WebKit/Source/core/layout/api/LayoutMediaItem.h index dfdc1903..0c100f2 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutMediaItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutMediaItem.h
@@ -20,7 +20,7 @@ explicit LayoutMediaItem(const LayoutItem& item) : LayoutImageItem(item) { - ASSERT(!item || item.isMedia()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isMedia()); } explicit LayoutMediaItem(std::nullptr_t) : LayoutImageItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h b/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h index ffc6ee11..125d16f 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutMenuListItem.h
@@ -21,7 +21,7 @@ explicit LayoutMenuListItem(const LayoutBlockItem& item) : LayoutBlockItem(item) { - ASSERT(!item || item.isMenuList()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isMenuList()); } explicit LayoutMenuListItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutPartItem.h b/third_party/WebKit/Source/core/layout/api/LayoutPartItem.h index c3351cb..1bff597 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutPartItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutPartItem.h
@@ -20,7 +20,7 @@ explicit LayoutPartItem(const LayoutItem& item) : LayoutBoxItem(item) { - ASSERT(!item || item.isLayoutPart()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutPart()); } explicit LayoutPartItem(std::nullptr_t) : LayoutBoxItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h b/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h index 8bf8e42..923f36c 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutProgressItem.h
@@ -21,7 +21,7 @@ explicit LayoutProgressItem(const LayoutBlockItem& item) : LayoutBlockItem(item) { - ASSERT(!item || item.isProgress()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isProgress()); } explicit LayoutProgressItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h b/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h index 75db0854..2cdd068 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutSliderItem.h
@@ -21,7 +21,7 @@ explicit LayoutSliderItem(const LayoutBlockItem& item) : LayoutBlockItem(item) { - ASSERT(!item || item.isSlider()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isSlider()); } explicit LayoutSliderItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h index 4de621c..8432b54 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutTextControlItem.h
@@ -21,7 +21,7 @@ explicit LayoutTextControlItem(const LayoutItem& item) : LayoutBoxModel(item) { - ASSERT(!item || item.isTextControl()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isTextControl()); } explicit LayoutTextControlItem(std::nullptr_t) : LayoutBoxModel(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h index a742e74..bc6e15e6 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutTextFragmentItem.h
@@ -23,7 +23,7 @@ explicit LayoutTextFragmentItem(const LayoutTextItem& item) : LayoutTextItem(item) { - ASSERT(!item || item.isTextFragment()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isTextFragment()); } explicit LayoutTextFragmentItem(std::nullptr_t) : LayoutTextItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h b/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h index 2a1fa153..cdb5afd 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutTextItem.h
@@ -23,7 +23,7 @@ explicit LayoutTextItem(const LayoutItem& item) : LayoutItem(item) { - ASSERT(!item || item.isText()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isText()); } explicit LayoutTextItem(std::nullptr_t) : LayoutItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h b/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h index 3aa626a..487c37e 100644 --- a/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h +++ b/third_party/WebKit/Source/core/layout/api/LayoutViewItem.h
@@ -21,7 +21,7 @@ explicit LayoutViewItem(const LayoutBlockItem& item) : LayoutBlockItem(item) { - ASSERT(!item || item.isLayoutView()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutView()); } explicit LayoutViewItem(std::nullptr_t) : LayoutBlockItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBR.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBR.h index dba5547..ffde4838 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutBR.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBR.h
@@ -20,7 +20,7 @@ explicit LineLayoutBR(const LineLayoutItem& item) : LineLayoutText(item) { - ASSERT(!item || item.isBR()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isBR()); } explicit LineLayoutBR(std::nullptr_t) : LineLayoutText(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h index f8a744d..6ef0dee 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBlockFlow.h
@@ -27,7 +27,7 @@ explicit LineLayoutBlockFlow(const LineLayoutItem& item) : LineLayoutBox(item) { - ASSERT(!item || item.isLayoutBlockFlow()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutBlockFlow()); } explicit LineLayoutBlockFlow(std::nullptr_t) : LineLayoutBox(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h index cf14b406..db3bb838 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBox.h
@@ -24,7 +24,7 @@ explicit LineLayoutBox(const LineLayoutItem& item) : LineLayoutBoxModel(item) { - ASSERT(!item || item.isBox()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isBox()); } explicit LineLayoutBox(std::nullptr_t) : LineLayoutBoxModel(nullptr) { } @@ -76,11 +76,21 @@ return toBox()->flipForWritingMode(point); } + LayoutPoint flipForWritingModeForChild(const LineLayoutBox& child, LayoutPoint childPoint) const + { + return toBox()->flipForWritingModeForChild(toLayoutBox(child.layoutObject()), childPoint); + } + void moveWithEdgeOfInlineContainerIfNecessary(bool isHorizontal) { toBox()->moveWithEdgeOfInlineContainerIfNecessary(isHorizontal); } + void move(const LayoutUnit& width, const LayoutUnit& height) + { + toBox()->move(width, height); + } + bool hasOverflowModel() const { return toBox()->hasOverflowModel(); @@ -119,6 +129,21 @@ return toBox()->inlineBoxWrapper(); } + void setInlineBoxWrapper(InlineBox* box) + { + return toBox()->setInlineBoxWrapper(box); + } + +#ifndef NDEBUG + + void showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1) const + { + if (layoutObject()->isLayoutBlockFlow()) + toLayoutBlockFlow(layoutObject())->showLineTreeAndMark(markedBox1, markedLabel1); + } + +#endif + private: LayoutBox* toBox() {
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h b/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h index 775fa68..69cd000 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutBoxModel.h
@@ -23,7 +23,7 @@ explicit LineLayoutBoxModel(const LineLayoutItem& item) : LineLayoutItem(item) { - ASSERT(!item || item.isBoxModelObject()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isBoxModelObject()); } explicit LineLayoutBoxModel(std::nullptr_t) : LineLayoutItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h b/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h index ef596cf..97f6868 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutInline.h
@@ -25,7 +25,7 @@ explicit LineLayoutInline(const LineLayoutItem& item) : LineLayoutBoxModel(item) { - ASSERT(!item || item.isLayoutInline()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isLayoutInline()); } explicit LineLayoutInline(std::nullptr_t) : LineLayoutBoxModel(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h index 7276729..6539c60 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutItem.h
@@ -63,6 +63,16 @@ return m_layoutObject == layoutObject; } + bool operator==(const LineLayoutItem& other) const + { + return m_layoutObject == other.m_layoutObject; + } + + bool operator!=(const LineLayoutItem& other) const + { + return !(*this == other); + } + String debugName() const { return m_layoutObject->debugName(); @@ -403,6 +413,21 @@ return m_layoutObject->hasOverflowClip(); } + bool documentBeingDestroyed() const + { + return m_layoutObject->documentBeingDestroyed(); + } + + void invalidateDisplayItemClient(const DisplayItemClient& displayItemClient) + { + return m_layoutObject->invalidateDisplayItemClient(displayItemClient); + } + + LayoutRect visualRect() const + { + return m_layoutObject->visualRect(); + } + bool isHashTableDeletedValue() const { return m_layoutObject == kHashTableDeletedValue; @@ -432,6 +457,16 @@ return m_layoutObject; } + void showTreeForThis() const + { + m_layoutObject->showTreeForThis(); + } + + String decoratedName() const + { + return m_layoutObject->decoratedName(); + } + #endif protected: @@ -444,6 +479,7 @@ friend class LayoutBlockFlow; friend class LineLayoutAPIShim; friend class LineLayoutBlockFlow; + friend class LineLayoutBox; friend class LineLayoutRubyRun; };
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutListMarker.h b/third_party/WebKit/Source/core/layout/api/LineLayoutListMarker.h index d115c8f0..55651cf 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutListMarker.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutListMarker.h
@@ -20,7 +20,7 @@ explicit LineLayoutListMarker(const LineLayoutItem& item) : LineLayoutBox(item) { - ASSERT(!item || item.isListMarker()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isListMarker()); } explicit LineLayoutListMarker(std::nullptr_t) : LineLayoutBox(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h b/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h index bea7db9..d5ed629 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutRubyRun.h
@@ -20,7 +20,7 @@ explicit LineLayoutRubyRun(const LineLayoutItem& item) : LineLayoutBlockFlow(item) { - ASSERT(!item || item.isRubyRun()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isRubyRun()); } explicit LineLayoutRubyRun(std::nullptr_t) : LineLayoutBlockFlow(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInline.h b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInline.h index e4c50e8..b5d0c9e9 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInline.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInline.h
@@ -20,7 +20,7 @@ explicit LineLayoutSVGInline(const LineLayoutItem& item) : LineLayoutInline(item) { - ASSERT(!item || item.isSVGInline()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isSVGInline()); } explicit LineLayoutSVGInline(std::nullptr_t) : LineLayoutInline(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInlineText.h b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInlineText.h index ec740def..9137952d 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInlineText.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGInlineText.h
@@ -20,7 +20,7 @@ explicit LineLayoutSVGInlineText(const LineLayoutItem& item) : LineLayoutText(item) { - ASSERT(!item || item.isSVGInlineText()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isSVGInlineText()); } explicit LineLayoutSVGInlineText(std::nullptr_t) : LineLayoutText(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGTextPath.h b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGTextPath.h index 80539a0..a7973d8 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutSVGTextPath.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutSVGTextPath.h
@@ -20,7 +20,7 @@ explicit LineLayoutSVGTextPath(const LineLayoutItem& item) : LineLayoutSVGInline(item) { - ASSERT(!item || item.isSVGTextPath()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isSVGTextPath()); } explicit LineLayoutSVGTextPath(std::nullptr_t) : LineLayoutSVGInline(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutText.h b/third_party/WebKit/Source/core/layout/api/LineLayoutText.h index 20ed6f5b..1650ef8 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutText.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutText.h
@@ -22,7 +22,7 @@ explicit LineLayoutText(const LineLayoutItem& item) : LineLayoutItem(item) { - ASSERT(!item || item.isText()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isText()); } explicit LineLayoutText(std::nullptr_t) : LineLayoutItem(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/api/LineLayoutTextCombine.h b/third_party/WebKit/Source/core/layout/api/LineLayoutTextCombine.h index b0f7186..3446688f 100644 --- a/third_party/WebKit/Source/core/layout/api/LineLayoutTextCombine.h +++ b/third_party/WebKit/Source/core/layout/api/LineLayoutTextCombine.h
@@ -20,7 +20,7 @@ explicit LineLayoutTextCombine(const LineLayoutItem& item) : LineLayoutText(item) { - ASSERT(!item || item.isCombineText()); + ASSERT_WITH_SECURITY_IMPLICATION(!item || item.isCombineText()); } explicit LineLayoutTextCombine(std::nullptr_t) : LineLayoutText(nullptr) { }
diff --git a/third_party/WebKit/Source/core/layout/line/EllipsisBox.h b/third_party/WebKit/Source/core/layout/line/EllipsisBox.h index 10d5f2b..2a2da72e 100644 --- a/third_party/WebKit/Source/core/layout/line/EllipsisBox.h +++ b/third_party/WebKit/Source/core/layout/line/EllipsisBox.h
@@ -30,9 +30,9 @@ class EllipsisBox final : public InlineBox { public: - EllipsisBox(InlineBox* inlineBox, const AtomicString& ellipsisStr, InlineFlowBox* parent, + EllipsisBox(LineLayoutItem item, const AtomicString& ellipsisStr, InlineFlowBox* parent, LayoutUnit width, int height, int x, int y, bool firstLine, bool isVertical) - : InlineBox(inlineBox, LayoutPoint(x, y), width, firstLine, true, false, false, isVertical, 0, 0, parent) + : InlineBox(item, LayoutPoint(x, y), width, firstLine, true, false, false, isVertical, 0, 0, parent) , m_height(height) , m_str(ellipsisStr) , m_selectionState(SelectionNone)
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp index 3f3c4566..b331788 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp
@@ -63,8 +63,8 @@ { // We do not need to issue invalidations if the page is being destroyed // since these objects will never be repainted. - if (!m_layoutObject.documentBeingDestroyed()) - m_layoutObject.invalidateDisplayItemClient(*this); + if (!m_lineLayoutItem.documentBeingDestroyed()) + m_lineLayoutItem.invalidateDisplayItemClient(*this); delete this; } @@ -97,18 +97,18 @@ LayoutRect InlineBox::visualRect() const { // TODO(chrishtr): tighten these bounds. - return layoutObject().visualRect(); + return getLineLayoutItem().visualRect(); } #ifndef NDEBUG void InlineBox::showTreeForThis() const { - layoutObject().showTreeForThis(); + getLineLayoutItem().showTreeForThis(); } void InlineBox::showLineTreeForThis() const { - layoutObject().containingBlock()->showLineTreeAndMark(this, "*"); + getLineLayoutItem().containingBlock().showLineTreeAndMark(this, "*"); } void InlineBox::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const LayoutObject* obj, int depth) const @@ -118,7 +118,7 @@ printedCharacters += fprintf(stderr, "%s", markedLabel1); if (this == markedBox2) printedCharacters += fprintf(stderr, "%s", markedLabel2); - if (&layoutObject() == obj) + if (getLineLayoutItem().isEqual(obj)) printedCharacters += fprintf(stderr, "*"); for (; printedCharacters < depth * 2; printedCharacters++) fputc(' ', stderr); @@ -132,7 +132,7 @@ for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) fputc(' ', stderr); fprintf(stderr, "\t%s %p {pos=%g,%g size=%g,%g} baseline=%i/%i\n", - layoutObject().decoratedName().ascii().data(), &layoutObject(), + getLineLayoutItem().decoratedName().ascii().data(), getLineLayoutItem().debugPointer(), x().toFloat(), y().toFloat(), width().toFloat(), height().toFloat(), baselinePosition(AlphabeticBaseline), baselinePosition(IdeographicBaseline)); } @@ -146,7 +146,7 @@ if (getLineLayoutItem().isText()) return m_bitfields.isText() ? LayoutUnit(getLineLayoutItem().style(isFirstLineStyle())->getFontMetrics().height()) : LayoutUnit(); if (getLineLayoutItem().isBox() && parent()) - return isHorizontal() ? toLayoutBox(layoutObject()).size().height() : toLayoutBox(layoutObject()).size().width(); + return isHorizontal() ? LineLayoutBox(getLineLayoutItem()).size().height() : LineLayoutBox(getLineLayoutItem()).size().width(); ASSERT(isInlineFlowBox()); LineLayoutBoxModel flowObject = boxModelObject(); @@ -187,7 +187,7 @@ void InlineBox::deleteLine() { if (!m_bitfields.extracted() && getLineLayoutItem().isBox()) - toLayoutBox(layoutObject()).setInlineBoxWrapper(nullptr); + LineLayoutBox(getLineLayoutItem()).setInlineBoxWrapper(nullptr); destroy(); } @@ -195,14 +195,14 @@ { m_bitfields.setExtracted(true); if (getLineLayoutItem().isBox()) - toLayoutBox(layoutObject()).setInlineBoxWrapper(nullptr); + LineLayoutBox(getLineLayoutItem()).setInlineBoxWrapper(nullptr); } void InlineBox::attachLine() { m_bitfields.setExtracted(false); if (getLineLayoutItem().isBox()) - toLayoutBox(layoutObject()).setInlineBoxWrapper(this); + LineLayoutBox(getLineLayoutItem()).setInlineBoxWrapper(this); } void InlineBox::move(const LayoutSize& delta) @@ -210,7 +210,7 @@ m_topLeft.move(delta); if (getLineLayoutItem().isAtomicInlineLevel()) - toLayoutBox(layoutObject()).move(delta.width(), delta.height()); + LineLayoutBox(getLineLayoutItem()).move(delta.width(), delta.height()); } void InlineBox::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit /* lineTop */, LayoutUnit /* lineBottom */) const @@ -225,7 +225,7 @@ // specification.) LayoutPoint childPoint = accumulatedOffset; if (parent()->getLineLayoutItem().hasFlippedBlocksWritingMode()) // Faster than calling containingBlock(). - childPoint = layoutObject().containingBlock()->flipForWritingModeForChild(&toLayoutBox(layoutObject()), childPoint); + childPoint = getLineLayoutItem().containingBlock().flipForWritingModeForChild(LineLayoutBox(getLineLayoutItem()), childPoint); if (getLineLayoutItem().style()->hasBorderRadius()) { LayoutRect borderRect = logicalFrameRect(); @@ -303,7 +303,7 @@ SelectionState InlineBox::getSelectionState() const { - return layoutObject().getSelectionState(); + return getLineLayoutItem().getSelectionState(); } bool InlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int ellipsisWidth) const @@ -390,7 +390,7 @@ void InlineBox::invalidateDisplayItemClientsRecursively() { - layoutObject().invalidateDisplayItemClient(*this); + getLineLayoutItem().invalidateDisplayItemClient(*this); if (!isInlineFlowBox()) return; for (InlineBox* child = toInlineFlowBox(this)->firstChild(); child; child = child->nextOnLine())
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.h b/third_party/WebKit/Source/core/layout/line/InlineBox.h index 5790fee..efebc57d 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineBox.h +++ b/third_party/WebKit/Source/core/layout/line/InlineBox.h
@@ -22,7 +22,6 @@ #define InlineBox_h #include "core/layout/LayoutBoxModelObject.h" -#include "core/layout/LayoutObject.h" #include "core/layout/api/LineLayoutBoxModel.h" #include "core/layout/api/LineLayoutItem.h" #include "core/layout/api/SelectionState.h" @@ -33,6 +32,7 @@ class HitTestRequest; class HitTestResult; +class LayoutObject; class RootInlineBox; enum MarkLineBoxes { MarkLineBoxesDirty, DontMarkLineBoxes }; @@ -42,11 +42,11 @@ class InlineBox : public DisplayItemClient { WTF_MAKE_NONCOPYABLE(InlineBox); public: - InlineBox(LayoutObject& obj) + InlineBox(LineLayoutItem obj) : m_next(nullptr) , m_prev(nullptr) , m_parent(nullptr) - , m_layoutObject(obj) + , m_lineLayoutItem(obj) , m_logicalWidth() #if ENABLE(ASSERT) , m_hasBadParent(false) @@ -54,12 +54,12 @@ { } - InlineBox(InlineBox* inlineBoxForLayoutObject, LayoutPoint topLeft, LayoutUnit logicalWidth, bool firstLine, bool constructed, + InlineBox(LineLayoutItem item, LayoutPoint topLeft, LayoutUnit logicalWidth, bool firstLine, bool constructed, bool dirty, bool extracted, bool isHorizontal, InlineBox* next, InlineBox* prev, InlineFlowBox* parent) : m_next(next) , m_prev(prev) , m_parent(parent) - , m_layoutObject(inlineBoxForLayoutObject->layoutObject()) + , m_lineLayoutItem(item) , m_topLeft(topLeft) , m_logicalWidth(logicalWidth) , m_bitfields(firstLine, constructed, dirty, extracted, isHorizontal) @@ -171,7 +171,7 @@ InlineBox* nextLeafChildIgnoringLineBreak() const; InlineBox* prevLeafChildIgnoringLineBreak() const; - LineLayoutItem getLineLayoutItem() const { return LineLayoutItem(&m_layoutObject); } + LineLayoutItem getLineLayoutItem() const { return m_lineLayoutItem; } InlineFlowBox* parent() const { @@ -278,7 +278,7 @@ LineLayoutBoxModel boxModelObject() const { if (!getLineLayoutItem().isText()) - return LineLayoutBoxModel(toLayoutBoxModelObject(&m_layoutObject)); + return LineLayoutBoxModel(m_lineLayoutItem); return LineLayoutBoxModel(nullptr); } @@ -398,7 +398,7 @@ InlineBox* m_prev; // The previous element on the same line as us. InlineFlowBox* m_parent; // The box that contains us. - LayoutObject& m_layoutObject; + LineLayoutItem m_lineLayoutItem; protected: // For RootInlineBox @@ -424,8 +424,6 @@ LayoutUnit m_logicalWidth; private: - LayoutObject& layoutObject() const { return m_layoutObject; } - InlineBoxBitfields m_bitfields; #if ENABLE(ASSERT)
diff --git a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h index 01c063e..9f50366 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h +++ b/third_party/WebKit/Source/core/layout/line/InlineFlowBox.h
@@ -42,8 +42,8 @@ class InlineFlowBox : public InlineBox { public: - InlineFlowBox(LayoutObject& obj) - : InlineBox(obj) + InlineFlowBox(LineLayoutItem lineLayoutItem) + : InlineBox(lineLayoutItem) , m_firstChild(nullptr) , m_lastChild(nullptr) , m_prevLineBox(nullptr) @@ -67,7 +67,7 @@ // an invisible marker exists. The side effect of having an invisible marker is that the quirks mode behavior of shrinking lines with no // text children must not apply. This change also means that gaps will exist between image bullet list items. Even when the list bullet // is an image, the line is still considered to be immune from the quirk. - m_hasTextChildren = obj.style()->display() == LIST_ITEM; + m_hasTextChildren = lineLayoutItem.style()->display() == LIST_ITEM; m_hasTextDescendants = m_hasTextChildren; }
diff --git a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h index d26ebede..005a20b 100644 --- a/third_party/WebKit/Source/core/layout/line/InlineTextBox.h +++ b/third_party/WebKit/Source/core/layout/line/InlineTextBox.h
@@ -40,8 +40,8 @@ class InlineTextBox : public InlineBox { public: - InlineTextBox(LayoutObject& obj, int start, unsigned short length) - : InlineBox(obj) + InlineTextBox(LineLayoutItem item, int start, unsigned short length) + : InlineBox(item) , m_prevTextBox(nullptr) , m_nextTextBox(nullptr) , m_start(start)
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp index d25f755..2aa65dd 100644 --- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp +++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.cpp
@@ -49,7 +49,7 @@ typedef WTF::HashMap<const RootInlineBox*, EllipsisBox*> EllipsisBoxMap; static EllipsisBoxMap* gEllipsisBoxMap = nullptr; -RootInlineBox::RootInlineBox(LayoutBlockFlow& block) +RootInlineBox::RootInlineBox(LineLayoutItem block) : InlineFlowBox(block) , m_lineBreakPos(0) , m_lineBreakObj(nullptr) @@ -117,7 +117,7 @@ LayoutUnit RootInlineBox::placeEllipsis(const AtomicString& ellipsisStr, bool ltr, LayoutUnit blockLeftEdge, LayoutUnit blockRightEdge, LayoutUnit ellipsisWidth) { // Create an ellipsis box. - EllipsisBox* ellipsisBox = new EllipsisBox(this, ellipsisStr, this, + EllipsisBox* ellipsisBox = new EllipsisBox(getLineLayoutItem(), ellipsisStr, this, ellipsisWidth, logicalHeight().toFloat(), x(), y(), !prevRootBox(), isHorizontal()); if (!gEllipsisBoxMap)
diff --git a/third_party/WebKit/Source/core/layout/line/RootInlineBox.h b/third_party/WebKit/Source/core/layout/line/RootInlineBox.h index f7d5338d..09df02a 100644 --- a/third_party/WebKit/Source/core/layout/line/RootInlineBox.h +++ b/third_party/WebKit/Source/core/layout/line/RootInlineBox.h
@@ -30,7 +30,6 @@ class EllipsisBox; class HitTestResult; -class LayoutBlockFlow; class LineLayoutBlockFlow; struct BidiStatus; @@ -38,7 +37,7 @@ class RootInlineBox : public InlineFlowBox { public: - explicit RootInlineBox(LayoutBlockFlow&); + explicit RootInlineBox(LineLayoutItem); void destroy() final;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp index 1d87a97..a7cf1950 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInline.cpp
@@ -54,7 +54,7 @@ InlineFlowBox* LayoutSVGInline::createInlineFlowBox() { - InlineFlowBox* box = new SVGInlineFlowBox(*this); + InlineFlowBox* box = new SVGInlineFlowBox(LineLayoutItem(this)); box->setHasVirtualLogicalHeight(); return box; }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp index 7c8d826..2cd0a20 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
@@ -96,7 +96,7 @@ InlineTextBox* LayoutSVGInlineText::createTextBox(int start, unsigned short length) { - InlineTextBox* box = new SVGInlineTextBox(*this, start, length); + InlineTextBox* box = new SVGInlineTextBox(LineLayoutItem(this), start, length); box->setHasVirtualLogicalHeight(); return box; }
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp index e1faa502..e382133 100644 --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGText.cpp
@@ -273,17 +273,12 @@ return; } - // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt. - FontCachePurgePreventer fontCachePurgePreventer; - - // The positioning elements cache depends on the size of each text layoutObject in the - // subtree. If this changes, clear the cache. It's going to be rebuilt below. + // The positioning elements cache depends on the size of each text object in + // the subtree. If this changes, clear the cache and mark it for rebuilding + // in the next layout. m_layoutAttributesBuilder.clearTextPositioningElements(); - - for (LayoutObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { - if (descendant->isSVGInlineText()) - m_layoutAttributesBuilder.buildLayoutAttributesForText(toLayoutSVGInlineText(descendant)); - } + setNeedsPositioningValuesUpdate(); + setNeedsLayoutAndFullPaintInvalidation(LayoutInvalidationReason::TextChanged); } static inline void updateFontInAllDescendants(LayoutObject* start, SVGTextLayoutAttributesBuilder* builder = nullptr) @@ -400,7 +395,7 @@ RootInlineBox* LayoutSVGText::createRootInlineBox() { - RootInlineBox* box = new SVGRootInlineBox(*this); + RootInlineBox* box = new SVGRootInlineBox(LineLayoutItem(this)); box->setHasVirtualLogicalHeight(); return box; }
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineFlowBox.h b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineFlowBox.h index 9e8955b..7920220 100644 --- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineFlowBox.h +++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineFlowBox.h
@@ -27,8 +27,8 @@ class SVGInlineFlowBox final : public InlineFlowBox { public: - SVGInlineFlowBox(LayoutObject& obj) - : InlineFlowBox(obj) + SVGInlineFlowBox(LineLayoutItem item) + : InlineFlowBox(item) , m_logicalHeight(0) { }
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp index d2a2287b..c7e7b47 100644 --- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp +++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.cpp
@@ -46,8 +46,8 @@ static_assert(sizeof(SVGInlineTextBox) == sizeof(ExpectedSVGInlineTextBoxSize), "SVGInlineTextBox has an unexpected size"); -SVGInlineTextBox::SVGInlineTextBox(LayoutObject& object, int start, unsigned short length) - : InlineTextBox(object, start, length) +SVGInlineTextBox::SVGInlineTextBox(LineLayoutItem item, int start, unsigned short length) + : InlineTextBox(item, start, length) , m_logicalHeight(0) , m_startsNewTextChunk(false) {
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h index ce6ce94e..8bededa 100644 --- a/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h +++ b/third_party/WebKit/Source/core/layout/svg/line/SVGInlineTextBox.h
@@ -29,7 +29,7 @@ class SVGInlineTextBox final : public InlineTextBox { public: - SVGInlineTextBox(LayoutObject&, int start, unsigned short length); + SVGInlineTextBox(LineLayoutItem, int start, unsigned short length); bool isSVGInlineTextBox() const override { return true; }
diff --git a/third_party/WebKit/Source/core/layout/svg/line/SVGRootInlineBox.h b/third_party/WebKit/Source/core/layout/svg/line/SVGRootInlineBox.h index cf5d704c..1b73d0a 100644 --- a/third_party/WebKit/Source/core/layout/svg/line/SVGRootInlineBox.h +++ b/third_party/WebKit/Source/core/layout/svg/line/SVGRootInlineBox.h
@@ -23,6 +23,7 @@ #ifndef SVGRootInlineBox_h #define SVGRootInlineBox_h +#include "core/layout/api/LineLayoutBlockFlow.h" #include "core/layout/line/RootInlineBox.h" #include "core/layout/svg/SVGTextLayoutEngine.h" @@ -30,7 +31,7 @@ class SVGRootInlineBox final : public RootInlineBox { public: - SVGRootInlineBox(LayoutBlockFlow& block) + SVGRootInlineBox(LineLayoutItem block) : RootInlineBox(block) , m_logicalHeight(0) {
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp index c5b90833..c10d6fc 100644 --- a/third_party/WebKit/Source/core/loader/DocumentLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentLoader.cpp
@@ -128,7 +128,7 @@ DocumentLoader::~DocumentLoader() { - ASSERT(!m_frame || !isLoading()); + ASSERT(!m_frame); ASSERT(!m_mainResource); ASSERT(!m_applicationCacheHost); } @@ -149,13 +149,6 @@ return m_mainResource ? m_mainResource->identifier() : 0; } -Document* DocumentLoader::document() const -{ - if (m_frame && m_frame->loader().documentLoader() == this) - return m_frame->document(); - return nullptr; -} - const ResourceRequest& DocumentLoader::originalRequest() const { return m_originalRequest; @@ -237,33 +230,6 @@ return unreachableURL().isEmpty() ? url() : unreachableURL(); } -void DocumentLoader::mainReceivedError(const ResourceError& error) -{ - ASSERT(!error.isNull()); - ASSERT(!m_frame || !m_frame->page()->defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame)); - if (m_applicationCacheHost) - m_applicationCacheHost->failedLoadingMainResource(); - if (!frameLoader()) - return; - m_state = MainResourceDone; - frameLoader()->receivedMainResourceError(this, error); - clearMainResourceHandle(); -} - -// Cancels the data source's pending loads. Conceptually, a data source only loads -// one document at a time, but one document may have many related resources. -// stopLoading will stop all loads initiated by the data source, -// but not loads initiated by child frames' data sources -- that's the WebFrame's job. -void DocumentLoader::stopLoading() -{ - RefPtrWillBeRawPtr<LocalFrame> protectFrame(m_frame.get()); - RefPtrWillBeRawPtr<DocumentLoader> protectLoader(this); - - if (isLoading()) - cancelMainResourceLoad(ResourceError::cancelledError(m_request.url())); - m_fetcher->stopFetching(); -} - void DocumentLoader::commitIfReady() { if (m_state < Committed) { @@ -272,14 +238,6 @@ } } -bool DocumentLoader::isLoading() const -{ - if (document() && document()->hasActiveParser()) - return true; - - return (m_state > NotStarted && m_state < MainResourceDone) || m_fetcher->isFetching(); -} - void DocumentLoader::notifyFinished(Resource* resource) { ASSERT_UNUSED(resource, m_mainResource == resource); @@ -292,7 +250,11 @@ return; } - mainReceivedError(m_mainResource->resourceError()); + if (m_applicationCacheHost) + m_applicationCacheHost->failedLoadingMainResource(); + m_state = MainResourceDone; + frameLoader()->loadFailed(this, m_mainResource->resourceError()); + clearMainResourceHandle(); } void DocumentLoader::finishedLoading(double finishTime) @@ -338,11 +300,11 @@ RefPtr<SecurityOrigin> redirectingOrigin = SecurityOrigin::create(redirectResponse.url()); if (!redirectingOrigin->canDisplay(requestURL)) { FrameLoader::reportLocalLoadFailed(m_frame, requestURL.getString()); - cancelMainResourceLoad(ResourceError::cancelledError(requestURL)); + m_fetcher->stopFetching(); return; } if (!frameLoader()->shouldContinueForNavigationPolicy(m_request, SubstituteData(), this, CheckContentSecurityPolicy, m_navigationType, NavigationPolicyCurrentTab, replacesCurrentHistoryItem(), isClientRedirect())) { - cancelMainResourceLoad(ResourceError::cancelledError(requestURL)); + m_fetcher->stopFetching(); return; } @@ -449,7 +411,7 @@ if (!shouldContinueForResponse()) { InspectorInstrumentation::continueWithPolicyIgnore(m_frame, this, m_mainResource->identifier(), m_response); - cancelMainResourceLoad(ResourceError::cancelledError(m_request.url())); + m_fetcher->stopFetching(); return; } @@ -507,10 +469,8 @@ // This can happen if document.close() is called by an event handler while // there's still pending incoming data. - if (m_frame && !m_frame->document()->parsing()) { - cancelMainResourceLoad(ResourceError::cancelledError(m_request.url())); + if (m_frame && !m_frame->document()->parsing()) return; - } if (length) m_state = DataReceived; @@ -574,7 +534,7 @@ // If we are sending data to MediaDocument, we should stop here // and cancel the request. if (m_frame && m_frame->document()->isMediaDocument()) - cancelMainResourceLoad(ResourceError::cancelledError(m_request.url())); + m_fetcher->stopFetching(); } void DocumentLoader::clearRedirectChain() @@ -595,7 +555,7 @@ // It never makes sense to have a document loader that is detached from its // frame have any loads active, so go ahead and kill all the loads. - stopLoading(); + m_fetcher->stopFetching(); // If that load cancellation triggered another detach, leave. // (fast/frames/detach-frame-nested-no-crash.html is an example of this.) @@ -603,7 +563,6 @@ return; m_fetcher->clearContext(); - m_applicationCacheHost->detachFromDocumentLoader(); m_applicationCacheHost.clear(); WeakIdentifierMap<DocumentLoader>::notifyObjectDestroyed(this); @@ -634,7 +593,7 @@ ensureWriter(mainResource->mimeType(), mainResource->url()); // The Document has now been created. - document()->enforceSandboxFlags(SandboxAll); + m_frame->document()->enforceSandboxFlags(SandboxAll); commitData(mainResource->data()->data(), mainResource->data()->size()); return true; @@ -705,17 +664,6 @@ m_mainResource->addClient(this); } -void DocumentLoader::cancelMainResourceLoad(const ResourceError& resourceError) -{ - RefPtrWillBeRawPtr<DocumentLoader> protect(this); - ResourceError error = resourceError.isNull() ? ResourceError::cancelledError(m_request.url()) : resourceError; - - if (mainResourceLoader()) - mainResourceLoader()->cancel(error); - - mainReceivedError(error); -} - void DocumentLoader::endWriting(DocumentWriter* writer) { ASSERT_UNUSED(writer, m_writer == writer);
diff --git a/third_party/WebKit/Source/core/loader/DocumentLoader.h b/third_party/WebKit/Source/core/loader/DocumentLoader.h index ec20778..c1ea3ba 100644 --- a/third_party/WebKit/Source/core/loader/DocumentLoader.h +++ b/third_party/WebKit/Source/core/loader/DocumentLoader.h
@@ -93,8 +93,6 @@ void didChangePerformanceTiming(); void updateForSameDocumentNavigation(const KURL&, SameDocumentNavigationSource); - void stopLoading(); - bool isLoading() const; const ResourceResponse& response() const { return m_response; } bool isClientRedirect() const { return m_isClientRedirect; } void setIsClientRedirect(bool isClientRedirect) { m_isClientRedirect = isClientRedirect; } @@ -110,7 +108,6 @@ void setNavigationType(NavigationType navigationType) { m_navigationType = navigationType; } void startLoadingMainResource(); - void cancelMainResourceLoad(const ResourceError&); void attachThreadedDataReceiver(PassRefPtrWillBeRawPtr<ThreadedDataReceiver>); void acceptDataFromThreadedReceiver(const char* data, int dataLength, int encodedDataLength); @@ -159,7 +156,6 @@ void ensureWriter(const AtomicString& mimeType, const KURL& overridingURL = KURL()); void endWriting(DocumentWriter*); - Document* document() const; FrameLoader* frameLoader() const; void commitIfReady(); @@ -170,7 +166,6 @@ bool maybeCreateArchive(); void finishedLoading(double finishTime); - void mainReceivedError(const ResourceError&); void cancelLoadAfterXFrameOptionsOrCSPDenied(const ResourceResponse&); void redirectReceived(Resource*, ResourceRequest&, const ResourceResponse&) final; void responseReceived(Resource*, const ResourceResponse&, PassOwnPtr<WebDataConsumerHandle>) final;
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp index 7a42c3e3..6d698aa 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.cpp
@@ -106,14 +106,13 @@ void DocumentThreadableLoader::loadResourceSynchronously(Document& document, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { // The loader will be deleted as soon as this function exits. - RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, &client, LoadSynchronously, options, resourceLoaderOptions)); + OwnPtr<DocumentThreadableLoader> loader = adoptPtr(new DocumentThreadableLoader(document, &client, LoadSynchronously, options, resourceLoaderOptions)); loader->start(request); - ASSERT(loader->hasOneRef()); } -PassRefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document& document, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) +PassOwnPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document& document, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { - return adoptRef(new DocumentThreadableLoader(document, client, LoadAsynchronously, options, resourceLoaderOptions)); + return adoptPtr(new DocumentThreadableLoader(document, client, LoadAsynchronously, options, resourceLoaderOptions)); } DocumentThreadableLoader::DocumentThreadableLoader(Document& document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) @@ -132,6 +131,7 @@ , m_requestStartedSeconds(0.0) , m_corsRedirectLimit(kMaxCORSRedirects) , m_redirectMode(WebURLRequest::FetchRedirectModeFollow) + , m_weakFactory(this) { ASSERT(client); } @@ -412,7 +412,7 @@ if (m_redirectMode == WebURLRequest::FetchRedirectModeManual) { // Keep |this| alive even if the client release a reference in // responseReceived(). - RefPtr<DocumentThreadableLoader> protect(this); + WeakPtr<DocumentThreadableLoader> self(m_weakFactory.createWeakPtr()); // We use |m_redirectMode| to check the original redirect mode. // |request| is a new request for redirect. So we don't set the redirect @@ -426,6 +426,11 @@ // because it doesn't store the body of redirect responses. responseReceived(resource, redirectResponse, adoptPtr(new EmptyDataHandle())); + if (!self) { + request = ResourceRequest(); + return; + } + if (m_client) { ASSERT(m_actualRequest.isNull()); notifyFinished(resource);
diff --git a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h index f4552e5..b313a14 100644 --- a/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/DocumentThreadableLoader.h
@@ -38,11 +38,13 @@ #include "core/frame/csp/ContentSecurityPolicy.h" #include "core/loader/ThreadableLoader.h" #include "platform/Timer.h" +#include "platform/heap/Handle.h" #include "platform/network/HTTPHeaderMap.h" #include "platform/network/ResourceError.h" #include "wtf/Forward.h" #include "wtf/OwnPtr.h" -#include "wtf/PassRefPtr.h" +#include "wtf/PassOwnPtr.h" +#include "wtf/WeakPtr.h" #include "wtf/text/WTFString.h" namespace blink { @@ -57,7 +59,7 @@ USING_FAST_MALLOC(DocumentThreadableLoader); public: static void loadResourceSynchronously(Document&, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); - static PassRefPtr<DocumentThreadableLoader> create(Document&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); + static PassOwnPtr<DocumentThreadableLoader> create(Document&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); ~DocumentThreadableLoader() override; void start(const ResourceRequest&) override; @@ -230,6 +232,8 @@ int m_corsRedirectLimit; WebURLRequest::FetchRedirectMode m_redirectMode; + + WeakPtrFactory<DocumentThreadableLoader> m_weakFactory; }; } // namespace blink
diff --git a/third_party/WebKit/Source/core/loader/EmptyClients.h b/third_party/WebKit/Source/core/loader/EmptyClients.h index 23d0d3b..5b9c4ff 100644 --- a/third_party/WebKit/Source/core/loader/EmptyClients.h +++ b/third_party/WebKit/Source/core/loader/EmptyClients.h
@@ -111,7 +111,7 @@ void addMessageToConsole(LocalFrame*, MessageSource, MessageLevel, const String&, unsigned, const String&, const String&) override {} bool canOpenBeforeUnloadConfirmPanel() override { return false; } - bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, const String&, bool) override { return true; } + bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, bool) override { return true; } void closeWindowSoon() override {}
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.cpp b/third_party/WebKit/Source/core/loader/FrameLoader.cpp index 79fd956..ad794a9b 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoader.cpp +++ b/third_party/WebKit/Source/core/loader/FrameLoader.cpp
@@ -701,12 +701,9 @@ ASSERT(!stateObject || frameLoadType == FrameLoadTypeBackForward); // If we have a provisional request for a different document, a fragment scroll should cancel it. - if (m_provisionalDocumentLoader) { - m_provisionalDocumentLoader->stopLoading(); - detachDocumentLoader(m_provisionalDocumentLoader); - if (!m_frame->host()) - return; - } + detachDocumentLoader(m_provisionalDocumentLoader); + if (!m_frame->host()) + return; TemporaryChange<FrameLoadType> loadTypeChange(m_loadType, frameLoadType); saveScrollState(); @@ -986,8 +983,7 @@ if (m_inStopAllLoaders) return; - // Calling stopLoading() on the provisional document loader can blow away - // the frame from underneath. + // Stopping a document loader can blow away the frame from underneath. RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get()); m_inStopAllLoaders = true; @@ -998,20 +994,21 @@ } m_frame->document()->suppressLoadEvent(); - // Don't stop loading the provisional loader if it is being protected (i.e. - // it is about to be committed) See prepareForCommit() for more details. - if (m_provisionalDocumentLoader && !m_protectProvisionalLoader) - m_provisionalDocumentLoader->stopLoading(); if (m_documentLoader) - m_documentLoader->stopLoading(); + m_documentLoader->fetcher()->stopFetching(); m_frame->document()->cancelParsing(); - if (!m_protectProvisionalLoader) detachDocumentLoader(m_provisionalDocumentLoader); m_checkTimer.stop(); m_frame->navigationScheduler().cancel(); + // It's possible that the above actions won't have stopped loading if load + // completion had been blocked on parsing or if we were in the middle of + // committing an empty document. In that case, emulate a failed navigation. + if (!m_provisionalDocumentLoader && m_documentLoader && m_frame->isLoading()) + loadFailed(!m_documentLoader->sentDidFinishLoad() ? m_documentLoader.get() : nullptr, ResourceError::cancelledError(m_documentLoader->url())); + m_inStopAllLoaders = false; } @@ -1223,16 +1220,13 @@ } } -void FrameLoader::receivedMainResourceError(DocumentLoader* loader, const ResourceError& error) +void FrameLoader::loadFailed(DocumentLoader* loader, const ResourceError& error) { // Retain because the stop may release the last reference to it. RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get()); RefPtrWillBeRawPtr<DocumentLoader> protectDocumentLoader(loader); - // FIXME: We really ought to be able to just check for isCancellation() here, but there are some - // ResourceErrors that setIsCancellation() but aren't created by ResourceError::cancelledError(). - ResourceError c(ResourceError::cancelledError(KURL())); - if ((error.errorCode() != c.errorCode() || error.domain() != c.domain()) && m_frame->owner()) { + if (!error.isCancellation() && m_frame->owner()) { // FIXME: For now, fallback content doesn't work cross process. if (m_frame->owner()->isLocal()) m_frame->deprecatedLocalOwner()->renderFallbackContent(); @@ -1391,11 +1385,7 @@ return; m_frame->document()->cancelParsing(); - - if (m_provisionalDocumentLoader) { - m_provisionalDocumentLoader->stopLoading(); - detachDocumentLoader(m_provisionalDocumentLoader); - } + detachDocumentLoader(m_provisionalDocumentLoader); // beforeunload fired above, and detaching a DocumentLoader can fire // events, which can detach this frame.
diff --git a/third_party/WebKit/Source/core/loader/FrameLoader.h b/third_party/WebKit/Source/core/loader/FrameLoader.h index b948aac8..3027655 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoader.h +++ b/third_party/WebKit/Source/core/loader/FrameLoader.h
@@ -110,7 +110,7 @@ DocumentLoader* documentLoader() const { return m_documentLoader.get(); } DocumentLoader* provisionalDocumentLoader() const { return m_provisionalDocumentLoader.get(); } - void receivedMainResourceError(DocumentLoader*, const ResourceError&); + void loadFailed(DocumentLoader*, const ResourceError&); bool isLoadingMainFrame() const;
diff --git a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp index bd12d90..182da3a 100644 --- a/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp +++ b/third_party/WebKit/Source/core/loader/LinkLoaderTest.cpp
@@ -13,6 +13,9 @@ #include "core/loader/NetworkHintsInterface.h" #include "core/testing/DummyPageHolder.h" #include "platform/network/ResourceLoadPriority.h" +#include "platform/testing/URLTestHelpers.h" +#include "public/platform/Platform.h" +#include "public/platform/WebUnitTestSupport.h" #include "testing/gtest/include/gtest/gtest.h" #include <base/macros.h> @@ -94,36 +97,36 @@ const bool expectingLoad; const char* accept; } cases[] = { - {"data://example.test/cat.jpg", "image", "", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, - {"data://example.test/cat.js", "script", "", ResourceLoadPriorityMedium, WebURLRequest::RequestContextScript, true, true, "*/*"}, - {"data://example.test/cat.css", "style", "", ResourceLoadPriorityHigh, WebURLRequest::RequestContextStyle, true, true, "text/css,*/*;q=0.1"}, + {"http://example.test/cat.jpg", "image", "", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, + {"http://example.test/cat.js", "script", "", ResourceLoadPriorityMedium, WebURLRequest::RequestContextScript, true, true, "*/*"}, + {"http://example.test/cat.css", "style", "", ResourceLoadPriorityHigh, WebURLRequest::RequestContextStyle, true, true, "text/css,*/*;q=0.1"}, // TODO(yoav): It doesn't seem like the audio context is ever used. That should probably be fixed (or we can consolidate audio and video). - {"data://example.test/cat.wav", "media", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, - {"data://example.test/cat.mp4", "media", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, - {"data://example.test/cat.vtt", "track", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextTrack, true, true, ""}, - {"data://example.test/cat.woff", "font", "", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, true, ""}, + {"http://example.test/cat.wav", "media", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, + {"http://example.test/cat.mp4", "media", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, + {"http://example.test/cat.vtt", "track", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextTrack, true, true, ""}, + {"http://example.test/cat.woff", "font", "", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, true, ""}, // TODO(yoav): subresource should be *very* low priority (rather than low). - {"data://example.test/cat.empty", "", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, true, ""}, - {"data://example.test/cat.blob", "blabla", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, false, false, ""}, + {"http://example.test/cat.empty", "", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, true, ""}, + {"http://example.test/cat.blob", "blabla", "", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, false, false, ""}, {"bla://example.test/cat.gif", "image", "", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextImage, false, false, ""}, // MIME type tests - {"data://example.test/cat.webp", "image", "image/webp", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, - {"data://example.test/cat.svg", "image", "image/svg+xml", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, - {"data://example.test/cat.jxr", "image", "image/jxr", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextImage, false, false, ""}, - {"data://example.test/cat.js", "script", "text/javascript", ResourceLoadPriorityMedium, WebURLRequest::RequestContextScript, true, true, "*/*"}, - {"data://example.test/cat.js", "script", "text/coffeescript", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextScript, false, false, ""}, - {"data://example.test/cat.css", "style", "text/css", ResourceLoadPriorityHigh, WebURLRequest::RequestContextStyle, true, true, "text/css,*/*;q=0.1"}, - {"data://example.test/cat.css", "style", "text/sass", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextStyle, false, false, ""}, - {"data://example.test/cat.wav", "media", "audio/wav", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, - {"data://example.test/cat.wav", "media", "audio/mp57", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextVideo, false, false, ""}, - {"data://example.test/cat.webm", "media", "video/webm", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, - {"data://example.test/cat.mp199", "media", "video/mp199", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextVideo, false, false, ""}, - {"data://example.test/cat.vtt", "track", "text/vtt", ResourceLoadPriorityLow, WebURLRequest::RequestContextTrack, true, true, ""}, - {"data://example.test/cat.vtt", "track", "text/subtitlething", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextTrack, false, false, ""}, - {"data://example.test/cat.woff", "font", "font/woff2", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, true, ""}, - {"data://example.test/cat.woff", "font", "font/woff84", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextFont, false, false, ""}, - {"data://example.test/cat.empty", "", "foo/bar", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, true, ""}, - {"data://example.test/cat.blob", "blabla", "foo/bar", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, false, false, ""}, + {"http://example.test/cat.webp", "image", "image/webp", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, + {"http://example.test/cat.svg", "image", "image/svg+xml", ResourceLoadPriorityVeryLow, WebURLRequest::RequestContextImage, true, true, "image/webp,image/*,*/*;q=0.8"}, + {"http://example.test/cat.jxr", "image", "image/jxr", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextImage, false, false, ""}, + {"http://example.test/cat.js", "script", "text/javascript", ResourceLoadPriorityMedium, WebURLRequest::RequestContextScript, true, true, "*/*"}, + {"http://example.test/cat.js", "script", "text/coffeescript", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextScript, false, false, ""}, + {"http://example.test/cat.css", "style", "text/css", ResourceLoadPriorityHigh, WebURLRequest::RequestContextStyle, true, true, "text/css,*/*;q=0.1"}, + {"http://example.test/cat.css", "style", "text/sass", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextStyle, false, false, ""}, + {"http://example.test/cat.wav", "media", "audio/wav", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, + {"http://example.test/cat.wav", "media", "audio/mp57", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextVideo, false, false, ""}, + {"http://example.test/cat.webm", "media", "video/webm", ResourceLoadPriorityLow, WebURLRequest::RequestContextVideo, true, true, ""}, + {"http://example.test/cat.mp199", "media", "video/mp199", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextVideo, false, false, ""}, + {"http://example.test/cat.vtt", "track", "text/vtt", ResourceLoadPriorityLow, WebURLRequest::RequestContextTrack, true, true, ""}, + {"http://example.test/cat.vtt", "track", "text/subtitlething", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextTrack, false, false, ""}, + {"http://example.test/cat.woff", "font", "font/woff2", ResourceLoadPriorityMedium, WebURLRequest::RequestContextFont, true, true, ""}, + {"http://example.test/cat.woff", "font", "font/woff84", ResourceLoadPriorityUnresolved, WebURLRequest::RequestContextFont, false, false, ""}, + {"http://example.test/cat.empty", "", "foo/bar", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, true, true, ""}, + {"http://example.test/cat.blob", "blabla", "foo/bar", ResourceLoadPriorityLow, WebURLRequest::RequestContextSubresource, false, false, ""}, }; // Test the cases with a single header @@ -133,6 +136,7 @@ OwnPtrWillBePersistent<MockLinkLoaderClient> loaderClient = MockLinkLoaderClient::create(testCase.linkLoaderShouldLoadValue); OwnPtrWillBeRawPtr<LinkLoader> loader = LinkLoader::create(loaderClient.get()); KURL hrefURL = KURL(KURL(), testCase.href); + URLTestHelpers::registerMockedErrorURLLoad(hrefURL); loader->loadLink(LinkRelAttribute("preload"), CrossOriginAttributeNotSet, testCase.type, @@ -164,6 +168,7 @@ dummyPageHolder->document().fetcher()->clearPreloads(); } memoryCache()->evictResources(); + Platform::current()->unitTestSupport()->unregisterAllMockedURLs(); } }
diff --git a/third_party/WebKit/Source/core/loader/MockThreadableLoader.h b/third_party/WebKit/Source/core/loader/MockThreadableLoader.h index 11920f9..dd05e484 100644 --- a/third_party/WebKit/Source/core/loader/MockThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/MockThreadableLoader.h
@@ -7,13 +7,13 @@ #include "core/loader/ThreadableLoader.h" #include "testing/gmock/include/gmock/gmock.h" -#include "wtf/PassRefPtr.h" +#include "wtf/PassOwnPtr.h" namespace blink { class MockThreadableLoader : public ThreadableLoader { public: - static PassRefPtr<MockThreadableLoader> create() { return adoptRef(new testing::StrictMock<MockThreadableLoader>); } + static PassOwnPtr<MockThreadableLoader> create() { return adoptPtr(new testing::StrictMock<MockThreadableLoader>); } MOCK_METHOD1(start, void(const ResourceRequest&)); MOCK_METHOD1(overrideTimeout, void(unsigned long));
diff --git a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp index a5f2726..147c9a0 100644 --- a/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp +++ b/third_party/WebKit/Source/core/loader/NavigationScheduler.cpp
@@ -393,7 +393,7 @@ // FIXME: This check seems out of place. if (!m_frame->loader().stateMachine()->committedFirstRealDocumentLoad() && m_frame->loader().provisionalDocumentLoader()) { RefPtrWillBeRawPtr<LocalFrame> protect(m_frame.get()); - m_frame->loader().provisionalDocumentLoader()->stopLoading(); + m_frame->loader().stopAllLoaders(); if (!m_frame->host()) return; }
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp index cf07e5cd..325030f 100644 --- a/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.cpp
@@ -40,7 +40,7 @@ namespace blink { -PassRefPtr<ThreadableLoader> ThreadableLoader::create(ExecutionContext& context, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) +PassOwnPtr<ThreadableLoader> ThreadableLoader::create(ExecutionContext& context, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { ASSERT(client);
diff --git a/third_party/WebKit/Source/core/loader/ThreadableLoader.h b/third_party/WebKit/Source/core/loader/ThreadableLoader.h index ed54332..b1ea490 100644 --- a/third_party/WebKit/Source/core/loader/ThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/ThreadableLoader.h
@@ -36,9 +36,7 @@ #include "platform/CrossThreadCopier.h" #include "wtf/Allocator.h" #include "wtf/Noncopyable.h" -#include "wtf/PassRefPtr.h" -#include "wtf/RefCounted.h" -#include "wtf/RefPtr.h" +#include "wtf/PassOwnPtr.h" namespace blink { @@ -128,7 +126,7 @@ // - ResourceLoaderOptions argument will be passed to the FetchRequest // that this ThreadableLoader creates. It can be altered e.g. when // redirect happens. -class CORE_EXPORT ThreadableLoader : public RefCounted<ThreadableLoader> { +class CORE_EXPORT ThreadableLoader { WTF_MAKE_NONCOPYABLE(ThreadableLoader); public: // ThreadableLoaderClient methods may not destroy the ThreadableLoader @@ -168,8 +166,8 @@ // ThreadableLoaderClient methods: // - may call cancel() // - can destroy the ThreadableLoader instance in them (by clearing - // RefPtr<ThreadableLoader>). - static PassRefPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); + // OwnPtr<ThreadableLoader>). + static PassOwnPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); // The methods on the ThreadableLoaderClient passed on create() call // may be called synchronous to start() call.
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp index 14795d1..83395328 100644 --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
@@ -73,7 +73,7 @@ void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { - RefPtr<WorkerThreadableLoader> loader = adoptRef(new WorkerThreadableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynchronously)); + OwnPtr<WorkerThreadableLoader> loader = adoptPtr(new WorkerThreadableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynchronously)); loader->start(request); }
diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h index 70285fa9..bbbdb57 100644 --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h
@@ -61,9 +61,9 @@ USING_FAST_MALLOC(WorkerThreadableLoader); public: static void loadResourceSynchronously(WorkerGlobalScope&, const ResourceRequest&, ThreadableLoaderClient&, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); - static PassRefPtr<WorkerThreadableLoader> create(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) + static PassOwnPtr<WorkerThreadableLoader> create(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions) { - return adoptRef(new WorkerThreadableLoader(workerGlobalScope, client, options, resourceLoaderOptions, LoadAsynchronously)); + return adoptPtr(new WorkerThreadableLoader(workerGlobalScope, client, options, resourceLoaderOptions, LoadAsynchronously)); } ~WorkerThreadableLoader() override; @@ -148,7 +148,7 @@ void mainThreadCancel(ExecutionContext*); // Only to be used on the main thread. - RefPtr<ThreadableLoader> m_mainThreadLoader; + OwnPtr<ThreadableLoader> m_mainThreadLoader; // ThreadableLoaderClientWrapper is to be used on the worker context thread. // The ref counting is done on either thread:
diff --git a/third_party/WebKit/Source/core/page/AutoscrollController.cpp b/third_party/WebKit/Source/core/page/AutoscrollController.cpp index e3b067cb..327d0219 100644 --- a/third_party/WebKit/Source/core/page/AutoscrollController.cpp +++ b/third_party/WebKit/Source/core/page/AutoscrollController.cpp
@@ -140,11 +140,10 @@ while (layoutObject && !(layoutObject->isBox() && toLayoutBox(layoutObject)->canAutoscroll())) layoutObject = layoutObject->parent(); - LayoutBox* autoscrollLayoutObject = layoutObject && layoutObject->isBox() ? toLayoutBox(layoutObject) : nullptr; - if (m_autoscrollLayoutObject && !autoscrollLayoutObject) - m_autoscrollType = NoAutoscroll; + m_autoscrollLayoutObject = layoutObject && layoutObject->isBox() ? toLayoutBox(layoutObject) : nullptr; - m_autoscrollLayoutObject = autoscrollLayoutObject; + if (m_autoscrollType != NoAutoscroll && !m_autoscrollLayoutObject) + m_autoscrollType = NoAutoscroll; } void AutoscrollController::updateDragAndDrop(Node* dropTargetNode, const IntPoint& eventPosition, double eventTime) @@ -271,7 +270,7 @@ break; #endif } - if (m_autoscrollType != NoAutoscroll) + if (m_autoscrollType != NoAutoscroll && m_autoscrollLayoutObject) m_page->chromeClient().scheduleAnimation(m_autoscrollLayoutObject->frame()->view()); }
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.cpp b/third_party/WebKit/Source/core/page/ChromeClient.cpp index 24c6fbdb..fc73d76 100644 --- a/third_party/WebKit/Source/core/page/ChromeClient.cpp +++ b/third_party/WebKit/Source/core/page/ChromeClient.cpp
@@ -93,8 +93,8 @@ bool ChromeClient::openBeforeUnloadConfirmPanel(const String& message, LocalFrame* frame, bool isReload) { ASSERT(frame); - return openJavaScriptDialog(frame, message, ChromeClient::HTMLDialog, [this, frame, &message, isReload]() { - return openBeforeUnloadConfirmPanelDelegate(frame, message, isReload); + return openJavaScriptDialog(frame, message, ChromeClient::HTMLDialog, [this, frame, isReload]() { + return openBeforeUnloadConfirmPanelDelegate(frame, isReload); }); }
diff --git a/third_party/WebKit/Source/core/page/ChromeClient.h b/third_party/WebKit/Source/core/page/ChromeClient.h index 1157ae3..ca79590 100644 --- a/third_party/WebKit/Source/core/page/ChromeClient.h +++ b/third_party/WebKit/Source/core/page/ChromeClient.h
@@ -269,7 +269,7 @@ virtual void showMouseOverURL(const HitTestResult&) = 0; virtual void setWindowRect(const IntRect&) = 0; - virtual bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, const String& message, bool isReload) = 0; + virtual bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, bool isReload) = 0; virtual bool openJavaScriptAlertDelegate(LocalFrame*, const String&) = 0; virtual bool openJavaScriptConfirmDelegate(LocalFrame*, const String&) = 0; virtual bool openJavaScriptPromptDelegate(LocalFrame*, const String& message, const String& defaultValue, String& result) = 0;
diff --git a/third_party/WebKit/Source/core/page/EventSource.h b/third_party/WebKit/Source/core/page/EventSource.h index 08cb7e13..47e94fc4f 100644 --- a/third_party/WebKit/Source/core/page/EventSource.h +++ b/third_party/WebKit/Source/core/page/EventSource.h
@@ -41,7 +41,7 @@ #include "platform/heap/Handle.h" #include "platform/weborigin/KURL.h" #include "wtf/Forward.h" -#include "wtf/RefPtr.h" +#include "wtf/OwnPtr.h" namespace blink { @@ -114,7 +114,7 @@ State m_state; Member<EventSourceParser> m_parser; - RefPtr<ThreadableLoader> m_loader; + OwnPtr<ThreadableLoader> m_loader; Timer<EventSource> m_connectTimer; unsigned long long m_reconnectDelay;
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp index 3de1af13..fb401607 100644 --- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp +++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -286,15 +286,16 @@ SkPaint paint; drawForContainer(patternPicture.context().canvas(), paint, containerSize, zoom, tile, srcRect, url); } - // TODO(fmalita): convert SkPictureBuilder to return sk_sp<SkPicture> - sk_sp<SkPicture> tilePicture(const_cast<SkPicture*>(patternPicture.endRecording().leakRef())); + RefPtr<const SkPicture> tilePicture = patternPicture.endRecording(); SkMatrix patternTransform; patternTransform.setTranslate(phase.x() + spacedTile.x(), phase.y() + spacedTile.y()); + RefPtr<SkShader> patternShader = adoptRef(SkShader::CreatePictureShader( + tilePicture.get(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, + &patternTransform, nullptr)); SkPaint paint; - paint.setShader(SkShader::MakePictureShader(std::move(tilePicture), - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &patternTransform, nullptr)); + paint.setShader(patternShader.get()); paint.setXfermodeMode(compositeOp); paint.setColorFilter(context.colorFilter()); context.drawRect(dstRect, paint);
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.cpp index ced72d1..c9fb8e4 100644 --- a/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerGlobalScope.cpp
@@ -53,7 +53,7 @@ } DedicatedWorkerGlobalScope::DedicatedWorkerGlobalScope(const KURL& url, const String& userAgent, DedicatedWorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilegeData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) - : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients) + : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients, true /* withInspector */) { }
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/SharedWorkerGlobalScope.cpp index 1002f172..a3181199 100644 --- a/third_party/WebKit/Source/core/workers/SharedWorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/SharedWorkerGlobalScope.cpp
@@ -59,7 +59,7 @@ } SharedWorkerGlobalScope::SharedWorkerGlobalScope(const String& name, const KURL& url, const String& userAgent, SharedWorkerThread* thread, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilegeData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) - : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(), starterOriginPrivilegeData, workerClients) + : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(), starterOriginPrivilegeData, workerClients, true /* withInspector */) , m_name(name) { }
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp index 2c5aa68..d9a2cb4 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.cpp
@@ -71,13 +71,13 @@ namespace blink { -WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) +WorkerGlobalScope::WorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilageData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients, bool withInspector) : m_url(url) , m_userAgent(userAgent) , m_v8CacheOptions(V8CacheOptionsDefault) , m_scriptController(WorkerOrWorkletScriptController::create(this, thread->isolate())) , m_thread(thread) - , m_workerInspectorController(adoptRefWillBeNoop(new WorkerInspectorController(this))) + , m_workerInspectorController(withInspector ? adoptRefWillBeNoop(new WorkerInspectorController(this)) : nullptr) , m_closing(false) , m_eventQueue(WorkerEventQueue::create(this)) , m_workerClients(workerClients) @@ -192,9 +192,10 @@ void WorkerGlobalScope::clearInspector() { - ASSERT(m_workerInspectorController); - m_workerInspectorController->dispose(); - m_workerInspectorController.clear(); + if (m_workerInspectorController) { + m_workerInspectorController->dispose(); + m_workerInspectorController.clear(); + } } void WorkerGlobalScope::dispose()
diff --git a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h index 5816921..a85e57e 100644 --- a/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h +++ b/third_party/WebKit/Source/core/workers/WorkerGlobalScope.h
@@ -153,7 +153,7 @@ DECLARE_VIRTUAL_TRACE(); protected: - WorkerGlobalScope(const KURL&, const String& userAgent, WorkerThread*, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData>, PassOwnPtrWillBeRawPtr<WorkerClients>); + WorkerGlobalScope(const KURL&, const String& userAgent, WorkerThread*, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData>, PassOwnPtrWillBeRawPtr<WorkerClients>, bool withInspector); void applyContentSecurityPolicyFromVector(const Vector<CSPHeaderAndType>& headers); void logExceptionToConsole(const String& errorMessage, int scriptId, const String& sourceURL, int lineNumber, int columnNumber, PassRefPtr<ScriptCallStack>) override;
diff --git a/third_party/WebKit/Source/core/workers/WorkerInspectorProxy.cpp b/third_party/WebKit/Source/core/workers/WorkerInspectorProxy.cpp index 6abe3aef..4e54271 100644 --- a/third_party/WebKit/Source/core/workers/WorkerInspectorProxy.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerInspectorProxy.cpp
@@ -59,7 +59,8 @@ static void connectToWorkerGlobalScopeInspectorTask(WorkerThread* workerThread) { - workerThread->workerGlobalScope()->workerInspectorController()->connectFrontend(); + if (WorkerInspectorController* inspector = workerThread->workerGlobalScope()->workerInspectorController()) + inspector->connectFrontend(); } void WorkerInspectorProxy::connectToInspector(WorkerInspectorProxy::PageInspector* pageInspector) @@ -73,7 +74,8 @@ static void disconnectFromWorkerGlobalScopeInspectorTask(WorkerThread* workerThread) { - workerThread->workerGlobalScope()->workerInspectorController()->disconnectFrontend(); + if (WorkerInspectorController* inspector = workerThread->workerGlobalScope()->workerInspectorController()) + inspector->disconnectFrontend(); } void WorkerInspectorProxy::disconnectFromInspector() @@ -85,7 +87,8 @@ static void dispatchOnInspectorBackendTask(const String& message, WorkerThread* workerThread) { - workerThread->workerGlobalScope()->workerInspectorController()->dispatchMessageFromFrontend(message); + if (WorkerInspectorController* inspector = workerThread->workerGlobalScope()->workerInspectorController()) + inspector->dispatchMessageFromFrontend(message); } void WorkerInspectorProxy::sendMessageToInspector(const String& message)
diff --git a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h index cd2283a..b067a07 100644 --- a/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h +++ b/third_party/WebKit/Source/core/workers/WorkerScriptLoader.h
@@ -37,6 +37,7 @@ #include "public/platform/WebURLRequest.h" #include "wtf/Allocator.h" #include "wtf/Functional.h" +#include "wtf/OwnPtr.h" #include "wtf/PassRefPtr.h" #include "wtf/RefCounted.h" #include "wtf/text/StringBuilder.h" @@ -109,7 +110,7 @@ OwnPtr<SameThreadClosure> m_responseCallback; OwnPtr<SameThreadClosure> m_finishedCallback; - RefPtr<ThreadableLoader> m_threadableLoader; + OwnPtr<ThreadableLoader> m_threadableLoader; String m_responseEncoding; OwnPtr<TextResourceDecoder> m_decoder; StringBuilder m_script;
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp index b6533b7c..0d10971 100644 --- a/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp +++ b/third_party/WebKit/Source/core/workers/WorkerThreadTest.cpp
@@ -68,7 +68,7 @@ typedef WorkerGlobalScope Base; FakeWorkerGlobalScope(const KURL& url, const String& userAgent, WorkerThread* thread, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilegeData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) - : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(), starterOriginPrivilegeData, workerClients) + : WorkerGlobalScope(url, userAgent, thread, monotonicallyIncreasingTime(), starterOriginPrivilegeData, workerClients, true /* withInspector */) , m_thread(thread) { }
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp index b70d02b4..22ab07a 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp
@@ -1019,7 +1019,7 @@ // If, window.onload contains open() and send(), m_loader will be set to // non 0 value. So, we cannot continue the outer open(). In such case, // just abort the outer open() by returning false. - RefPtr<ThreadableLoader> loader = m_loader.release(); + OwnPtr<ThreadableLoader> loader = m_loader.release(); loader->cancel(); // If abort() called internalAbort() and a nested open() ended up
diff --git a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h index c592a29..32518c9 100644 --- a/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h +++ b/third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h
@@ -264,7 +264,7 @@ Member<Blob> m_responseBlob; Member<Stream> m_responseLegacyStream; - RefPtr<ThreadableLoader> m_loader; + OwnPtr<ThreadableLoader> m_loader; State m_state; ResourceResponse m_response;
diff --git a/third_party/WebKit/Source/devtools/devtools.gypi b/third_party/WebKit/Source/devtools/devtools.gypi index 9caf540..5664aba4 100644 --- a/third_party/WebKit/Source/devtools/devtools.gypi +++ b/third_party/WebKit/Source/devtools/devtools.gypi
@@ -136,11 +136,11 @@ 'front_end/sdk/CSSMatchedStyles.js', 'front_end/sdk/CSSMedia.js', 'front_end/sdk/CSSMetadata.js', + 'front_end/sdk/CSSModel.js', 'front_end/sdk/CSSParser.js', 'front_end/sdk/CSSProperty.js', 'front_end/sdk/CSSRule.js', 'front_end/sdk/CSSStyleDeclaration.js', - 'front_end/sdk/CSSStyleModel.js', 'front_end/sdk/CSSStyleSheetHeader.js', 'front_end/sdk/DebuggerModel.js', 'front_end/sdk/DOMModel.js',
diff --git a/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js b/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js index a638205..cbcb1109 100644 --- a/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js +++ b/third_party/WebKit/Source/devtools/front_end/animation/AnimationModel.js
@@ -392,7 +392,7 @@ else return; - var cssModel = WebInspector.CSSStyleModel.fromTarget(node.target()); + var cssModel = WebInspector.CSSModel.fromTarget(node.target()); if (!cssModel) return; cssModel.setEffectivePropertyValueForNode(node.id, animationPrefix + "duration", duration + "ms");
diff --git a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js index 307b5c53..2a872f0b 100644 --- a/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js +++ b/third_party/WebKit/Source/devtools/front_end/audits/AuditRules.js
@@ -374,7 +374,7 @@ doRun: function(target, requests, result, callback, progress) { var domModel = WebInspector.DOMModel.fromTarget(target); - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (!domModel || !cssModel) { callback(null); return; @@ -856,7 +856,7 @@ doRun: function(target, requests, result, callback, progress) { var domModel = WebInspector.DOMModel.fromTarget(target); - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (!domModel || !cssModel) { callback(null); return; @@ -1237,7 +1237,7 @@ */ doRun: function(target, requests, result, callback, progress) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (!cssModel) { callback(null); return;
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/CSSWorkspaceBinding.js b/third_party/WebKit/Source/devtools/front_end/bindings/CSSWorkspaceBinding.js index 62835f6..13f0e110 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/CSSWorkspaceBinding.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/CSSWorkspaceBinding.js
@@ -14,7 +14,7 @@ this._workspace = workspace; this._networkMapping = networkMapping; - /** @type {!Map.<!WebInspector.CSSStyleModel, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */ + /** @type {!Map.<!WebInspector.CSSModel, !WebInspector.CSSWorkspaceBinding.TargetInfo>} */ this._modelToTargetInfo = new Map(); targetManager.observeTargets(this); @@ -28,7 +28,7 @@ */ targetAdded: function(target) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) this._modelToTargetInfo.set(cssModel, new WebInspector.CSSWorkspaceBinding.TargetInfo(cssModel, this._workspace, this._networkMapping)); }, @@ -39,7 +39,7 @@ */ targetRemoved: function(target) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) this._modelToTargetInfo.remove(cssModel)._dispose(); }, @@ -83,7 +83,7 @@ _mainFrameCreatedOrNavigated: function(event) { var target = /** @type {!WebInspector.ResourceTreeModel} */ (event.target).target(); - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) this._modelToTargetInfo.get(cssModel)._reset(); }, @@ -171,7 +171,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.Workspace} workspace * @param {!WebInspector.NetworkMapping} networkMapping */ @@ -184,8 +184,8 @@ /** @type {!Map.<string, !WebInspector.CSSWorkspaceBinding.HeaderInfo>} */ this._headerInfoById = new Map(); - cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); } WebInspector.CSSWorkspaceBinding.TargetInfo.prototype = { @@ -231,8 +231,8 @@ _dispose: function() { this._reset(); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); }, _reset: function() @@ -310,7 +310,7 @@ /** * @constructor * @extends {WebInspector.LiveLocation} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {?WebInspector.CSSStyleSheetHeader} header * @param {!WebInspector.CSSLocation} rawLocation * @param {!WebInspector.CSSWorkspaceBinding} binding @@ -360,15 +360,15 @@ { this._header = header; this._binding._addLiveLocation(this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); }, _clearStyleSheet: function() { delete this._header; - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); }, /** @@ -393,8 +393,8 @@ WebInspector.LiveLocation.prototype.dispose.call(this); if (this._header) this._binding._removeLiveLocation(this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); }, /**
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js index 5444905..0e3d738 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/NetworkProject.js
@@ -87,10 +87,10 @@ debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this); } - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) { - cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); } target.targetManager().addEventListener(WebInspector.TargetManager.Events.SuspendStateChanged, this._suspendStateChanged, this); } @@ -430,10 +430,10 @@ debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); debuggerModel.removeEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._parsedScriptSource, this); } - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) { - cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._styleSheetAdded, this); - cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); + cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._styleSheetAdded, this); + cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._styleSheetRemoved, this); } delete target[WebInspector.NetworkProject._networkProjectSymbol]; },
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js index 778525e..71a2428 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/SASSSourceMapping.js
@@ -31,7 +31,7 @@ /** * @constructor * @implements {WebInspector.CSSSourceMapping} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.NetworkMapping} networkMapping * @param {!WebInspector.NetworkProject} networkProject */ @@ -41,7 +41,7 @@ this._networkProject = networkProject; this._reset(); WebInspector.moduleSetting("cssSourceMapsEnabled").addChangeListener(this._toggleSourceMapSupport, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._styleSheetChanged, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._styleSheetChanged, this); cssModel.target().resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._reset, this); this._networkMapping = networkMapping; }
diff --git a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js index 56e29eaa..5f2d196 100644 --- a/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js +++ b/third_party/WebKit/Source/devtools/front_end/bindings/StylesSourceMapping.js
@@ -31,7 +31,7 @@ /** * @constructor * @implements {WebInspector.CSSSourceMapping} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.Workspace} workspace * @param {!WebInspector.NetworkMapping} networkMapping */ @@ -46,7 +46,7 @@ cssModel.target().resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._unbindAllUISourceCodes, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._styleSheetChanged, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._styleSheetChanged, this); /** @type {!Map<string, !Map<string, !Map<string, !WebInspector.CSSStyleSheetHeader>>>} */ this._urlToHeadersByFrameId = new Map(); /** @type {!Map.<!WebInspector.UISourceCode, !WebInspector.StyleFile>} */
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js index 9fde204a..31a20f8 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ComputedStyleWidget.js
@@ -240,7 +240,7 @@ }, /** - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.CSSMatchedStyles} matchedStyles * @param {!WebInspector.DOMNode} node * @param {!TreeElement} rootTreeElement
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js index a7eb282..69c9f35 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js
@@ -25,7 +25,7 @@ var node = WebInspector.context.flavor(WebInspector.DOMNode); if (!node) return; - WebInspector.CSSStyleModel.fromNode(node).forcePseudoState(node, event.target.state, event.target.checked); + WebInspector.CSSModel.fromNode(node).forcePseudoState(node, event.target.state, event.target.checked); } /** @@ -65,13 +65,13 @@ return; if (this._target) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(this._target); - cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.PseudoStateForced, this._pseudoStateForced, this) + var cssModel = WebInspector.CSSModel.fromTarget(this._target); + cssModel.removeEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this._pseudoStateForced, this) } this._target = target; if (target) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); - cssModel.addEventListener(WebInspector.CSSStyleModel.Events.PseudoStateForced, this._pseudoStateForced, this) + var cssModel = WebInspector.CSSModel.fromTarget(target); + cssModel.addEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this._pseudoStateForced, this) } }, @@ -101,7 +101,7 @@ { var node = WebInspector.context.flavor(WebInspector.DOMNode); if (node) { - var nodePseudoState = WebInspector.CSSStyleModel.fromNode(node).pseudoState(node); + var nodePseudoState = WebInspector.CSSModel.fromNode(node).pseudoState(node); for (var input of this._inputs) { input.disabled = !!node.pseudoType(); input.checked = nodePseudoState.indexOf(input.state) >= 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js index 077af779..62fddf5 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -1236,7 +1236,7 @@ */ decorate: function(node) { - return { color: "orange", title: WebInspector.UIString("Element state: %s", ":" + WebInspector.CSSStyleModel.fromNode(node).pseudoState(node).join(", :")) }; + return { color: "orange", title: WebInspector.UIString("Element state: %s", ":" + WebInspector.CSSModel.fromNode(node).pseudoState(node).join(", :")) }; } }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js index 14b4fc0..e69fae5 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsSidebarPane.js
@@ -25,7 +25,7 @@ }, /** - * @return {?WebInspector.CSSStyleModel} + * @return {?WebInspector.CSSModel} */ cssModel: function() { @@ -86,19 +86,19 @@ var domModel = null; var resourceTreeModel = null; if (target) { - this._cssModel = WebInspector.CSSStyleModel.fromTarget(target); + this._cssModel = WebInspector.CSSModel.fromTarget(target); domModel = WebInspector.DOMModel.fromTarget(target); resourceTreeModel = target.resourceTreeModel; } if (this._cssModel && domModel && resourceTreeModel) { this._targetEvents = [ - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this.onCSSModelChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this.onCSSModelChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this.onCSSModelChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged, this.onCSSModelChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.PseudoStateForced, this.onCSSModelChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.ModelWasEnabled, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this.onCSSModelChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.ModelWasEnabled, this.onCSSModelChanged, this), domModel.addEventListener(WebInspector.DOMModel.Events.DOMMutated, this._domModelChanged, this), resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.FrameResized, this._onFrameResized, this), ];
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js index 9b61c0d..17f10e6 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -121,7 +121,7 @@ WebInspector.ElementsTreeElement.populateForcedPseudoStateItems = function(subMenu, node) { const pseudoClasses = ["active", "hover", "focus", "visited"]; - var forcedPseudoState = WebInspector.CSSStyleModel.fromNode(node).pseudoState(node); + var forcedPseudoState = WebInspector.CSSModel.fromNode(node).pseudoState(node); for (var i = 0; i < pseudoClasses.length; ++i) { var pseudoClassForced = forcedPseudoState.indexOf(pseudoClasses[i]) >= 0; subMenu.appendCheckboxItem(":" + pseudoClasses[i], setPseudoStateCallback.bind(null, pseudoClasses[i], !pseudoClassForced), pseudoClassForced, false); @@ -133,7 +133,7 @@ */ function setPseudoStateCallback(pseudoState, enabled) { - WebInspector.CSSStyleModel.fromNode(node).forcePseudoState(node, pseudoState, enabled); + WebInspector.CSSModel.fromNode(node).forcePseudoState(node, pseudoState, enabled); } }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/MetricsSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/MetricsSidebarPane.js index 620f76f..670ca2b 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/MetricsSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/MetricsSidebarPane.js
@@ -67,7 +67,7 @@ this._updateMetrics(style); } /** - * @param {?WebInspector.CSSStyleModel.InlineStyleResult} inlineStyleResult + * @param {?WebInspector.CSSModel.InlineStyleResult} inlineStyleResult * @this {WebInspector.MetricsSidebarPane} */ function inlineStyleCallback(inlineStyleResult)
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/PropertyChangeHighlighter.js b/third_party/WebKit/Source/devtools/front_end/elements/PropertyChangeHighlighter.js index 52de522..653bad06 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/PropertyChangeHighlighter.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/PropertyChangeHighlighter.js
@@ -5,7 +5,7 @@ /** * @constructor * @param {!WebInspector.StylesSidebarPane} ssp - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.StyleSheetId} styleSheetId * @param {!WebInspector.TextRange} range */
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/SharedSidebarModel.js b/third_party/WebKit/Source/devtools/front_end/elements/SharedSidebarModel.js index 831ee0b..bcf26d33 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/SharedSidebarModel.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/SharedSidebarModel.js
@@ -41,7 +41,7 @@ }, /** - * @return {?WebInspector.CSSStyleModel} + * @return {?WebInspector.CSSModel} */ cssModel: function() { @@ -72,18 +72,18 @@ this._target = target; var domModel = null; if (target) { - this._cssModel = WebInspector.CSSStyleModel.fromTarget(target); + this._cssModel = WebInspector.CSSModel.fromTarget(target); domModel = WebInspector.DOMModel.fromTarget(target); } if (domModel && this._cssModel) { this._targetEvents = [ - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._onComputedStyleChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._onComputedStyleChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._onComputedStyleChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged, this._onComputedStyleChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.PseudoStateForced, this._onComputedStyleChanged, this), - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.ModelWasEnabled, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.PseudoStateForced, this._onComputedStyleChanged, this), + this._cssModel.addEventListener(WebInspector.CSSModel.Events.ModelWasEnabled, this._onComputedStyleChanged, this), domModel.addEventListener(WebInspector.DOMModel.Events.DOMMutated, this._onComputedStyleChanged, this) ]; }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js index 033d037..b179e4f 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/Spectrum.js
@@ -915,7 +915,7 @@ this._frequencyMap = new Map(); var stylesheetPromises = []; for (var target of WebInspector.targetManager.targets(WebInspector.Target.Type.Page)) { - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); for (var stylesheet of cssModel.allStyleSheets()) stylesheetPromises.push(new Promise(this._processStylesheet.bind(this, stylesheet))); }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js index 56535fb..bd44f0f 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/StylesSidebarPane.js
@@ -48,7 +48,7 @@ this._keyDownBound = this._keyDown.bind(this); this._keyUpBound = this._keyUp.bind(this); - WebInspector.targetManager.addModelListener(WebInspector.CSSStyleModel, WebInspector.CSSStyleModel.Events.LayoutEditorChange, this._onLayoutEditorChange, this); + WebInspector.targetManager.addModelListener(WebInspector.CSSModel, WebInspector.CSSModel.Events.LayoutEditorChange, this._onLayoutEditorChange, this); } /** @@ -111,7 +111,7 @@ */ _onLayoutEditorChange: function(event) { - var cssModel = /** @type {!WebInspector.CSSStyleModel} */(event.target); + var cssModel = /** @type {!WebInspector.CSSModel} */(event.target); var styleSheetId = event.data["id"]; var sourceRange = /** @type {!CSSAgent.SourceRange} */(event.data["range"]); var range = WebInspector.TextRange.fromObject(sourceRange); @@ -298,7 +298,7 @@ */ onCSSModelChanged: function(event) { - var edit = event && event.data ? /** @type {?WebInspector.CSSStyleModel.Edit} */(event.data.edit) : null; + var edit = event && event.data ? /** @type {?WebInspector.CSSModel.Edit} */(event.data.edit) : null; if (edit) { for (var section of this.allSections()) section._styleSheetEdited(edit); @@ -984,7 +984,7 @@ }, /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ _styleSheetEdited: function(edit) { @@ -1609,7 +1609,7 @@ } /** - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.Linkifier} linkifier * @param {string} styleSheetId * @param {!WebInspector.TextRange} ruleLocation
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js index a386051..9ee96a8d 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js +++ b/third_party/WebKit/Source/devtools/front_end/emulation/MediaQueryInspector.js
@@ -45,13 +45,13 @@ // FIXME: adapt this to multiple targets. if (this._cssModel) return; - this._cssModel = WebInspector.CSSStyleModel.fromTarget(target); + this._cssModel = WebInspector.CSSModel.fromTarget(target); if (!this._cssModel) return; - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this); - this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this); + this._cssModel.addEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this); }, /** @@ -60,12 +60,12 @@ */ targetRemoved: function(target) { - if (WebInspector.CSSStyleModel.fromTarget(target) !== this._cssModel) + if (WebInspector.CSSModel.fromTarget(target) !== this._cssModel) return; - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this); - this._cssModel.removeEventListener(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetAdded, this._scheduleMediaQueriesUpdate, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetRemoved, this._scheduleMediaQueriesUpdate, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.StyleSheetChanged, this._scheduleMediaQueriesUpdate, this); + this._cssModel.removeEventListener(WebInspector.CSSModel.Events.MediaQueryResultChanged, this._scheduleMediaQueriesUpdate, this); delete this._cssModel; },
diff --git a/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js b/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js index 571d51a4..f806dd5 100644 --- a/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js +++ b/third_party/WebKit/Source/devtools/front_end/main/RenderingOptions.js
@@ -117,7 +117,7 @@ _applyPrintMediaOverride: function(target) { target.emulationAgent().setEmulatedMedia(this._mediaCheckbox.checked ? this._mediaSelect.value : ""); - var cssModel = WebInspector.CSSStyleModel.fromTarget(target); + var cssModel = WebInspector.CSSModel.fromTarget(target); if (cssModel) cssModel.mediaQueryResultChanged(); },
diff --git a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js index 808595e1..99a64e6 100644 --- a/third_party/WebKit/Source/devtools/front_end/platform/utilities.js +++ b/third_party/WebKit/Source/devtools/front_end/platform/utilities.js
@@ -304,10 +304,21 @@ { if (!string) return 0; - var result = 0; - for (var i = 0; i < string.length; ++i) - result = (result * 31 + string.charCodeAt(i)) | 0; - return Math.abs(result); + // Hash algorithm for substrings is described in "Über die Komplexität der Multiplikation in + // eingeschränkten Branchingprogrammmodellen" by Woelfe. + // http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000 + var p = ((1 << 30) * 4 - 5); // prime: 2^32 - 5 + var z = 0x5033d967; // 32 bits from random.org + var z2 = 0x59d2f15d; // random odd 32 bit number + var s = 0; + var zi = 1; + for (var i = 0; i < string.length; i++) { + var xi = string.charCodeAt(i) * z2; + s = (s + zi * xi) % p; + zi = (zi * z) % p; + } + s = (s + zi * (p - 1)) % p; + return Math.abs(s|0); } /**
diff --git a/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js b/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js index f430a55e..b7694892 100644 --- a/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js +++ b/third_party/WebKit/Source/devtools/front_end/sass/ASTSourceMap.js
@@ -20,7 +20,7 @@ /** * @param {!WebInspector.ASTService} astService - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.SourceMap} sourceMap * @return {!Promise<?WebInspector.ASTSourceMap>} */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMatchedStyles.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMatchedStyles.js index 21cd964..1791a22a 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMatchedStyles.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMatchedStyles.js
@@ -4,7 +4,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!WebInspector.DOMNode} node * @param {?CSSAgent.CSSStyle} inlinePayload * @param {?CSSAgent.CSSStyle} attributesPayload @@ -134,7 +134,7 @@ }, /** - * @return {!WebInspector.CSSStyleModel} + * @return {!WebInspector.CSSModel} */ cssModel: function() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMedia.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMedia.js index 81e94d8..d07e2e7 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSMedia.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSMedia.js
@@ -108,7 +108,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSMedia} payload */ WebInspector.CSSMedia = function(cssModel, payload) @@ -125,7 +125,7 @@ }; /** - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSMedia} payload * @return {!WebInspector.CSSMedia} */ @@ -135,7 +135,7 @@ } /** - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!Array.<!CSSAgent.CSSMedia>} payload * @return {!Array.<!WebInspector.CSSMedia>} */ @@ -167,7 +167,7 @@ }, /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js similarity index 85% rename from third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js rename to third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js index da98c85..aa6cda5 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSModel.js
@@ -33,12 +33,12 @@ * @extends {WebInspector.SDKModel} * @param {!WebInspector.Target} target */ -WebInspector.CSSStyleModel = function(target) +WebInspector.CSSModel = function(target) { - WebInspector.SDKModel.call(this, WebInspector.CSSStyleModel, target); + WebInspector.SDKModel.call(this, WebInspector.CSSModel, target); this._domModel = WebInspector.DOMModel.fromTarget(target); this._agent = target.cssAgent(); - this._styleLoader = new WebInspector.CSSStyleModel.ComputedStyleLoader(this); + this._styleLoader = new WebInspector.CSSModel.ComputedStyleLoader(this); target.resourceTreeModel.addEventListener(WebInspector.ResourceTreeModel.EventTypes.MainFrameNavigated, this._mainFrameNavigated, this); target.registerCSSDispatcher(new WebInspector.CSSDispatcher(this)); this._agent.enable().then(this._wasEnabled.bind(this)); @@ -48,7 +48,7 @@ this._styleSheetIdsForURL = new Map(); } -WebInspector.CSSStyleModel.Events = { +WebInspector.CSSModel.Events = { LayoutEditorChange: "LayoutEditorChange", MediaQueryResultChanged: "MediaQueryResultChanged", ModelWasEnabled: "ModelWasEnabled", @@ -58,9 +58,9 @@ StyleSheetRemoved: "StyleSheetRemoved" } -WebInspector.CSSStyleModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"]; +WebInspector.CSSModel.MediaTypes = ["all", "braille", "embossed", "handheld", "print", "projection", "screen", "speech", "tty", "tv"]; -WebInspector.CSSStyleModel.PseudoStateMarker = "pseudo-state-marker"; +WebInspector.CSSModel.PseudoStateMarker = "pseudo-state-marker"; /** * @constructor @@ -69,7 +69,7 @@ * @param {string} newText * @param {?Object} payload */ -WebInspector.CSSStyleModel.Edit = function(styleSheetId, oldRange, newText, payload) +WebInspector.CSSModel.Edit = function(styleSheetId, oldRange, newText, payload) { this.styleSheetId = styleSheetId; this.oldRange = oldRange; @@ -77,7 +77,7 @@ this.payload = payload; } -WebInspector.CSSStyleModel.prototype = { +WebInspector.CSSModel.prototype = { /** * @return {!WebInspector.DOMModel} */ @@ -99,7 +99,7 @@ * @param {?Protocol.Error} error * @param {?Array<!CSSAgent.CSSStyle>} stylePayloads * @return {boolean} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function parsePayload(error, stylePayloads) { @@ -109,7 +109,7 @@ if (majorChange) this._domModel.markUndoableState(); for (var i = 0; i < ranges.length; ++i) { - var edit = new WebInspector.CSSStyleModel.Edit(styleSheetIds[i], ranges[i], texts[i], stylePayloads[i]); + var edit = new WebInspector.CSSModel.Edit(styleSheetIds[i], ranges[i], texts[i], stylePayloads[i]); this._fireStyleSheetChanged(styleSheetIds[i], edit); } return true; @@ -141,14 +141,14 @@ * @param {?Protocol.Error} error * @param {?CSSAgent.SelectorList} selectorPayload * @return {boolean} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function callback(error, selectorPayload) { if (error || !selectorPayload) return false; this._domModel.markUndoableState(); - var edit = new WebInspector.CSSStyleModel.Edit(styleSheetId, range, text, selectorPayload); + var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, selectorPayload); this._fireStyleSheetChanged(styleSheetId, edit); return true; } @@ -170,14 +170,14 @@ * @param {?Protocol.Error} error * @param {!CSSAgent.Value} payload * @return {boolean} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function callback(error, payload) { if (error || !payload) return false; this._domModel.markUndoableState(); - var edit = new WebInspector.CSSStyleModel.Edit(styleSheetId, range, text, payload); + var edit = new WebInspector.CSSModel.Edit(styleSheetId, range, text, payload); this._fireStyleSheetChanged(styleSheetId, edit); return true; } @@ -196,7 +196,7 @@ * @param {?Protocol.Error} error * @param {?Array.<!CSSAgent.CSSMedia>} payload * @return {!Array.<!WebInspector.CSSMedia>} - * @this {!WebInspector.CSSStyleModel} + * @this {!WebInspector.CSSModel} */ function parsePayload(error, payload) { @@ -224,7 +224,7 @@ return; } this._isEnabled = true; - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.ModelWasEnabled); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.ModelWasEnabled); }, /** @@ -242,7 +242,7 @@ * @param {!Array.<!CSSAgent.InheritedStyleEntry>=} inheritedPayload * @param {!Array.<!CSSAgent.CSSKeyframesRule>=} animationsPayload * @return {?WebInspector.CSSMatchedStyles} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function callback(error, inlinePayload, attributesPayload, matchedPayload, pseudoPayload, inheritedPayload, animationsPayload) { @@ -330,7 +330,7 @@ /** * @param {!DOMAgent.NodeId} nodeId - * @return {!Promise.<?WebInspector.CSSStyleModel.InlineStyleResult>} + * @return {!Promise.<?WebInspector.CSSModel.InlineStyleResult>} */ inlineStylesPromise: function(nodeId) { @@ -338,8 +338,8 @@ * @param {?Protocol.Error} error * @param {?CSSAgent.CSSStyle=} inlinePayload * @param {?CSSAgent.CSSStyle=} attributesStylePayload - * @return {?WebInspector.CSSStyleModel.InlineStyleResult} - * @this {WebInspector.CSSStyleModel} + * @return {?WebInspector.CSSModel.InlineStyleResult} + * @this {WebInspector.CSSModel} */ function callback(error, inlinePayload, attributesStylePayload) { @@ -347,7 +347,7 @@ return null; var inlineStyle = inlinePayload ? new WebInspector.CSSStyleDeclaration(this, null, inlinePayload, WebInspector.CSSStyleDeclaration.Type.Inline) : null; var attributesStyle = attributesStylePayload ? new WebInspector.CSSStyleDeclaration(this, null, attributesStylePayload, WebInspector.CSSStyleDeclaration.Type.Attributes) : null; - return new WebInspector.CSSStyleModel.InlineStyleResult(inlineStyle, attributesStyle); + return new WebInspector.CSSModel.InlineStyleResult(inlineStyle, attributesStyle); } return this._agent.getInlineStylesForNode(nodeId, callback.bind(this)); @@ -361,22 +361,22 @@ */ forcePseudoState: function(node, pseudoClass, enable) { - var pseudoClasses = node.marker(WebInspector.CSSStyleModel.PseudoStateMarker) || []; + var pseudoClasses = node.marker(WebInspector.CSSModel.PseudoStateMarker) || []; if (enable) { if (pseudoClasses.indexOf(pseudoClass) >= 0) return false; pseudoClasses.push(pseudoClass); - node.setMarker(WebInspector.CSSStyleModel.PseudoStateMarker, pseudoClasses); + node.setMarker(WebInspector.CSSModel.PseudoStateMarker, pseudoClasses); } else { if (pseudoClasses.indexOf(pseudoClass) < 0) return false; pseudoClasses.remove(pseudoClass); if (!pseudoClasses.length) - node.setMarker(WebInspector.CSSStyleModel.PseudoStateMarker, null); + node.setMarker(WebInspector.CSSModel.PseudoStateMarker, null); } this._agent.forcePseudoState(node.id, pseudoClasses); - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.PseudoStateForced, { node: node, pseudoClass: pseudoClass, enable: enable }); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.PseudoStateForced, { node: node, pseudoClass: pseudoClass, enable: enable }); return true; }, @@ -386,7 +386,7 @@ */ pseudoState: function(node) { - return node.marker(WebInspector.CSSStyleModel.PseudoStateMarker) || []; + return node.marker(WebInspector.CSSModel.PseudoStateMarker) || []; }, /** @@ -400,14 +400,14 @@ * @param {?Protocol.Error} error * @param {!CSSAgent.CSSMedia} mediaPayload * @return {boolean} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function parsePayload(error, mediaPayload) { if (!mediaPayload) return false; this._domModel.markUndoableState(); - var edit = new WebInspector.CSSStyleModel.Edit(media.parentStyleSheetId, media.range, newMediaText, mediaPayload); + var edit = new WebInspector.CSSModel.Edit(media.parentStyleSheetId, media.range, newMediaText, mediaPayload); this._fireStyleSheetChanged(media.parentStyleSheetId, edit); return true; } @@ -434,14 +434,14 @@ * @param {?Protocol.Error} error * @param {?CSSAgent.CSSRule} rulePayload * @return {?WebInspector.CSSStyleRule} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function parsePayload(error, rulePayload) { if (error || !rulePayload) return null; this._domModel.markUndoableState(); - var edit = new WebInspector.CSSStyleModel.Edit(styleSheetId, ruleLocation, ruleText, rulePayload); + var edit = new WebInspector.CSSModel.Edit(styleSheetId, ruleLocation, ruleText, rulePayload); this._fireStyleSheetChanged(styleSheetId, edit); return new WebInspector.CSSStyleRule(this, rulePayload); } @@ -467,7 +467,7 @@ * @param {?Protocol.Error} error * @param {?CSSAgent.StyleSheetId} styleSheetId * @return {?WebInspector.CSSStyleSheetHeader} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function innerCallback(error, styleSheetId) { @@ -481,7 +481,7 @@ mediaQueryResultChanged: function() { - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.MediaQueryResultChanged); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.MediaQueryResultChanged); }, /** @@ -503,11 +503,11 @@ /** * @param {!CSSAgent.StyleSheetId} styleSheetId - * @param {!WebInspector.CSSStyleModel.Edit=} edit + * @param {!WebInspector.CSSModel.Edit=} edit */ _fireStyleSheetChanged: function(styleSheetId, edit) { - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, edit: edit }); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetChanged, { styleSheetId: styleSheetId, edit: edit }); }, /** @@ -528,7 +528,7 @@ frameIdToStyleSheetIds[styleSheetHeader.frameId] = styleSheetIds; } styleSheetIds.push(styleSheetHeader.id); - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetAdded, styleSheetHeader); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetAdded, styleSheetHeader); }, /** @@ -550,7 +550,7 @@ if (!Object.keys(frameIdToStyleSheetIds).length) this._styleSheetIdsForURL.remove(url); } - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, header); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetRemoved, header); }, /** @@ -579,7 +579,7 @@ { var header = this._styleSheetIdToHeader.get(styleSheetId); console.assert(header); - newText = WebInspector.CSSStyleModel.trimSourceURL(newText); + newText = WebInspector.CSSModel.trimSourceURL(newText); if (header.hasSourceURL) newText += "\n/*# sourceURL=" + header.sourceURL + " */"; return this._agent.setStyleSheetText(header.id, newText, callback.bind(this)); @@ -588,7 +588,7 @@ * @param {?Protocol.Error} error * @param {string=} sourceMapURL * @return {?Protocol.Error} - * @this {WebInspector.CSSStyleModel} + * @this {WebInspector.CSSModel} */ function callback(error, sourceMapURL) { @@ -620,7 +620,7 @@ text = ""; // Fall through. } - return WebInspector.CSSStyleModel.trimSourceURL(text); + return WebInspector.CSSModel.trimSourceURL(text); } return this._agent.getStyleSheetText(styleSheetId, textCallback) @@ -638,7 +638,7 @@ this._styleSheetIdsForURL.clear(); this._styleSheetIdToHeader.clear(); for (var i = 0; i < headers.length; ++i) - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.StyleSheetRemoved, headers[i]); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.StyleSheetRemoved, headers[i]); }, /** @@ -666,7 +666,7 @@ */ _layoutEditorChange: function(id, range) { - this.dispatchEventToListeners(WebInspector.CSSStyleModel.Events.LayoutEditorChange, {id: id, range: range}); + this.dispatchEventToListeners(WebInspector.CSSModel.Events.LayoutEditorChange, {id: id, range: range}); }, /** @@ -686,7 +686,7 @@ * @param {string} text * @return {string} */ -WebInspector.CSSStyleModel.trimSourceURL = function(text) +WebInspector.CSSModel.trimSourceURL = function(text) { var sourceURLIndex = text.lastIndexOf("/*# sourceURL="); if (sourceURLIndex === -1) { @@ -724,7 +724,7 @@ WebInspector.CSSLocation.prototype = { /** - * @return {!WebInspector.CSSStyleModel} + * @return {!WebInspector.CSSModel} */ cssModel: function() { @@ -745,7 +745,7 @@ /** * @constructor * @implements {CSSAgent.Dispatcher} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel */ WebInspector.CSSDispatcher = function(cssModel) { @@ -801,16 +801,16 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel */ -WebInspector.CSSStyleModel.ComputedStyleLoader = function(cssModel) +WebInspector.CSSModel.ComputedStyleLoader = function(cssModel) { this._cssModel = cssModel; /** @type {!Map<!DOMAgent.NodeId, !Promise<?Map<string, string>>>} */ this._nodeIdToPromise = new Map(); } -WebInspector.CSSStyleModel.ComputedStyleLoader.prototype = { +WebInspector.CSSModel.ComputedStyleLoader.prototype = { /** * @param {!DOMAgent.NodeId} nodeId * @return {!Promise<?Map<string, string>>} @@ -840,7 +840,7 @@ /** * @param {?Map.<string, string>} computedStyle * @return {?Map.<string, string>} - * @this {WebInspector.CSSStyleModel.ComputedStyleLoader} + * @this {WebInspector.CSSModel.ComputedStyleLoader} */ function cleanUp(computedStyle) { @@ -852,22 +852,22 @@ /** * @param {!WebInspector.Target} target - * @return {?WebInspector.CSSStyleModel} + * @return {?WebInspector.CSSModel} */ -WebInspector.CSSStyleModel.fromTarget = function(target) +WebInspector.CSSModel.fromTarget = function(target) { if (!target.isPage()) return null; - return /** @type {?WebInspector.CSSStyleModel} */ (target.model(WebInspector.CSSStyleModel)); + return /** @type {?WebInspector.CSSModel} */ (target.model(WebInspector.CSSModel)); } /** * @param {!WebInspector.DOMNode} node - * @return {!WebInspector.CSSStyleModel} + * @return {!WebInspector.CSSModel} */ -WebInspector.CSSStyleModel.fromNode = function(node) +WebInspector.CSSModel.fromNode = function(node) { - return /** @type {!WebInspector.CSSStyleModel} */ (WebInspector.CSSStyleModel.fromTarget(node.target())); + return /** @type {!WebInspector.CSSModel} */ (WebInspector.CSSModel.fromTarget(node.target())); } /** @@ -875,7 +875,7 @@ * @param {?WebInspector.CSSStyleDeclaration} inlineStyle * @param {?WebInspector.CSSStyleDeclaration} attributesStyle */ -WebInspector.CSSStyleModel.InlineStyleResult = function(inlineStyle, attributesStyle) +WebInspector.CSSModel.InlineStyleResult = function(inlineStyle, attributesStyle) { this.inlineStyle = inlineStyle; this.attributesStyle = attributesStyle;
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSProperty.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSProperty.js index b5e0238..47ba1773 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSProperty.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSProperty.js
@@ -50,7 +50,7 @@ WebInspector.CSSProperty.prototype = { /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js index bfbcc39..ac35fb1b 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSRule.js
@@ -15,7 +15,7 @@ WebInspector.CSSValue.prototype = { /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) { @@ -27,7 +27,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {{style: !CSSAgent.CSSStyle, styleSheetId: (string|undefined), origin: !CSSAgent.StyleSheetOrigin}} payload */ WebInspector.CSSRule = function(cssModel, payload) @@ -45,7 +45,7 @@ WebInspector.CSSRule.prototype = { /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) { @@ -101,7 +101,7 @@ /** * @constructor * @extends {WebInspector.CSSRule} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSRule} payload */ WebInspector.CSSStyleRule = function(cssModel, payload) @@ -113,7 +113,7 @@ } /** - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {string} selectorText * @return {!WebInspector.CSSStyleRule} */ @@ -209,7 +209,7 @@ /** * @override - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) { @@ -232,7 +232,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSKeyframesRule} payload */ WebInspector.CSSKeyframesRule = function(cssModel, payload) @@ -263,7 +263,7 @@ /** * @constructor * @extends {WebInspector.CSSRule} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSKeyframeRule} payload */ WebInspector.CSSKeyframeRule = function(cssModel, payload) @@ -291,7 +291,7 @@ /** * @override - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleDeclaration.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleDeclaration.js index 2dad838..c92a61a 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleDeclaration.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleDeclaration.js
@@ -4,7 +4,7 @@ /** * @constructor - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {?WebInspector.CSSRule} parentRule * @param {!CSSAgent.CSSStyle} payload * @param {!WebInspector.CSSStyleDeclaration.Type} type @@ -26,7 +26,7 @@ WebInspector.CSSStyleDeclaration.prototype = { /** - * @param {!WebInspector.CSSStyleModel.Edit} edit + * @param {!WebInspector.CSSModel.Edit} edit */ rebase: function(edit) { @@ -167,7 +167,7 @@ }, /** - * @return {!WebInspector.CSSStyleModel} + * @return {!WebInspector.CSSModel} */ cssModel: function() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js index a494a73..cf43e45b 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/CSSStyleSheetHeader.js
@@ -5,7 +5,7 @@ /** * @constructor * @implements {WebInspector.ContentProvider} - * @param {!WebInspector.CSSStyleModel} cssModel + * @param {!WebInspector.CSSModel} cssModel * @param {!CSSAgent.CSSStyleSheetHeader} payload */ WebInspector.CSSStyleSheetHeader = function(cssModel, payload) @@ -44,7 +44,7 @@ }, /** - * @return {!WebInspector.CSSStyleModel} + * @return {!WebInspector.CSSModel} */ cssModel: function() {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js index 2b38ea16..ccb48e424 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/Target.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/Target.js
@@ -43,7 +43,7 @@ if (this._type === WebInspector.Target.Type.Page) { new WebInspector.DOMModel(this); - new WebInspector.CSSStyleModel(this); + new WebInspector.CSSModel(this); } /** @type {?WebInspector.WorkerManager} */
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/module.json b/third_party/WebKit/Source/devtools/front_end/sdk/module.json index b379c00..141854b 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/module.json +++ b/third_party/WebKit/Source/devtools/front_end/sdk/module.json
@@ -62,11 +62,11 @@ "CSSMatchedStyles.js", "CSSMedia.js", "CSSMetadata.js", + "CSSModel.js", "CSSParser.js", "CSSProperty.js", "CSSRule.js", "CSSStyleDeclaration.js", - "CSSStyleModel.js", "CSSStyleSheetHeader.js", "DOMModel.js", "DebuggerModel.js",
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js index d59e1f8..dd62942 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelinePanel.js
@@ -2124,7 +2124,7 @@ { this._targets = []; this._throttlingRate = 1.; // No throttling - WebInspector.targetManager.observeTargets(this); + WebInspector.targetManager.observeTargets(this, WebInspector.Target.Type.Page); } WebInspector.CPUThrottlingManager.prototype = {
diff --git a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js index e1adb37..6d8e58c9 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js +++ b/third_party/WebKit/Source/devtools/front_end/ui_lazy/FlameChart.js
@@ -310,9 +310,9 @@ /** * @constructor * @param {!{min: number, max: number}|number=} hueSpace - * @param {!{min: number, max: number, count: number}|number=} satSpace - * @param {!{min: number, max: number, count: number}|number=} lightnessSpace - * @param {!{min: number, max: number, count: number}|number=} alphaSpace + * @param {!{min: number, max: number, count: (number|undefined)}|number=} satSpace + * @param {!{min: number, max: number, count: (number|undefined)}|number=} lightnessSpace + * @param {!{min: number, max: number, count: (number|undefined)}|number=} alphaSpace */ WebInspector.FlameChart.ColorGenerator = function(hueSpace, satSpace, lightnessSpace, alphaSpace) { @@ -355,46 +355,25 @@ _generateColorForID: function(id) { var hash = String.hashCode(id); - var h = this._indexToDistinctValueInSpace(this._colors.size, this._hueSpace); - var s = this._indexToValueInSpace(hash, this._satSpace); - var l = this._indexToValueInSpace(hash, this._lightnessSpace); - var a = this._indexToValueInSpace(hash, this._alphaSpace); + var h = this._indexToValueInSpace(hash, this._hueSpace); + var s = this._indexToValueInSpace(hash >> 8, this._satSpace); + var l = this._indexToValueInSpace(hash >> 16, this._lightnessSpace); + var a = this._indexToValueInSpace(hash >> 24, this._alphaSpace); return "hsla(" + h + ", " + s + "%, " + l + "%, " + a + ")"; }, /** * @param {number} index - * @param {!{min: number, max: number, count: number}|number} space + * @param {!{min: number, max: number, count: (number|undefined)}|number} space * @return {number} */ _indexToValueInSpace: function(index, space) { if (typeof space === "number") return space; - index %= space.count; - return space.min + Math.floor(index / (space.count - 1) * (space.max - space.min)); - }, - - /** - * @param {number} index - * @param {!{min: number, max: number}|number} space - * @return {number} - */ - _indexToDistinctValueInSpace: function(index, space) - { - if (typeof space === "number") - return space; - index |= 0; - var result = 0; - var count = 0; - // Reverse bits in index. - do { - result = (result << 1) | (index & 1); - index >>= 1; - ++count; - } while (index); - result /= 1 << count; - return space.min + Math.floor(result * (space.max - space.min)); + var count = space.count || space.max - space.min; + index %= count; + return space.min + Math.floor(index / (count - 1) * (space.max - space.min)); } }
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.cpp index dd66695..b33670c3 100644 --- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerGlobalScope.cpp
@@ -23,7 +23,7 @@ } CompositorWorkerGlobalScope::CompositorWorkerGlobalScope(const KURL& url, const String& userAgent, CompositorWorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilegeData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) - : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients) + : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients, false /* withInspector */) , m_callbackCollection(this) { }
diff --git a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp index e1eac62..ab08ead 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.cpp
@@ -13,6 +13,7 @@ #include "platform/blob/BlobRegistry.h" #include "platform/blob/BlobURL.h" #include "platform/network/ResourceRequest.h" +#include "wtf/OwnPtr.h" namespace blink { @@ -101,7 +102,7 @@ } private: - PassRefPtr<ThreadableLoader> createLoader(ExecutionContext* executionContext, ThreadableLoaderClient* client) const + PassOwnPtr<ThreadableLoader> createLoader(ExecutionContext* executionContext, ThreadableLoaderClient* client) const { ThreadableLoaderOptions options; options.preflightPolicy = ConsiderPreflight; @@ -152,14 +153,14 @@ RefPtr<BlobDataHandle> m_blobDataHandle; Persistent<FetchBlobDataConsumerHandle::LoaderFactory> m_loaderFactory; - RefPtr<ThreadableLoader> m_loader; + OwnPtr<ThreadableLoader> m_loader; bool m_receivedResponse; }; class DefaultLoaderFactory final : public FetchBlobDataConsumerHandle::LoaderFactory { public: - PassRefPtr<ThreadableLoader> create( + PassOwnPtr<ThreadableLoader> create( ExecutionContext& executionContext, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options,
diff --git a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.h b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.h index f1d383d..2167b4b7 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.h +++ b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandle.h
@@ -24,7 +24,7 @@ public: class MODULES_EXPORT LoaderFactory : public GarbageCollectedFinalized<LoaderFactory> { public: - virtual PassRefPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&) = 0; + virtual PassOwnPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&) = 0; virtual ~LoaderFactory() { } DEFINE_INLINE_VIRTUAL_TRACE() { } };
diff --git a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandleTest.cpp b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandleTest.cpp index 9d98a616..fa67bd3 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandleTest.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchBlobDataConsumerHandleTest.cpp
@@ -18,6 +18,7 @@ #include "platform/testing/UnitTestHelpers.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "wtf/OwnPtr.h" #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" #include <string.h> @@ -51,7 +52,12 @@ class MockLoaderFactory : public FetchBlobDataConsumerHandle::LoaderFactory { public: - MOCK_METHOD4(create, PassRefPtr<ThreadableLoader>(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&)); + PassOwnPtr<ThreadableLoader> create(ExecutionContext& executionContext, ThreadableLoaderClient* client, const ThreadableLoaderOptions& threadableLoaderOptions, const ResourceLoaderOptions& resourceLoaderOptions) override + { + return adoptPtr(createInternal(executionContext, client, threadableLoaderOptions, resourceLoaderOptions)); + } + + MOCK_METHOD4(createInternal, ThreadableLoader*(ExecutionContext&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&)); }; PassRefPtr<BlobDataHandle> createBlobDataHandle(const char* s) @@ -93,17 +99,18 @@ ThreadableLoaderOptions options; ResourceLoaderOptions resourceLoaderOptions; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll( + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(DoAll( SaveArg<2>(&options), SaveArg<3>(&resourceLoaderOptions), - Return(loader.get()))); - EXPECT_CALL(*loader, start(_)).WillOnce(SaveArg<0>(&request)); + Return(loader.leakPtr()))); + EXPECT_CALL(*loaderPtr, start(_)).WillOnce(SaveArg<0>(&request)); EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); OwnPtr<WebDataConsumerHandle> handle @@ -137,14 +144,15 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(Return(loader.get())); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(Return(loader.leakPtr())); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); EXPECT_CALL(checkpoint, Call(3)); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); @@ -166,15 +174,16 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(Return(loader.get())); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(Return(loader.leakPtr())); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); EXPECT_CALL(checkpoint, Call(3)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); EXPECT_CALL(checkpoint, Call(4)); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); @@ -200,15 +209,16 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); ThreadableLoaderClient* client = nullptr; InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.get()))); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.leakPtr()))); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); OwnPtr<WebDataConsumerHandle> handle @@ -238,15 +248,16 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); ThreadableLoaderClient* client = nullptr; InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.get()))); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.leakPtr()))); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); OwnPtr<WebDataConsumerHandle> handle @@ -276,13 +287,14 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); ThreadableLoaderClient* client = nullptr; InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.get()))); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.leakPtr()))); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); @@ -305,15 +317,16 @@ auto factory = new StrictMock<MockLoaderFactory>; Checkpoint checkpoint; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + MockThreadableLoader* loaderPtr = loader.get(); ThreadableLoaderClient* client = nullptr; InSequence s; EXPECT_CALL(checkpoint, Call(1)); - EXPECT_CALL(*factory, create(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.get()))); - EXPECT_CALL(*loader, start(_)); + EXPECT_CALL(*factory, createInternal(Ref(document()), _, _, _)).WillOnce(DoAll(SaveArg<1>(&client), Return(loader.leakPtr()))); + EXPECT_CALL(*loaderPtr, start(_)); EXPECT_CALL(checkpoint, Call(2)); - EXPECT_CALL(*loader, cancel()); + EXPECT_CALL(*loaderPtr, cancel()); RefPtr<BlobDataHandle> blobDataHandle = createBlobDataHandle("Once upon a time"); OwnPtr<WebDataConsumerHandle> handle
diff --git a/third_party/WebKit/Source/modules/fetch/FetchFormDataConsumerHandleTest.cpp b/third_party/WebKit/Source/modules/fetch/FetchFormDataConsumerHandleTest.cpp index 208d70f4..cfad31f 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchFormDataConsumerHandleTest.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchFormDataConsumerHandleTest.cpp
@@ -15,6 +15,7 @@ #include "platform/weborigin/KURL.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" +#include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" @@ -52,11 +53,11 @@ explicit LoaderFactory(PassOwnPtr<WebDataConsumerHandle> handle) : m_client(nullptr) , m_handle(handle) {} - PassRefPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient* client, const ThreadableLoaderOptions&, const ResourceLoaderOptions&) override + PassOwnPtr<ThreadableLoader> create(ExecutionContext&, ThreadableLoaderClient* client, const ThreadableLoaderOptions&, const ResourceLoaderOptions&) override { m_client = client; - RefPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); + OwnPtr<MockThreadableLoader> loader = MockThreadableLoader::create(); EXPECT_CALL(*loader, start(_)).WillOnce(InvokeWithoutArgs(this, &LoaderFactory::handleDidReceiveResponse)); EXPECT_CALL(*loader, cancel()).Times(1); return loader.release();
diff --git a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp index b7a7331..4050ba6 100644 --- a/third_party/WebKit/Source/modules/fetch/FetchManager.cpp +++ b/third_party/WebKit/Source/modules/fetch/FetchManager.cpp
@@ -39,6 +39,7 @@ #include "platform/weborigin/SecurityPolicy.h" #include "public/platform/WebURLRequest.h" #include "wtf/HashSet.h" +#include "wtf/OwnPtr.h" #include "wtf/Vector.h" #include "wtf/text/WTFString.h" @@ -167,7 +168,7 @@ Member<FetchManager> m_fetchManager; Member<ScriptPromiseResolver> m_resolver; Member<FetchRequestData> m_request; - RefPtr<ThreadableLoader> m_loader; + OwnPtr<ThreadableLoader> m_loader; bool m_failed; bool m_finished; int m_responseHttpStatusCode;
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp index 8bb957d8..35fd590 100644 --- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp +++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerGlobalScope.cpp
@@ -78,7 +78,7 @@ } ServiceWorkerGlobalScope::ServiceWorkerGlobalScope(const KURL& url, const String& userAgent, ServiceWorkerThread* thread, double timeOrigin, PassOwnPtr<SecurityOrigin::PrivilegeData> starterOriginPrivilegeData, PassOwnPtrWillBeRawPtr<WorkerClients> workerClients) - : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients) + : WorkerGlobalScope(url, userAgent, thread, timeOrigin, starterOriginPrivilegeData, workerClients, true /* withInspector */) , m_didEvaluateScript(false) , m_hadErrorInTopLevelEventHandler(false) , m_eventNestingLevel(0)
diff --git a/third_party/WebKit/Source/platform/audio/AudioBus.cpp b/third_party/WebKit/Source/platform/audio/AudioBus.cpp index 2b29e70..677b3d7 100644 --- a/third_party/WebKit/Source/platform/audio/AudioBus.cpp +++ b/third_party/WebKit/Source/platform/audio/AudioBus.cpp
@@ -216,24 +216,9 @@ if (&sourceBus == this) return; - unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); - unsigned numberOfDestinationChannels = numberOfChannels(); - - if (numberOfDestinationChannels == numberOfSourceChannels) { - for (unsigned i = 0; i < numberOfSourceChannels; ++i) - channel(i)->copyFrom(sourceBus.channel(i)); - } else { - switch (channelInterpretation) { - case Speakers: - speakersCopyFrom(sourceBus); - break; - case Discrete: - discreteCopyFrom(sourceBus); - break; - default: - ASSERT_NOT_REACHED(); - } - } + // Copying bus is equivalent to zeroing and then summing. + zero(); + sumFrom(sourceBus, channelInterpretation); } void AudioBus::sumFrom(const AudioBus& sourceBus, ChannelInterpretation channelInterpretation) @@ -244,148 +229,26 @@ unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); unsigned numberOfDestinationChannels = numberOfChannels(); - if (numberOfDestinationChannels == numberOfSourceChannels) { + // If the channel numbers are equal, perform channels-wise summing. + if (numberOfSourceChannels == numberOfDestinationChannels) { for (unsigned i = 0; i < numberOfSourceChannels; ++i) channel(i)->sumFrom(sourceBus.channel(i)); - } else { - switch (channelInterpretation) { - case Speakers: - speakersSumFrom(sourceBus); - break; - case Discrete: - discreteSumFrom(sourceBus); - break; - default: - ASSERT_NOT_REACHED(); - } + + return; } -} -void AudioBus::speakersCopyFrom(const AudioBus& sourceBus) -{ - // FIXME: Implement down mixing 5.1 to stereo. - // https://bugs.webkit.org/show_bug.cgi?id=79192 - - unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); - unsigned numberOfDestinationChannels = numberOfChannels(); - - if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) { - // Handle mono -> stereo case (for now simply copy mono channel into both left and right) - // FIXME: Really we should apply an equal-power scaling factor here, since we're effectively panning center... - const AudioChannel* sourceChannel = sourceBus.channel(0); - channel(0)->copyFrom(sourceChannel); - channel(1)->copyFrom(sourceChannel); - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) { - // Handle stereo -> mono case. output = 0.5 * (input.L + input.R). - AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); - - const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); - const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); - - float* destination = channelByType(ChannelLeft)->mutableData(); - vadd(sourceL, 1, sourceR, 1, destination, 1, length()); - float scale = 0.5; - vsmul(destination, 1, &scale, destination, 1, length()); - } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) { - // Handle mono -> 5.1 case, copy mono channel to center. - channel(2)->copyFrom(sourceBus.channel(0)); - channel(0)->zero(); - channel(1)->zero(); - channel(3)->zero(); - channel(4)->zero(); - channel(5)->zero(); - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) { - // Handle 5.1 -> mono case. - zero(); - speakersSumFrom5_1_ToMono(sourceBus); - } else { - // Fallback for unknown combinations. - discreteCopyFrom(sourceBus); - } -} - -void AudioBus::speakersSumFrom(const AudioBus& sourceBus) -{ - // FIXME: Implement down mixing 5.1 to stereo. - // https://bugs.webkit.org/show_bug.cgi?id=79192 - - unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); - unsigned numberOfDestinationChannels = numberOfChannels(); - - if (numberOfDestinationChannels == 2 && numberOfSourceChannels == 1) { - // Handle mono -> stereo case (summing mono channel into both left and right). - const AudioChannel* sourceChannel = sourceBus.channel(0); - channel(0)->sumFrom(sourceChannel); - channel(1)->sumFrom(sourceChannel); - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 2) { - // Handle stereo -> mono case. output += 0.5 * (input.L + input.R). - AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); - - const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); - const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); - - float* destination = channelByType(ChannelLeft)->mutableData(); - float scale = 0.5; - vsma(sourceL, 1, &scale, destination, 1, length()); - vsma(sourceR, 1, &scale, destination, 1, length()); - } else if (numberOfDestinationChannels == 6 && numberOfSourceChannels == 1) { - // Handle mono -> 5.1 case, sum mono channel into center. - channel(2)->sumFrom(sourceBus.channel(0)); - } else if (numberOfDestinationChannels == 1 && numberOfSourceChannels == 6) { - // Handle 5.1 -> mono case. - speakersSumFrom5_1_ToMono(sourceBus); - } else { - // Fallback for unknown combinations. + // Otherwise perform up/down-mix or the discrete transfer based on the + // number of channels and the channel interpretation. + switch (channelInterpretation) { + case Speakers: + if (numberOfSourceChannels < numberOfDestinationChannels) + sumFromByUpMixing(sourceBus); + else + sumFromByDownMixing(sourceBus); + break; + case Discrete: discreteSumFrom(sourceBus); - } -} - -void AudioBus::speakersSumFrom5_1_ToMono(const AudioBus& sourceBus) -{ - AudioBus& sourceBusSafe = const_cast<AudioBus&>(sourceBus); - - const float* sourceL = sourceBusSafe.channelByType(ChannelLeft)->data(); - const float* sourceR = sourceBusSafe.channelByType(ChannelRight)->data(); - const float* sourceC = sourceBusSafe.channelByType(ChannelCenter)->data(); - const float* sourceSL = sourceBusSafe.channelByType(ChannelSurroundLeft)->data(); - const float* sourceSR = sourceBusSafe.channelByType(ChannelSurroundRight)->data(); - - float* destination = channelByType(ChannelLeft)->mutableData(); - - AudioFloatArray temp(length()); - float* tempData = temp.data(); - - // Sum in L and R. - vadd(sourceL, 1, sourceR, 1, tempData, 1, length()); - float scale = 0.7071; - vsmul(tempData, 1, &scale, tempData, 1, length()); - vadd(tempData, 1, destination, 1, destination, 1, length()); - - // Sum in SL and SR. - vadd(sourceSL, 1, sourceSR, 1, tempData, 1, length()); - scale = 0.5; - vsmul(tempData, 1, &scale, tempData, 1, length()); - vadd(tempData, 1, destination, 1, destination, 1, length()); - - // Sum in center. - vadd(sourceC, 1, destination, 1, destination, 1, length()); -} - -void AudioBus::discreteCopyFrom(const AudioBus& sourceBus) -{ - unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); - unsigned numberOfDestinationChannels = numberOfChannels(); - - if (numberOfDestinationChannels < numberOfSourceChannels) { - // Down-mix by copying channels and dropping the remaining. - for (unsigned i = 0; i < numberOfDestinationChannels; ++i) - channel(i)->copyFrom(sourceBus.channel(i)); - } else if (numberOfDestinationChannels > numberOfSourceChannels) { - // Up-mix by copying as many channels as we have, then zeroing remaining channels. - for (unsigned i = 0; i < numberOfSourceChannels; ++i) - channel(i)->copyFrom(sourceBus.channel(i)); - for (unsigned i = numberOfSourceChannels; i < numberOfDestinationChannels; ++i) - channel(i)->zero(); + break; } } @@ -405,6 +268,172 @@ } } +void AudioBus::sumFromByUpMixing(const AudioBus& sourceBus) +{ + unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); + unsigned numberOfDestinationChannels = numberOfChannels(); + + if ((numberOfSourceChannels == 1 && numberOfDestinationChannels == 2) || (numberOfSourceChannels == 1 && numberOfDestinationChannels == 4)) { + // Up-mixing: 1 -> 2, 1 -> 4 + // output.L = input + // output.R = input + // output.SL = 0 (in the case of 1 -> 4) + // output.SR = 0 (in the case of 1 -> 4) + const AudioChannel* sourceL = sourceBus.channelByType(ChannelLeft); + channelByType(ChannelLeft)->sumFrom(sourceL); + channelByType(ChannelRight)->sumFrom(sourceL); + } else if (numberOfSourceChannels == 1 && numberOfDestinationChannels == 6) { + // Up-mixing: 1 -> 5.1 + // output.L = 0 + // output.R = 0 + // output.C = input (put in center channel) + // output.LFE = 0 + // output.SL = 0 + // output.SR = 0 + channelByType(ChannelCenter)->sumFrom(sourceBus.channelByType(ChannelLeft)); + } else if ((numberOfSourceChannels == 2 && numberOfDestinationChannels == 4) || (numberOfSourceChannels == 2 && numberOfDestinationChannels == 6)) { + // Up-mixing: 2 -> 4, 2 -> 5.1 + // output.L = input.L + // output.R = input.R + // output.C = 0 (in the case of 2 -> 5.1) + // output.LFE = 0 (in the case of 2 -> 5.1) + // output.SL = 0 + // output.SR = 0 + channelByType(ChannelLeft)->sumFrom(sourceBus.channelByType(ChannelLeft)); + channelByType(ChannelRight)->sumFrom(sourceBus.channelByType(ChannelRight)); + } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 6) { + // Up-mixing: 4 -> 5.1 + // output.L = input.L + // output.R = input.R + // output.C = 0 + // output.LFE = 0 + // output.SL = input.SL + // output.SR = input.SR + channelByType(ChannelLeft)->sumFrom(sourceBus.channelByType(ChannelLeft)); + channelByType(ChannelRight)->sumFrom(sourceBus.channelByType(ChannelRight)); + channelByType(ChannelSurroundLeft)->sumFrom(sourceBus.channelByType(ChannelSurroundLeft)); + channelByType(ChannelSurroundRight)->sumFrom(sourceBus.channelByType(ChannelSurroundRight)); + } else { + // All other cases, fall back to the discrete sum. This will silence the + // excessive channels. + discreteSumFrom(sourceBus); + } +} + +void AudioBus::sumFromByDownMixing(const AudioBus& sourceBus) +{ + unsigned numberOfSourceChannels = sourceBus.numberOfChannels(); + unsigned numberOfDestinationChannels = numberOfChannels(); + + if (numberOfSourceChannels == 2 && numberOfDestinationChannels == 1) { + // Down-mixing: 2 -> 1 + // output = 0.5 * (input.L + input.R) + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + + float* destination = channelByType(ChannelLeft)->mutableData(); + float scale = 0.5; + + vsma(sourceL, 1, &scale, destination, 1, length()); + vsma(sourceR, 1, &scale, destination, 1, length()); + } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 1) { + // Down-mixing: 4 -> 1 + // output = 0.25 * (input.L + input.R + input.SL + input.SR) + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data(); + const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data(); + + float* destination = channelByType(ChannelLeft)->mutableData(); + float scale = 0.25; + + vsma(sourceL, 1, &scale, destination, 1, length()); + vsma(sourceR, 1, &scale, destination, 1, length()); + vsma(sourceSL, 1, &scale, destination, 1, length()); + vsma(sourceSR, 1, &scale, destination, 1, length()); + } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 1) { + // Down-mixing: 5.1 -> 1 + // output = sqrt(1/2) * (input.L + input.R) + input.C + // + 0.5 * (input.SL + input.SR) + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + const float* sourceC = sourceBus.channelByType(ChannelCenter)->data(); + const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data(); + const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data(); + + float* destination = channelByType(ChannelLeft)->mutableData(); + float scaleSqrtHalf = sqrtf(0.5); + float scaleHalf = 0.5; + + vsma(sourceL, 1, &scaleSqrtHalf, destination, 1, length()); + vsma(sourceR, 1, &scaleSqrtHalf, destination, 1, length()); + vadd(sourceC, 1, destination, 1, destination, 1, length()); + vsma(sourceSL, 1, &scaleHalf, destination, 1, length()); + vsma(sourceSR, 1, &scaleHalf, destination, 1, length()); + } else if (numberOfSourceChannels == 4 && numberOfDestinationChannels == 2) { + // Down-mixing: 4 -> 2 + // output.L = 0.5 * (input.L + input.SL) + // output.R = 0.5 * (input.R + input.SR) + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data(); + const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data(); + + float* destinationL = channelByType(ChannelLeft)->mutableData(); + float* destinationR = channelByType(ChannelRight)->mutableData(); + float scaleHalf = 0.5; + + vsma(sourceL, 1, &scaleHalf, destinationL, 1, length()); + vsma(sourceSL, 1, &scaleHalf, destinationL, 1, length()); + vsma(sourceR, 1, &scaleHalf, destinationR, 1, length()); + vsma(sourceSR, 1, &scaleHalf, destinationR, 1, length()); + } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 2) { + // Down-mixing: 5.1 -> 2 + // output.L = input.L + sqrt(1/2) * (input.C + input.SL) + // output.R = input.R + sqrt(1/2) * (input.C + input.SR) + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + const float* sourceC = sourceBus.channelByType(ChannelCenter)->data(); + const float* sourceSL = sourceBus.channelByType(ChannelSurroundLeft)->data(); + const float* sourceSR = sourceBus.channelByType(ChannelSurroundRight)->data(); + + float* destinationL = channelByType(ChannelLeft)->mutableData(); + float* destinationR = channelByType(ChannelRight)->mutableData(); + float scaleSqrtHalf = sqrtf(0.5); + + vadd(sourceL, 1, destinationL, 1, destinationL, 1, length()); + vsma(sourceC, 1, &scaleSqrtHalf, destinationL, 1, length()); + vsma(sourceSL, 1, &scaleSqrtHalf, destinationL, 1, length()); + vadd(sourceR, 1, destinationR, 1, destinationR, 1, length()); + vsma(sourceC, 1, &scaleSqrtHalf, destinationR, 1, length()); + vsma(sourceSR, 1, &scaleSqrtHalf, destinationR, 1, length()); + } else if (numberOfSourceChannels == 6 && numberOfDestinationChannels == 4) { + // Down-mixing: 5.1 -> 4 + // output.L = input.L + sqrt(1/2) * input.C + // output.R = input.R + sqrt(1/2) * input.C + // output.SL = input.SL + // output.SR = input.SR + const float* sourceL = sourceBus.channelByType(ChannelLeft)->data(); + const float* sourceR = sourceBus.channelByType(ChannelRight)->data(); + const float* sourceC = sourceBus.channelByType(ChannelCenter)->data(); + + float* destinationL = channelByType(ChannelLeft)->mutableData(); + float* destinationR = channelByType(ChannelRight)->mutableData(); + float scaleSqrtHalf = sqrtf(0.5); + + vadd(sourceL, 1, destinationL, 1, destinationL, 1, length()); + vsma(sourceC, 1, &scaleSqrtHalf, destinationL, 1, length()); + vadd(sourceR, 1, destinationR, 1, destinationR, 1, length()); + vsma(sourceC, 1, &scaleSqrtHalf, destinationR, 1, length()); + channel(2)->sumFrom(sourceBus.channel(4)); + channel(3)->sumFrom(sourceBus.channel(5)); + } else { + // All other cases, fall back to the discrete sum. This will perform + // channel-wise sum until the destination channels run out. + discreteSumFrom(sourceBus); + } +} + void AudioBus::copyWithGainFrom(const AudioBus &sourceBus, float* lastMixGain, float targetGain) { if (!topologyMatches(sourceBus)) {
diff --git a/third_party/WebKit/Source/platform/audio/AudioBus.h b/third_party/WebKit/Source/platform/audio/AudioBus.h index 5657f4f7..eb20236 100644 --- a/third_party/WebKit/Source/platform/audio/AudioBus.h +++ b/third_party/WebKit/Source/platform/audio/AudioBus.h
@@ -151,11 +151,12 @@ AudioBus(unsigned numberOfChannels, size_t length, bool allocate); - void speakersCopyFrom(const AudioBus&); - void discreteCopyFrom(const AudioBus&); - void speakersSumFrom(const AudioBus&); void discreteSumFrom(const AudioBus&); - void speakersSumFrom5_1_ToMono(const AudioBus&); + + // Up/down-mix by in-place summing upon the existing channel content. + // http://webaudio.github.io/web-audio-api/#channel-up-mixing-and-down-mixing + void sumFromByUpMixing(const AudioBus&); + void sumFromByDownMixing(const AudioBus&); size_t m_length; Vector<OwnPtr<AudioChannel>> m_channels;
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi index d6b7077..9e8e7a3 100644 --- a/third_party/WebKit/Source/platform/blink_platform.gypi +++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -832,6 +832,7 @@ 'inspector_protocol/Parser.h', 'inspector_protocol/FrontendChannel.h', 'inspector_protocol/String16.h', + 'inspector_protocol/String16WTF.cpp', 'inspector_protocol/String16WTF.h', 'inspector_protocol/Values.cpp', 'inspector_protocol/Values.h', @@ -1074,6 +1075,7 @@ 'v8_inspector/V8StringUtil.h', 'v8_inspector/public/V8EventListenerInfo.h', 'v8_inspector/public/V8ContentSearchUtil.h', + 'v8_inspector/public/V8ContextInfo.h', 'v8_inspector/public/V8Debugger.h', 'v8_inspector/public/V8DebuggerAgent.h', 'v8_inspector/public/V8DebuggerClient.h',
diff --git a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp index de0dcb6..7e9d0cf2 100644 --- a/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp +++ b/third_party/WebKit/Source/platform/graphics/BitmapImageTest.cpp
@@ -115,6 +115,16 @@ m_image->advanceAnimation(0); } + int repetitionCount() + { + return m_image->repetitionCount(true); + } + + int animationFinished() + { + return m_image->m_animationFinished; + } + PassRefPtr<Image> imageForDefaultFrame() { return m_image->imageForDefaultFrame(); @@ -167,6 +177,22 @@ EXPECT_FALSE(m_image->maybeAnimated()); } +TEST_F(BitmapImageTest, animationRepetitions) +{ + loadImage("/LayoutTests/fast/images/resources/full2loop.gif"); + int expectedRepetitionCount = 2; + EXPECT_EQ(expectedRepetitionCount, repetitionCount()); + + // We actually loop once more than stored repetition count. + for (int repeat = 0; repeat < expectedRepetitionCount + 1; ++repeat) { + for (size_t i = 0; i < frameCount(); ++i) { + EXPECT_FALSE(animationFinished()); + advanceAnimation(); + } + } + EXPECT_TRUE(animationFinished()); +} + TEST_F(BitmapImageTest, isAllDataReceived) { RefPtr<SharedBuffer> imageData = readFile("/LayoutTests/fast/images/resources/green.jpg");
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.cpp b/third_party/WebKit/Source/platform/graphics/Gradient.cpp index e59ebf7..9736e023 100644 --- a/third_party/WebKit/Source/platform/graphics/Gradient.cpp +++ b/third_party/WebKit/Source/platform/graphics/Gradient.cpp
@@ -84,7 +84,7 @@ } m_stops.append(stop); - m_gradient.reset(); + m_gradient.clear(); } void Gradient::sortStopsIfNecessary() @@ -117,7 +117,7 @@ return; m_drawInPMColorSpace = drawInPMColorSpace; - m_gradient.reset(); + m_gradient.clear(); } void Gradient::setGradientSpaceTransform(const AffineTransform& gradientSpaceTransformation) @@ -126,7 +126,7 @@ return; m_gradientSpaceTransformation = gradientSpaceTransformation; - m_gradient.reset(); + m_gradient.clear(); } // Determine the total number of stops needed, including pseudo-stops at the @@ -189,10 +189,10 @@ } } -sk_sp<SkShader> Gradient::shader() +SkShader* Gradient::shader() { if (m_gradient) - return m_gradient; + return m_gradient.get(); sortStopsIfNecessary(); ASSERT(m_stopsSorted); @@ -233,25 +233,25 @@ // Since the two-point radial gradient is slower than the plain radial, // only use it if we have to. if (m_p0 == m_p1 && m_r0 <= 0.0f) { - m_gradient = SkGradientShader::MakeRadial(m_p1.data(), m_r1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix); + m_gradient = adoptRef(SkGradientShader::CreateRadial(m_p1.data(), m_r1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } else { // The radii we give to Skia must be positive. If we're given a // negative radius, ask for zero instead. SkScalar radius0 = m_r0 >= 0.0f ? WebCoreFloatToSkScalar(m_r0) : 0; SkScalar radius1 = m_r1 >= 0.0f ? WebCoreFloatToSkScalar(m_r1) : 0; - m_gradient = SkGradientShader::MakeTwoPointConical(m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix); + m_gradient = adoptRef(SkGradientShader::CreateTwoPointConical(m_p0.data(), radius0, m_p1.data(), radius1, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } } else { SkPoint pts[2] = { m_p0.data(), m_p1.data() }; SkMatrix localMatrix = affineTransformToSkMatrix(m_gradientSpaceTransformation); - m_gradient = SkGradientShader::MakeLinear(pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix); + m_gradient = adoptRef(SkGradientShader::CreateLinear(pts, colors.data(), pos.data(), static_cast<int>(countUsed), tile, shouldDrawInPMColorSpace, &localMatrix)); } if (!m_gradient) { // use last color, since our "geometry" was degenerate (e.g. radius==0) - m_gradient = SkShader::MakeColorShader(colors[countUsed - 1]); + m_gradient = adoptRef(SkShader::CreateColorShader(colors[countUsed - 1])); } - return m_gradient; + return m_gradient.get(); } void Gradient::applyToPaint(SkPaint& paint)
diff --git a/third_party/WebKit/Source/platform/graphics/Gradient.h b/third_party/WebKit/Source/platform/graphics/Gradient.h index 0a43ecb..49e0f740 100644 --- a/third_party/WebKit/Source/platform/graphics/Gradient.h +++ b/third_party/WebKit/Source/platform/graphics/Gradient.h
@@ -34,10 +34,10 @@ #include "platform/graphics/Color.h" #include "platform/graphics/GraphicsTypes.h" #include "platform/transforms/AffineTransform.h" -#include "third_party/skia/include/core/SkRefCnt.h" #include "wtf/Noncopyable.h" #include "wtf/PassRefPtr.h" #include "wtf/RefCounted.h" +#include "wtf/RefPtr.h" #include "wtf/Vector.h" class SkPaint; @@ -126,7 +126,7 @@ Gradient(const FloatPoint& p0, const FloatPoint& p1); Gradient(const FloatPoint& p0, float r0, const FloatPoint& p1, float r1, float aspectRatio); - sk_sp<SkShader> shader(); + SkShader* shader(); void destroyShader(); void sortStopsIfNecessary(); @@ -143,7 +143,7 @@ GradientSpreadMethod m_spreadMethod; AffineTransform m_gradientSpaceTransformation; - sk_sp<SkShader> m_gradient; + RefPtr<SkShader> m_gradient; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp index 7826b23..55a6b12e 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -635,10 +635,11 @@ SkMatrix localMatrix; localMatrix.setTranslate(originX, originY); + RefPtr<SkShader> shader = adoptRef(SkShader::CreateBitmapShader( + *misspellBitmap[index], SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); SkPaint paint; - paint.setShader(SkShader::MakeBitmapShader(*misspellBitmap[index], - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); + paint.setShader(shader.get()); SkRect rect; rect.set(originX, originY, originX + WebCoreFloatToSkScalar(width) * deviceScaleFactor, originY + SkIntToScalar(misspellBitmap[index]->height()));
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp index 7d4ae14..36e0b9d 100644 --- a/third_party/WebKit/Source/platform/graphics/Image.cpp +++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -185,11 +185,11 @@ namespace { -sk_sp<SkShader> createPatternShader(const SkImage* image, const SkMatrix& shaderMatrix, +PassRefPtr<SkShader> createPatternShader(const SkImage* image, const SkMatrix& shaderMatrix, const SkPaint& paint, const FloatSize& spacing) { if (spacing.isZero()) - return image->makeShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix); + return adoptRef(image->newShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix)); // Arbitrary tiling is currently only supported for SkPictureShader - so we use it instead // of a plain bitmap shader to implement spacing. @@ -200,10 +200,10 @@ SkPictureRecorder recorder; SkCanvas* canvas = recorder.beginRecording(tileRect); canvas->drawImage(image, 0, 0, &paint); - sk_sp<SkPicture> picture(recorder.endRecordingAsPicture()); + RefPtr<const SkPicture> picture = adoptRef(recorder.endRecordingAsPicture()); - return SkShader::MakePictureShader( - std::move(picture), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix, nullptr); + return adoptRef(SkShader::CreatePictureShader( + picture.get(), SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &shaderMatrix, nullptr)); } } // anonymous namespace @@ -249,8 +249,9 @@ paint.setXfermodeMode(compositeOp); paint.setFilterQuality(context.computeFilterQuality(this, destRect, normSrcRect)); paint.setAntiAlias(context.shouldAntialias()); - paint.setShader(createPatternShader(image.get(), localMatrix, paint, - FloatSize(repeatSpacing.width() / scale.width(), repeatSpacing.height() / scale.height()))); + RefPtr<SkShader> shader = createPatternShader(image.get(), localMatrix, paint, + FloatSize(repeatSpacing.width() / scale.width(), repeatSpacing.height() / scale.height())); + paint.setShader(shader.get()); context.drawRect(destRect, paint); }
diff --git a/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp b/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp index a11609e..32f4aa9 100644 --- a/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp +++ b/third_party/WebKit/Source/platform/graphics/ImagePattern.cpp
@@ -30,16 +30,16 @@ } } -sk_sp<SkShader> ImagePattern::createShader() +PassRefPtr<SkShader> ImagePattern::createShader() { if (!m_tileImage) - return SkShader::MakeColorShader(SK_ColorTRANSPARENT); + return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation); if (isRepeatXY()) { // Fast path: for repeatXY we just return a shader from the original image. - return sk_sp<SkShader>(m_tileImage->newShader(SkShader::kRepeat_TileMode, + return adoptRef(m_tileImage->newShader(SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix)); } @@ -61,7 +61,7 @@ RefPtr<SkSurface> surface = adoptRef(SkSurface::NewRasterN32Premul( m_tileImage->width() + expandW, m_tileImage->height() + expandH)); if (!surface) - return SkShader::MakeColorShader(SK_ColorTRANSPARENT); + return adoptRef(SkShader::CreateColorShader(SK_ColorTRANSPARENT)); surface->getCanvas()->clear(SK_ColorTRANSPARENT); SkPaint paint; @@ -69,7 +69,7 @@ surface->getCanvas()->drawImage(m_tileImage.get(), 0, 0, &paint); RefPtr<SkImage> expandedImage = adoptRef(surface->newImageSnapshot()); - return sk_sp<SkShader>(expandedImage->newShader(tileModeX, tileModeY, &localMatrix)); + return adoptRef(expandedImage->newShader(tileModeX, tileModeY, &localMatrix)); } bool ImagePattern::isTextureBacked() const
diff --git a/third_party/WebKit/Source/platform/graphics/ImagePattern.h b/third_party/WebKit/Source/platform/graphics/ImagePattern.h index 2dcee62..d8315c2 100644 --- a/third_party/WebKit/Source/platform/graphics/ImagePattern.h +++ b/third_party/WebKit/Source/platform/graphics/ImagePattern.h
@@ -20,7 +20,7 @@ bool isTextureBacked() const override; protected: - sk_sp<SkShader> createShader() override; + PassRefPtr<SkShader> createShader() override; private: ImagePattern(PassRefPtr<Image>, RepeatMode);
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/third_party/WebKit/Source/platform/graphics/Pattern.cpp index ae725b4..ce773d5 100644 --- a/third_party/WebKit/Source/platform/graphics/Pattern.cpp +++ b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
@@ -65,7 +65,7 @@ m_pattern = createShader(); } - paint.setShader(m_pattern); + paint.setShader(m_pattern.get()); } void Pattern::setPatternSpaceTransform(const AffineTransform& patternSpaceTransformation) @@ -74,7 +74,7 @@ return; m_patternSpaceTransformation = patternSpaceTransformation; - m_pattern.reset(); + m_pattern.clear(); } void Pattern::adjustExternalMemoryAllocated(int64_t delta)
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.h b/third_party/WebKit/Source/platform/graphics/Pattern.h index a855cca..c2068ea 100644 --- a/third_party/WebKit/Source/platform/graphics/Pattern.h +++ b/third_party/WebKit/Source/platform/graphics/Pattern.h
@@ -32,11 +32,11 @@ #include "platform/PlatformExport.h" #include "platform/graphics/Image.h" #include "platform/transforms/AffineTransform.h" -#include "third_party/skia/include/core/SkRefCnt.h" #include "wtf/Noncopyable.h" #include "wtf/PassRefPtr.h" #include "wtf/RefCounted.h" +#include "wtf/RefPtr.h" class SkPaint; class SkPicture; @@ -71,7 +71,7 @@ virtual bool isTextureBacked() const { return false; } protected: - virtual sk_sp<SkShader> createShader() = 0; + virtual PassRefPtr<SkShader> createShader() = 0; void adjustExternalMemoryAllocated(int64_t delta); @@ -81,7 +81,7 @@ Pattern(RepeatMode, int64_t externalMemoryAllocated = 0); private: - sk_sp<SkShader> m_pattern; + RefPtr<SkShader> m_pattern; int64_t m_externalMemoryAllocated; };
diff --git a/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp b/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp index f01e6b3..728a27e 100644 --- a/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp +++ b/third_party/WebKit/Source/platform/graphics/PicturePattern.cpp
@@ -18,7 +18,7 @@ PicturePattern::PicturePattern(PassRefPtr<const SkPicture> picture, RepeatMode mode) : Pattern(mode) - , m_tilePicture(const_cast<SkPicture*>(picture.leakRef())) + , m_tilePicture(picture) { // All current clients use RepeatModeXY, so we only support this mode for now. ASSERT(isRepeatXY()); @@ -30,13 +30,13 @@ { } -sk_sp<SkShader> PicturePattern::createShader() +PassRefPtr<SkShader> PicturePattern::createShader() { SkMatrix localMatrix = affineTransformToSkMatrix(m_patternSpaceTransformation); SkRect tileBounds = m_tilePicture->cullRect(); - return SkShader::MakePictureShader(m_tilePicture, - SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix, &tileBounds); + return adoptRef(SkShader::CreatePictureShader(m_tilePicture.get(), + SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &localMatrix, &tileBounds)); } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/PicturePattern.h b/third_party/WebKit/Source/platform/graphics/PicturePattern.h index d4266fa..1ae4d28 100644 --- a/third_party/WebKit/Source/platform/graphics/PicturePattern.h +++ b/third_party/WebKit/Source/platform/graphics/PicturePattern.h
@@ -16,12 +16,12 @@ ~PicturePattern() override; protected: - sk_sp<SkShader> createShader() override; + PassRefPtr<SkShader> createShader() override; private: PicturePattern(PassRefPtr<const SkPicture>, RepeatMode); - sk_sp<SkPicture> m_tilePicture; + RefPtr<const SkPicture> m_tilePicture; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp index e57cbef..92d0d58 100644 --- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp +++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp
@@ -499,4 +499,21 @@ } } +TEST(GIFImageDecoderTest, verifyRepetitionCount) +{ + const int expectedRepetitionCount = 2; + OwnPtr<ImageDecoder> decoder = createDecoder(); + RefPtr<SharedBuffer> data = readFile(layoutTestResourcesDir, "full2loop.gif"); + ASSERT_TRUE(data.get()); + decoder->setData(data.get(), true); + EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount()); // Default value before decode. + + for (size_t i = 0; i < decoder->frameCount(); ++i) { + ImageFrame* frame = decoder->frameBufferAtIndex(i); + EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus()); + } + + EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); // Expected value after decode. +} + } // namespace blink
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/Array.h b/third_party/WebKit/Source/platform/inspector_protocol/Array.h index 087f848b..27bb6b2 100644 --- a/third_party/WebKit/Source/platform/inspector_protocol/Array.h +++ b/third_party/WebKit/Source/platform/inspector_protocol/Array.h
@@ -33,7 +33,7 @@ errors->push(); OwnPtr<Array<T>> result = adoptPtr(new Array<T>()); for (size_t i = 0; i < array->size(); ++i) { - errors->setName("[" + String16::number(i) + "]"); + errors->setName(String16::number(i)); T item = FromValue<T>::parse(array->at(i), errors); result->m_vector.append(item); } @@ -94,7 +94,7 @@ OwnPtr<Array<T>> result = adoptPtr(new Array<T>()); errors->push(); for (size_t i = 0; i < array->size(); ++i) { - errors->setName("[" + String16::number(i) + "]"); + errors->setName(String16::number(i)); OwnPtr<T> item = FromValue<T>::parse(array->at(i), errors); result->m_vector.append(item.release()); }
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/ErrorSupport.cpp b/third_party/WebKit/Source/platform/inspector_protocol/ErrorSupport.cpp index 0b36009..f27feff 100644 --- a/third_party/WebKit/Source/platform/inspector_protocol/ErrorSupport.cpp +++ b/third_party/WebKit/Source/platform/inspector_protocol/ErrorSupport.cpp
@@ -13,8 +13,12 @@ ErrorSupport::ErrorSupport(String16* errorString) : m_errorString(errorString) { } ErrorSupport::~ErrorSupport() { - if (m_errorString && hasErrors()) - *m_errorString = "Internal error(s): " + errors(); + if (m_errorString && hasErrors()) { + String16Builder builder; + builder.append("Internal error(s): "); + builder.append(errors()); + *m_errorString = builder.toString(); + } } void ErrorSupport::setName(const String16& name)
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/Parser.cpp b/third_party/WebKit/Source/platform/inspector_protocol/Parser.cpp index 3495255..6e79ed2b 100644 --- a/third_party/WebKit/Source/platform/inspector_protocol/Parser.cpp +++ b/third_party/WebKit/Source/platform/inspector_protocol/Parser.cpp
@@ -33,8 +33,7 @@ const char* const trueString = "true"; const char* const falseString = "false"; -template<typename CharType> -bool parseConstToken(const CharType* start, const CharType* end, const CharType** tokenEnd, const char* token) +bool parseConstToken(const UChar* start, const UChar* end, const UChar** tokenEnd, const char* token) { while (start < end && *token != '\0' && *start++ == *token++) { } if (*token != '\0') @@ -43,8 +42,7 @@ return true; } -template<typename CharType> -bool readInt(const CharType* start, const CharType* end, const CharType** tokenEnd, bool canHaveLeadingZeros) +bool readInt(const UChar* start, const UChar* end, const UChar** tokenEnd, bool canHaveLeadingZeros) { if (start == end) return false; @@ -62,14 +60,13 @@ return true; } -template<typename CharType> -bool parseNumberToken(const CharType* start, const CharType* end, const CharType** tokenEnd) +bool parseNumberToken(const UChar* start, const UChar* end, const UChar** tokenEnd) { // We just grab the number here. We validate the size in DecodeNumber. // According to RFC4627, a valid number is: [minus] int [frac] [exp] if (start == end) return false; - CharType c = *start; + UChar c = *start; if ('-' == c) ++start; @@ -112,13 +109,12 @@ return true; } -template<typename CharType> -bool readHexDigits(const CharType* start, const CharType* end, const CharType** tokenEnd, int digits) +bool readHexDigits(const UChar* start, const UChar* end, const UChar** tokenEnd, int digits) { if (end - start < digits) return false; for (int i = 0; i < digits; ++i) { - CharType c = *start++; + UChar c = *start++; if (!(('0' <= c && c <= '9') || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'))) return false; } @@ -126,11 +122,10 @@ return true; } -template<typename CharType> -bool parseStringToken(const CharType* start, const CharType* end, const CharType** tokenEnd) +bool parseStringToken(const UChar* start, const UChar* end, const UChar** tokenEnd) { while (start < end) { - CharType c = *start++; + UChar c = *start++; if ('\\' == c) { c = *start++; // Make sure the escaped char is valid. @@ -164,8 +159,7 @@ return false; } -template<typename CharType> -bool skipComment(const CharType* start, const CharType* end, const CharType** commentEnd) +bool skipComment(const UChar* start, const UChar* end, const UChar** commentEnd) { if (start == end) return false; @@ -188,7 +182,7 @@ } if (*start == '*') { - CharType previous = '\0'; + UChar previous = '\0'; // Block comment, read until end marker. for (++start; start < end; previous = *start++) { if (previous == '*' && *start == '/') { @@ -203,14 +197,13 @@ return false; } -template<typename CharType> -void skipWhitespaceAndComments(const CharType* start, const CharType* end, const CharType** whitespaceEnd) +void skipWhitespaceAndComments(const UChar* start, const UChar* end, const UChar** whitespaceEnd) { while (start < end) { if (isSpaceOrNewline(*start)) { ++start; } else if (*start == '/') { - const CharType* commentEnd; + const UChar* commentEnd; if (!skipComment(start, end, &commentEnd)) break; start = commentEnd; @@ -221,8 +214,7 @@ *whitespaceEnd = start; } -template<typename CharType> -Token parseToken(const CharType* start, const CharType* end, const CharType** tokenStart, const CharType** tokenEnd) +Token parseToken(const UChar* start, const UChar* end, const UChar** tokenStart, const UChar** tokenEnd) { skipWhitespaceAndComments(start, end, tokenStart); start = *tokenStart; @@ -283,8 +275,7 @@ return InvalidToken; } -template<typename CharType> -inline int hexToInt(CharType c) +inline int hexToInt(UChar c) { if ('0' <= c && c <= '9') return c - '0'; @@ -296,52 +287,7 @@ return 0; } -template<typename CharType> -bool decodeUTF8(const CharType* start, const CharType* end, const CharType** utf8charEnd, String16Builder* output) -{ - UChar utf16[4] = {0}; - char utf8[6] = {0}; - size_t utf8count = 0; - - while (start < end) { - if (start + 1 >= end || *start != '\\' || *(start + 1) != 'x') - return false; - start += 2; - - // Accumulate one more utf8 character and try converting to utf16. - if (start + 1 >= end) - return false; - utf8[utf8count++] = (hexToInt(*start) << 4) + hexToInt(*(start + 1)); - start += 2; - - const char* utf8start = utf8; - UChar* utf16start = utf16; - String16::ConversionResult conversionResult = String16::convertUTF8ToUTF16(&utf8start, utf8start + utf8count, &utf16start, utf16start + 4, nullptr, true); - - if (conversionResult == String16::sourceIllegal) - return false; - - if (conversionResult == String16::conversionOK) { - // Not all utf8 characters were consumed - failed parsing. - if (utf8start != utf8 + utf8count) - return false; - - size_t utf16length = utf16start - utf16; - output->append(utf16, utf16length); - *utf8charEnd = start; - return true; - } - - // Keep accumulating utf8 characters up to buffer length (6 should be enough). - if (utf8count >= 6) - return false; - } - - return false; -} - -template<typename CharType> -bool decodeString(const CharType* start, const CharType* end, String16Builder* output) +bool decodeString(const UChar* start, const UChar* end, String16Builder* output) { while (start < end) { UChar c = *start++; @@ -352,10 +298,8 @@ c = *start++; if (c == 'x') { - // Rewind "\x". - if (!decodeUTF8(start - 2, end, &start, output)) - return false; - continue; + // \x is not supported. + return false; } switch (c) { @@ -396,8 +340,7 @@ return true; } -template<typename CharType> -bool decodeString(const CharType* start, const CharType* end, String16* output) +bool decodeString(const UChar* start, const UChar* end, String16* output) { if (start == end) { *output = ""; @@ -410,21 +353,17 @@ if (!decodeString(start, end, &buffer)) return false; *output = buffer.toString(); - // Validate constructed utf16 string. - if (!output->validateUTF8()) - return false; return true; } -template<typename CharType> -PassOwnPtr<Value> buildValue(const CharType* start, const CharType* end, const CharType** valueTokenEnd, int depth) +PassOwnPtr<Value> buildValue(const UChar* start, const UChar* end, const UChar** valueTokenEnd, int depth) { if (depth > stackLimit) return nullptr; OwnPtr<Value> result; - const CharType* tokenStart; - const CharType* tokenEnd; + const UChar* tokenStart; + const UChar* tokenEnd; Token token = parseToken(start, end, &tokenStart, &tokenEnd); switch (token) { case InvalidToken: @@ -533,11 +472,10 @@ return result.release(); } -template<typename CharType> -PassOwnPtr<Value> parseJSONInternal(const CharType* start, unsigned length) +PassOwnPtr<Value> parseJSONInternal(const UChar* start, unsigned length) { - const CharType* end = start + length; - const CharType *tokenEnd; + const UChar* end = start + length; + const UChar *tokenEnd; OwnPtr<Value> value = buildValue(start, end, &tokenEnd, 0); if (!value || tokenEnd != end) return nullptr; @@ -550,8 +488,6 @@ { if (json.isEmpty()) return nullptr; - if (json.is8Bit()) - return parseJSONInternal(json.characters8(), json.length()); return parseJSONInternal(json.characters16(), json.length()); }
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/ParserTest.cpp b/third_party/WebKit/Source/platform/inspector_protocol/ParserTest.cpp index 6f4d5c7..b6bbf01 100644 --- a/third_party/WebKit/Source/platform/inspector_protocol/ParserTest.cpp +++ b/third_party/WebKit/Source/platform/inspector_protocol/ParserTest.cpp
@@ -226,21 +226,13 @@ // Test hex and unicode escapes including the null character. root = parseJSON("\"\\x41\\x00\\u1234\""); - ASSERT_TRUE(root.get()); - EXPECT_EQ(Value::TypeString, root->type()); - EXPECT_TRUE(root->asString(&strVal)); - UChar tmp1[] = {0x41, 0, 0x1234}; - EXPECT_EQ(String16(tmp1, 3), strVal); + EXPECT_FALSE(root.get()); // Test invalid strings root = parseJSON("\"no closing quote"); EXPECT_FALSE(root.get()); root = parseJSON("\"\\z invalid escape char\""); EXPECT_FALSE(root.get()); - root = parseJSON("\"\\xAQ invalid hex code\""); - EXPECT_FALSE(root.get()); - root = parseJSON("not enough hex chars\\x1\""); - EXPECT_FALSE(root.get()); root = parseJSON("\"not enough escape chars\\u123\""); EXPECT_FALSE(root.get()); root = parseJSON("\"extra backslash at end of input\\\""); @@ -314,7 +306,7 @@ ASSERT_TRUE(root.get()); EXPECT_EQ(Value::TypeObject, root->type()); - root = parseJSON("{\"number\":9.87654321, \"null\":null , \"\\x53\" : \"str\" }"); + root = parseJSON("{\"number\":9.87654321, \"null\":null , \"S\" : \"str\" }"); ASSERT_TRUE(root.get()); EXPECT_EQ(Value::TypeObject, root->type()); protocol::DictionaryValue* objectVal = DictionaryValue::cast(root.get()); @@ -333,7 +325,7 @@ "{\n" " \"number\":9.87654321,\n" " \"null\":null,\n" - " \"\\x53\":\"str\"\n" + " \"S\":\"str\"\n" "}\n"); ASSERT_TRUE(root2.get()); EXPECT_EQ(root->toJSONString(), root2->toJSONString()); @@ -342,7 +334,7 @@ "{\r\n" " \"number\":9.87654321,\r\n" " \"null\":null,\r\n" - " \"\\x53\":\"str\"\r\n" + " \"S\":\"str\"\r\n" "}\r\n"); ASSERT_TRUE(root2.get()); EXPECT_EQ(root->toJSONString(), root2->toJSONString()); @@ -449,27 +441,6 @@ // Test utf8 encoded input root = parseJSON("\"\\xe7\\xbd\\x91\\xe9\\xa1\\xb5\""); - ASSERT_TRUE(root.get()); - EXPECT_EQ(Value::TypeString, root->type()); - EXPECT_TRUE(root->asString(&strVal)); - UChar tmp4[] = {0x7f51, 0x9875}; - EXPECT_EQ(String16(tmp4, 2), strVal); - - root = parseJSON("{\"path\": \"/tmp/\\xc3\\xa0\\xc3\\xa8\\xc3\\xb2.png\"}"); - ASSERT_TRUE(root.get()); - EXPECT_EQ(Value::TypeObject, root->type()); - objectVal = DictionaryValue::cast(root.get()); - ASSERT_TRUE(objectVal); - EXPECT_TRUE(objectVal->getString("path", &strVal)); - UChar tmp5[] = {0x2f, 0x74, 0x6d, 0x70, 0x2f, 0xe0, 0xe8, 0xf2, 0x2e, 0x70, 0x6e, 0x67}; - EXPECT_EQ(String16(tmp5, 12), strVal); - - // Test invalid utf8 encoded input - root = parseJSON("\"345\\xb0\\xa1\\xb0\\xa2\""); - ASSERT_FALSE(root.get()); - root = parseJSON("\"123\\xc0\\x81\""); - ASSERT_FALSE(root.get()); - root = parseJSON("\"abc\\xc0\\xae\""); ASSERT_FALSE(root.get()); // Test utf16 encoded strings. @@ -487,22 +458,6 @@ UChar tmp3[] = {0xd83d, 0xdca9, 0xd83d, 0xdc6c}; EXPECT_EQ(String16(tmp3, 4), strVal); - // Test invalid utf16 strings. - const char* const cases[] = { - "\"\\u123\"", // Invalid scalar. - "\"\\ud83d\"", // Invalid scalar. - "\"\\u$%@!\"", // Invalid scalar. - "\"\\uzz89\"", // Invalid scalar. - "\"\\ud83d\\udca\"", // Invalid lower surrogate. - "\"\\ud83d\\ud83d\"", // Invalid lower surrogate. - "\"\\ud83foo\"", // No lower surrogate. - "\"\\ud83\\foo\"" // No lower surrogate. - }; - for (size_t i = 0; i < 8; ++i) { - root = parseJSON(cases[i]); - EXPECT_FALSE(root.get()) << cases[i]; - } - // Test literal root objects. root = parseJSON("null"); EXPECT_EQ(Value::TypeNull, root->type());
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.cpp b/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.cpp new file mode 100644 index 0000000..387ecc3 --- /dev/null +++ b/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.cpp
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform/inspector_protocol/String16WTF.h" + +namespace blink { +namespace protocol { + +String16::String16(const String16& other) : m_impl(other.m_impl) { } + +String16::String16(const UChar* u, unsigned length) : m_impl(u, length) { } + +String16::String16(const char* characters) : String16(characters, strlen(characters)) { } + +String16::String16(const WTF::String& other) +{ + if (other.isNull()) + return; + if (!other.is8Bit()) { + m_impl = other; + return; + } + + UChar* data; + const LChar* characters = other.characters8(); + size_t length = other.length(); + m_impl = String::createUninitialized(length, data); + for (size_t i = 0; i < length; ++i) + data[i] = characters[i]; +} + +String16::String16(const char* characters, size_t length) +{ + UChar* data; + m_impl = String::createUninitialized(length, data); + for (size_t i = 0; i < length; ++i) + data[i] = characters[i]; +} + +String16 String16::createUninitialized(unsigned length, UChar*& data) +{ + return String::createUninitialized(length, data); +} + +} // namespace protocol +} // namespace blink
diff --git a/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.h b/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.h index f34ebb6..b48162c 100644 --- a/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.h +++ b/third_party/WebKit/Source/platform/inspector_protocol/String16WTF.h
@@ -10,93 +10,56 @@ #include "wtf/text/StringBuilder.h" #include "wtf/text/StringConcatenate.h" #include "wtf/text/StringHash.h" -#include "wtf/text/UTF8.h" #include "wtf/text/WTFString.h" namespace blink { namespace protocol { -class String16 { +class PLATFORM_EXPORT String16 { public: String16() { } - String16(const String16& other) : m_impl(other.m_impl) { } - String16(const UChar* u, unsigned length) : m_impl(u, length) { } - String16(const char* characters) : m_impl(characters) { } - String16(const char* characters, size_t size) : m_impl(characters, size) { } - String16(const WebString& other) : m_impl(other) { } + String16(const String16& other); + String16(const UChar*, unsigned); + String16(const char*); + String16(const char*, size_t); + static String16 createUninitialized(unsigned length, UChar*& data); + + // WTF convenience constructors and helper methods. + String16(const WebString& other) : String16(String(other)) { } template<typename StringType1, typename StringType2> - String16(const WTF::StringAppend<StringType1, StringType2>& impl) : m_impl(impl) { } + String16(const WTF::StringAppend<StringType1, StringType2>& impl) : String16(String(impl)) { } + String16(const WTF::AtomicString& impl) : String16(String(impl)) { } + String16(const WTF::String& impl); + String16(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } + bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } + operator WTF::String() const { return m_impl; } + operator WebString() { return m_impl; } + const WTF::String& impl() const { return m_impl; } + ~String16() { } - // Integration constructors. - String16(const WTF::String& impl) : m_impl(impl) { } - String16(const WTF::AtomicString& impl) : m_impl(impl) { } - String16(WTF::HashTableDeletedValueType) : m_impl(WTF::HashTableDeletedValue) { } - - static String16 fromUTF8(const char* characters, size_t length) { return String::fromUTF8(characters, length); } static String16 number(int i) { return String::number(i); } static String16 fromDouble(double number) { return Decimal::fromDouble(number).toString(); } - static String16 createUninitialized(unsigned length, UChar*& data) { return String::createUninitialized(length, data); } - static bool codePointCompareLessThan(const String16& a, const String16& b) - { - return codePointCompare(a.impl(), b.impl()) < 0; - } - - typedef enum { - conversionOK, - sourceExhausted, - targetExhausted, - sourceIllegal - } ConversionResult; - - static ConversionResult convertUTF8ToUTF16(const char** sourceStart, const char* sourceEnd, UChar** targetStart, UChar* targetEnd, bool* isSourceAllASCII = 0, bool strict = true) - { - return static_cast<ConversionResult>(WTF::Unicode::convertUTF8ToUTF16(sourceStart, sourceEnd, targetStart, targetEnd, isSourceAllASCII, strict)); - } - - bool validateUTF8() - { - return !m_impl.utf8(StrictUTF8Conversion).isNull(); - } size_t length() const { return m_impl.length(); } bool isEmpty() const { return m_impl.isEmpty(); } - bool isNull() const { return m_impl.isNull(); } UChar operator[](unsigned index) const { return m_impl[index]; } - bool is8Bit() const { return m_impl.is8Bit(); } unsigned sizeInBytes() const { return m_impl.sizeInBytes(); } - const LChar* characters8() const { return m_impl.characters8(); } - const UChar* characters16() const { return m_impl.characters16(); } - String16 latin1Data() - { - CString latin1 = m_impl.latin1(); - // Include terminating zero. - return String16(latin1.data(), latin1.length() + 1); - } - - operator WTF::String() const { return m_impl; } - operator WebString() const { return m_impl; } - WTF::String impl() const { return m_impl; } + const UChar* characters16() const { return m_impl.isEmpty() ? nullptr : m_impl.characters16(); } static double charactersToDouble(const LChar* characters, size_t length, bool* ok = 0) { return ::charactersToDouble(characters, length, ok); } static double charactersToDouble(const UChar* characters, size_t length, bool* ok = 0) { return ::charactersToDouble(characters, length, ok); } String16 substring(unsigned pos, unsigned len = UINT_MAX) const { return m_impl.substring(pos, len); } - String16 left(unsigned len) const { return m_impl.substring(0, len); } String16 stripWhiteSpace() const { return m_impl.stripWhiteSpace(); } int toInt(bool* ok = 0) const { return m_impl.toInt(ok); } - unsigned toUInt(bool* ok = 0) const { return m_impl.toUInt(ok); } size_t find(UChar c, unsigned start = 0) const { return m_impl.find(c, start); } - size_t find(const String16& str) const { return m_impl.find(str.impl()); } - size_t find(const String16& str, unsigned start) const { return m_impl.find(str.impl(), start); } + size_t find(const String16& str, unsigned start = 0) const { return m_impl.find(str.impl(), start); } size_t reverseFind(const String16& str, unsigned start = UINT_MAX) const { return m_impl.reverseFind(str.impl(), start); } - void append(const String16& str) { m_impl.append(str); }; - bool isHashTableDeletedValue() const { return m_impl.isHashTableDeletedValue(); } - bool startWith(const String16& s) const { return m_impl.startsWith(s); } bool startWith(UChar character) const { return m_impl.startsWith(character); } bool endsWith(const String16& s) const { return m_impl.endsWith(s); } @@ -167,7 +130,7 @@ template<> struct HashTraits<String16> : SimpleClassHashTraits<String16> { static const bool hasIsEmptyValueFunction = true; - static bool isEmptyValue(const String16& a) { return a.isNull(); } + static bool isEmptyValue(const String16& a) { return a.impl().isNull(); } }; } // namespace WTF
diff --git a/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp b/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp index 82b6cf1b..ba26c811 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/InjectedScript.cpp
@@ -447,7 +447,7 @@ if (!hadException) { result = toProtocolValue(function.context(), resultValue); if (!result) - result = protocol::StringValue::create("Object has too long reference chain(must not be longer than " + String16::number(protocol::Value::maxDepth) + ")"); + result = protocol::StringValue::create("Object has too long reference chain"); } else { result = protocol::StringValue::create("Exception while making a call."); } @@ -501,7 +501,7 @@ } else { result = toProtocolValue(function.context(), resultValue); if (!result) - result = protocol::StringValue::create("Object has too long reference chain(must not be longer than " + String16::number(protocol::Value::maxDepth) + ")"); + result = protocol::StringValue::create("Object has too long reference chain"); } return result.release(); }
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp index dfe9817..45ee38c 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.cpp
@@ -113,10 +113,7 @@ size_t current = 0; const uint32_t* data = nullptr; - if (str.is8Bit()) - data = reinterpret_cast<const uint32_t*>(str.characters8()); - else - data = reinterpret_cast<const uint32_t*>(str.characters16()); + data = reinterpret_cast<const uint32_t*>(str.characters16()); for (size_t i = 0; i < str.sizeInBytes() / 4; i += 4) { uint32_t v = data[i]; uint64_t xi = v * randomOdd[current] & 0x7FFFFFFF; @@ -145,10 +142,10 @@ return hash.toString(); } -PassOwnPtr<V8DebuggerAgent> V8DebuggerAgent::create(V8RuntimeAgent* runtimeAgent, int contextGroupId) +PassOwnPtr<V8DebuggerAgent> V8DebuggerAgent::create(V8RuntimeAgent* runtimeAgent) { V8RuntimeAgentImpl* runtimeAgentImpl = static_cast<V8RuntimeAgentImpl*>(runtimeAgent); - return adoptPtr(new V8DebuggerAgentImpl(runtimeAgentImpl->getInjectedScriptManager(), runtimeAgentImpl->debugger(), contextGroupId)); + return adoptPtr(new V8DebuggerAgentImpl(runtimeAgentImpl->getInjectedScriptManager(), runtimeAgentImpl->debugger(), runtimeAgentImpl->contextGroupId())); } V8DebuggerAgentImpl::V8DebuggerAgentImpl(InjectedScriptManager* injectedScriptManager, V8DebuggerImpl* debugger, int contextGroupId) @@ -204,7 +201,7 @@ // debugger().addListener may result in reporting all parsed scripts to // the agent so it should already be in enabled state by then. m_enabled = true; - debugger().addAgent(m_contextGroupId, this); + debugger().addDebuggerAgent(m_contextGroupId, this); // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends debugger().setBreakpointsActivated(true); } @@ -235,7 +232,7 @@ m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false); m_state->setBoolean(DebuggerAgentState::promiseTrackerCaptureStacks, false); - debugger().removeAgent(m_contextGroupId); + debugger().removeDebuggerAgent(m_contextGroupId); m_pausedContext.Reset(); m_currentCallStack.Reset(); m_scripts.clear(); @@ -1062,7 +1059,7 @@ // Current AsyncCallChain corresponds to the bottommost JS call frame. ASSERT(!m_currentAsyncCallChain); - m_currentAsyncCallChain = V8StackTraceImpl::clone(chain, m_maxAsyncCallStackDepth - 1); + m_currentAsyncCallChain = chain->clone(); m_currentAsyncOperationId = operationId; m_pendingTraceAsyncOperationCompleted = false; m_nestedAsyncCallCount = 1; @@ -1084,7 +1081,7 @@ { if (!m_nestedAsyncCallCount) return; - ASSERT(m_currentAsyncCallChain); +// ASSERT(m_currentAsyncCallChain); --m_nestedAsyncCallCount; if (!m_nestedAsyncCallCount) { clearCurrentAsyncOperation(); @@ -1303,16 +1300,12 @@ if (m_pausedContext.IsEmpty() || !trackingAsyncCalls() || !m_currentAsyncCallChain) return nullptr; - return m_currentAsyncCallChain->buildInspectorObject(); + return m_currentAsyncCallChain->buildInspectorObjectForTail(this); } -PassOwnPtr<V8StackTraceImpl> V8DebuggerAgentImpl::currentAsyncStackTraceForRuntime() +V8StackTraceImpl* V8DebuggerAgentImpl::currentAsyncCallChain() { - if (!trackingAsyncCalls()) - return nullptr; - - // TODO(dgozman): -1 is here to not exceed max async depth. Clean this up between V8StackTraceImpl and agent. - return V8StackTraceImpl::clone(m_currentAsyncCallChain.get(), m_maxAsyncCallStackDepth - 1); + return trackingAsyncCalls() ? m_currentAsyncCallChain.get() : nullptr; } void V8DebuggerAgentImpl::didParseSource(const V8DebuggerParsedScript& parsedScript)
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h index 3d5bf5c..827ccc7 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerAgentImpl.h
@@ -187,7 +187,8 @@ void didReceiveV8PromiseEvent(v8::Local<v8::Context>, v8::Local<v8::Object> promise, v8::Local<v8::Value> parentPromise, int status); v8::Isolate* isolate() { return m_isolate; } - PassOwnPtr<V8StackTraceImpl> currentAsyncStackTraceForRuntime(); + int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; } + V8StackTraceImpl* currentAsyncCallChain(); private: bool checkEnabled(ErrorString*); @@ -270,7 +271,7 @@ protocol::HashSet<int> m_asyncOperationNotifications; protocol::HashSet<int> m_asyncOperationBreakpoints; protocol::HashSet<int> m_pausingAsyncOperations; - unsigned m_maxAsyncCallStackDepth; + int m_maxAsyncCallStackDepth; OwnPtr<V8StackTraceImpl> m_currentAsyncCallChain; unsigned m_nestedAsyncCallCount; int m_currentAsyncOperationId;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp index c5601c94..ea1ab6d5 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.cpp
@@ -37,6 +37,7 @@ #include "platform/v8_inspector/ScriptBreakpoint.h" #include "platform/v8_inspector/V8DebuggerAgentImpl.h" #include "platform/v8_inspector/V8JavaScriptCallFrame.h" +#include "platform/v8_inspector/V8RuntimeAgentImpl.h" #include "platform/v8_inspector/V8StackTraceImpl.h" #include "platform/v8_inspector/V8StringUtil.h" #include "platform/v8_inspector/public/V8DebuggerClient.h" @@ -144,16 +145,16 @@ size_t commaPos = dataString.find(","); if (commaPos == kNotFound) return 0; - return dataString.left(commaPos).toInt(); + return dataString.substring(0, commaPos).toInt(); } -void V8DebuggerImpl::addAgent(int contextGroupId, V8DebuggerAgentImpl* agent) +void V8DebuggerImpl::addDebuggerAgent(int contextGroupId, V8DebuggerAgentImpl* agent) { ASSERT(contextGroupId); - ASSERT(!m_agentsMap.contains(contextGroupId)); - if (m_agentsMap.isEmpty()) + ASSERT(!m_debuggerAgentsMap.contains(contextGroupId)); + if (m_debuggerAgentsMap.isEmpty()) enable(); - m_agentsMap.set(contextGroupId, agent); + m_debuggerAgentsMap.set(contextGroupId, agent); protocol::Vector<V8DebuggerParsedScript> compiledScripts; getCompiledScripts(contextGroupId, compiledScripts); @@ -161,27 +162,49 @@ agent->didParseSource(compiledScripts[i]); } -void V8DebuggerImpl::removeAgent(int contextGroupId) +void V8DebuggerImpl::removeDebuggerAgent(int contextGroupId) { ASSERT(contextGroupId); - if (!m_agentsMap.contains(contextGroupId)) + if (!m_debuggerAgentsMap.contains(contextGroupId)) return; if (!m_pausedContext.IsEmpty() && getGroupId(m_pausedContext) == contextGroupId) continueProgram(); - m_agentsMap.remove(contextGroupId); + m_debuggerAgentsMap.remove(contextGroupId); - if (m_agentsMap.isEmpty()) + if (m_debuggerAgentsMap.isEmpty()) disable(); } -V8DebuggerAgentImpl* V8DebuggerImpl::getAgentForContext(v8::Local<v8::Context> context) +V8DebuggerAgentImpl* V8DebuggerImpl::getDebuggerAgentForContext(v8::Local<v8::Context> context) { int groupId = getGroupId(context); if (!groupId) return nullptr; - return m_agentsMap.get(groupId); + return m_debuggerAgentsMap.get(groupId); +} + +void V8DebuggerImpl::addRuntimeAgent(int contextGroupId, V8RuntimeAgentImpl* agent) +{ + ASSERT(contextGroupId); + ASSERT(!m_runtimeAgentsMap.contains(contextGroupId)); + m_runtimeAgentsMap.set(contextGroupId, agent); +} + +void V8DebuggerImpl::removeRuntimeAgent(int contextGroupId) +{ + ASSERT(contextGroupId); + if (m_runtimeAgentsMap.contains(contextGroupId)) + m_runtimeAgentsMap.remove(contextGroupId); +} + +V8RuntimeAgentImpl* V8DebuggerImpl::getRuntimeAgentForContext(v8::Local<v8::Context> context) +{ + int groupId = getGroupId(context); + if (!groupId) + return nullptr; + return m_runtimeAgentsMap.get(groupId); } void V8DebuggerImpl::getCompiledScripts(int contextGroupId, protocol::Vector<V8DebuggerParsedScript>& result) @@ -535,7 +558,7 @@ if (m_runningNestedMessageLoop) return; - V8DebuggerAgentImpl* agent = getAgentForContext(pausedContext); + V8DebuggerAgentImpl* agent = getDebuggerAgentForContext(pausedContext); if (!agent) return; @@ -558,7 +581,7 @@ ASSERT(groupId); m_client->runMessageLoopOnPause(groupId); // The agent may have been removed in the nested loop. - agent = getAgentForContext(pausedContext); + agent = getDebuggerAgentForContext(pausedContext); if (agent) agent->didContinue(); m_runningNestedMessageLoop = false; @@ -602,7 +625,7 @@ v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); ASSERT(!eventContext.IsEmpty()); - V8DebuggerAgentImpl* agent = getAgentForContext(eventContext); + V8DebuggerAgentImpl* agent = getDebuggerAgentForContext(eventContext); if (agent) { v8::HandleScope scope(m_isolate); if (event == v8::AfterCompile || event == v8::CompileError) { @@ -789,13 +812,27 @@ PassOwnPtr<V8StackTrace> V8DebuggerImpl::createStackTrace(v8::Local<v8::StackTrace> stackTrace, size_t maxStackSize) { - V8DebuggerAgentImpl* agent = getAgentForContext(m_isolate->GetCurrentContext()); + V8DebuggerAgentImpl* agent = getDebuggerAgentForContext(m_isolate->GetCurrentContext()); return V8StackTraceImpl::create(agent, stackTrace, maxStackSize); } +void V8DebuggerImpl::contextCreated(const V8ContextInfo& info) +{ + V8RuntimeAgentImpl* agent = getRuntimeAgentForContext(info.context); + if (agent) + agent->reportExecutionContextCreated(info); +} + +void V8DebuggerImpl::contextDestroyed(v8::Local<v8::Context> context) +{ + V8RuntimeAgentImpl* agent = getRuntimeAgentForContext(context); + if (agent) + agent->reportExecutionContextDestroyed(context); +} + PassOwnPtr<V8StackTrace> V8DebuggerImpl::captureStackTrace(size_t maxStackSize) { - V8DebuggerAgentImpl* agent = getAgentForContext(m_isolate->GetCurrentContext()); + V8DebuggerAgentImpl* agent = getDebuggerAgentForContext(m_isolate->GetCurrentContext()); return V8StackTraceImpl::capture(agent, maxStackSize); }
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h index 7d765ef..185dd37 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8DebuggerImpl.h
@@ -46,6 +46,7 @@ class JavaScriptCallFrame; struct ScriptBreakpoint; class V8DebuggerAgentImpl; +class V8RuntimeAgentImpl; class V8DebuggerImpl : public V8Debugger { PROTOCOL_DISALLOW_COPY(V8DebuggerImpl); @@ -55,8 +56,10 @@ bool enabled() const; - void addAgent(int contextGroupId, V8DebuggerAgentImpl*); - void removeAgent(int contextGroupId); + void addDebuggerAgent(int contextGroupId, V8DebuggerAgentImpl*); + void removeDebuggerAgent(int contextGroupId); + void addRuntimeAgent(int contextGroupId, V8RuntimeAgentImpl*); + void removeRuntimeAgent(int contextGroupId); String16 setBreakpoint(const String16& sourceID, const ScriptBreakpoint&, int* actualLineNumber, int* actualColumnNumber, bool interstatementLocation); void removeBreakpoint(const String16& breakpointId); @@ -99,6 +102,8 @@ v8::Local<v8::Context> regexContext(); // V8Debugger implementation + void contextCreated(const V8ContextInfo&) override; + void contextDestroyed(v8::Local<v8::Context>) override; PassOwnPtr<V8StackTrace> createStackTrace(v8::Local<v8::StackTrace>, size_t maxStackSize) override; PassOwnPtr<V8StackTrace> captureStackTrace(size_t maxStackSize) override; @@ -109,7 +114,8 @@ // Only scripts whose debug data matches |contextGroupId| will be reported. // Passing 0 will result in reporting all scripts. void getCompiledScripts(int contextGroupId, protocol::Vector<V8DebuggerParsedScript>&); - V8DebuggerAgentImpl* getAgentForContext(v8::Local<v8::Context>); + V8DebuggerAgentImpl* getDebuggerAgentForContext(v8::Local<v8::Context>); + V8RuntimeAgentImpl* getRuntimeAgentForContext(v8::Local<v8::Context>); void compileDebuggerScript(); v8::MaybeLocal<v8::Value> callDebuggerMethod(const char* functionName, int argc, v8::Local<v8::Value> argv[]); @@ -132,8 +138,10 @@ v8::Isolate* m_isolate; V8DebuggerClient* m_client; - using AgentsMap = protocol::HashMap<int, V8DebuggerAgentImpl*>; - AgentsMap m_agentsMap; + using DebuggerAgentsMap = protocol::HashMap<int, V8DebuggerAgentImpl*>; + DebuggerAgentsMap m_debuggerAgentsMap; + using RuntimeAgentsMap = protocol::HashMap<int, V8RuntimeAgentImpl*>; + RuntimeAgentsMap m_runtimeAgentsMap; bool m_breakpointsActivated; v8::Global<v8::FunctionTemplate> m_breakProgramCallbackTemplate; v8::Global<v8::Object> m_debuggerScript;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp index d6225c5a..232af5a 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8HeapProfilerAgentImpl.cpp
@@ -11,6 +11,7 @@ #include "platform/v8_inspector/V8StringUtil.h" #include "platform/v8_inspector/public/V8DebuggerClient.h" #include <v8-profiler.h> +#include <v8-version.h> namespace blink { @@ -18,7 +19,9 @@ static const char heapProfilerEnabled[] = "heapProfilerEnabled"; static const char heapObjectsTrackingEnabled[] = "heapObjectsTrackingEnabled"; static const char allocationTrackingEnabled[] = "allocationTrackingEnabled"; +#if V8_MAJOR_VERSION >= 5 static const char samplingHeapProfilerEnabled[] = "samplingHeapProfilerEnabled"; +#endif } namespace { @@ -42,7 +45,11 @@ class GlobalObjectNameResolver final : public v8::HeapProfiler::ObjectNameResolver { public: - explicit GlobalObjectNameResolver(V8RuntimeAgentImpl* runtimeAgent) : m_runtimeAgent(runtimeAgent) { } + explicit GlobalObjectNameResolver(V8RuntimeAgentImpl* runtimeAgent) : m_offset(0), m_runtimeAgent(runtimeAgent) + { + m_strings.resize(10000); + } + const char* GetName(v8::Local<v8::Object> object) override { int contextId = V8Debugger::contextId(object->CreationContext()); @@ -51,13 +58,23 @@ InjectedScript* injectedScript = m_runtimeAgent->getInjectedScriptManager()->findInjectedScript(contextId); if (!injectedScript) return ""; - String16 name = injectedScript->origin().latin1Data(); - m_strings.append(name); - return reinterpret_cast<const char *>(name.characters8()); + String16 name = injectedScript->origin(); + size_t length = name.length(); + if (m_offset + length + 1 >= m_strings.size()) + return ""; + for (size_t i = 0; i < length; ++i) { + UChar ch = name[i]; + m_strings[m_offset + i] = ch > 0xff ? '?' : static_cast<char>(ch); + } + m_strings[m_offset + length] = '\0'; + char* result = &*m_strings.begin() + m_offset; + m_offset += length + 1; + return result; } private: - protocol::Vector<String16> m_strings; + size_t m_offset; + protocol::Vector<char> m_strings; V8RuntimeAgentImpl* m_runtimeAgent; }; @@ -77,7 +94,7 @@ protocol::Frontend::HeapProfiler* m_frontend; }; -v8::Local<v8::Object> objectByHeapObjectId(v8::Isolate* isolate, unsigned id) +v8::Local<v8::Object> objectByHeapObjectId(v8::Isolate* isolate, int id) { v8::HeapProfiler* profiler = isolate->GetHeapProfiler(); v8::Local<v8::Value> value = profiler->FindObjectById(id); @@ -88,13 +105,13 @@ class InspectableHeapObject final : public V8RuntimeAgent::Inspectable { public: - explicit InspectableHeapObject(unsigned heapObjectId) : m_heapObjectId(heapObjectId) { } + explicit InspectableHeapObject(int heapObjectId) : m_heapObjectId(heapObjectId) { } v8::Local<v8::Value> get(v8::Local<v8::Context> context) override { return objectByHeapObjectId(context->GetIsolate(), m_heapObjectId); } private: - unsigned m_heapObjectId; + int m_heapObjectId; }; class HeapStatsStream final : public v8::OutputStream { @@ -160,10 +177,12 @@ m_frontend->resetProfiles(); if (m_state->booleanProperty(HeapProfilerAgentState::heapObjectsTrackingEnabled, false)) startTrackingHeapObjectsInternal(m_state->booleanProperty(HeapProfilerAgentState::allocationTrackingEnabled, false)); +#if V8_MAJOR_VERSION >= 5 if (m_state->booleanProperty(HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) { ErrorString error; startSampling(&error); } +#endif } void V8HeapProfilerAgentImpl::collectGarbage(ErrorString*) @@ -194,11 +213,13 @@ void V8HeapProfilerAgentImpl::disable(ErrorString* error) { stopTrackingHeapObjectsInternal(); +#if V8_MAJOR_VERSION >= 5 if (m_state->booleanProperty(HeapProfilerAgentState::samplingHeapProfilerEnabled, false)) { v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); if (profiler) profiler->StopSamplingHeapProfiler(); } +#endif m_isolate->GetHeapProfiler()->ClearObjectIds(); m_state->setBoolean(HeapProfilerAgentState::heapProfilerEnabled, false); } @@ -228,7 +249,7 @@ void V8HeapProfilerAgentImpl::getObjectByHeapObjectId(ErrorString* error, const String16& heapSnapshotObjectId, const protocol::Maybe<String16>& objectGroup, OwnPtr<protocol::Runtime::RemoteObject>* result) { bool ok; - unsigned id = heapSnapshotObjectId.toUInt(&ok); + int id = heapSnapshotObjectId.toInt(&ok); if (!ok) { *error = "Invalid heap snapshot object id"; return; @@ -248,7 +269,7 @@ void V8HeapProfilerAgentImpl::addInspectedHeapObject(ErrorString* errorString, const String16& inspectedHeapObjectId) { bool ok; - unsigned id = inspectedHeapObjectId.toUInt(&ok); + int id = inspectedHeapObjectId.toInt(&ok); if (!ok) { *errorString = "Invalid heap snapshot object id"; return; @@ -292,6 +313,7 @@ void V8HeapProfilerAgentImpl::startSampling(ErrorString* errorString) { +#if V8_MAJOR_VERSION >= 5 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); if (!profiler) { *errorString = "Cannot access v8 heap profiler"; @@ -299,8 +321,10 @@ } m_state->setBoolean(HeapProfilerAgentState::samplingHeapProfilerEnabled, true); profiler->StartSamplingHeapProfiler(); +#endif } +#if V8_MAJOR_VERSION >= 5 namespace { PassOwnPtr<protocol::HeapProfiler::SamplingHeapProfileNode> buildSampingHeapProfileNode(const v8::AllocationProfile::Node* node) { @@ -321,9 +345,11 @@ return result.release(); } } // namespace +#endif void V8HeapProfilerAgentImpl::stopSampling(ErrorString* errorString, OwnPtr<protocol::HeapProfiler::SamplingHeapProfile>* profile) { +#if V8_MAJOR_VERSION >= 5 v8::HeapProfiler* profiler = m_isolate->GetHeapProfiler(); if (!profiler) { *errorString = "Cannot access v8 heap profiler"; @@ -340,6 +366,7 @@ v8::AllocationProfile::Node* root = v8Profile->GetRootNode(); *profile = protocol::HeapProfiler::SamplingHeapProfile::create() .setHead(buildSampingHeapProfileNode(root)).build(); +#endif } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp index 0f16980..22767809 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8InjectedScriptHost.cpp
@@ -221,11 +221,13 @@ v8SetReturnValue(info, properties); } -static v8::Local<v8::Array> wrapListenerFunctions(v8::Isolate* isolate, const protocol::Vector<V8EventListenerInfo>& listeners) +static v8::Local<v8::Array> wrapListenerFunctions(v8::Isolate* isolate, const V8EventListenerInfoList& listeners, const String16& type) { v8::Local<v8::Array> result = v8::Array::New(isolate); size_t handlersCount = listeners.size(); for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) { + if (listeners[i].eventType != type) + continue; v8::Local<v8::Object> function = listeners[i].handler; v8::Local<v8::Object> listenerEntry = v8::Object::New(isolate); listenerEntry->Set(toV8StringInternalized(isolate, "listener"), function); @@ -244,19 +246,18 @@ if (!host->debugger()) return; V8DebuggerClient* client = host->debugger()->client(); - V8EventListenerInfoMap listenerInfo; + V8EventListenerInfoList listenerInfo; client->eventListeners(info[0], listenerInfo); v8::Local<v8::Object> result = v8::Object::New(info.GetIsolate()); - protocol::Vector<String16> types; - for (auto& it : listenerInfo) - types.append(it.first); - std::sort(types.begin(), types.end(), String16::codePointCompareLessThan); - for (const String16& type : types) { - v8::Local<v8::Array> listeners = wrapListenerFunctions(info.GetIsolate(), *listenerInfo.get(type)); + protocol::HashSet<String16> types; + for (auto& info : listenerInfo) + types.add(info.eventType); + for (const auto& it : types) { + v8::Local<v8::Array> listeners = wrapListenerFunctions(info.GetIsolate(), listenerInfo, it.first); if (!listeners->Length()) continue; - result->Set(toV8String(info.GetIsolate(), type), listeners); + result->Set(toV8String(info.GetIsolate(), it.first), listeners); } v8SetReturnValue(info, result);
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8ProfilerAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8ProfilerAgentImpl.cpp index cbe769f..0152959 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8ProfilerAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8ProfilerAgentImpl.cpp
@@ -153,7 +153,7 @@ String16 id; String16 resolvedTitle; // Take last started profile if no title was passed. - if (title.isNull()) { + if (title.isEmpty()) { if (m_startedProfiles.isEmpty()) return; id = m_startedProfiles.last().m_id;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8Regex.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8Regex.cpp index 3a83f53..32053d4b 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8Regex.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8Regex.cpp
@@ -35,7 +35,7 @@ if (matchLength) *matchLength = 0; - if (m_regex.IsEmpty() || string.isNull()) + if (m_regex.IsEmpty() || string.isEmpty()) return -1; // v8 strings are limited to int.
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp index f3933b3..3a666bb 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.cpp
@@ -50,23 +50,25 @@ using protocol::Runtime::ExceptionDetails; using protocol::Runtime::RemoteObject; -PassOwnPtr<V8RuntimeAgent> V8RuntimeAgent::create(V8Debugger* debugger, Client* client) +PassOwnPtr<V8RuntimeAgent> V8RuntimeAgent::create(V8Debugger* debugger, int contextGroupId) { - return adoptPtr(new V8RuntimeAgentImpl(static_cast<V8DebuggerImpl*>(debugger), client)); + return adoptPtr(new V8RuntimeAgentImpl(static_cast<V8DebuggerImpl*>(debugger), contextGroupId)); } -V8RuntimeAgentImpl::V8RuntimeAgentImpl(V8DebuggerImpl* debugger, Client* client) - : m_client(client) +V8RuntimeAgentImpl::V8RuntimeAgentImpl(V8DebuggerImpl* debugger, int contextGroupId) + : m_contextGroupId(contextGroupId) , m_state(nullptr) , m_frontend(nullptr) , m_injectedScriptManager(InjectedScriptManager::create(debugger)) , m_debugger(debugger) , m_enabled(false) { + m_debugger->addRuntimeAgent(m_contextGroupId, this); } V8RuntimeAgentImpl::~V8RuntimeAgentImpl() { + m_debugger->removeRuntimeAgent(m_contextGroupId); } void V8RuntimeAgentImpl::evaluate( @@ -320,11 +322,17 @@ void V8RuntimeAgentImpl::enable(ErrorString* errorString) { m_enabled = true; - m_client->reportExecutionContexts(); + v8::HandleScope handles(m_debugger->isolate()); + V8ContextInfoVector contexts; + m_debugger->client()->contextsToReport(m_contextGroupId, contexts); + for (const V8ContextInfo& info : contexts) + reportExecutionContextCreated(info); } void V8RuntimeAgentImpl::disable(ErrorString* errorString) { + if (!m_enabled) + return; m_enabled = false; m_compiledScripts.clear(); clearInspectedObjects(); @@ -393,22 +401,22 @@ m_injectedScriptManager->injectedScriptHost()->clearInspectedObjects(); } -void V8RuntimeAgentImpl::reportExecutionContextCreated(v8::Local<v8::Context> context, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId) +void V8RuntimeAgentImpl::reportExecutionContextCreated(const V8ContextInfo& info) { if (!m_enabled) return; - InjectedScript* injectedScript = m_injectedScriptManager->injectedScriptFor(context); + InjectedScript* injectedScript = m_injectedScriptManager->injectedScriptFor(info.context); if (!injectedScript) return; int contextId = injectedScript->contextId(); - injectedScript->setOrigin(origin); + injectedScript->setOrigin(info.origin); OwnPtr<protocol::Runtime::ExecutionContextDescription> description = protocol::Runtime::ExecutionContextDescription::create() .setId(contextId) - .setName(humanReadableName) - .setOrigin(origin) - .setFrameId(frameId).build(); - if (!type.isEmpty()) - description->setType(type); + .setName(info.humanReadableName) + .setOrigin(info.origin) + .setFrameId(info.frameId).build(); + if (!info.type.isEmpty()) + description->setType(info.type); m_frontend->executionContextCreated(description.release()); }
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.h index 92318f4..a8e54dd 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8RuntimeAgentImpl.h
@@ -49,7 +49,7 @@ class V8RuntimeAgentImpl : public V8RuntimeAgent { PROTOCOL_DISALLOW_COPY(V8RuntimeAgentImpl); public: - V8RuntimeAgentImpl(V8DebuggerImpl*, Client*); + V8RuntimeAgentImpl(V8DebuggerImpl*, int contextGroupId); ~V8RuntimeAgentImpl() override; // State management methods. @@ -111,6 +111,10 @@ V8DebuggerImpl* debugger() { return m_debugger; } InjectedScriptManager* getInjectedScriptManager() { return m_injectedScriptManager.get(); } + int contextGroupId() { return m_contextGroupId; } + + void reportExecutionContextCreated(const V8ContextInfo&); + void reportExecutionContextDestroyed(v8::Local<v8::Context>); void setClearConsoleCallback(PassOwnPtr<ClearConsoleCallback>) override; void setInspectObjectCallback(PassOwnPtr<InspectCallback>) override; @@ -123,11 +127,9 @@ void clearInspectedObjects() override; private: - void reportExecutionContextCreated(v8::Local<v8::Context>, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId) override; - void reportExecutionContextDestroyed(v8::Local<v8::Context>) override; PassOwnPtr<protocol::Runtime::ExceptionDetails> createExceptionDetails(v8::Isolate*, v8::Local<v8::Message>); - Client* m_client; + int m_contextGroupId; protocol::DictionaryValue* m_state; protocol::Frontend::Runtime* m_frontend; OwnPtr<InjectedScriptManager> m_injectedScriptManager;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.cpp index 5e5b380..6c8ff71 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.cpp
@@ -12,12 +12,13 @@ #include <v8-debug.h> #include <v8-profiler.h> +#include <v8-version.h> namespace blink { namespace { -V8StackTraceImpl::Frame toCallFrame(v8::Local<v8::StackFrame> frame) +V8StackTraceImpl::Frame toFrame(v8::Local<v8::StackFrame> frame) { String16 scriptId = String16::number(frame->GetScriptId()); String16 sourceName; @@ -35,7 +36,7 @@ return V8StackTraceImpl::Frame(functionName, scriptId, sourceName, sourceLineNumber, sourceColumn); } -void toCallFramesVector(v8::Local<v8::StackTrace> stackTrace, protocol::Vector<V8StackTraceImpl::Frame>& scriptCallFrames, size_t maxStackSize, v8::Isolate* isolate) +void toFramesVector(v8::Local<v8::StackTrace> stackTrace, protocol::Vector<V8StackTraceImpl::Frame>& frames, size_t maxStackSize, v8::Isolate* isolate) { ASSERT(isolate->InContext()); int frameCount = stackTrace->GetFrameCount(); @@ -43,7 +44,7 @@ frameCount = maxStackSize; for (int i = 0; i < frameCount; i++) { v8::Local<v8::StackFrame> stackFrame = stackTrace->GetFrame(i); - scriptCallFrames.append(toCallFrame(stackFrame)); + frames.append(toFrame(stackFrame)); } } @@ -88,18 +89,36 @@ { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); - protocol::Vector<V8StackTraceImpl::Frame> scriptCallFrames; + protocol::Vector<V8StackTraceImpl::Frame> frames; if (!stackTrace.IsEmpty()) - toCallFramesVector(stackTrace, scriptCallFrames, maxStackSize, isolate); + toFramesVector(stackTrace, frames, maxStackSize, isolate); - OwnPtr<V8StackTraceImpl> asyncCallStack; - if (agent && agent->trackingAsyncCalls() && maxStackSize > 1) - asyncCallStack = agent->currentAsyncStackTraceForRuntime(); + int maxAsyncCallChainDepth = 1; + V8StackTraceImpl* asyncCallChain = nullptr; + if (agent && maxStackSize > 1) { + asyncCallChain = agent->currentAsyncCallChain(); + maxAsyncCallChainDepth = agent->maxAsyncCallChainDepth(); + } - if (stackTrace.IsEmpty() && !asyncCallStack) + // Only the top stack in the chain may be empty, so ensure that second stack is non-empty (it's the top of appended chain). + if (asyncCallChain && asyncCallChain->isEmpty()) + asyncCallChain = asyncCallChain->m_parent.get(); + + if (stackTrace.IsEmpty() && !asyncCallChain) return nullptr; - return V8StackTraceImpl::create(description, scriptCallFrames, asyncCallStack.release()); + OwnPtr<V8StackTraceImpl> result = adoptPtr(new V8StackTraceImpl(description, frames, asyncCallChain ? asyncCallChain->clone() : nullptr)); + + // Crop to not exceed maxAsyncCallChainDepth. + V8StackTraceImpl* deepest = result.get(); + while (deepest && maxAsyncCallChainDepth) { + deepest = deepest->m_parent.get(); + maxAsyncCallChainDepth--; + } + if (deepest) + deepest->m_parent.clear(); + + return result.release(); } PassOwnPtr<V8StackTraceImpl> V8StackTraceImpl::capture(V8DebuggerAgentImpl* agent, size_t maxStackSize, const String16& description) @@ -108,32 +127,18 @@ v8::HandleScope handleScope(isolate); v8::Local<v8::StackTrace> stackTrace; if (isolate->InContext()) { +#if V8_MAJOR_VERSION >= 5 isolate->GetCpuProfiler()->CollectSample(); +#endif stackTrace = v8::StackTrace::CurrentStackTrace(isolate, maxStackSize, stackTraceOptions); } return V8StackTraceImpl::create(agent, stackTrace, maxStackSize, description); } -PassOwnPtr<V8StackTraceImpl> V8StackTraceImpl::create(const String16& description, protocol::Vector<Frame>& frames, PassOwnPtr<V8StackTraceImpl> parent) +PassOwnPtr<V8StackTraceImpl> V8StackTraceImpl::clone() { - return adoptPtr(new V8StackTraceImpl(description, frames, parent)); -} - -PassOwnPtr<V8StackTraceImpl> V8StackTraceImpl::clone(V8StackTraceImpl* origin, size_t maxStackSize) -{ - if (!origin) - return nullptr; - - // TODO(dgozman): move this check to call-site. - if (!origin->m_frames.size()) - return V8StackTraceImpl::clone(origin->m_parent.get(), maxStackSize); - - OwnPtr<V8StackTraceImpl> parent; - if (origin->m_parent && maxStackSize) - parent = V8StackTraceImpl::clone(origin->m_parent.get(), maxStackSize - 1); - - protocol::Vector<Frame> frames(origin->m_frames); - return adoptPtr(new V8StackTraceImpl(origin->m_description, frames, parent.release())); + protocol::Vector<Frame> framesCopy(m_frames); + return adoptPtr(new V8StackTraceImpl(m_description, framesCopy, m_parent ? m_parent->clone() : nullptr)); } V8StackTraceImpl::V8StackTraceImpl(const String16& description, protocol::Vector<Frame>& frames, PassOwnPtr<V8StackTraceImpl> parent) @@ -192,6 +197,16 @@ return stackTrace.release(); } +PassOwnPtr<protocol::Runtime::StackTrace> V8StackTraceImpl::buildInspectorObjectForTail(V8DebuggerAgentImpl* agent) const +{ + v8::HandleScope handleScope(v8::Isolate::GetCurrent()); + // Next call collapses possible empty stack and ensures maxAsyncCallChainDepth. + OwnPtr<V8StackTraceImpl> fullChain = V8StackTraceImpl::create(agent, v8::Local<v8::StackTrace>(), V8StackTrace::maxCallStackSizeToCapture); + if (!fullChain || !fullChain->m_parent) + return nullptr; + return fullChain->m_parent->buildInspectorObject(); +} + String16 V8StackTraceImpl::toString() const { String16Builder stackTrace;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.h b/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.h index 41c40a7c..647d249 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.h +++ b/third_party/WebKit/Source/platform/v8_inspector/V8StackTraceImpl.h
@@ -14,6 +14,9 @@ class TracedValue; class V8DebuggerAgentImpl; +// Note: async stack trace may have empty top stack with non-empty tail to indicate +// that current native-only state had some async story. +// On the other hand, any non-top async stack is guaranteed to be non-empty. class V8StackTraceImpl final : public V8StackTrace { PROTOCOL_DISALLOW_COPY(V8StackTraceImpl); public: @@ -41,11 +44,11 @@ int m_columnNumber; }; - static PassOwnPtr<V8StackTraceImpl> create(const String16& description, protocol::Vector<Frame>&, PassOwnPtr<V8StackTraceImpl>); static PassOwnPtr<V8StackTraceImpl> create(V8DebuggerAgentImpl*, v8::Local<v8::StackTrace>, size_t maxStackSize, const String16& description = String16()); static PassOwnPtr<V8StackTraceImpl> capture(V8DebuggerAgentImpl*, size_t maxStackSize, const String16& description = String16()); - static PassOwnPtr<V8StackTraceImpl> clone(V8StackTraceImpl*, size_t maxAsyncStackSize); + PassOwnPtr<V8StackTraceImpl> clone(); + PassOwnPtr<protocol::Runtime::StackTrace> buildInspectorObjectForTail(V8DebuggerAgentImpl*) const; ~V8StackTraceImpl() override; // V8StackTrace implementation.
diff --git a/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp b/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp index 5aa5b1f..720b8ab 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp +++ b/third_party/WebKit/Source/platform/v8_inspector/V8StringUtil.cpp
@@ -125,7 +125,7 @@ unsigned lineEnd = endings->at(lineNumber); String16 line = text.substring(start, lineEnd - start); if (line.endsWith('\r')) - line = line.left(line.length() - 1); + line = line.substring(0, line.length() - 1); int matchLength; if (regex.match(line, 0, &matchLength) != -1) @@ -154,19 +154,15 @@ v8::Local<v8::String> toV8String(v8::Isolate* isolate, const String16& string) { - if (string.isNull()) + if (string.isEmpty()) return v8::String::Empty(isolate); - if (string.is8Bit()) - return v8::String::NewFromOneByte(isolate, string.characters8(), v8::NewStringType::kNormal, string.length()).ToLocalChecked(); return v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(string.characters16()), v8::NewStringType::kNormal, string.length()).ToLocalChecked(); } v8::Local<v8::String> toV8StringInternalized(v8::Isolate* isolate, const String16& string) { - if (string.isNull()) + if (string.isEmpty()) return v8::String::Empty(isolate); - if (string.is8Bit()) - return v8::String::NewFromOneByte(isolate, string.characters8(), v8::NewStringType::kInternalized, string.length()).ToLocalChecked(); return v8::String::NewFromTwoByte(isolate, reinterpret_cast<const uint16_t*>(string.characters16()), v8::NewStringType::kInternalized, string.length()).ToLocalChecked(); }
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8ContextInfo.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8ContextInfo.h new file mode 100644 index 0000000..d84e097 --- /dev/null +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8ContextInfo.h
@@ -0,0 +1,37 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef V8ContextInfo_h +#define V8ContextInfo_h + +#include "platform/inspector_protocol/Collections.h" +#include "platform/inspector_protocol/String16.h" + +#include <v8.h> + +namespace blink { + +class V8ContextInfo { +public: + V8ContextInfo(v8::Local<v8::Context> context, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId) + : context(context) + , type(type) + , origin(origin) + , humanReadableName(humanReadableName) + , frameId(frameId) + { + } + + v8::Local<v8::Context> context; + const String16 type; + const String16 origin; + const String16 humanReadableName; + const String16 frameId; +}; + +using V8ContextInfoVector = protocol::Vector<V8ContextInfo>; + +} // namespace blink + +#endif // V8ContextInfo_h
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8Debugger.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8Debugger.h index 90c4a9e1..78f55630 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/public/V8Debugger.h +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8Debugger.h
@@ -13,6 +13,7 @@ namespace blink { +class V8ContextInfo; class V8DebuggerClient; class V8StackTrace; @@ -40,6 +41,10 @@ static void setContextDebugData(v8::Local<v8::Context>, const String16& type, int contextGroupId); static int contextId(v8::Local<v8::Context>); + // Context should have been already marked with |setContextDebugData| call. + virtual void contextCreated(const V8ContextInfo&) = 0; + virtual void contextDestroyed(v8::Local<v8::Context>) = 0; + static v8::Local<v8::Symbol> commandLineAPISymbol(v8::Isolate*); static bool isCommandLineAPIMethod(const String16& name);
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerAgent.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerAgent.h index 15eaca83..e7a9909 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerAgent.h +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerAgent.h
@@ -17,7 +17,7 @@ public: static const char backtraceObjectGroup[]; - static PassOwnPtr<V8DebuggerAgent> create(V8RuntimeAgent*, int contextGroupId); + static PassOwnPtr<V8DebuggerAgent> create(V8RuntimeAgent*); virtual ~V8DebuggerAgent() { } // API for the embedder to report native activities.
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerClient.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerClient.h index f142144..21691cab 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerClient.h +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8DebuggerClient.h
@@ -6,6 +6,7 @@ #define V8DebuggerClient_h #include "platform/PlatformExport.h" +#include "platform/v8_inspector/public/V8ContextInfo.h" #include "platform/v8_inspector/public/V8EventListenerInfo.h" #include <v8.h> @@ -19,7 +20,8 @@ virtual void quitMessageLoopOnPause() = 0; virtual void muteWarningsAndDeprecations() = 0; virtual void unmuteWarningsAndDeprecations() = 0; - virtual void eventListeners(v8::Local<v8::Value>, V8EventListenerInfoMap&) = 0; + virtual void eventListeners(v8::Local<v8::Value>, V8EventListenerInfoList&) = 0; + virtual void contextsToReport(int contextGroupId, V8ContextInfoVector&) = 0; virtual bool callingContextCanAccessContext(v8::Local<v8::Context> calling, v8::Local<v8::Context> target) = 0; virtual v8::MaybeLocal<v8::Object> instantiateObject(v8::Local<v8::Function>) = 0;
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8EventListenerInfo.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8EventListenerInfo.h index e261b6c..1acb360 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/public/V8EventListenerInfo.h +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8EventListenerInfo.h
@@ -27,7 +27,7 @@ }; -using V8EventListenerInfoMap = protocol::HashMap<String16, OwnPtr<protocol::Vector<V8EventListenerInfo>>>; +using V8EventListenerInfoList = protocol::Vector<V8EventListenerInfo>; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/v8_inspector/public/V8RuntimeAgent.h b/third_party/WebKit/Source/platform/v8_inspector/public/V8RuntimeAgent.h index 7b91591..d8f2cd7 100644 --- a/third_party/WebKit/Source/platform/v8_inspector/public/V8RuntimeAgent.h +++ b/third_party/WebKit/Source/platform/v8_inspector/public/V8RuntimeAgent.h
@@ -7,6 +7,7 @@ #include "platform/PlatformExport.h" #include "platform/inspector_protocol/Dispatcher.h" +#include "platform/v8_inspector/public/V8ContextInfo.h" #include "platform/v8_inspector/public/V8Debugger.h" #include "wtf/Functional.h" @@ -25,18 +26,9 @@ virtual ~Inspectable() { } }; - class Client { - public: - virtual void reportExecutionContexts() = 0; - }; - - static PassOwnPtr<V8RuntimeAgent> create(V8Debugger*, Client*); + static PassOwnPtr<V8RuntimeAgent> create(V8Debugger*, int contextGroupId); virtual ~V8RuntimeAgent() { } - // Embedder notification API. - virtual void reportExecutionContextCreated(v8::Local<v8::Context>, const String16& type, const String16& origin, const String16& humanReadableName, const String16& frameId) = 0; - virtual void reportExecutionContextDestroyed(v8::Local<v8::Context>) = 0; - // Embedder API. using ClearConsoleCallback = Function<void()>; virtual void setClearConsoleCallback(PassOwnPtr<ClearConsoleCallback>) = 0;
diff --git a/third_party/WebKit/Source/web/AssociatedURLLoader.h b/third_party/WebKit/Source/web/AssociatedURLLoader.h index 6dcd06e..df5712f 100644 --- a/third_party/WebKit/Source/web/AssociatedURLLoader.h +++ b/third_party/WebKit/Source/web/AssociatedURLLoader.h
@@ -31,6 +31,7 @@ #ifndef AssociatedURLLoader_h #define AssociatedURLLoader_h +#include "platform/heap/Handle.h" #include "public/platform/WebURLLoader.h" #include "public/web/WebURLLoaderOptions.h" #include "wtf/Noncopyable.h" @@ -64,7 +65,7 @@ WebURLLoaderOptions m_options; WebURLLoaderClient* m_client; OwnPtr<ClientAdapter> m_clientAdapter; - RefPtr<DocumentThreadableLoader> m_loader; + OwnPtr<DocumentThreadableLoader> m_loader; }; } // namespace blink
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index 60b805e..2cf2cbf 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -399,11 +399,11 @@ return !!m_webView->client(); } -bool ChromeClientImpl::openBeforeUnloadConfirmPanelDelegate(LocalFrame* frame, const String& message, bool isReload) +bool ChromeClientImpl::openBeforeUnloadConfirmPanelDelegate(LocalFrame* frame, bool isReload) { notifyPopupOpeningObservers(); WebLocalFrameImpl* webframe = WebLocalFrameImpl::fromFrame(frame); - return webframe->client() && webframe->client()->runModalBeforeUnloadDialog(isReload, message); + return webframe->client() && webframe->client()->runModalBeforeUnloadDialog(isReload); } void ChromeClientImpl::closeWindowSoon()
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.h b/third_party/WebKit/Source/web/ChromeClientImpl.h index 5483e30..14b318e 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.h +++ b/third_party/WebKit/Source/web/ChromeClientImpl.h
@@ -82,7 +82,7 @@ const String& message, unsigned lineNumber, const String& sourceID, const String& stackTrace) override; bool canOpenBeforeUnloadConfirmPanel() override; - bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, const String&, bool isReload) override; + bool openBeforeUnloadConfirmPanelDelegate(LocalFrame*, bool isReload) override; void closeWindowSoon() override; bool openJavaScriptAlertDelegate(LocalFrame*, const String&) override; bool openJavaScriptConfirmDelegate(LocalFrame*, const String&) override;
diff --git a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp index 16d1b60e..31c776e 100644 --- a/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp +++ b/third_party/WebKit/Source/web/WebDevToolsAgentImpl.cpp
@@ -338,7 +338,7 @@ m_inspectorAgent = inspectorAgentPtr.get(); m_agents.append(inspectorAgentPtr.release()); - OwnPtrWillBeRawPtr<PageRuntimeAgent> pageRuntimeAgentPtr(PageRuntimeAgent::create(this, mainThreadDebugger->debugger(), m_inspectedFrames.get())); + OwnPtrWillBeRawPtr<PageRuntimeAgent> pageRuntimeAgentPtr(PageRuntimeAgent::create(this, mainThreadDebugger->debugger(), m_inspectedFrames.get(), mainThreadDebugger->contextGroupId(m_inspectedFrames->root()))); m_pageRuntimeAgent = pageRuntimeAgentPtr.get(); m_agents.append(pageRuntimeAgentPtr.release()); @@ -443,7 +443,7 @@ m_agents.append(InspectorApplicationCacheAgent::create(m_inspectedFrames.get())); m_agents.append(InspectorIndexedDBAgent::create(m_inspectedFrames.get())); - OwnPtrWillBeRawPtr<InspectorDebuggerAgent> debuggerAgentPtr(PageDebuggerAgent::create(MainThreadDebugger::instance(), m_inspectedFrames.get(), m_pageRuntimeAgent->v8Agent())); + OwnPtrWillBeRawPtr<InspectorDebuggerAgent> debuggerAgentPtr(PageDebuggerAgent::create(m_inspectedFrames.get(), m_pageRuntimeAgent->v8Agent())); InspectorDebuggerAgent* debuggerAgent = debuggerAgentPtr.get(); m_agents.append(debuggerAgentPtr.release());
diff --git a/third_party/WebKit/public/web/WebFrameClient.h b/third_party/WebKit/public/web/WebFrameClient.h index 0493b746..4741cd8 100644 --- a/third_party/WebKit/public/web/WebFrameClient.h +++ b/third_party/WebKit/public/web/WebFrameClient.h
@@ -400,12 +400,10 @@ const WebString& message, const WebString& defaultValue, WebString* actualValue) { return false; } - // Displays a modal confirmation dialog containing the given message as - // description and OK/Cancel choices, where 'OK' means that it is okay - // to proceed with closing the view. Returns true if the user selects - // 'OK' or false otherwise. - virtual bool runModalBeforeUnloadDialog( - bool isReload, const WebString& message) { return true; } + // Displays a modal confirmation dialog with OK/Cancel choices, where 'OK' + // means that it is okay to proceed with closing the view. Returns true if + // the user selects 'OK' or false otherwise. + virtual bool runModalBeforeUnloadDialog(bool isReload) { return true; } // UI ------------------------------------------------------------------
diff --git a/third_party/sqlite/BUILD.gn b/third_party/sqlite/BUILD.gn index 8400837..3ed3b3fd6 100644 --- a/third_party/sqlite/BUILD.gn +++ b/third_party/sqlite/BUILD.gn
@@ -224,6 +224,9 @@ source_set("sqlite") { public_configs = [ ":sqlite_config" ] if (is_ios) { + public_deps = [ + ":sqlite_recover", + ] deps = [ ":sqlite_regexp", ] @@ -231,6 +234,15 @@ } if (is_ios) { + source_set("sqlite_recover") { + sources = [ + # TODO(shess): Move out of the SQLite source tree, perhaps to ext/. + "src/src/recover.c", + "src/src/recover.h", + "src/src/recover_varint.c", + ] + } + source_set("sqlite_regexp") { defines = [ # Necessary to statically compile the extension.
diff --git a/third_party/sqlite/sqlite.gyp b/third_party/sqlite/sqlite.gyp index fca9006..01da115d 100644 --- a/third_party/sqlite/sqlite.gyp +++ b/third_party/sqlite/sqlite.gyp
@@ -67,6 +67,7 @@ 'conditions': [ ['OS == "ios"', { 'dependencies': [ + 'sqlite_recover', 'sqlite_regexp', ], 'link_settings': { @@ -243,6 +244,18 @@ ['OS == "ios"', { 'targets': [ { + # Virtual table used by sql::Recovery to recover corrupt + # databases, for use with USE_SYSTEM_SQLITE. + 'target_name': 'sqlite_recover', + 'type': 'static_library', + 'sources': [ + # TODO(shess): Move out of the SQLite source tree, perhaps to ext/. + 'src/src/recover_varint.c', + 'src/src/recover.c', + 'src/src/recover.h', + ], + }, + { 'target_name': 'sqlite_regexp', 'type': 'static_library', 'dependencies': [
diff --git a/third_party/sqlite/src/src/recover.c b/third_party/sqlite/src/src/recover.c index 9ad2d1c..c22fd4d 100644 --- a/third_party/sqlite/src/src/recover.c +++ b/third_party/sqlite/src/src/recover.c
@@ -252,10 +252,10 @@ /* From section 1.5. */ static const unsigned kiPageTypeOffset = 0; -static const unsigned kiPageFreeBlockOffset = 1; +/* static const unsigned kiPageFreeBlockOffset = 1; */ static const unsigned kiPageCellCountOffset = 3; -static const unsigned kiPageCellContentOffset = 5; -static const unsigned kiPageFragmentedBytesOffset = 7; +/* static const unsigned kiPageCellContentOffset = 5; */ +/* static const unsigned kiPageFragmentedBytesOffset = 7; */ static const unsigned knPageLeafHeaderBytes = 8; /* Interior pages contain an additional field. */ static const unsigned kiPageRightChildOffset = 8; @@ -701,8 +701,6 @@ * interiorCursorDestroy - release all resources associated with the * cursor and any parent cursors. * interiorCursorCreate - create a cursor with the given parent and page. - * interiorCursorEOF - returns true if neither the cursor nor the - * parent cursors can return any more data. * interiorCursorNextPage - fetch the next child page from the cursor. * * Logically, interiorCursorNextPage() returns the next child page @@ -719,11 +717,6 @@ * Note that while interiorCursorNextPage() will refuse to follow * loops, it does not keep track of pages returned for purposes of * preventing duplication. - * - * Note that interiorCursorEOF() could return false (not at EOF), and - * interiorCursorNextPage() could still return SQLITE_DONE. This - * could happen if there are more cells to iterate in an interior - * page, but those cells refer to invalid pages. */ typedef struct RecoverInteriorCursor RecoverInteriorCursor; struct RecoverInteriorCursor { @@ -839,14 +832,6 @@ return 0; } -static int interiorCursorEOF(RecoverInteriorCursor *pCursor){ - /* Find a parent with remaining children. EOF if none found. */ - while( pCursor && pCursor->iChild>=pCursor->nChildren ){ - pCursor = pCursor->pParent; - } - return pCursor==NULL; -} - /* Internal helper. Used to detect if iPage would cause a loop. */ static int interiorCursorPageInUse(RecoverInteriorCursor *pCursor, unsigned iPage){
diff --git a/tools/android/eclipse/.classpath b/tools/android/eclipse/.classpath index d9a45166..04959840 100644 --- a/tools/android/eclipse/.classpath +++ b/tools/android/eclipse/.classpath
@@ -59,6 +59,9 @@ <classpathentry kind="src" path="content/shell/android/linker_test_apk/src"/> <classpathentry kind="src" path="content/shell/android/shell_apk/src"/> <classpathentry kind="src" path="device/battery/android/java/src"/> + <classpathentry kind="src" path="device/bluetooth/android/java/src"/> + <classpathentry kind="src" path="device/usb/android/java/src"/> + <classpathentry kind="src" path="device/vibration/android/java/src"/> <classpathentry kind="src" path="media/base/android/java/src"/> <classpathentry kind="src" path="mojo/android/system/src"/> <classpathentry kind="src" path="mojo/android/javatests/src"/>
diff --git a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp index 3d12b5f..1e22e9c0 100644 --- a/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp +++ b/tools/clang/rewrite_to_chrome_style/RewriteToChromeStyle.cpp
@@ -62,6 +62,7 @@ const char kBlinkFieldPrefix[] = "m_"; const char kBlinkStaticMemberPrefix[] = "s_"; +const char kGeneratedFileRegex[] = "^gen/|/gen/"; AST_MATCHER(clang::FunctionDecl, isOverloadedOperator) { return Node.isOverloadedOperator(); @@ -86,54 +87,114 @@ InnerMatcher.matches(*NodeAsDecl, Finder, Builder)); } -bool IsDeclContextInBlinkOrWTF(const clang::DeclContext* decl_context, - bool blink, - bool wtf) { - assert(blink || wtf); // Else, what's the point? +bool IsDeclContextInWTF(const clang::DeclContext* decl_context) { auto* namespace_decl = clang::dyn_cast_or_null<clang::NamespaceDecl>( decl_context->getEnclosingNamespaceContext()); - return namespace_decl && namespace_decl->getParent()->isTranslationUnit() && - ((blink && namespace_decl->getName() == "blink") || - (wtf && namespace_decl->getName() == "WTF")); + if (!namespace_decl) + return false; + if (namespace_decl->getParent()->isTranslationUnit() && + namespace_decl->getName() == "WTF") + return true; + return IsDeclContextInWTF(namespace_decl->getParent()); } -// A method is from Blink if it is from the Blink namespace or overrides a -// method from the Blink namespace. -bool IsBlinkOrWTFMethod(const clang::CXXMethodDecl& decl) { - bool overrides_blink = false; - bool overrides_non_blink = false; +template <typename T> +bool MatchAllOverriddenMethods( + const clang::CXXMethodDecl& decl, + T&& inner_matcher, + clang::ast_matchers::internal::ASTMatchFinder* finder, + clang::ast_matchers::internal::BoundNodesTreeBuilder* builder) { + bool override_matches = false; + bool override_not_matches = false; for (auto it = decl.begin_overridden_methods(); it != decl.end_overridden_methods(); ++it) { - if (IsBlinkOrWTFMethod(**it)) - overrides_blink = true; + if (MatchAllOverriddenMethods(**it, inner_matcher, finder, builder)) + override_matches = true; else - overrides_non_blink = true; + override_not_matches = true; } - // If this fires we have a class overriding a method from a class in blink, - // and also overriding a method of the same name from a class not in blink, - // without a common base class. The blink method will be renamed but the - // non-blink method will not, meaning no matter what we do here we stop - // overriding one of the two which creates a behaviour change. So assert and - // demand the user to fix the code first. T_T - if (overrides_blink || overrides_non_blink) - assert(overrides_blink != overrides_non_blink); + // If this fires we have a class overriding a method that matches, and a + // method that does not match the inner matcher. In that case we will match + // one ancestor method but not the other. If we rename one of the and not the + // other it will break what this class overrides, disconnecting it from the + // one we did not rename which creates a behaviour change. So assert and + // demand the user to fix the code first (or add the method to our + // blacklist T_T). + if (override_matches || override_not_matches) + assert(override_matches != override_not_matches); - // If the method overrides something from outside blink then it's not a blink - // method. - if (overrides_non_blink) + // If the method overrides something that doesn't match, so the method itself + // doesn't match. + if (override_not_matches) return false; - // If the method overrides something from inside blink, then it is also a - // blink method. - if (overrides_blink) + // If the method overrides something that matches, so the method ifself + // matches. + if (override_matches) return true; - // Otherwise decide for itself. - return IsDeclContextInBlinkOrWTF(decl.getDeclContext(), true, true); + + return inner_matcher.matches(decl, finder, builder); } -AST_MATCHER(clang::CXXMethodDecl, isBlinkOrWTFMethod) { - return IsBlinkOrWTFMethod(Node); +AST_MATCHER_P(clang::CXXMethodDecl, + includeAllOverriddenMethods, + clang::ast_matchers::internal::Matcher<clang::CXXMethodDecl>, + InnerMatcher) { + return MatchAllOverriddenMethods(Node, InnerMatcher, Finder, Builder); +} + +bool IsMethodOverrideOf(const clang::CXXMethodDecl& decl, + const char* class_name) { + if (decl.getParent()->getQualifiedNameAsString() == class_name) + return true; + for (auto it = decl.begin_overridden_methods(); + it != decl.end_overridden_methods(); ++it) { + if (IsMethodOverrideOf(**it, class_name)) + return true; + } + return false; +} + +bool IsBlacklistedMethod(const clang::CXXMethodDecl& decl) { + if (decl.isStatic()) + return false; + + clang::StringRef name = decl.getName(); + + // These methods should never be renamed. + static const char* kBlacklistMethods[] = {"trace", "lock", "unlock", + "try_lock"}; + for (const auto& b : kBlacklistMethods) { + if (name == b) + return true; + } + + // Iterator methods shouldn't be renamed to work with stl and range-for + // loops. + std::string ret_type = decl.getReturnType().getAsString(); + if (ret_type.find("iterator") != std::string::npos || + ret_type.find("Iterator") != std::string::npos) { + static const char* kIteratorBlacklist[] = {"begin", "end", "rbegin", + "rend"}; + for (const auto& b : kIteratorBlacklist) { + if (name == b) + return true; + } + } + + // Subclasses of InspectorAgent will subclass "disable()" from both blink and + // from gen/, which is problematic, but DevTools folks don't want to rename + // it or split this up. So don't rename it at all. + if (name.equals("disable") && + IsMethodOverrideOf(decl, "blink::InspectorAgent")) + return true; + + return false; +} + +AST_MATCHER(clang::CXXMethodDecl, isBlacklistedMethod) { + return IsBlacklistedMethod(Node); } // Helper to convert from a camelCaseName to camel_case_name. It uses some @@ -257,30 +318,6 @@ bool GetNameForDecl(const clang::CXXMethodDecl& decl, const clang::ASTContext& context, std::string& name) { - StringRef original_name = decl.getName(); - - if (!decl.isStatic()) { - std::string ret_type = decl.getReturnType().getAsString(); - if (ret_type.find("iterator") != std::string::npos || - ret_type.find("Iterator") != std::string::npos) { - // Iterator methods shouldn't be renamed to work with stl and range-for - // loops. - static const char* kIteratorBlacklist[] = {"begin", "end", "rbegin", - "rend"}; - for (const auto& b : kIteratorBlacklist) { - if (original_name == b) - return false; - } - } - - // Some methods shouldn't be renamed because reasons. - static const char* kBlacklist[] = {"trace", "lock", "unlock", "try_lock"}; - for (const auto& b : kBlacklist) { - if (original_name == b) - return false; - } - } - name = decl.getName().str(); name[0] = clang::toUppercase(name[0]); return true; @@ -332,7 +369,7 @@ // Struct consts in WTF do not become kFoo cuz stuff like type traits // should stay as lowercase. const clang::DeclContext* decl_context = decl.getDeclContext(); - bool is_in_wtf = IsDeclContextInBlinkOrWTF(decl_context, false, true); + bool is_in_wtf = IsDeclContextInWTF(decl_context); const clang::CXXRecordDecl* parent = clang::dyn_cast_or_null<clang::CXXRecordDecl>(decl_context); if (is_in_wtf && parent && parent->isStruct()) @@ -530,10 +567,8 @@ auto in_blink_namespace = decl(hasAncestor(namespaceDecl(anyOf(hasName("blink"), hasName("WTF")), - hasParent(translationUnitDecl())))); - // The ^gen/ rule is used for production code, but the /gen/ one exists here - // too for making testing easier. - auto is_generated = decl(isExpansionInFileMatching("^gen/|/gen/")); + hasParent(translationUnitDecl()))), + unless(isExpansionInFileMatching(kGeneratedFileRegex))); // Field, variable, and enum declarations ======== // Given @@ -543,12 +578,10 @@ // enum { VALUE }; // }; // matches |x|, |y|, and |VALUE|. - auto field_decl_matcher = - id("decl", fieldDecl(in_blink_namespace, unless(is_generated))); - auto var_decl_matcher = - id("decl", varDecl(in_blink_namespace, unless(is_generated))); + auto field_decl_matcher = id("decl", fieldDecl(in_blink_namespace)); + auto var_decl_matcher = id("decl", varDecl(in_blink_namespace)); auto enum_member_decl_matcher = - id("decl", enumConstantDecl(in_blink_namespace, unless(is_generated))); + id("decl", enumConstantDecl(in_blink_namespace)); FieldDeclRewriter field_decl_rewriter(&replacements); match_finder.addMatcher(field_decl_matcher, &field_decl_rewriter); @@ -618,7 +651,7 @@ // Out-of-line overloaded operators have special names and should // never be renamed. isOverloadedOperator())), - in_blink_namespace, unless(is_generated))); + in_blink_namespace)); FunctionDeclRewriter function_decl_rewriter(&replacements); match_finder.addMatcher(function_decl_matcher, &function_decl_rewriter); @@ -638,21 +671,27 @@ // void g(); // }; // matches |g|. - auto method_decl_matcher = - id("decl", - cxxMethodDecl(unless(anyOf(is_generated, - // Overloaded operators have special names - // and should never be renamed. - isOverloadedOperator(), - // Similarly, constructors, destructors, and - // conversion functions should not be - // considered for renaming. - cxxConstructorDecl(), cxxDestructorDecl(), - cxxConversionDecl())), - // Check this last after excluding things, to avoid - // asserts about overriding non-blink and blink for the - // same method. - isBlinkOrWTFMethod())); + // For a method to be considered for rewrite, it must not override something + // that we're not rewriting. Any methods that we would not normally consider + // but that override something we are rewriting should also be rewritten. So + // we use includeAllOverriddenMethods() to check these rules not just for the + // method being matched but for the methods it overrides also. + auto is_blink_method = includeAllOverriddenMethods( + allOf(in_blink_namespace, unless(isBlacklistedMethod()))); + auto method_decl_matcher = id( + "decl", + cxxMethodDecl( + unless(anyOf( + // Overloaded operators have special names and should never be + // renamed. + isOverloadedOperator(), + // Similarly, constructors, destructors, and conversion functions + // should not be considered for renaming. + cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl())), + // Check this last after excluding things, to avoid + // asserts about overriding non-blink and blink for the + // same method. + is_blink_method)); MethodDeclRewriter method_decl_rewriter(&replacements); match_finder.addMatcher(method_decl_matcher, &method_decl_rewriter); @@ -701,10 +740,9 @@ // using blink::X; // matches |using blink::X|. auto function_template_decl_matcher = - id("decl", - functionTemplateDecl( - templatedDecl(anyOf(function_decl_matcher, method_decl_matcher)), - in_blink_namespace, unless(is_generated))); + id("decl", functionTemplateDecl(templatedDecl(anyOf(function_decl_matcher, + method_decl_matcher)), + in_blink_namespace)); UsingDeclRewriter using_decl_rewriter(&replacements); match_finder.addMatcher( id("decl",
diff --git a/tools/clang/rewrite_to_chrome_style/tests/gen/thing.h b/tools/clang/rewrite_to_chrome_style/tests/gen/thing.h index 772eaac..900b65c 100644 --- a/tools/clang/rewrite_to_chrome_style/tests/gen/thing.h +++ b/tools/clang/rewrite_to_chrome_style/tests/gen/thing.h
@@ -4,4 +4,8 @@ namespace blink { void genThing(); + +class GenClass { + virtual void genMethod() {} +}; }
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc index 343e4e1..766145e 100644 --- a/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc +++ b/tools/clang/rewrite_to_chrome_style/tests/methods-expected.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "gen/thing.h" + namespace v8 { class InterfaceOutsideOfBlink { @@ -93,6 +95,25 @@ int ptr_; }; +namespace subname { + +class SubnameParent { + virtual void SubnameMethod() {} +}; + +} // namespace subname + +class SubnameChild : public subname::SubnameParent { + // This subclasses from blink::subname::SubnameParent and should be renamed. + void SubnameMethod() override {} +}; + +class GenChild : public blink::GenClass { + // This subclasses from the blink namespace but in the gen directory so it + // should not be renamed. + void genMethod() override {} +}; + } // namespace blink // Test that overrides from outside the Blink namespace are also updated.
diff --git a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc index 040582dd..12165b7 100644 --- a/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc +++ b/tools/clang/rewrite_to_chrome_style/tests/methods-original.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "gen/thing.h" + namespace v8 { class InterfaceOutsideOfBlink { @@ -97,6 +99,25 @@ int m_ptr; }; +namespace subname { + +class SubnameParent { + virtual void subnameMethod() {} +}; + +} // namespace subname + +class SubnameChild : public subname::SubnameParent { + // This subclasses from blink::subname::SubnameParent and should be renamed. + void subnameMethod() override {} +}; + +class GenChild : public blink::GenClass { + // This subclasses from the blink namespace but in the gen directory so it + // should not be renamed. + void genMethod() override {} +}; + } // namespace blink // Test that overrides from outside the Blink namespace are also updated.
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py index b005520..1e24d7c 100755 --- a/tools/clang/scripts/update.py +++ b/tools/clang/scripts/update.py
@@ -339,7 +339,8 @@ # or a system-wide installation otherwise. sys.path.append(os.path.join(CHROMIUM_DIR, 'tools', 'gyp', 'pylib')) import gyp.MSVSVersion - vs_version = gyp.MSVSVersion.SelectVisualStudioVersion('2013') + vs_version = gyp.MSVSVersion.SelectVisualStudioVersion( + vs_toolchain.GetVisualStudioVersion()) return vs_version
diff --git a/tools/gn/command_format.cc b/tools/gn/command_format.cc index d7301c92..ae36e37 100644 --- a/tools/gn/command_format.cc +++ b/tools/gn/command_format.cc
@@ -35,6 +35,16 @@ "\n" " Formats .gn file to a standard format.\n" "\n" + " The contents of some lists ('sources', 'deps', etc.) will be sorted to\n" + " a canonical order. To suppress this, you can add a comment of the form\n" + " \"# NOSORT\" immediately preceeding the assignment. e.g.\n" + "\n" + " # NOSORT\n" + " sources = [\n" + " \"z.cc\",\n" + " \"a.cc\",\n" + " ]\n" + "\n" "Arguments\n" " --dry-run\n" " Does not change or output anything, but sets the process exit code\n" @@ -315,6 +325,12 @@ } void Printer::SortIfSourcesOrDeps(const BinaryOpNode* binop) { + if (binop && binop->comments() && !binop->comments()->before().empty() && + binop->comments()->before()[0].value().as_string() == "# NOSORT") { + // Allow disabling of sort for specific actions that might be + // order-sensitive. + return; + } const IdentifierNode* ident = binop->left()->AsIdentifier(); const ListNode* list = binop->right()->AsList(); if ((binop->op().value() == "=" || binop->op().value() == "+=" ||
diff --git a/tools/gn/command_format_unittest.cc b/tools/gn/command_format_unittest.cc index 8e8c256..7c79d41 100644 --- a/tools/gn/command_format_unittest.cc +++ b/tools/gn/command_format_unittest.cc
@@ -103,3 +103,4 @@ FORMAT_TEST(063) FORMAT_TEST(064) FORMAT_TEST(065) +FORMAT_TEST(066)
diff --git a/tools/gn/docs/quick_start.md b/tools/gn/docs/quick_start.md index d59abc8a..8b064deb 100644 --- a/tools/gn/docs/quick_start.md +++ b/tools/gn/docs/quick_start.md
@@ -72,7 +72,6 @@ ## Configuring goma - Run `gn args out/Default` (substituting your build directory as needed). Add: @@ -282,6 +281,24 @@ Hello, Bill and Joy. ``` +## Add a new build argument + +You declare which arguments you accept and specify default values via +`declare_args`. + +``` +declare_args() { + enable_teleporter = true + enable_doom_melon = false +} +``` + +See `gn help buildargs` for an overview of how this works. +See `gn help declare_args` for specifics on declaring them. + +It is an error to declare a given argument more than once in a given scope, so +care should be used in scoping and naming arguments. + ## Don't know what's going on? You can run GN in verbose mode to see lots of messages about what it's
diff --git a/tools/gn/docs/style_guide.md b/tools/gn/docs/style_guide.md index 40c5286..de46564 100644 --- a/tools/gn/docs/style_guide.md +++ b/tools/gn/docs/style_guide.md
@@ -182,3 +182,43 @@ to do otherwise. A static library is a standalone library which can be slow to generate. A source set just links all the object files from that target into the targets depending on it, which saves the "lib" step. + +## Build arguments + +### Scope + +Build arguments should be scoped to a unit of behavior, e.g. enabling a feature. +Typically an argument would be declared in an imported file to share it with +the subset of the build that could make use of it. + +### Type + +Arguments support all the [GN language types](language.md#Language). + +In the vast majority of cases `boolean` is the preferred type, since most +arguments are enabling or disabling features or includes. + +`String`s are typically used for filepaths. They are also used for enumerated +types, though `integer`s are sometimes used as well. + +### Naming conventions + +While there are no hard and fast rules around argument naming there are +many common conventions. If you ever want to see the current list of argument +names and default values for your current checkout use +`gn args out/Debug --list --short`. + +`use_foo` - indicates dependencies or major codepaths to include (e.g. +`use_open_ssl`, `use_ozone`, `use_cups`) + +`enable_foo` - indicates feature or tools to be enabled (e.g. +`enable_google_now`, `enable_nacl`, `enable_remoting`, `enable_pdf`) + +`disable_foo` - _NOT_ recommended, use `enable_foo` instead with swapped default +value + +`is_foo` - usually a global state descriptor (e.g. `is_chrome_branded`, +`is_desktop_linux`); poor choice for non-globals + +`foo_use_bar` - prefixes can be used to indicate a limited scope for an argument +(e.g. `rtc_use_h264`, `v8_use_snapshot`)
diff --git a/tools/gn/format_test_data/066.gn b/tools/gn/format_test_data/066.gn new file mode 100644 index 0000000..c62eb2a --- /dev/null +++ b/tools/gn/format_test_data/066.gn
@@ -0,0 +1,30 @@ +# Suppress sorting based on comment. + +# NOSORT +sources = [] + +# NOSORT +sources = [ + "a", +] + +# NOSORT +sources += [ + "a", +] + +# NOSORT +sources = [ + "z", + "z2", + "a", + "y.cc", +] + +# NOSORT +sources += [ + "z", + "z2", + "a", + "y.cc", +]
diff --git a/tools/gn/format_test_data/066.golden b/tools/gn/format_test_data/066.golden new file mode 100644 index 0000000..45467b88 --- /dev/null +++ b/tools/gn/format_test_data/066.golden
@@ -0,0 +1,28 @@ +# Suppress sorting based on comment. + +# NOSORT +sources = [] + +# NOSORT +sources = [ + "a", +] + +# NOSORT +sources += [ "a" ] + +# NOSORT +sources = [ + "z", + "z2", + "a", + "y.cc", +] + +# NOSORT +sources += [ + "z", + "z2", + "a", + "y.cc", +]
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index a08ad20..3e1ec97a 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -28,7 +28,7 @@ 'android_gyp_debug_static_bot_arm64': ['android', 'gyp', 'debug_static_bot', 'arm64'], 'android_gyp_debug_trybot': ['android', 'gyp', 'debug_trybot'], 'android_gyp_debug_trybot_arm64': ['android', 'gyp', 'debug_trybot', 'arm64'], - 'android_gyp_release_bot': ['android', 'gyp', 'release_bot'], + 'android_gyp_release_bot_minimal_symbols': ['android', 'gyp', 'release_bot_minimal_symbols'], 'android_without_codecs_gyp_release_bot_minimal_symbols': ['android_without_codecs', 'gyp', 'release_bot_minimal_symbols'], 'android_gyp_release_trybot': ['android', 'gyp', 'release_trybot'], 'cast_gn_release_bot': ['cast', 'gn', 'release_bot'], @@ -538,12 +538,12 @@ }, 'chromium.linux': { 'Android Arm64 Builder (dbg)': 'android_gyp_debug_static_bot_arm64', - 'Android Builder': 'android_gyp_release_bot', + 'Android Builder': 'android_gyp_release_bot_minimal_symbols', 'Android Builder (dbg)': 'android_gyp_debug_static_bot', 'Android Clang Builder (dbg)': 'android_clang_asan_gyp_debug_bot', 'Android GN': 'android_gn_release_bot', 'Android GN (dbg)': 'android_gn_debug_bot', - 'Android Tests': 'android_gyp_release_bot', + 'Android Tests': 'android_gyp_release_bot_minimal_symbols', 'Android Tests (dbg)': 'android_gyp_debug_static_bot', 'Cast Android (dbg)': 'android_cast_gyp_debug_static_bot', 'Cast Linux': 'cast_gn_release_bot',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 4c4981d9..bbee64d7 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6972,6 +6972,12 @@ <histogram name="DataReductionProxy.RequestCompletionErrorCodes" enum="NetErrorCodes"> + <obsolete> + Deprecated in 2/2016, since it didn't get recorded for many kinds of error + codes when it should have been recorded, and + Net.HttpRequestCompletionErrorCodes is a good enough replacement when + filtering for clients with the Data Reduction Proxy enabled. + </obsolete> <owner>sclittle@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -6982,6 +6988,12 @@ <histogram name="DataReductionProxy.RequestCompletionErrorCodes.MainFrame" enum="NetErrorCodes"> + <obsolete> + Deprecated in 2/2016, since it didn't get recorded for many kinds of error + codes when it should have been recorded, and + Net.HttpRequestCompletionErrorCodes is a good enough replacement when + filtering for clients with the Data Reduction Proxy enabled. + </obsolete> <owner>sclittle@chromium.org</owner> <owner>bengr@chromium.org</owner> <summary> @@ -18122,6 +18134,9 @@ </histogram> <histogram name="JSDialogs.CountOfOnBeforeUnloadMessageCharacters"> + <obsolete> + Deprecated 2016-02. + </obsolete> <owner>avi@chromium.org</owner> <summary> The count of the number of characters in onbeforeunload messages. @@ -18129,6 +18144,9 @@ </histogram> <histogram name="JSDialogs.CountOfOnBeforeUnloadMessageNewlines"> + <obsolete> + Deprecated 2016-02. + </obsolete> <owner>avi@chromium.org</owner> <summary> The count of the number of newlines in onbeforeunload messages. (This does @@ -28512,6 +28530,25 @@ <summary>Time to complete a speculative certificate verification.</summary> </histogram> +<histogram name="Net.SSLProtocolErrorCipher" enum="SSLCipherSuite"> + <owner>davidben@chromium.org</owner> + <summary> + The cipher suite used when the corresponding operation on an SSLClientSocket + fails with ERR_SSL_PROTOCOL_ERROR. This histogram will be removed when + https://crbug.com/593963 is resolved. + </summary> +</histogram> + +<histogram name="Net.SSLProtocolErrorReason" enum="BoringSSLReasonCode"> + <owner>davidben@chromium.org</owner> + <summary> + The internal, version-specific BoringSSL error reason reported when the + corresponding operation on an SSLClientSocket fails with + ERR_SSL_PROTOCOL_ERROR. This histogram will be removed when + https://crbug.com/593963 is resolved. + </summary> +</histogram> + <histogram name="Net.SSLProtocolNegotiation" enum="SSLProtocolNegotiation"> <owner>bnc@chromium.org</owner> <summary> @@ -58483,6 +58520,31 @@ </summary> </histogram> +<histogram name="Windows.GetVersionExVersion" enum="WindowsVersion"> + <owner>scottmg@chromium.org</owner> + <summary> + The Windows version (base::win::Version) as reported by GetVersionEx(). This + is queried shortly after startup. + </summary> +</histogram> + +<histogram name="Windows.InCompatibilityMode" enum="BooleanCompatibilityMode"> + <owner>scottmg@chromium.org</owner> + <summary> + A boolean used to indicate when the Windows version reported by + GetVersionEx() and the Windows version reported by VerQueryValue() on + kernel32 do not match. This is queried shortly after startup. + </summary> +</histogram> + +<histogram name="Windows.Kernel32Version" enum="WindowsVersion"> + <owner>scottmg@chromium.org</owner> + <summary> + The Windows version (base::win::Version) as reported by VeryQueryValue() on + kernel32.dll. This is queried shortly after startup. + </summary> +</histogram> + <histogram name="Windows.Tablet" enum="BooleanTablet"> <owner>zturner@chromium.org</owner> <summary>Count of browser launches from a Windows tablet pc.</summary> @@ -60172,6 +60234,11 @@ <int value="1" label="Common Name used"/> </enum> +<enum name="BooleanCompatibilityMode" type="int"> + <int value="0" label="Not in compatibility mode"/> + <int value="1" label="In compatibility mode"/> +</enum> + <enum name="BooleanCompleted" type="int"> <int value="0" label="Not Completed"/> <int value="1" label="Completed"/> @@ -60612,6 +60679,13 @@ <int value="1" label="Wiped out"/> </enum> +<enum name="BoringSSLReasonCode" type="int"> + <details> + See include/openssl/ssl.h at the corresponding BoringSSL revision for the + corresponding values. + </details> +</enum> + <enum name="BrokenAlternateProtocolLocation" type="int"> <int value="0" label="HTTP_STREAM_FACTORY_IMPL_JOB"/> <int value="1" label="QUIC_STREAM_FACTORY"/> @@ -73113,6 +73187,7 @@ <int value="11" label="Continuing main thread scroll"/> <int value="12" label="Non-invertible transform"/> <int value="13" label="Page based scrolling"/> + <int value="14" label="Animating scroll on main thread"/> </enum> <enum name="MakeChromeDefaultResult" type="int"> @@ -84199,6 +84274,9 @@ <int value="3" label="Vista"/> <int value="4" label="Windows 7"/> <int value="5" label="Windows 8"/> + <int value="6" label="Windows 8.1"/> + <int value="7" label="Windows 10"/> + <int value="8" label="Windows 10 TH2"/> </enum> <enum name="WindowType" type="int"> @@ -89352,6 +89430,14 @@ <affected-histogram name="SimpleCache.SyncOpenResult"/> </histogram_suffixes> +<histogram_suffixes name="SocketOperation" separator="."> + <affected-histogram name="Net.SSLProtocolErrorCipher"/> + <affected-histogram name="Net.SSLProtocolErrorReason"/> + <suffix name="Connect"/> + <suffix name="Read"/> + <suffix name="Write"/> +</histogram_suffixes> + <histogram_suffixes name="SocketType"> <obsolete> Deprecated as of 03/2015.
diff --git a/tools/perf/docs/perf_bot_sheriffing.md b/tools/perf/docs/perf_bot_sheriffing.md index 7e26c6f2..3f368ee 100644 --- a/tools/perf/docs/perf_bot_sheriffing.md +++ b/tools/perf/docs/perf_bot_sheriffing.md
@@ -5,17 +5,11 @@ ## Key Responsibilities - * [Keeping the chromium.perf waterfall green](#chromiumperf) - * [Handling Test Failures](#testfailures) - * [Handling Device and Bot Failures](#botfailures) - * [Follow up on failures](#followup) + * [Handle Device and Bot Failures](#botfailures) + * [Handle Test Failures](#testfailures) + * [Follow up on failures](#followup) -###<a name="chromiumperf"></a> Keeping the chromium.perf waterfall green - -The primary responsibility of the perfbot health sheriff is to keep the -chromium.perf waterfall green. - -####<a name="waterfallstate"></a> Understanding the Waterfall State +##<a name="waterfallstate"></a> Understanding the Waterfall State Everyone can view the chromium.perf waterfall at https://build.chromium.org/p/chromium.perf/, but for Googlers it is recommended @@ -49,20 +43,74 @@ them with specific bugs. You can see a list of all previously filed bugs using the -**[Performance-BotHealth](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth)** +**[Performance-BotHealth](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth)** label in crbug. Please also check the recent **[perf-sheriffs@chromium.org](https://groups.google.com/a/chromium.org/forum/#!forum/perf-sheriffs)** postings for important announcements about bot turndowns and other known issues. -####<a name="testfailures"></a> Handling Test Failures +##<a name="botfailures"></a> Handle Device and Bot Failures + +###<a name="purplebots"></a> Purple bots + +When a bot goes purple, it's it's usually because of an infrastructure failure +outside of the tests. But you should first check the logs of a purple bot to +try to better understand the problem. Sometimes a telemetry test failure can +turn the bot purple, for example. + +If the bot goes purple and you believe it's an infrastructure issue, file a bug +with +[this template](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Troopers,OS-?&comment=Link+to+buildbot+status+page:&summary=Purple+Bot+on+chromium.perf), +which will automatically add the bug to the trooper queue. Be sure to note +which step is failing, and paste any relevant info from the logs into the bug. + +###<a name="devicefailures"></a> Android Device failures + +There are two types of device failures: + +1. A device is blacklisted in the `device_status_check` step. You can look at + the buildbot status page to see how many devices were listed as online during + this step. You should always see 7 devices online. If you see fewer than 7 + devices online, there is a problem in the lab. +2. A device is passing `device_status_check` but still in poor health. The + symptom of this is that all the tests are failing on it. You can see that on + the buildbot status page by looking at the `Device Affinity`. If all tests + with the same device affinity number are failing, it's probably a device + failure. + +For both types of failures, please file a bug with [this template](https://bugs.chromium.org/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Labs,OS-Android&comment=Link+to+buildbot+status+page:&summary=Device+offline+on+chromium.perf) +which will add an issue to the infra labs queue. + +If you need help triaging, here are the common labels you should use: + + * **Performance-BotHealth** should go on all bugs you file about the bots; + it's the label we use to track all the issues. + * **Infra-Troopers** adds the bug to the trooper queue. This is for high + priority issues, like a build breakage. Please add a comment explaining + what you want the trooper to do. + * **Infra-Labs** adds the bug to the labs queue. If there is a hardware + problem, like an android device not responding or a bot that likely needs + a restart, please use this label. Make sure you set the **OS-** label + correctly as well, and add a comment explaining what you want the labs + team to do. + * **Infra** label is appropriate for bugs that are not high priority, but we + need infra team's help to triage. For example, the buildbot status page + UI is weird or we are getting some infra-related log spam. The infra team + works to triage these bugs within 24 hours, so you should ping if you do + not get a response. + * **Cr-Tests-Telemetry** for telemetry failures. + * **Cr-Tests-AutoBisect** for bisect and perf try job failures. + + If you still need help, ask the speed infra chat, or escalate to sullivan@. + +##<a name="testfailures"></a> Handle Test Failures You want to keep the waterfall green! So any bot that is red or purple needs to be investigated. When a test fails: 1. File a bug using - [this template](https://code.google.com/p/chromium/issues/entry?labels=Performance-BotHealth,Pri-1,Type-Bug-Regression,OS-?&comment=Revision+range+first+seen:%0ALink+to+failing+step+log:%0A%0A%0AIf%20the%20test%20is%20disabled,%20please%20downgrade%20to%20Pri-2.&summary=%3Ctest%3E+failure+on+chromium.perf+at+%3Crevisionrange%3E). + [this template](https://bugs.chromium.org/p/chromium/issues/entry?labels=Performance-BotHealth,Pri-1,Type-Bug-Regression,OS-?&comment=Revision+range+first+seen:%0ALink+to+failing+step+log:%0A%0A%0AIf%20the%20test%20is%20disabled,%20please%20downgrade%20to%20Pri-2.&summary=%3Ctest%3E+failure+on+chromium.perf+at+%3Crevisionrange%3E). You'll want to be sure to include: * Link to buildbot status page of failing build. * Copy and paste of relevant failure snippet from the stdio. @@ -97,11 +145,11 @@ the tab did not crash. -#####<a name="telemetryfailures"></a> Disabling Telemetry Tests +###<a name="telemetryfailures"></a> Disabling Telemetry Tests If the test is a telemetry test, its name will have a '.' in it, such as -thread_times.key_mobile_sites, or page_cycler.top_10. The part before the first -dot will be a python file in [tools/perf/benchmarks]( +`thread_times.key_mobile_sites`, or `page_cycler.top_10`. The part before the +first dot will be a python file in [tools/perf/benchmarks]( https://code.google.com/p/chromium/codesearch#chromium/src/tools/perf/benchmarks/). If a telemetry test is failing and there is no clear culprit to revert @@ -134,80 +182,26 @@ Disabling CLs can be TBR-ed to anyone in tools/perf/OWNERS, but please do **not** submit with NOTRY=true. -#####<a name="otherfailures"></a> Disabling Other Tests +###<a name="otherfailures"></a> Disabling Other Tests Non-telemetry tests are configured in [chromium.perf.json](https://code.google.com/p/chromium/codesearch#chromium/src/testing/buildbot/chromium.perf.json). You can TBR any of the per-file OWNERS, but please do **not** submit with NOTRY=true. -####<a name="botfailures"></a> Handling Device and Bot Failures +##<a name="followup"></a> Follow up on failures -#####<a name="purplebots"></a> Purple bots - -When a bot goes purple, it's it's usually because of an infrastructure failure -outside of the tests. But you should first check the logs of a purple bot to -try to better understand the problem. Sometimes a telemetry test failure can -turn the bot purple, for example. - -If the bot goes purple and you believe it's an infrastructure issue, file a bug -with -[this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Troopers,OS-?&comment=Link+to+buildbot+status+page:&summary=Purple+Bot+on+chromium.perf), -which will automatically add the bug to the trooper queue. Be sure to note -which step is failing, and paste any relevant info from the logs into the bug. - -#####<a name="devicefailures"></a> Android Device failures - -There are two types of device failures: - -1. A device is blacklisted in the `device_status_check` step. You can look at - the buildbot status page to see how many devices were listed as online during - this step. You should always see 7 devices online. If you see fewer than 7 - devices online, there is a problem in the lab. -2. A device is passing `device_status_check` but still in poor health. The - symptom of this is that all the tests are failing on it. You can see that on - the buildbot status page by looking at the `Device Affinity`. If all tests - with the same device affinity number are failing, it's probably a device - failure. - -For both types of failures, please file a bug with [this template](https://code.google.com/p/chromium/issues/entry?labels=Pri-1,Performance-BotHealth,Infra-Labs,OS-Android&comment=Link+to+buildbot+status+page:&summary=Device+offline+on+chromium.perf) -which will add an issue to the infra labs queue. - -If you need help triaging, here are the common labels you should use: - - * **Performance-BotHealth** should go on all bugs you file about the bots; - it's the label we use to track all the issues. - * **Infra-Troopers** adds the bug to the trooper queue. This is for high - priority issues, like a build breakage. Please add a comment explaining - what you want the trooper to do. - * **Infra-Labs** adds the bug to the labs queue. If there is a hardware - problem, like an android device not responding or a bot that likely needs - a restart, please use this label. Make sure you set the **OS-** label - correctly as well, and add a comment explaining what you want the labs - team to do. - * **Infra** label is appropriate for bugs that are not high priority, but we - need infra team's help to triage. For example, the buildbot status page - UI is weird or we are getting some infra-related log spam. The infra team - works to triage these bugs within 24 hours, so you should ping if you do - not get a response. - * **Cr-Tests-Telemetry** for telemetry failures. - * **Cr-Tests-AutoBisect** for bisect and perf try job failures. - - If you still need help, ask the speed infra chat, or escalate to sullivan@. - -####<a name="followup"></a> Follow up on failures - -**[Pri-0 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-0)** +**[Pri-0 bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-0)** should have an owner or contact on speed infra team and be worked on as top priority. Pri-0 generally implies an entire waterfall is down. -**[Pri-1 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-1)** +**[Pri-1 bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-1)** should be pinged daily, and checked to make sure someone is following up. Pri-1 bugs are for a red test (not yet disabled), purple bot, or failing device. -**[Pri-2 bugs](https://code.google.com/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-2)** +**[Pri-2 bugs](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label%3APerformance-BotHealth+label%3APri-2)** are for disabled tests. These should be pinged weekly, and work towards fixing should be ongoing when the sheriff is not working on a Pri-1 issue. Here is the -[list of Pri-2 bugs that have not been pinged in a week](https://code.google.com/p/chromium/issues/list?can=2&q=label:Performance-BotHealth%20label:Pri-2%20modified-before:today-7&sort=modified) +[list of Pri-2 bugs that have not been pinged in a week](https://bugs.chromium.org/p/chromium/issues/list?can=2&q=label:Performance-BotHealth%20label:Pri-2%20modified-before:today-7&sort=modified) <!-- Unresolved issues: 1. Do perf sheriffs watch the bisect waterfall?
diff --git a/tools/perf/docs/perf_regression_sheriffing.md b/tools/perf/docs/perf_regression_sheriffing.md index 8f45b682..a7cc703 100644 --- a/tools/perf/docs/perf_regression_sheriffing.md +++ b/tools/perf/docs/perf_regression_sheriffing.md
@@ -12,7 +12,7 @@ * [Follow up on Performance Regressions](#followup) * [Give Feedback on our Infrastructure](#feedback) -###<a name="triage"></a> Triage Regressions on the Perf Dashboard +##<a name="triage"></a> Triage Regressions on the Perf Dashboard Open the perf dashboard [alerts page](https://chromeperf.appspot.com/alerts). @@ -73,7 +73,7 @@ bisects as you feel are necessary to investigate; [give feedback](#feedback) below if you feel that is not the case. -###<a name="datastoppage"></a> Triaging data stoppage alerts +##<a name="datastoppage"></a> Triaging data stoppage alerts Data stoppage alerts are listed on the [perf dashboard alerts page](https://chromeperf.appspot.com/alerts). Whenever @@ -108,7 +108,7 @@ sent to the perf dashboard. Are there null values? Sometimes it lists a reason as well. Please put your finding in the bug. -###<a name="followup"></a> Follow up on Performance Regressions +##<a name="followup"></a> Follow up on Performance Regressions During your shift, you should try to follow up on each of the bugs you filed. Once you've triaged all the alerts, check to see if the bisects have come back, @@ -129,7 +129,7 @@ certain that a specific CL caused a performance regression, and the author does not have an immediate plan to address the problem, please revert the CL. -###<a name="feedback"></a> Give Feedback on our Infrastructure +##<a name="feedback"></a> Give Feedback on our Infrastructure Perf regression sheriffs have their eyes on the perf dashboard and bisects more than anyone else, and their feedback is invaluable for making sure these
diff --git a/tools/perf/record_wpr b/tools/perf/record_wpr index b600c13..89af476 100755 --- a/tools/perf/record_wpr +++ b/tools/perf/record_wpr
@@ -6,7 +6,6 @@ import sys -from core import path_util from chrome_telemetry_build import chromium_config sys.path.append(chromium_config.GetTelemetryDir()) @@ -18,4 +17,4 @@ if __name__ == '__main__': - sys.exit(record_wpr.Main(path_util.GetPerfDir())) + sys.exit(record_wpr.Main(environment=chromium_config.ChromiumConfig()))
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index 53ca55e..2c037f7 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -203,10 +203,15 @@ sources += [ "android/events_jni_registrar.cc", "android/events_jni_registrar.h", + "android/key_event_utils.cc", + "android/key_event_utils.h", "android/motion_event_android.cc", "android/motion_event_android.h", ] - deps += [ ":motionevent_jni_headers" ] + deps += [ + ":keyevent_jni_headers", + ":motionevent_jni_headers", + ] } } @@ -371,6 +376,7 @@ ":test_support", "//base", "//base/test:run_all_unittests", + "//base/test:test_support", "//ipc:test_support", "//skia", "//testing/gmock", @@ -457,4 +463,9 @@ jni_package = "ui" classes = [ "android/view/MotionEvent.class" ] } + + generate_jar_jni("keyevent_jni_headers") { + jni_package = "ui" + classes = [ "android/view/KeyEvent.class" ] + } }
diff --git a/ui/events/android/events_jni_registrar.cc b/ui/events/android/events_jni_registrar.cc index f75e5e6b..03f9344 100644 --- a/ui/events/android/events_jni_registrar.cc +++ b/ui/events/android/events_jni_registrar.cc
@@ -7,6 +7,7 @@ #include "base/android/jni_android.h" #include "base/android/jni_registrar.h" #include "base/macros.h" +#include "ui/events/android/key_event_utils.h" #include "ui/events/android/motion_event_android.h" namespace ui { @@ -15,6 +16,7 @@ static base::android::RegistrationMethod kAndroidRegisteredMethods[] = { {"MotionEventAndroid", ui::MotionEventAndroid::RegisterMotionEventAndroid}, + {"KeyEventUtils", RegisterKeyEvent}, }; bool RegisterJni(JNIEnv* env) {
diff --git a/ui/events/android/key_event_utils.cc b/ui/events/android/key_event_utils.cc new file mode 100644 index 0000000..af2f2c5b --- /dev/null +++ b/ui/events/android/key_event_utils.cc
@@ -0,0 +1,32 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/android/key_event_utils.h" + +#include "jni/KeyEvent_jni.h" + +namespace ui { +namespace events { +namespace android { + +bool RegisterKeyEvent(JNIEnv* env) { + return JNI_KeyEvent::RegisterNativesImpl(env); +} + +base::android::ScopedJavaLocalRef<jobject> CreateKeyEvent(JNIEnv* env, + int action, + int key_code) { + return JNI_KeyEvent::Java_KeyEvent_ConstructorAVKE_I_I(env, action, key_code); +} + +int GetKeyEventUnicodeChar(JNIEnv* env, + const base::android::JavaRef<jobject>& event, + int meta_state) { + return static_cast<int>(JNI_KeyEvent::Java_KeyEvent_getUnicodeCharI_I( + env, event.obj(), meta_state)); +} + +} // namespace android +} // namespace events +} // namespace ui
diff --git a/ui/events/android/key_event_utils.h b/ui/events/android/key_event_utils.h new file mode 100644 index 0000000..83445d1 --- /dev/null +++ b/ui/events/android/key_event_utils.h
@@ -0,0 +1,31 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_ANDROID_KEY_EVENT_UTILS_H_ +#define UI_EVENTS_ANDROID_KEY_EVENT_UTILS_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "ui/events/events_export.h" + +namespace ui { +namespace events { +namespace android { + +bool RegisterKeyEvent(JNIEnv* env); + +EVENTS_EXPORT base::android::ScopedJavaLocalRef<jobject> +CreateKeyEvent(JNIEnv* env, int action, int key_code); + +EVENTS_EXPORT int GetKeyEventUnicodeChar( + JNIEnv* env, + const base::android::JavaRef<jobject>& event, + int meta_state); + +} // namespace android +} // namespace events +} // namespace ui + +#endif // UI_EVENTS_ANDROID_KEY_EVENT_UTISL_H_
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc index 1889a89..267d7399 100644 --- a/ui/events/blink/input_handler_proxy.cc +++ b/ui/events/blink/input_handler_proxy.cc
@@ -384,8 +384,9 @@ return DID_NOT_HANDLE; } -void RecordMainThreadScrollingReasons(WebInputEvent::Type type, - uint32_t reasons) { +void InputHandlerProxy::RecordMainThreadScrollingReasons( + WebInputEvent::Type type, + uint32_t reasons) { static const char* kGestureHistogramName = "Renderer4.MainThreadGestureScrollReason"; static const char* kWheelHistogramName =
diff --git a/ui/events/blink/input_handler_proxy.h b/ui/events/blink/input_handler_proxy.h index 2da4bc9..a1ccc83 100644 --- a/ui/events/blink/input_handler_proxy.h +++ b/ui/events/blink/input_handler_proxy.h
@@ -89,6 +89,10 @@ return gesture_scroll_on_impl_thread_; } + protected: + void RecordMainThreadScrollingReasons(blink::WebInputEvent::Type type, + uint32_t reasons); + private: friend class test::InputHandlerProxyTest;
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc index b798dc9..f3545d7 100644 --- a/ui/events/blink/input_handler_proxy_unittest.cc +++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -6,6 +6,7 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/test/histogram_tester.h" #include "cc/input/main_thread_scrolling_reason.h" #include "cc/trees/swap_promise_monitor.h" #include "testing/gmock/include/gmock/gmock.h" @@ -259,6 +260,17 @@ cc::InputHandler::SCROLL_IGNORED, cc::MainThreadScrollingReason::kNotScrollable); +class TestInputHandlerProxy : public InputHandlerProxy { + public: + TestInputHandlerProxy(cc::InputHandler* input_handler, + InputHandlerProxyClient* client) + : InputHandlerProxy(input_handler, client) {} + void RecordMainThreadScrollingReasonsForTest(blink::WebInputEvent::Type type, + uint32_t reasons) { + RecordMainThreadScrollingReasons(type, reasons); + } +}; + } // namespace class InputHandlerProxyTest @@ -272,7 +284,7 @@ GetParam() == CHILD_SCROLL_SYNCHRONOUS_HANDLER), expected_disposition_(InputHandlerProxy::DID_HANDLE) { input_handler_.reset( - new ui::InputHandlerProxy( + new TestInputHandlerProxy( &mock_input_handler_, &mock_client_)); scroll_result_did_scroll_.did_scroll = true; scroll_result_did_not_scroll_.did_scroll = false; @@ -381,7 +393,7 @@ testing::StrictMock<MockInputHandler> mock_input_handler_; testing::StrictMock<MockSynchronousInputHandler> mock_synchronous_input_handler_; - scoped_ptr<ui::InputHandlerProxy> input_handler_; + scoped_ptr<TestInputHandlerProxy> input_handler_; testing::StrictMock<MockInputHandlerProxyClient> mock_client_; WebGestureEvent gesture_; InputHandlerProxy::EventDisposition expected_disposition_; @@ -2690,7 +2702,7 @@ testing::StrictMock<MockInputHandlerProxyClientWithDidAnimateForInput> mock_client; input_handler_.reset( - new ui::InputHandlerProxy( + new TestInputHandlerProxy( &mock_input_handler_, &mock_client)); if (install_synchronous_handler_) { EXPECT_CALL(mock_input_handler_, RequestUpdateForSynchronousInputHandler()) @@ -2789,6 +2801,22 @@ testing::Mock::VerifyAndClearExpectations(&mock_synchronous_input_handler); } +TEST_P(InputHandlerProxyTest, MainThreadScrollingMouseWheelHistograms) { + base::HistogramTester histogram_tester; + input_handler_->RecordMainThreadScrollingReasonsForTest( + WebInputEvent::MouseWheel, + cc::MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects | + cc::MainThreadScrollingReason::kThreadedScrollingDisabled | + cc::MainThreadScrollingReason::kPageOverlay | + cc::MainThreadScrollingReason::kAnimatingScrollOnMainThread); + + EXPECT_THAT( + histogram_tester.GetAllSamples("Renderer4.MainThreadWheelScrollReason"), + testing::ElementsAre(base::Bucket(1, 1), base::Bucket(3, 1), + base::Bucket(5, 1), base::Bucket(14, 1))); +} + + INSTANTIATE_TEST_CASE_P(AnimateInput, InputHandlerProxyTest, testing::ValuesIn(test_types));
diff --git a/ui/events/events.gyp b/ui/events/events.gyp index b905a482..f6f7911 100644 --- a/ui/events/events.gyp +++ b/ui/events/events.gyp
@@ -208,9 +208,12 @@ 'android/events_jni_registrar.h', 'android/motion_event_android.cc', 'android/motion_event_android.h', + 'android/key_event_utils.cc', + 'android/key_event_utils.h', ], 'dependencies': [ 'motionevent_jni_headers', + 'keyevent_jni_headers', ], }], ], @@ -386,6 +389,15 @@ }, 'includes': [ '../../build/jar_file_jni_generator.gypi' ], }, + { + 'target_name': 'keyevent_jni_headers', + 'type': 'none', + 'variables': { + 'jni_gen_package': 'ui', + 'input_java_class': 'android/view/KeyEvent.class', + }, + 'includes': [ '../../build/jar_file_jni_generator.gypi' ], + }, ], }], ],
diff --git a/ui/views/animation/button_ink_drop_delegate.cc b/ui/views/animation/button_ink_drop_delegate.cc index 5b753c2..7d25f57 100644 --- a/ui/views/animation/button_ink_drop_delegate.cc +++ b/ui/views/animation/button_ink_drop_delegate.cc
@@ -29,6 +29,10 @@ ink_drop_animation_controller_->AnimateToState(state); } +void ButtonInkDropDelegate::SnapToActivated() { + ink_drop_animation_controller_->SnapToActivated(); +} + void ButtonInkDropDelegate::SetHovered(bool is_hovered) { ink_drop_animation_controller_->SetHovered(is_hovered); }
diff --git a/ui/views/animation/button_ink_drop_delegate.h b/ui/views/animation/button_ink_drop_delegate.h index 9184309..b1e1b5f 100644 --- a/ui/views/animation/button_ink_drop_delegate.h +++ b/ui/views/animation/button_ink_drop_delegate.h
@@ -30,6 +30,7 @@ // InkDropDelegate: void OnAction(InkDropState state) override; + void SnapToActivated() override; void SetHovered(bool is_hovered) override; // ui::EventHandler:
diff --git a/ui/views/animation/flood_fill_ink_drop_animation.cc b/ui/views/animation/flood_fill_ink_drop_animation.cc index 77db9b26..77e091e4 100644 --- a/ui/views/animation/flood_fill_ink_drop_animation.cc +++ b/ui/views/animation/flood_fill_ink_drop_animation.cc
@@ -158,6 +158,12 @@ AbortAllAnimations(); } +void FloodFillInkDropAnimation::SnapToActivated() { + InkDropAnimation::SnapToActivated(); + SetOpacity(kVisibleOpacity); + painted_layer_.SetTransform(GetActivatedTargetTransform()); +} + ui::Layer* FloodFillInkDropAnimation::GetRootLayer() { return &root_layer_; } @@ -209,7 +215,10 @@ case InkDropState::QUICK_ACTION: { DCHECK(old_ink_drop_state == InkDropState::HIDDEN || old_ink_drop_state == InkDropState::ACTION_PENDING); - + if (old_ink_drop_state == InkDropState::HIDDEN) { + AnimateStateChange(old_ink_drop_state, InkDropState::ACTION_PENDING, + animation_observer); + } AnimateToOpacity(kHiddenOpacity, GetAnimationDuration(QUICK_ACTION_FADE_OUT), ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, @@ -240,9 +249,8 @@ AnimateToOpacity(kVisibleOpacity, GetAnimationDuration(ACTIVATED_FADE_IN), ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, gfx::Tween::EASE_IN, animation_observer); - const gfx::Transform transform = CalculateTransform( - CalculateLargestDistanceToCorners(size_, center_point_)); - AnimateToTransform(transform, GetAnimationDuration(ACTIVATED_TRANSFORM), + AnimateToTransform(GetActivatedTargetTransform(), + GetAnimationDuration(ACTIVATED_TRANSFORM), ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET, gfx::Tween::EASE_IN_OUT, animation_observer); break; @@ -328,4 +336,9 @@ return transform; } +gfx::Transform FloodFillInkDropAnimation::GetActivatedTargetTransform() const { + return CalculateTransform( + CalculateLargestDistanceToCorners(size_, center_point_)); +} + } // namespace views
diff --git a/ui/views/animation/flood_fill_ink_drop_animation.h b/ui/views/animation/flood_fill_ink_drop_animation.h index fa6942f..e838e282 100644 --- a/ui/views/animation/flood_fill_ink_drop_animation.h +++ b/ui/views/animation/flood_fill_ink_drop_animation.h
@@ -54,6 +54,7 @@ ~FloodFillInkDropAnimation() override; // InkDropAnimation: + void SnapToActivated() override; ui::Layer* GetRootLayer() override; bool IsVisible() const override; @@ -97,6 +98,9 @@ // |target_radius|. gfx::Transform CalculateTransform(float target_radius) const; + // Returns the target Transform for the ACTIVATED animation. + gfx::Transform GetActivatedTargetTransform() const; + // The clip Size. const gfx::Size size_;
diff --git a/ui/views/animation/ink_drop_animation.cc b/ui/views/animation/ink_drop_animation.cc index 2f55a25ff..3f04376dd 100644 --- a/ui/views/animation/ink_drop_animation.cc +++ b/ui/views/animation/ink_drop_animation.cc
@@ -68,6 +68,23 @@ // AnimationEndedCallback which can delete |this|. } +void InkDropAnimation::SnapToActivated() { + AbortAllAnimations(); + // |animation_observer| will be deleted when AnimationEndedCallback() returns + // true. + // TODO(bruthig): Implement a safer ownership model for the + // |animation_observer|. + ui::CallbackLayerAnimationObserver* animation_observer = + new ui::CallbackLayerAnimationObserver( + base::Bind(&InkDropAnimation::AnimationStartedCallback, + base::Unretained(this), InkDropState::ACTIVATED), + base::Bind(&InkDropAnimation::AnimationEndedCallback, + base::Unretained(this), InkDropState::ACTIVATED)); + GetRootLayer()->SetVisible(true); + target_ink_drop_state_ = InkDropState::ACTIVATED; + animation_observer->SetActive(); +} + void InkDropAnimation::HideImmediately() { AbortAllAnimations(); SetStateToHidden();
diff --git a/ui/views/animation/ink_drop_animation.h b/ui/views/animation/ink_drop_animation.h index 52eba9c9..e7b4bf0 100644 --- a/ui/views/animation/ink_drop_animation.h +++ b/ui/views/animation/ink_drop_animation.h
@@ -64,6 +64,11 @@ // state transition to HIDDEN! void HideImmediately(); + // Immediately snaps the ink drop to the ACTIVATED target state. All pending + // animations are aborted. Events will be raised for the pending animations + // as well as the transition to the ACTIVATED state. + virtual void SnapToActivated(); + // The root Layer that can be added in to a Layer tree. virtual ui::Layer* GetRootLayer() = 0;
diff --git a/ui/views/animation/ink_drop_animation_controller.h b/ui/views/animation/ink_drop_animation_controller.h index 2d71307..ec511e2 100644 --- a/ui/views/animation/ink_drop_animation_controller.h +++ b/ui/views/animation/ink_drop_animation_controller.h
@@ -37,6 +37,12 @@ // Animates from the current InkDropState to |ink_drop_state|. virtual void AnimateToState(InkDropState ink_drop_state) = 0; + // Immediately snaps the InkDropState to ACTIVATED. This more specific + // implementation of the non-existent SnapToState(InkDropState) function is + // the only one available because it was the only InkDropState that clients + // needed to skip animations for. + virtual void SnapToActivated() = 0; + // Enables or disables the hover state. virtual void SetHovered(bool is_hovered) = 0;
diff --git a/ui/views/animation/ink_drop_animation_controller_factory.cc b/ui/views/animation/ink_drop_animation_controller_factory.cc index 9a9c8ed..19bae013 100644 --- a/ui/views/animation/ink_drop_animation_controller_factory.cc +++ b/ui/views/animation/ink_drop_animation_controller_factory.cc
@@ -28,6 +28,7 @@ InkDropState GetTargetInkDropState() const override; bool IsVisible() const override; void AnimateToState(InkDropState state) override; + void SnapToActivated() override; void SetHovered(bool is_hovered) override; private: @@ -48,6 +49,8 @@ void InkDropAnimationControllerStub::AnimateToState(InkDropState state) {} +void InkDropAnimationControllerStub::SnapToActivated() {} + void InkDropAnimationControllerStub::SetHovered(bool is_hovered) {} } // namespace
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.cc b/ui/views/animation/ink_drop_animation_controller_impl.cc index f7dbd12..def6df3b 100644 --- a/ui/views/animation/ink_drop_animation_controller_impl.cc +++ b/ui/views/animation/ink_drop_animation_controller_impl.cc
@@ -54,6 +54,7 @@ InkDropHost* ink_drop_host) : ink_drop_host_(ink_drop_host), root_layer_(new ui::Layer(ui::LAYER_NOT_DRAWN)), + is_hovered_(false), hover_after_animation_timer_(nullptr) { root_layer_->set_name("InkDropAnimationControllerImpl:RootLayer"); ink_drop_host_->AddInkDropLayer(root_layer_.get()); @@ -86,16 +87,22 @@ kHoverFadeOutBeforeAnimationDurationInMs)); } - // Make sure the ink drop starts from the HIDDEN state it was going to auto - // transition to it. - if (ink_drop_animation_->target_ink_drop_state() == InkDropState::HIDDEN || - ShouldAnimateToHidden(ink_drop_animation_->target_ink_drop_state())) { - ink_drop_animation_->HideImmediately(); - } + CompleteHiddenTargetedAnimations(); ink_drop_animation_->AnimateToState(ink_drop_state); } +void InkDropAnimationControllerImpl::SnapToActivated() { + if (!ink_drop_animation_) + CreateInkDropAnimation(); + + SetHoveredInternal(false, base::TimeDelta()); + + CompleteHiddenTargetedAnimations(); + ink_drop_animation_->SnapToActivated(); +} + void InkDropAnimationControllerImpl::SetHovered(bool is_hovered) { + is_hovered_ = is_hovered; SetHoveredInternal(is_hovered, is_hovered ? base::TimeDelta::FromMilliseconds( kHoverFadeInFromUserInputDurationInMs) @@ -103,6 +110,13 @@ kHoverFadeOutFromUserInputDurationInMs)); } +void InkDropAnimationControllerImpl::CompleteHiddenTargetedAnimations() { + if (ink_drop_animation_->target_ink_drop_state() == InkDropState::HIDDEN || + ShouldAnimateToHidden(ink_drop_animation_->target_ink_drop_state())) { + ink_drop_animation_->HideImmediately(); + } +} + void InkDropAnimationControllerImpl::CreateInkDropAnimation() { DestroyInkDropAnimation(); ink_drop_animation_ = ink_drop_host_->CreateInkDropAnimation(); @@ -149,7 +163,8 @@ if (ShouldAnimateToHidden(ink_drop_state)) { ink_drop_animation_->AnimateToState(views::InkDropState::HIDDEN); } else if (ink_drop_state == views::InkDropState::HIDDEN) { - StartHoverAfterAnimationTimer(); + if (is_hovered_) + StartHoverAfterAnimationTimer(); // TODO(bruthig): Investigate whether creating and destroying // InkDropAnimations is expensive and consider creating an // InkDropAnimationPool. See www.crbug.com/522175.
diff --git a/ui/views/animation/ink_drop_animation_controller_impl.h b/ui/views/animation/ink_drop_animation_controller_impl.h index 92feae61..8aaf6bc 100644 --- a/ui/views/animation/ink_drop_animation_controller_impl.h +++ b/ui/views/animation/ink_drop_animation_controller_impl.h
@@ -37,12 +37,17 @@ InkDropState GetTargetInkDropState() const override; bool IsVisible() const override; void AnimateToState(InkDropState ink_drop_state) override; + void SnapToActivated() override; void SetHovered(bool is_hovered) override; private: friend class InkDropAnimationControllerFactoryTest; friend class InkDropAnimationControllerImplTest; + // Forcibly transition to the HIDDEN state if completing the current animation + // sequence would eventually be HIDDEN. + void CompleteHiddenTargetedAnimations(); + // Creates a new InkDropAnimation and sets it to |ink_drop_animation_|. If // |ink_drop_animation_| wasn't null then it will be destroyed using // DestroyInkDropAnimation(). @@ -94,6 +99,10 @@ // The current InkDropHover. Lazily created using CreateInkDropHover(); scoped_ptr<InkDropHover> hover_; + // Tracks the logical hovered state of |this| as manipulated by the public + // SetHovered() function. + bool is_hovered_; + // The current InkDropAnimation. Created on demand using // CreateInkDropAnimation(). scoped_ptr<InkDropAnimation> ink_drop_animation_;
diff --git a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc index 633c332..4f98549 100644 --- a/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc +++ b/ui/views/animation/ink_drop_animation_controller_impl_unittest.cc
@@ -70,8 +70,19 @@ } TEST_F(InkDropAnimationControllerImplTest, - HoveredStateAfterHoverTimerFiresWhenHostIsHovered) { + HoverDoesntFadeInAfterAnimationIfHoverNotSet) { ink_drop_host_.set_should_show_hover(true); + ink_drop_animation_controller_.SetHovered(false); + ink_drop_animation_controller_.AnimateToState(InkDropState::QUICK_ACTION); + + EXPECT_FALSE(task_runner_->HasPendingTask()); + EXPECT_FALSE(is_hover_fading_in_or_visible()); +} + +TEST_F(InkDropAnimationControllerImplTest, + HoverFadesInAfterAnimationWhenHostIsHovered) { + ink_drop_host_.set_should_show_hover(true); + ink_drop_animation_controller_.SetHovered(true); ink_drop_animation_controller_.AnimateToState(InkDropState::QUICK_ACTION); EXPECT_TRUE(task_runner_->HasPendingTask()); @@ -82,8 +93,9 @@ } TEST_F(InkDropAnimationControllerImplTest, - HoveredStateAfterHoverTimerFiresWhenHostIsNotHovered) { + HoverDoesntFadeInAfterAnimationWhenHostIsNotHovered) { ink_drop_host_.set_should_show_hover(false); + ink_drop_animation_controller_.SetHovered(true); ink_drop_animation_controller_.AnimateToState(InkDropState::QUICK_ACTION); EXPECT_TRUE(task_runner_->HasPendingTask()); @@ -115,4 +127,15 @@ EXPECT_FALSE(hover()); } +TEST_F(InkDropAnimationControllerImplTest, HoverFadesOutOnSnapToActivated) { + ink_drop_host_.set_should_show_hover(true); + ink_drop_animation_controller_.SetHovered(true); + + EXPECT_TRUE(is_hover_fading_in_or_visible()); + + ink_drop_animation_controller_.SnapToActivated(); + + EXPECT_FALSE(is_hover_fading_in_or_visible()); +} + } // namespace views
diff --git a/ui/views/animation/ink_drop_animation_unittest.cc b/ui/views/animation/ink_drop_animation_unittest.cc index 6f98549..22f6230 100644 --- a/ui/views/animation/ink_drop_animation_unittest.cc +++ b/ui/views/animation/ink_drop_animation_unittest.cc
@@ -269,6 +269,52 @@ EXPECT_FALSE(ink_drop_animation_->IsVisible()); } +TEST_P(InkDropAnimationTest, SnapToActivatedWithoutActiveAnimations) { + ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); + test_api_->CompleteAnimations(); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + EXPECT_EQ(2, observer_.last_animation_ended_ordinal()); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::ACTIVATED, + ink_drop_animation_->target_ink_drop_state()); + + ink_drop_animation_->SnapToActivated(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::ACTIVATED, + ink_drop_animation_->target_ink_drop_state()); + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); + + EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); + EXPECT_TRUE(ink_drop_animation_->IsVisible()); +} + +// Verifies all active animations are aborted and the InkDropState is set to +// ACTIVATED after invoking SnapToActivated(). +TEST_P(InkDropAnimationTest, SnapToActivatedWithActiveAnimations) { + ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING); + EXPECT_TRUE(test_api_->HasActiveAnimations()); + EXPECT_NE(InkDropState::ACTIVATED, + ink_drop_animation_->target_ink_drop_state()); + EXPECT_EQ(1, observer_.last_animation_started_ordinal()); + + ink_drop_animation_->SnapToActivated(); + + EXPECT_FALSE(test_api_->HasActiveAnimations()); + EXPECT_EQ(views::InkDropState::ACTIVATED, + ink_drop_animation_->target_ink_drop_state()); + EXPECT_EQ(3, observer_.last_animation_started_ordinal()); + EXPECT_EQ(4, observer_.last_animation_ended_ordinal()); + EXPECT_EQ(InkDropState::ACTIVATED, observer_.last_animation_state_ended()); + EXPECT_EQ(InkDropAnimationObserver::InkDropAnimationEndedReason::SUCCESS, + observer_.last_animation_ended_reason()); + + EXPECT_EQ(InkDropAnimation::kVisibleOpacity, test_api_->GetCurrentOpacity()); + EXPECT_TRUE(ink_drop_animation_->IsVisible()); +} + TEST_P(InkDropAnimationTest, AnimateToVisibleFromHidden) { EXPECT_EQ(InkDropState::HIDDEN, ink_drop_animation_->target_ink_drop_state()); ink_drop_animation_->AnimateToState(views::InkDropState::ACTION_PENDING);
diff --git a/ui/views/animation/ink_drop_delegate.h b/ui/views/animation/ink_drop_delegate.h index 99b1e82c..6123524 100644 --- a/ui/views/animation/ink_drop_delegate.h +++ b/ui/views/animation/ink_drop_delegate.h
@@ -29,6 +29,9 @@ // as well as a NONE value. virtual void OnAction(InkDropState state) = 0; + // Immediately snaps the InkDropState to ACTIVATED. + virtual void SnapToActivated() = 0; + // Enables or disables the hover state. virtual void SetHovered(bool is_hovered) = 0;
diff --git a/ui/views/animation/square_ink_drop_animation.cc b/ui/views/animation/square_ink_drop_animation.cc index eb6890e..5d78b43 100644 --- a/ui/views/animation/square_ink_drop_animation.cc +++ b/ui/views/animation/square_ink_drop_animation.cc
@@ -195,6 +195,14 @@ AbortAllAnimations(); } +void SquareInkDropAnimation::SnapToActivated() { + InkDropAnimation::SnapToActivated(); + SetOpacity(kVisibleOpacity); + InkDropTransforms transforms; + GetActivatedTargetTransforms(&transforms); + SetTransforms(transforms); +} + ui::Layer* SquareInkDropAnimation::GetRootLayer() { return &root_layer_; } @@ -269,6 +277,10 @@ case InkDropState::QUICK_ACTION: { DCHECK(old_ink_drop_state == InkDropState::HIDDEN || old_ink_drop_state == InkDropState::ACTION_PENDING); + if (old_ink_drop_state == InkDropState::HIDDEN) { + AnimateStateChange(old_ink_drop_state, InkDropState::ACTION_PENDING, + animation_observer); + } AnimateToOpacity(kHiddenOpacity, GetAnimationDuration(QUICK_ACTION_FADE_OUT), ui::LayerAnimator::ENQUEUE_NEW_ANIMATION, @@ -333,7 +345,7 @@ ui::LayerAnimator::ENQUEUE_NEW_ANIMATION; } - CalculateRectTransforms(small_size_, small_corner_radius_, &transforms); + GetActivatedTargetTransforms(&transforms); AnimateToTransforms(transforms, GetAnimationDuration(ACTIVATED_RECT_TRANSFORM), rect_transform_preemption_strategy, @@ -498,6 +510,11 @@ (*transforms_out)[i] = painted_layers_[i]->transform(); } +void SquareInkDropAnimation::GetActivatedTargetTransforms( + InkDropTransforms* transforms_out) const { + CalculateRectTransforms(small_size_, small_corner_radius_, transforms_out); +} + void SquareInkDropAnimation::AddPaintLayer(PaintedShape painted_shape) { ui::LayerDelegate* delegate = nullptr; switch (painted_shape) {
diff --git a/ui/views/animation/square_ink_drop_animation.h b/ui/views/animation/square_ink_drop_animation.h index 9a0bfcb..d897a59 100644 --- a/ui/views/animation/square_ink_drop_animation.h +++ b/ui/views/animation/square_ink_drop_animation.h
@@ -59,6 +59,7 @@ ~SquareInkDropAnimation() override; // InkDropAnimation: + void SnapToActivated() override; ui::Layer* GetRootLayer() override; bool IsVisible() const override; @@ -138,6 +139,10 @@ // of the painted shape Layers. void GetCurrentTransforms(InkDropTransforms* transforms_out) const; + // Updates all of the Transforms in |transforms_out| with the target + // Transforms for the ACTIVATED animation. + void GetActivatedTargetTransforms(InkDropTransforms* transforms_out) const; + // Adds and configures a new |painted_shape| layer to |painted_layers_|. void AddPaintLayer(PaintedShape painted_shape);
diff --git a/ui/views/animation/test/test_ink_drop_delegate.cc b/ui/views/animation/test/test_ink_drop_delegate.cc index 103edf2..a251d78a 100644 --- a/ui/views/animation/test/test_ink_drop_delegate.cc +++ b/ui/views/animation/test/test_ink_drop_delegate.cc
@@ -16,6 +16,10 @@ state_ = state; } +void TestInkDropDelegate::SnapToActivated() { + state_ = InkDropState::ACTIVATED; +} + void TestInkDropDelegate::SetHovered(bool is_hovered) { is_hovered_ = is_hovered; }
diff --git a/ui/views/animation/test/test_ink_drop_delegate.h b/ui/views/animation/test/test_ink_drop_delegate.h index 0fe2cbac..a3eee3e 100644 --- a/ui/views/animation/test/test_ink_drop_delegate.h +++ b/ui/views/animation/test/test_ink_drop_delegate.h
@@ -22,6 +22,7 @@ // InkDropDelegate: void OnAction(InkDropState state) override; + void SnapToActivated() override; void SetHovered(bool is_hovered) override; private:
diff --git a/ui/views/controls/button/custom_button.cc b/ui/views/controls/button/custom_button.cc index cb36cb7..d655ac34 100644 --- a/ui/views/controls/button/custom_button.cc +++ b/ui/views/controls/button/custom_button.cc
@@ -295,6 +295,10 @@ // we won't get a mouse exited and reset state. Reset it now to be sure. if (state_ != STATE_DISABLED) SetState(STATE_NORMAL); + if (ink_drop_delegate_) { + ink_drop_delegate_->SetHovered(false); + ink_drop_delegate_->OnAction(InkDropState::HIDDEN); + } View::ShowContextMenu(p, source_type); }
diff --git a/ui/views/controls/button/custom_button_unittest.cc b/ui/views/controls/button/custom_button_unittest.cc index 10f4e97..0b07a34 100644 --- a/ui/views/controls/button/custom_button_unittest.cc +++ b/ui/views/controls/button/custom_button_unittest.cc
@@ -14,7 +14,9 @@ #include "ui/gfx/screen.h" #include "ui/views/animation/ink_drop_delegate.h" #include "ui/views/animation/ink_drop_host.h" +#include "ui/views/animation/test/test_ink_drop_delegate.h" #include "ui/views/animation/test/test_ink_drop_host.h" +#include "ui/views/context_menu_controller.h" #include "ui/views/controls/button/checkbox.h" #include "ui/views/controls/button/image_button.h" #include "ui/views/controls/button/label_button.h" @@ -32,8 +34,25 @@ namespace views { +using test::TestInkDropDelegate; + namespace { +// No-op test double of a ContextMenuController. +class TestContextMenuController : public ContextMenuController { + public: + TestContextMenuController() {} + ~TestContextMenuController() override {} + + // ContextMenuController: + void ShowContextMenuForView(View* source, + const gfx::Point& point, + ui::MenuSourceType source_type) override {} + + private: + DISALLOW_COPY_AND_ASSIGN(TestContextMenuController); +}; + class TestCustomButton : public CustomButton, public ButtonListener { public: explicit TestCustomButton() @@ -66,15 +85,11 @@ }; // An InkDropDelegate that keeps track of ink drop visibility. -class TestInkDropDelegate : public InkDropDelegate { +class TestInkDropDelegateThatTracksVisibilty : public InkDropDelegate { public: - TestInkDropDelegate(InkDropHost* ink_drop_host, - bool* ink_shown, - bool* ink_hidden) - : ink_drop_host_(ink_drop_host), - ink_shown_(ink_shown), - ink_hidden_(ink_hidden) {} - ~TestInkDropDelegate() override {} + TestInkDropDelegateThatTracksVisibilty(bool* ink_shown, bool* ink_hidden) + : ink_shown_(ink_shown), ink_hidden_(ink_hidden) {} + ~TestInkDropDelegateThatTracksVisibilty() override {} // InkDropDelegate: void OnAction(InkDropState state) override { @@ -94,23 +109,22 @@ } } + void SnapToActivated() override { *ink_shown_ = true; } + void SetHovered(bool is_hovered) override {} private: - InkDropHost* ink_drop_host_; bool* ink_shown_; bool* ink_hidden_; - DISALLOW_COPY_AND_ASSIGN(TestInkDropDelegate); + DISALLOW_COPY_AND_ASSIGN(TestInkDropDelegateThatTracksVisibilty); }; // A test Button class that owns a TestInkDropDelegate. class TestButtonWithInkDrop : public TestCustomButton { public: - TestButtonWithInkDrop(bool* ink_shown, bool* ink_hidden) - : TestCustomButton(), - ink_drop_delegate_( - new TestInkDropDelegate(this, ink_shown, ink_hidden)) { + TestButtonWithInkDrop(scoped_ptr<InkDropDelegate> ink_drop_delegate) + : TestCustomButton(), ink_drop_delegate_(std::move(ink_drop_delegate)) { set_ink_drop_delegate(ink_drop_delegate_.get()); } ~TestButtonWithInkDrop() override {} @@ -149,19 +163,15 @@ ViewsTestBase::TearDown(); } - void CreateButtonWithInkDrop() { + void CreateButtonWithInkDrop(scoped_ptr<InkDropDelegate> ink_drop_delegate) { delete button_; - ink_shown_ = false; - ink_hidden_ = false; - button_ = new TestButtonWithInkDrop(&ink_shown_, &ink_hidden_); + button_ = new TestButtonWithInkDrop(std::move(ink_drop_delegate)); widget_->SetContentsView(button_); } protected: Widget* widget() { return widget_.get(); } TestCustomButton* button() { return button_; } - bool ink_shown() const { return ink_shown_; } - bool ink_hidden() const { return ink_hidden_; } void SetDraggedView(View* dragged_view) { widget_->dragged_view_ = dragged_view; } @@ -169,8 +179,6 @@ private: scoped_ptr<Widget> widget_; TestCustomButton* button_; - bool ink_shown_ = false; - bool ink_hidden_ = false; DISALLOW_COPY_AND_ASSIGN(CustomButtonTest); }; @@ -383,40 +391,75 @@ // may enter a different ink drop state. TEST_F(CustomButtonTest, ButtonClickTogglesInkDrop) { gfx::Point old_cursor = gfx::Screen::GetScreen()->GetCursorScreenPoint(); - CreateButtonWithInkDrop(); + bool ink_shown = false; + bool ink_hidden = false; + CreateButtonWithInkDrop(make_scoped_ptr( + new TestInkDropDelegateThatTracksVisibilty(&ink_shown, &ink_hidden))); ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow()); generator.set_current_location(gfx::Point(50, 50)); generator.PressLeftButton(); - EXPECT_TRUE(ink_shown()); - EXPECT_FALSE(ink_hidden()); + EXPECT_TRUE(ink_shown); + EXPECT_FALSE(ink_hidden); generator.ReleaseLeftButton(); - EXPECT_FALSE(ink_hidden()); + EXPECT_FALSE(ink_hidden); } // Tests that pressing a button shows and releasing capture hides ink drop. // Releasing capture should also reset PRESSED button state to NORMAL. TEST_F(CustomButtonTest, CaptureLossHidesInkDrop) { gfx::Point old_cursor = gfx::Screen::GetScreen()->GetCursorScreenPoint(); - CreateButtonWithInkDrop(); + bool ink_shown = false; + bool ink_hidden = false; + CreateButtonWithInkDrop(make_scoped_ptr( + new TestInkDropDelegateThatTracksVisibilty(&ink_shown, &ink_hidden))); ui::test::EventGenerator generator(GetContext(), widget()->GetNativeWindow()); generator.set_current_location(gfx::Point(50, 50)); generator.PressLeftButton(); - EXPECT_TRUE(ink_shown()); - EXPECT_FALSE(ink_hidden()); + EXPECT_TRUE(ink_shown); + EXPECT_FALSE(ink_hidden); EXPECT_EQ(Button::ButtonState::STATE_PRESSED, button()->state()); SetDraggedView(button()); widget()->SetCapture(button()); widget()->ReleaseCapture(); SetDraggedView(nullptr); - EXPECT_TRUE(ink_hidden()); + EXPECT_TRUE(ink_hidden); EXPECT_EQ(ui::MaterialDesignController::IsModeMaterial() ? Button::ButtonState::STATE_NORMAL : Button::ButtonState::STATE_PRESSED, button()->state()); } +TEST_F(CustomButtonTest, InkDropAfterShowingContextMenu) { + TestInkDropDelegate* ink_drop_delegate = new TestInkDropDelegate(); + CreateButtonWithInkDrop(make_scoped_ptr(ink_drop_delegate)); + TestContextMenuController context_menu_controller; + button()->set_context_menu_controller(&context_menu_controller); + + ink_drop_delegate->SetHovered(true); + ink_drop_delegate->OnAction(InkDropState::ACTION_PENDING); + + button()->ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); + + EXPECT_FALSE(ink_drop_delegate->is_hovered()); + EXPECT_EQ(InkDropState::HIDDEN, ink_drop_delegate->state()); +} + +TEST_F(CustomButtonTest, InkDropAfterTryingToShowContextMenu) { + TestInkDropDelegate* ink_drop_delegate = new TestInkDropDelegate(); + CreateButtonWithInkDrop(make_scoped_ptr(ink_drop_delegate)); + button()->set_context_menu_controller(nullptr); + + ink_drop_delegate->SetHovered(true); + ink_drop_delegate->OnAction(InkDropState::ACTION_PENDING); + + button()->ShowContextMenu(gfx::Point(), ui::MENU_SOURCE_MOUSE); + + EXPECT_TRUE(ink_drop_delegate->is_hovered()); + EXPECT_EQ(InkDropState::ACTION_PENDING, ink_drop_delegate->state()); +} + } // namespace views
diff --git a/ui/views/controls/button/menu_button.cc b/ui/views/controls/button/menu_button.cc index 599e06a..41921b9 100644 --- a/ui/views/controls/button/menu_button.cc +++ b/ui/views/controls/button/menu_button.cc
@@ -47,8 +47,12 @@ //////////////////////////////////////////////////////////////////////////////// MenuButton::PressedLock::PressedLock(MenuButton* menu_button) + : PressedLock(menu_button, false) {} + +MenuButton::PressedLock::PressedLock(MenuButton* menu_button, + bool is_sibling_menu_show) : menu_button_(menu_button->weak_factory_.GetWeakPtr()) { - menu_button_->IncrementPressedLocked(); + menu_button_->IncrementPressedLocked(is_sibling_menu_show); } MenuButton::PressedLock::~PressedLock() { @@ -368,13 +372,17 @@ Activate(&event); } -void MenuButton::IncrementPressedLocked() { +void MenuButton::IncrementPressedLocked(bool snap_ink_drop_to_activated) { ++pressed_lock_count_; if (increment_pressed_lock_called_) *increment_pressed_lock_called_ = true; should_disable_after_press_ = state() == STATE_DISABLED; - if (state() != STATE_PRESSED && ink_drop_delegate()) - ink_drop_delegate()->OnAction(InkDropState::ACTIVATED); + if (state() != STATE_PRESSED && ink_drop_delegate()) { + if (snap_ink_drop_to_activated) + ink_drop_delegate()->SnapToActivated(); + else + ink_drop_delegate()->OnAction(InkDropState::ACTIVATED); + } SetState(STATE_PRESSED); }
diff --git a/ui/views/controls/button/menu_button.h b/ui/views/controls/button/menu_button.h index 91504d2e..696a9414 100644 --- a/ui/views/controls/button/menu_button.h +++ b/ui/views/controls/button/menu_button.h
@@ -32,6 +32,7 @@ class VIEWS_EXPORT PressedLock { public: explicit PressedLock(MenuButton* menu_button); + PressedLock(MenuButton* menu_button, bool is_sibling_menu_show); ~PressedLock(); private: @@ -105,8 +106,10 @@ friend class PressedLock; // Increment/decrement the number of "pressed" locks this button has, and - // set the state accordingly. - void IncrementPressedLocked(); + // set the state accordingly. The ink drop is snapped to the final ACTIVATED + // state if |snap_ink_drop_to_activated| is true, otherwise the ink drop will + // be animated to the ACTIVATED state. + void IncrementPressedLocked(bool snap_ink_drop_to_activated); void DecrementPressedLocked(); // Compute the maximum X coordinate for the current screen. MenuButtons
diff --git a/ui/views/controls/menu/menu_controller.cc b/ui/views/controls/menu/menu_controller.cc index 3bbb045..7e0ba88 100644 --- a/ui/views/controls/menu/menu_controller.cc +++ b/ui/views/controls/menu/menu_controller.cc
@@ -1451,7 +1451,8 @@ // There is a sibling menu, update the button state, hide the current menu // and show the new one. - pressed_lock_.reset(new MenuButton::PressedLock(button)); + pressed_lock_.reset( + new MenuButton::PressedLock(button, true /* is_sibling_menu_show */)); // Need to reset capture when we show the menu again, otherwise we aren't // going to get any events.
diff --git a/ui/views/test/widget_test.cc b/ui/views/test/widget_test.cc index 9beca6d..0f4b3513 100644 --- a/ui/views/test/widget_test.cc +++ b/ui/views/test/widget_test.cc
@@ -132,5 +132,23 @@ return true; // Same default as DefaultWidgetDelegate in widget.cc. } +TestInitialFocusWidgetDelegate::TestInitialFocusWidgetDelegate( + gfx::NativeWindow context) + : view_(new View) { + view_->SetFocusable(true); + + Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); + params.context = context; + params.delegate = this; + GetWidget()->Init(params); + GetWidget()->GetContentsView()->AddChildView(view_); +} + +TestInitialFocusWidgetDelegate::~TestInitialFocusWidgetDelegate() {} + +View* TestInitialFocusWidgetDelegate::GetInitiallyFocusedView() { + return view_; +} + } // namespace test } // namespace views
diff --git a/ui/views/test/widget_test.h b/ui/views/test/widget_test.h index 0eee5ee..3b7dfe1 100644 --- a/ui/views/test/widget_test.h +++ b/ui/views/test/widget_test.h
@@ -151,6 +151,24 @@ DISALLOW_COPY_AND_ASSIGN(TestDesktopWidgetDelegate); }; +// Testing widget delegate that creates a widget with a single view, which is +// the initially focused view. +class TestInitialFocusWidgetDelegate : public TestDesktopWidgetDelegate { + public: + explicit TestInitialFocusWidgetDelegate(gfx::NativeWindow context); + ~TestInitialFocusWidgetDelegate() override; + + View* view() { return view_; } + + // WidgetDelegate override: + View* GetInitiallyFocusedView() override; + + private: + View* view_; + + DISALLOW_COPY_AND_ASSIGN(TestInitialFocusWidgetDelegate); +}; + } // namespace test } // namespace views
diff --git a/ui/views/widget/native_widget_aura.cc b/ui/views/widget/native_widget_aura.cc index 85ab0ae..aca2d236 100644 --- a/ui/views/widget/native_widget_aura.cc +++ b/ui/views/widget/native_widget_aura.cc
@@ -495,7 +495,10 @@ // SetInitialFocus() should be always be called, even for // SHOW_STATE_INACTIVE. If the window has to stay inactive, the method will // do the right thing. - SetInitialFocus(state); + // Activate() might fail if the window is non-activatable. In this case, we + // should pass SHOW_STATE_INACTIVE to SetInitialFocus() to stop the initial + // focused view from getting focused. See crbug.com/515594 for example. + SetInitialFocus(IsActive() ? state : ui::SHOW_STATE_INACTIVE); } // On desktop aura, a window is activated first even when it is shown as
diff --git a/ui/views/widget/native_widget_aura_unittest.cc b/ui/views/widget/native_widget_aura_unittest.cc index f10981f..0a626ae4 100644 --- a/ui/views/widget/native_widget_aura_unittest.cc +++ b/ui/views/widget/native_widget_aura_unittest.cc
@@ -19,9 +19,12 @@ #include "ui/events/event_utils.h" #include "ui/gfx/screen.h" #include "ui/views/layout/fill_layout.h" +#include "ui/views/test/widget_test.h" #include "ui/views/widget/root_view.h" #include "ui/views/widget/widget_delegate.h" +#include "ui/wm/core/base_focus_rules.h" #include "ui/wm/core/default_activation_client.h" +#include "ui/wm/core/focus_controller.h" namespace views { namespace { @@ -34,19 +37,50 @@ return static_cast<NativeWidgetAura*>(widget->native_widget()); } +// TestFocusRules is intended to provide a way to manually set a window's +// activatability so that the focus rules can be tested. +class TestFocusRules : public wm::BaseFocusRules { + public: + TestFocusRules() {} + ~TestFocusRules() override {} + + void set_can_activate(bool can_activate) { can_activate_ = can_activate; } + + // wm::BaseFocusRules overrides: + bool SupportsChildActivation(aura::Window* window) const override { + return true; + } + + bool CanActivateWindow(aura::Window* window) const override { + return can_activate_; + } + + private: + bool can_activate_ = true; + + DISALLOW_COPY_AND_ASSIGN(TestFocusRules); +}; + class NativeWidgetAuraTest : public aura::test::AuraTestBase { public: NativeWidgetAuraTest() {} ~NativeWidgetAuraTest() override {} + TestFocusRules* test_focus_rules() { return test_focus_rules_; } + // testing::Test overrides: void SetUp() override { AuraTestBase::SetUp(); - new wm::DefaultActivationClient(root_window()); + test_focus_rules_ = new TestFocusRules; + focus_controller_.reset(new wm::FocusController(test_focus_rules_)); + aura::client::SetActivationClient(root_window(), focus_controller_.get()); host()->SetBounds(gfx::Rect(640, 480)); } private: + scoped_ptr<wm::FocusController> focus_controller_; + TestFocusRules* test_focus_rules_; + DISALLOW_COPY_AND_ASSIGN(NativeWidgetAuraTest); }; @@ -485,5 +519,20 @@ widget->CloseNow(); } +// Tests that if a widget has a view which should be initially focused when the +// widget is shown, this view should not get focused if the associated window +// can not be activated. +TEST_F(NativeWidgetAuraTest, PreventFocusOnNonActivableWindow) { + test_focus_rules()->set_can_activate(false); + views::test::TestInitialFocusWidgetDelegate delegate(root_window()); + delegate.GetWidget()->Show(); + EXPECT_FALSE(delegate.view()->HasFocus()); + + test_focus_rules()->set_can_activate(true); + views::test::TestInitialFocusWidgetDelegate delegate2(root_window()); + delegate2.GetWidget()->Show(); + EXPECT_TRUE(delegate2.view()->HasFocus()); +} + } // namespace } // namespace views
diff --git a/ui/views/widget/widget.cc b/ui/views/widget/widget.cc index ffc5e0d..4c44b655 100644 --- a/ui/views/widget/widget.cc +++ b/ui/views/widget/widget.cc
@@ -1307,7 +1307,7 @@ show_state == ui::SHOW_STATE_MINIMIZED) { // If not focusing the window now, tell the focus manager which view to // focus when the window is restored. - if (v) + if (v && focus_manager_.get()) focus_manager_->SetStoredFocusView(v); return true; }
diff --git a/ui/views/widget/widget_interactive_uitest.cc b/ui/views/widget/widget_interactive_uitest.cc index d077c3d4..e9f9397 100644 --- a/ui/views/widget/widget_interactive_uitest.cc +++ b/ui/views/widget/widget_interactive_uitest.cc
@@ -1172,31 +1172,6 @@ RunPendingMessages(); } -// Testing widget delegate that creates a widget with a single view, which -// should be initially focused. -class TestInitialFocusWidgetDelegate : public TestDesktopWidgetDelegate { - public: - explicit TestInitialFocusWidgetDelegate(gfx::NativeWindow context) - : view_(new View) { - view_->SetFocusable(true); - - Widget::InitParams params(Widget::InitParams::TYPE_WINDOW); - params.context = context; - InitWidget(params); - GetWidget()->GetContentsView()->AddChildView(view_); - } - - View* view() { return view_; } - - // DialogDelegateView: - View* GetInitiallyFocusedView() override { return view_; } - - private: - View* view_; - - DISALLOW_COPY_AND_ASSIGN(TestInitialFocusWidgetDelegate); -}; - // Testing initial focus is assigned properly for normal top-level widgets, // and subclasses that specify a initially focused child view. TEST_F(WidgetTestInteractive, InitialFocus) {
diff --git a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js index e0b2415..9833a30 100644 --- a/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js +++ b/ui/webui/resources/cr_elements/cr_shared_menu/cr_shared_menu.js
@@ -11,6 +11,16 @@ value: false, reflectToAttribute: true }, + + /** + * The contextual item that this menu was clicked for. + * e.g. the data used to render an item in an <iron-list> or <dom-repeat> + * @type {?Object} + */ + itemData: { + type: Object, + value: null, + }, }, /** @@ -35,14 +45,17 @@ /** Closes the menu. */ closeMenu: function() { this.menuOpen = false; + this.itemData = null; }, /** * Opens the menu at the anchor location. * @param {!Element} anchor The location to display the menu. + * @param {!Object} itemData The contextual item's data. */ - openMenu: function(anchor) { + openMenu: function(anchor, itemData) { this.menuOpen = true; + this.itemData = itemData; this.lastAnchor_ = anchor; // Move the menu to the anchor. @@ -66,11 +79,12 @@ /** * Toggles the menu for the anchor that is passed in. * @param {!Element} anchor The location to display the menu. + * @param {!Object} itemData The contextual item's data. */ - toggleMenu: function(anchor) { + toggleMenu: function(anchor, itemData) { if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else - this.openMenu(anchor); + this.openMenu(anchor, itemData); }, });